diff --git a/.Rbuildignore b/.Rbuildignore index 3983c2b..d910125 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -9,6 +9,7 @@ src/libgwmodel/Doxygen\.zh-Hans src/libgwmodel/\.readthedocs\.yaml src/libgwmodel/test src/libgwmodel/docs +tests/others ^_pkgdown\.yml$ ^docs$ ^pkgdown$ diff --git a/.github/workflows/cran-check.yml b/.github/workflows/cran-check.yml index f6423b3..f042a2d 100644 --- a/.github/workflows/cran-check.yml +++ b/.github/workflows/cran-check.yml @@ -38,7 +38,7 @@ jobs: check-dir: '"check"' check_macos: - runs-on: macos-12 + runs-on: macos-14 steps: - name: Checkout uses: actions/checkout@v3 @@ -49,7 +49,9 @@ jobs: with: r-version: 'release' - name: Install Dependencies - run: brew install gsl pandoc + run: brew install gsl pandoc open-mpi + - name: Install Rmpi + run: Rscript -e 'install.packages("Rmpi", configure.args = c("--with-Rmpi-include=/opt/homebrew/include/", "--with-Rmpi-libpath=/opt/homebrew/lib/", "--with-Rmpi-type=OPENMPI"))' - name: Install R Dependencies uses: r-lib/actions/setup-r-dependencies@v2 with: diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 5242fe4..77c3671 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -34,7 +34,7 @@ jobs: - name: Install C++ dependencies run: | sudo apt-get update -qq - sudo apt-get install -qq libgsl-dev + sudo apt-get install -qq libgsl-dev libopenmpi-dev - name: Set up R uses: r-lib/actions/setup-r@v2 diff --git a/.gitignore b/.gitignore index f7fcd1b..96e8e71 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,5 @@ docs /doc/ /Meta/ *.lib +*.log +*.out diff --git a/DESCRIPTION b/DESCRIPTION index ae8fe41..0bbdf90 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -47,6 +47,7 @@ RoxygenNote: 7.2.3 Suggests: testthat (>= 3.0.0), knitr, - rmarkdown + rmarkdown, + Rmpi Config/testthat/edition: 3 VignetteBuilder: knitr diff --git a/R/gwr_basic.R b/R/gwr_basic.R index b5a48c2..05f4efb 100644 --- a/R/gwr_basic.R +++ b/R/gwr_basic.R @@ -67,6 +67,15 @@ gwr_basic <- function( kernel = match.arg(kernel) parallel_method = match.arg(parallel_method) attr(data, "na.action") <- getOption("na.action") + is_mpi_workers <- F + if (is.loaded("mpi_initialize")) { + if (requireNamespace("Rmpi", quietly = TRUE)) { + if (Rmpi::mpi.comm.size(0) > 1) { + parallel_method <- paste0("mpi.", parallel_method) + is_mpi_workers <- Rmpi::mpi.comm.rank(0) > 0 + } + } + } ### Extract coords data <- do.call(na.action(data), args = list(data)) @@ -116,6 +125,11 @@ gwr_basic <- function( ), error = function (e) { stop("Error:", conditionMessage(e)) }) + + if (is_mpi_workers) { + return(NULL) + } + if (optim_bw) bw <- c_result$bandwidth betas <- c_result$betas diff --git a/R/gwr_multiscale.R b/R/gwr_multiscale.R index 9b6b5e5..3fbbda5 100644 --- a/R/gwr_multiscale.R +++ b/R/gwr_multiscale.R @@ -115,6 +115,15 @@ gwr_multiscale <- function( parallel_method <- match.arg(parallel_method) criterion <- match.arg(criterion) attr(data, "na.action") <- getOption("na.action") + is_mpi_workers <- F + if (is.loaded("mpi_initialize")) { + if (requireNamespace("Rmpi", quietly = TRUE)) { + if (Rmpi::mpi.comm.size(0) > 1) { + parallel_method <- paste0("mpi.", parallel_method) + is_mpi_workers <- Rmpi::mpi.comm.rank(0) > 0 + } + } + } ### Extract coords data <- do.call(na.action(data), args = list(data)) @@ -216,6 +225,10 @@ gwr_multiscale <- function( ), error = function (e) { stop("Error:", conditionMessage(e)) }) + if (is_mpi_workers) { + return(NULL) + } + bw_value <- c_result$bw_value betas <- c_result$betas fitted <- c_result$fitted diff --git a/R/utils.R b/R/utils.R index 7aa335f..8570665 100644 --- a/R/utils.R +++ b/R/utils.R @@ -172,10 +172,12 @@ enum_list <- function(x, labels, default = labels[[1]]) { } parallel_types <- list( - "none" = 1, + "no" = 1, "omp" = 2, "cuda" = 4, - "cluster" = 8 + "mpi.no" = 9, + "mpi.omp" = 10, + "mpi.cuda" = 12 ) kernel_enums <- c("gaussian", "exp", "bisquare", "tricube", "boxcar") diff --git a/configure b/configure index 614a79f..b3062d9 100755 --- a/configure +++ b/configure @@ -1,9 +1,9 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for GWmodel3 0.2-2. +# Generated by GNU Autoconf 2.72 for GWmodel3 0.2-2. # # -# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # @@ -15,7 +15,6 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -24,12 +23,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -101,7 +101,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -131,15 +131,14 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="as_nop=: -if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: @@ -147,12 +146,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else \$as_nop - case \`(set -o) 2>/dev/null\` in #( +else case e in #( + e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi " @@ -170,8 +170,9 @@ as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : -else \$as_nop - exitcode=1; echo positional parameters were not saved. +else case e in #( + e) exitcode=1; echo positional parameters were not saved. ;; +esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) @@ -184,14 +185,15 @@ test -x / || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes -else $as_nop - as_have_required=no +else case e in #( + e) as_have_required=no ;; +esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do @@ -224,12 +226,13 @@ IFS=$as_save_IFS if $as_found then : -else $as_nop - if { test -f "$SHELL" || test -f "$SHELL.exe"; } && +else case e in #( + e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes -fi +fi ;; +esac fi @@ -251,7 +254,7 @@ case $- in # (((( esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. +# out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi @@ -270,7 +273,8 @@ $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 -fi +fi ;; +esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} @@ -309,14 +313,6 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -385,11 +381,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -403,21 +400,14 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -491,6 +481,8 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits /[$]LINENO/= ' <$as_myself | sed ' + t clear + :clear s/[$]LINENO.*/&-/ t lineno b @@ -539,7 +531,6 @@ esac as_echo='printf %s\n' as_echo_n='printf %s' - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -551,9 +542,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -578,10 +569,12 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 /dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -825,7 +823,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1038,7 +1036,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1054,7 +1052,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1084,8 +1082,8 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" + -*) as_fn_error $? "unrecognized option: '$ac_option' +Try '$0 --help' for more information" ;; *=*) @@ -1093,7 +1091,7 @@ Try \`$0 --help' for more information" # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1143,7 +1141,7 @@ do as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done -# There might be people who depend on the old broken behavior: `$host' +# There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias @@ -1211,7 +1209,7 @@ if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` @@ -1239,7 +1237,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 GWmodel3 0.2-2 to adapt to many kinds of systems. +'configure' configures GWmodel3 0.2-2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1253,11 +1251,11 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages + -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' + -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] + --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -1265,10 +1263,10 @@ Installation directories: --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. +By default, 'make install' will install all the files in +'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify +an installation prefix other than '$ac_default_prefix' using '--prefix', +for instance '--prefix=\$HOME'. For better control, use the options below. @@ -1310,6 +1308,7 @@ Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-cuda install cuda (default no) + --enable-mpi install mpi (default no) --disable-openmp do not use OpenMP Some influential environment variables: @@ -1322,7 +1321,7 @@ Some influential environment variables: you have headers in a nonstandard directory CXXCPP C++ preprocessor -Use these variables to override the choices made by `configure' or to help +Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. @@ -1390,9 +1389,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF GWmodel3 configure 0.2-2 -generated by GNU Autoconf 2.71 +generated by GNU Autoconf 2.72 -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1431,11 +1430,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -1469,11 +1469,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -1511,11 +1512,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would @@ -1551,7 +1553,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by GWmodel3 $as_me 0.2-2, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -1797,10 +1799,10 @@ esac printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } fi done @@ -2047,12 +2049,12 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) @@ -2061,18 +2063,18 @@ printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. @@ -2088,11 +2090,11 @@ printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi done if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## @@ -2138,8 +2140,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CXX"; then +else case e in #( + e) if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2161,7 +2163,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then @@ -2187,8 +2190,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CXX"; then +else case e in #( + e) if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -2210,7 +2213,8 @@ done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then @@ -2310,8 +2314,8 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' + # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. +# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. @@ -2331,7 +2335,7 @@ do ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' + # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. @@ -2342,8 +2346,9 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else $as_nop - ac_file='' +else case e in #( + e) ac_file='' ;; +esac fi if test -z "$ac_file" then : @@ -2352,13 +2357,14 @@ printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 printf %s "checking for C++ compiler default output file name... " >&6; } @@ -2382,10 +2388,10 @@ printf "%s\n" "$ac_try_echo"; } >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. + # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) +# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will +# work properly (i.e., refer to 'conftest.exe'), while it won't with +# 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in @@ -2395,11 +2401,12 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -2415,6 +2422,8 @@ int main (void) { FILE *f = fopen ("conftest.out", "w"); + if (!f) + return 1; return ferror (f) || fclose (f) != 0; ; @@ -2454,26 +2463,27 @@ printf "%s\n" "$ac_try_echo"; } >&5 if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C++ compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } +If you meant to cross compile, use '--host'. +See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +rm -f conftest.$ac_ext conftest$ac_cv_exeext \ + conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2505,16 +2515,18 @@ then : break;; esac done -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext +rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } @@ -2525,8 +2537,8 @@ printf %s "checking whether the compiler supports GNU C++... " >&6; } if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2543,12 +2555,14 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } @@ -2566,8 +2580,8 @@ printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_cxx_werror_flag=$ac_cxx_werror_flag +else case e in #( + e) ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" @@ -2585,8 +2599,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes -else $as_nop - CXXFLAGS="" +else case e in #( + e) CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -2601,8 +2615,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : -else $as_nop - ac_cxx_werror_flag=$ac_save_cxx_werror_flag +else case e in #( + e) ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -2619,12 +2633,15 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag + ac_cxx_werror_flag=$ac_save_cxx_werror_flag ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } @@ -2648,11 +2665,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} +if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_11=no +else case e in #( + e) ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -2669,36 +2686,39 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext -CXX=$ac_save_CXX +CXX=$ac_save_CXX ;; +esac fi if test "x$ac_cv_prog_cxx_cxx11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx11" = x +else case e in #( + e) if test "x$ac_cv_prog_cxx_cxx11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx11" + CXX="$CXX $ac_cv_prog_cxx_cxx11" ;; +esac fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 - ac_prog_cxx_stdcxx=cxx11 + ac_prog_cxx_stdcxx=cxx11 ;; +esac fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} +if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_98=no +else case e in #( + e) ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -2715,25 +2735,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext -CXX=$ac_save_CXX +CXX=$ac_save_CXX ;; +esac fi if test "x$ac_cv_prog_cxx_cxx98" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx98" = x +else case e in #( + e) if test "x$ac_cv_prog_cxx_cxx98" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx98" + CXX="$CXX $ac_cv_prog_cxx_cxx98" ;; +esac fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 - ac_prog_cxx_stdcxx=cxx98 + ac_prog_cxx_stdcxx=cxx98 ;; +esac fi fi @@ -2755,8 +2778,8 @@ if test -z "$CXXCPP"; then if test ${ac_cv_prog_CXXCPP+y} then : printf %s "(cached) " >&6 -else $as_nop - # Double quotes because $CXX needs to be expanded +else case e in #( + e) # Double quotes because $CXX needs to be expanded for CXXCPP in "$CXX -E" cpp /lib/cpp do ac_preproc_ok=false @@ -2774,9 +2797,10 @@ _ACEOF if ac_fn_cxx_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -2790,15 +2814,16 @@ if ac_fn_cxx_try_cpp "$LINENO" then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : @@ -2807,7 +2832,8 @@ fi done ac_cv_prog_CXXCPP=$CXXCPP - + ;; +esac fi CXXCPP=$ac_cv_prog_CXXCPP else @@ -2830,9 +2856,10 @@ _ACEOF if ac_fn_cxx_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -2846,24 +2873,26 @@ if ac_fn_cxx_try_cpp "$LINENO" then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi ac_ext=cpp @@ -2882,8 +2911,8 @@ printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_GSL_CONFIG+y} then : printf %s "(cached) " >&6 -else $as_nop - case $GSL_CONFIG in +else case e in #( + e) case $GSL_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_GSL_CONFIG="$GSL_CONFIG" # Let the user override the test with a path. ;; @@ -2908,6 +2937,7 @@ done IFS=$as_save_IFS ;; +esac ;; esac fi GSL_CONFIG=$ac_cv_path_GSL_CONFIG @@ -2966,20 +2996,21 @@ printf "%s\n" "\"using CUDA_HOME=${CUDA_HOME}\"" >&6; } if test ${ENABLE_CUDA} -eq 1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking \"whether this is the 64 bit linux version of CUDA\"" >&5 printf %s "checking \"whether this is the 64 bit linux version of CUDA\"... " >&6; } - as_ac_File=`printf "%s\n" "ac_cv_file_${CUDA_HOME}/lib64/libcudart.so" | $as_tr_sh` + as_ac_File=`printf "%s\n" "ac_cv_file_${CUDA_HOME}/lib64/libcudart.so" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${CUDA_HOME}/lib64/libcudart.so" >&5 printf %s "checking for ${CUDA_HOME}/lib64/libcudart.so... " >&6; } if eval test \${$as_ac_File+y} then : printf %s "(cached) " >&6 -else $as_nop - test "$cross_compiling" = yes && +else case e in #( + e) test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "${CUDA_HOME}/lib64/libcudart.so"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" -fi +fi ;; +esac fi eval ac_res=\$$as_ac_File { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 @@ -3038,6 +3069,73 @@ NVCC="${CUDA_HOME}/bin/nvcc" printf "%s\n" "building the cuda include path" >&6; } CUDA_INCL="${CUDA_HOME}/include" +ENABLE_MPI=0 +# Check whether --enable-mpi was given. +if test ${enable_mpi+y} +then : + enableval=$enable_mpi; case "${enableval}" in + yes) ENABLE_MPI=1 ;; + no) ENABLE_MPI=0 ;; + *) as_fn_error $? "bad value ${enableval} for --enable-mpi" "$LINENO" 5 ;; +esac +fi + + +if test ${ENABLE_MPI} -eq 1; then + # Extract the first word of "mpicc", so it can be a program name with args. +set dummy mpicc; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_MPICC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) case $MPICC in + [\\/]* | ?:[\\/]*) + ac_cv_path_MPICC="$MPICC" # 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + 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_MPICC="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac ;; +esac +fi +MPICC=$ac_cv_path_MPICC +if test -n "$MPICC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MPICC" >&5 +printf "%s\n" "$MPICC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + + if test "${MPICC}" != ""; then + MPI_CFLAGS=`${MPICC} -showme:compile` + MPI_LIBS=`${MPICC} -showme:link` + else + as_fn_error $? "mpicc not found, is MPI installed?" "$LINENO" 5 + fi +fi GWmodel_CUDA_LIB_PATH="~/.cache/GWmodel" @@ -3051,6 +3149,9 @@ printf "%s\n" "$as_me: Building Makevars" >&6;} + + + ac_config_files="$ac_config_files src/Makevars" if test -e penmp || test -e mp; then @@ -3069,8 +3170,8 @@ printf %s "checking for $CXX option to support OpenMP... " >&6; } if test ${ac_cv_prog_cxx_openmp+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_openmp='not found' +else case e in #( + e) ac_cv_prog_cxx_openmp='not found' for ac_option in '' -fopenmp -xopenmp -openmp -mp -omp -qsmp=omp -homp \ -Popenmp --openmp; do @@ -3101,8 +3202,9 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : ac_cv_prog_cxx_openmp=$ac_option -else $as_nop - ac_cv_prog_cxx_openmp='unsupported' +else case e in #( + e) ac_cv_prog_cxx_openmp='unsupported' ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -3119,7 +3221,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext elif test "$ac_cv_prog_cxx_openmp" = ''; then ac_cv_prog_cxx_openmp='none needed' fi - rm -f penmp mp + rm -f penmp mp ;; +esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_openmp" >&5 printf "%s\n" "$ac_cv_prog_cxx_openmp" >&6; } @@ -3140,8 +3243,8 @@ cat >confcache <<\_ACEOF # 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 +# '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 @@ -3171,14 +3274,14 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} (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 + # '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. + # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | @@ -3242,9 +3345,7 @@ s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote -s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g -s/\[/\\&/g -s/\]/\\&/g +s/[][ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\$/$$/g H :any @@ -3304,7 +3405,6 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh @@ -3313,12 +3413,13 @@ then : # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -3390,7 +3491,7 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 @@ -3419,7 +3520,6 @@ as_fn_error () } # as_fn_error - # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -3459,11 +3559,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -3477,11 +3578,12 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith @@ -3564,9 +3666,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -3647,10 +3749,12 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 @@ -3666,7 +3770,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by GWmodel3 $as_me 0.2-2, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -3693,7 +3797,7 @@ _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions +'$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. @@ -3721,10 +3825,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ GWmodel3 config.status 0.2-2 -configured by $0, generated by GNU Autoconf 2.71, +configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -3781,8 +3885,8 @@ do ac_cs_silent=: ;; # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; + -*) as_fn_error $? "unrecognized option: '$1' +Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; @@ -3832,7 +3936,7 @@ do case $ac_config_target in "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done @@ -3850,7 +3954,7 @@ fi # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. +# after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= @@ -3874,7 +3978,7 @@ ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. +# This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then @@ -4040,7 +4144,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -4062,19 +4166,19 @@ do -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. + # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done - # Let's still pretend it is `configure' which instantiates (i.e., don't + # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` @@ -4198,7 +4302,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 esac _ACEOF -# Neutralize VPATH when `$srcdir' = `.'. +# Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 @@ -4227,9 +4331,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" diff --git a/configure.ac b/configure.ac index 911bdb6..7555bff 100644 --- a/configure.ac +++ b/configure.ac @@ -84,6 +84,24 @@ NVCC="${CUDA_HOME}/bin/nvcc" AC_MSG_RESULT(building the cuda include path) CUDA_INCL="${CUDA_HOME}/include" +ENABLE_MPI=0 +AC_ARG_ENABLE([mpi], [AS_HELP_STRING([--enable-mpi],[install mpi (default no)])], +[ case "${enableval}" in + yes) ENABLE_MPI=1 ;; + no) ENABLE_MPI=0 ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-mpi) ;; +esac]) + +if test ${ENABLE_MPI} -eq 1; then + AC_PATH_PROG([MPICC], [mpicc]) + + if test "${MPICC}" != ""; then + MPI_CFLAGS=`${MPICC} -showme:compile` + MPI_LIBS=`${MPICC} -showme:link` + else + AC_MSG_ERROR([mpicc not found, is MPI installed?]) + fi +fi AC_SUBST(GWmodel_CUDA_LIB_PATH,["~/.cache/GWmodel"]) @@ -94,6 +112,9 @@ AC_SUBST(NVCC) AC_SUBST(PKG_LIBS) AC_SUBST(CUDA_INCL) AC_SUBST(ENABLE_CUDA) +AC_SUBST(ENABLE_MPI) +AC_SUBST(MPI_CFLAGS) +AC_SUBST(MPI_LIBS) AC_CONFIG_FILES([src/Makevars]) AC_OPENMP diff --git a/src/Makevars.in b/src/Makevars.in index 17eacae..3f32023 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -102,6 +102,17 @@ OBJECTS_CUDA_CXX = endif ### [End] +### [Begin] Configure MPI +ENABLE_MPI = @ENABLE_MPI@ +ifeq ($(ENABLE_MPI),1) +MPI_CFLAGS = @MPI_CFLAGS@ +MPI_LIBS = @MPI_LIBS@ +PKG_CXXFLAGS += ${MPI_CFLAGS} -DENABLE_MPI +PKG_LIBS += ${MPI_LIBS} +OBJECTS_CXX += libgwmodel/src/gwmodelpp/utils/armampi.o +endif +### [End] + OBJECTS = ${OBJECTS_CUDA_CU} ${OBJECTS_CUDA_CXX} ${OBJECTS_CXX} .PHONY: all clean diff --git a/src/Makevars.win b/src/Makevars.win index 32f2be8..8d0a6d0 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -78,5 +78,14 @@ endif endif ### [End] +### [Begin] Configure MPI +MPI_ENABLED = ${ENABLE_MPI} +ifeq ($(MPI_ENABLED),1) +PKG_CXXFLAGS += -DENABLE_MPI +PKG_LIBS += -lmsmpi +OBJECTS_LIBGWMODEL += libgwmodel/src/gwmodelpp/utils/armampi.o +endif +### [End] + OBJECTS = $(OBJECTS_LIBGWMODEL) $(OBJECTS_TELEGRAM) $(OBJECTS_GWMODEL) diff --git a/src/gwr_basic.cpp b/src/gwr_basic.cpp index ca61203..0a67bac 100644 --- a/src/gwr_basic.cpp +++ b/src/gwr_basic.cpp @@ -8,6 +8,10 @@ #include "gwmodelcuda/IGWRBasicGpuTask.h" #endif // ENABLE_CUDA_SHARED +#ifdef ENABLE_MPI +#include "mpi.h" +#endif // ENABLE_MPI + using namespace std; using namespace Rcpp; using namespace arma; @@ -80,6 +84,14 @@ int verbose } #endif // ENABLE_CUDA_SHARED + MYMPI_COMM_INFO_DECL +#ifdef ENABLE_MPI + if (parallel_type & ParallelType::MPI) + { + MYMPI_COMM_INFO_GET + } +#endif // ENABLE_MPI + // Make Spatial Weight BandwidthWeight bandwidth(bw, adaptive, BandwidthWeight::KernelFunctionType((size_t)kernel)); Distance* distance = nullptr; @@ -110,32 +122,50 @@ int verbose algorithm.setGoldenLowerBounds(optim_bw_lower); if (optim_bw_upper < R_PosInf) algorithm.setGoldenUpperBounds(optim_bw_upper); - switch (ParallelType(size_t(parallel_type))) + algorithm.setParallelType(ParallelType(parallel_type)); + switch (algorithm.parallelType()) { case ParallelType::SerialOnly: - algorithm.setParallelType(ParallelType::SerialOnly); +#ifdef ENABLE_MPI + case ParallelType::MPI_Serial: +#endif // ENABLE_MPI break; -#ifdef _OPENMP case ParallelType::OpenMP: - algorithm.setParallelType(ParallelType::OpenMP); +#ifdef ENABLE_MPI + case ParallelType::MPI_MP: +#endif // ENABLE_MPI +#ifdef _OPENMP algorithm.setOmpThreadNum(vpar_args[0]); break; +#else + throw std::logic_error("OpenMP method not implemented."); #endif case ParallelType::CUDA: +#ifdef ENABLE_MPI + case ParallelType::MPI_CUDA: +#endif // ENABLE_MPI #ifdef ENABLE_CUDA if (vpar_args.size() < 2) throw std::length_error("CUDA parallelisation needs two parallel args."); - algorithm.setParallelType(ParallelType::CUDA); algorithm.setGPUId(vpar_args[0]); algorithm.setGroupSize(vpar_args[1]); #else // ENABLE_CUDA throw std::logic_error("Method not implemented."); #endif // ENABLE_CUDA default: - algorithm.setParallelType(ParallelType::SerialOnly); break; } +#ifdef ENABLE_MPI + if (algorithm.parallelType() & ParallelType::MPI) + { + Rcout << "MPI mode\n"; + algorithm.setWorkerId(iProcess); + algorithm.setWorkerNum(nProcess); + } +#endif // ENABLE_MPI + MYMPI_MASTER_BEGIN if (verbose) algorithm.setTelegram(make_unique(algorithm, as>(variable_names), verbose)); + MYMPI_MASTER_END try { algorithm.fit(); @@ -146,8 +176,11 @@ int verbose } // Return Results + List result_list; + + MYMPI_MASTER_BEGIN mat betas = algorithm.betas(); - List result_list = List::create( + result_list = List::create( Named("betas") = betas, Named("betasSE") = algorithm.betasSE(), Named("sTrace") = algorithm.sHat(), @@ -171,6 +204,10 @@ int verbose { result_list["fitted"] = GWRBasic::Fitted(x, betas); } + MYMPI_MASTER_END + + if (parallel_type & ParallelType::MPI) + result_list["mpi_rank"] = iProcess; return result_list; } diff --git a/src/gwr_multiscale.cpp b/src/gwr_multiscale.cpp index 0354b9c..63485a2 100644 --- a/src/gwr_multiscale.cpp +++ b/src/gwr_multiscale.cpp @@ -4,6 +4,10 @@ #include "gwmodel.h" #include "telegrams/GWRMultiscaleTelegram.h" +#ifdef ENABLE_MPI +#include +#endif // ENABLE_MPI + using namespace std; using namespace Rcpp; using namespace arma; @@ -91,25 +95,44 @@ List gwr_multiscale_fit ( algorithm.setHasHatMatrix(hatmatrix); algorithm.setBandwidthSelectRetryTimes(retry_times); algorithm.setMaxIteration(max_iterations); + algorithm.setParallelType(ParallelType(parallel_type)); switch (ParallelType(size_t(parallel_type))) { - case ParallelType::SerialOnly: - algorithm.setParallelType(ParallelType::SerialOnly); - break; -#ifdef _OPENMP case ParallelType::OpenMP: +#ifdef ENABLE_MPI + case ParallelType::MPI_MP: +#endif // ENABLE_MPI +#ifdef _OPENMP algorithm.setParallelType(ParallelType::OpenMP); algorithm.setOmpThreadNum(vpar_args[0]); break; +#else + throw std::logic_error("OpenMP method not implemented."); #endif default: - algorithm.setParallelType(ParallelType::SerialOnly); break; } + + MYMPI_COMM_INFO_DECL +#ifdef ENABLE_MPI + if (algorithm.parallelType() & ParallelType::MPI) + { + MYMPI_COMM_INFO_GET + algorithm.setWorkerId(iProcess); + algorithm.setWorkerNum(nProcess); + MYMPI_MASTER_BEGIN + Rcout << "* MPI mode\n"; + MYMPI_MASTER_END + } +#endif // ENABLE_MPI + + MYMPI_MASTER_BEGIN if (verbose > 0) { algorithm.setTelegram(make_unique(algorithm, as>(variable_names), verbose)); } + MYMPI_MASTER_END + try { algorithm.fit(); @@ -118,7 +141,10 @@ List gwr_multiscale_fit ( { stop(e.what()); } + + List result_list; + MYMPI_MASTER_BEGIN // Get bandwidth vector bw_value; const vector& spatialWeights = algorithm.spatialWeights(); @@ -130,12 +156,18 @@ List gwr_multiscale_fit ( // Return Results mat betas = algorithm.betas(); vec fitted = sum(x % betas, 1); - List result_list = List::create( + result_list = List::create( Named("betas") = betas, Named("diagnostic") = mywrap(algorithm.diagnostic()), Named("bw_value") = wrap(bw_value), Named("fitted") = fitted ); + MYMPI_MASTER_END + +#ifdef ENABLE_MPI + if (parallel_type & ParallelType::MPI) + result_list["mpi_rank"] = iProcess; +#endif // ENABLE_MPI return result_list; } diff --git a/src/libgwmodel b/src/libgwmodel index 56b31b2..00110f7 160000 --- a/src/libgwmodel +++ b/src/libgwmodel @@ -1 +1 @@ -Subproject commit 56b31b280ff044f7ad4d6a1e0604e6477e754607 +Subproject commit 00110f7733765749c825c709cca4fed31f8397ec diff --git a/src/utils.h b/src/utils.h index e668844..37274da 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,3 +5,20 @@ Rcpp::List mywrap(const gwm::RegressionDiagnostic& diagnostic); Rcpp::List mywrap(const gwm::VariablesCriterionList& criterion_list); + +#define MYMPI_COMM_INFO_DECL \ + int iProcess = 0, nProcess = 1; + +#define MYMPI_COMM_INFO_GET \ + MPI_Comm_rank(MPI_COMM_WORLD, &iProcess); \ + MPI_Comm_size(MPI_COMM_WORLD, &nProcess); + +#define MYMPI_MASTER_BEGIN \ + if (iProcess == 0) { + +#define MYMPI_MASTER_END } + +#define MYMPI_WORKER_BEGIN \ + if (nProcess == 0) { + +#define MYMPI_WORKER_END } diff --git a/tests/others/cuda-gwr_basic.R b/tests/others/cuda-gwr_basic.R new file mode 100644 index 0000000..d325da6 --- /dev/null +++ b/tests/others/cuda-gwr_basic.R @@ -0,0 +1,5 @@ +library(sf) +library(GWmodel3, lib.loc = "../../../Rlibrary.tmp") +data(wuhan.hp, package = "hgwrr") +whhp <- with(wuhan.hp, sf::st_as_sf(data, coords = c("lon", "lat"))) +gwr_basic(Price ~ d.PrimarySchool + BuildingArea + Fee, whhp, bw = 64, parallel_method = "cuda", parallel_arg = c(0, 64)) \ No newline at end of file diff --git a/tests/others/mpi-gwr_basic.R b/tests/others/mpi-gwr_basic.R new file mode 100644 index 0000000..7dabe5c --- /dev/null +++ b/tests/others/mpi-gwr_basic.R @@ -0,0 +1,8 @@ +library(sf) +library(GWmodel3, lib.loc = "../../../Rlibrary.tmp") +library(Rmpi) +# data(LondonHP) +# gwr_basic(PURCHASE~FLOORSZ+UNEMPLOY, LondonHP, 64, TRUE, verbose = 2) +data(wuhan.hp, package = "hgwrr") +gwr_basic(Price ~ d.PrimarySchool + BuildingArea + Fee, wuhan.hp, bw = 512, adaptive = T, verbose = 2, optim_bw_range = c(256, Inf)) +invisible(mpi.finalize()) \ No newline at end of file diff --git a/tests/others/mpi-gwr_multiscale.R b/tests/others/mpi-gwr_multiscale.R new file mode 100644 index 0000000..40597f7 --- /dev/null +++ b/tests/others/mpi-gwr_multiscale.R @@ -0,0 +1,8 @@ +library(sf) +library(GWmodel3, lib.loc = "../../../Rlibrary.tmp") +library(Rmpi) +# data(LondonHP) +# gwr_basic(PURCHASE~FLOORSZ+UNEMPLOY, LondonHP, 64, TRUE, verbose = 2) +data(wuhan.hp, package = "hgwrr") +gwr_multiscale(Price ~ d.PrimarySchool + BuildingArea + Fee, wuhan.hp, config = list(mgwr_config(adaptive = T)), optim_bw_range = c(256, Inf)) +invisible(mpi.finalize()) \ No newline at end of file diff --git a/tests/testthat/test-gwr_basic.R b/tests/testthat/test-gwr_basic.R index 1e9439d..d5213e9 100644 --- a/tests/testthat/test-gwr_basic.R +++ b/tests/testthat/test-gwr_basic.R @@ -67,15 +67,10 @@ test_that("Basic GWR: CUDA", { test_that("Basic GWR: CUDA for Windows development", { skip("This test case is only used for development on Windows") - library(GWmodel3, lib.loc = "../Rlibrary.tmp") + library(GWmodel3, lib.loc = "../../../Rlibrary.tmp") data(LondonHP) expect_no_error({ m_cuda <- gwr_basic(PURCHASE~FLOORSZ+UNEMPLOY, LondonHP, 64, TRUE, parallel_method = "cuda", parallel_arg = c(0, 64), verbose = 1) predict(m_cuda, LondonHP, verbose = 1) }) - expect_no_error({ - data(wuhan.hp, package = "hgwrr") - whhp <- with(wuhan.hp, sf::st_as_sf(data, coords = c("lon", "lat"))) - gwr_basic(Price ~ d.PrimarySchool + BuildingArea + Fee, whhp, bw = 64, parallel_method = "cuda", parallel_arg = c(0, 64)) - }) }) diff --git a/vignettes/other-01-hpc.Rmd b/vignettes/other-01-hpc.Rmd index cd3e09c..6be5490 100644 --- a/vignettes/other-01-hpc.Rmd +++ b/vignettes/other-01-hpc.Rmd @@ -19,30 +19,32 @@ To solve this problem, this package provided some techniques to speed up the com - Multithreading based on OpenMP - GPU comoputing based on NVIDIA CUDA computing toolkit +- Multiprocessing based on MPI Currently, almost all algorithms have a serial implementation and one or two high-performance implementation. -| Algorithm | Multithreading | GPU computing | -| -------------- | -------------- | ------------- | -| Basic GWR | o | o | -| Multiscale GWR | o | | -| GWDR | o | | +| Algorithm | Multithreading | GPU computing | Multiprocessing | +| -------------- | -------------- | ------------- | --------------- | +| Basic GWR | o | o | o | +| Multiscale GWR | o | | o | +| GWDR | o | | | -All the parallelizable algorithms take two parameters to control parallelization: `parallel_method` and `parallel_arg`. +The multithreading- and GPU- parallelization algorithms take two parameters to control parallelization: `parallel_method` and `parallel_arg`. The `parallel_method` is used to pick a high-performance implementation. The valid options are `"omp"` and `"cuda"`, representing multithreading and GPU computing respectively. The `parallel_arg` is used to pass arguments. Different parallel methods needs different arguments. +For the multiprocessing parallelization, please see below for further details. -However, not all platform support both techniques, and some platform may have limited performance. +However, not all platform support all the techniques, and some platform may have limited performance. When users choosed unsupported method, it will fall back to the serial implementation. Please refer to the table below for additional information regarding platform support. -| Platform | Multithreading | GPU computing | -| ---------------------- | -------------- | ------------- | -| Windows | o | o\* | -| macOS (Apple Sillicon) | | | -| Linux | o | o | +| Platform | Multithreading | GPU computing | Multiprocessing | +| ---------------------- | -------------- | ------------- | --------------- | +| Windows | o | o\* | o | +| macOS (Apple Sillicon) | | | o | +| Linux | o | o | o | \*On Windows, GPU computing is supported through an additional library called "GWmodelCUDA", which is built with MSVC. This is because CUDA does not support the MinGW compiler, which is used to compile R packages. @@ -136,3 +138,69 @@ remotes::install_github("GWmodel-Lab/GWmodel3", build_opts = c("--configure-args ``` Before installing the package, make sure that the environment variable `CUDA_HOME` is defined as the path to the CUDA toolkit. + +# Multiprocessing + +The multiprocessing parallel is implemented by the Message Passing Interface (MPI). +To use enable the paralleling, we need to install an implementation of MPI and [**Rmpi**](https://cran.r-project.org/web/packages/Rmpi/). +Please follow the instructions on the [official site](https://fisher.stats.uwo.ca/faculty/yu/Rmpi/) to install the package. + +## Install + +### Linux + +Available implementations of MPI are: + +- [OpenMPI](https://www.open-mpi.org/) +- [MPICH](https://www.mpich.org/) + +After cloning the source package, install this package with the following script. + +```bash +R CMD INSTALL GWmodel3 --configure-args=--enable-mpi=yes +``` + +### Windows + +Available implementations of MPI are: + +- [Microsoft MPI](https://learn.microsoft.com/en-us/message-passing-interface/microsoft-mpi) + +Then set a environment `ENABLE_MPI=1`, and use the following script to install the package. + +```powershell +R.exe CMD INSTALL GWmodel3 +``` + +## Usage + +Note that programs running with MPI parallel processing execute the same script in each process, unlike the multi-session parallelism provided by the **parallel** package. +When we are writing an R script to be paralleled by MPI, it is targeted to configure one process of the cluster. +For example, the following script let every process use the serial algorithm to fit the GWR model and set the bandwidth to 64 nearest neighbours. + +```r +# test.R +library(sf) +library(Rmpi) +library(GWmodel3) +data(LondonHP) +gwr_basic( + formula = PURCHASE ~ FLOORSZ + UNEMPLOY + PROF, + data = LondonHP, + bw = 64, + adaptive = TRUE +) +invisible(mpi.finalize()) +``` + +If we save the script to file `test.R`, we can run it by 4 processes with the following script. + +```bash +mpiexec -np 4 Rscript test.R +``` + +The number `4` can be changed to other numbers of processes. +In this case, all the processes run on the same machine. + +To run scripts on a high-performance cluster using MPI, a scheduler that supports MPI, such as Slurm, is required. +The specific method for execution should be referenced from the scheduler's documentation.