diff --git a/include/galsim/Std.h b/include/galsim/Std.h index a149800e92..6d38a74482 100644 --- a/include/galsim/Std.h +++ b/include/galsim/Std.h @@ -47,6 +47,12 @@ #include #ifdef _WIN32 +// Suppress Windows.h's ``min``/``max`` macros which clash with std::min/std::max +// (and Eigen's templated members). Set this before the include even though the +// MSVC build also passes ``/DNOMINMAX`` -- belt and suspenders for direct includes. +#ifndef NOMINMAX +#define NOMINMAX +#endif #include #else #include diff --git a/include/galsim/Stopwatch.h b/include/galsim/Stopwatch.h index efd062d20b..19b5c9c189 100644 --- a/include/galsim/Stopwatch.h +++ b/include/galsim/Stopwatch.h @@ -20,31 +20,31 @@ #ifndef GalSim_Stopwatch_H #define GalSim_Stopwatch_H -#include +#include namespace galsim { class Stopwatch { private: + typedef std::chrono::steady_clock clock_type; double seconds; - struct timeval tpStart; + clock_type::time_point tpStart; bool running; public: Stopwatch() : seconds(0.), running(false) {} - void start() { gettimeofday(&tpStart, NULL); running=true; } + void start() { tpStart = clock_type::now(); running = true; } void stop() { if (!running) return; - struct timeval tp; - gettimeofday(&tp, NULL); - seconds += (tp.tv_sec - tpStart.tv_sec) - + 1e-6*(tp.tv_usec - tpStart.tv_usec); + auto tp = clock_type::now(); + std::chrono::duration dt = tp - tpStart; + seconds += dt.count(); running = false; } - void reset() { seconds=0.; running=false; } + void reset() { seconds = 0.; running = false; } operator double() const { return seconds; } }; diff --git a/setup.py b/setup.py index 05d7a16a98..0882fc9af4 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,6 @@ from setuptools.command.install import install from setuptools.command.install_scripts import install_scripts from setuptools.command.easy_install import easy_install - from setuptools.command.test import test import setuptools print("Using setuptools version",setuptools.__version__) except ImportError: @@ -45,6 +44,14 @@ print() raise +# setuptools.command.test was removed in setuptools 72.0.0; tolerate its absence. +try: + from setuptools.command.test import test # noqa: F401 +except ImportError: + pass + +IS_WINDOWS = sys.platform == 'win32' + # Turn this on for more verbose debugging output about compile attempts. debug = False @@ -85,6 +92,8 @@ def all_files_from(dir, ext=''): '-Wno-openmp-mapping','-Wno-unknown-cuda-version', '-Wno-shorten-64-to-32','-fvisibility=hidden', '-DGALSIM_USE_GPU'], 'nvc++' : ['-O2','-std=c++14','-mp=gpu','-DGALSIM_USE_GPU'], + 'msvc' : ['/O2', '/std:c++14', '/EHsc', '/openmp', + '/Zc:__cplusplus', '/utf-8', '/DNOMINMAX'], 'unknown' : [], } lopt = { @@ -98,6 +107,7 @@ def all_files_from(dir, ext=''): 'clang w/ GPU' : ['-fopenmp','-fopenmp-targets=nvptx64-nvidia-cuda', '-Wno-openmp-mapping','-Wno-unknown-cuda-version'], 'nvc++' : ['-mp=gpu'], + 'msvc' : [], 'unknown' : [], } @@ -116,7 +126,8 @@ def all_files_from(dir, ext=''): else: # Including mmgr.cpp in the library leads to problems if the other files don't # include mmgr.h. So remove it. - cpp_sources.remove('src/mmgr.cpp') + mmgr_path = os.path.join('src', 'mmgr.cpp') + cpp_sources = [s for s in cpp_sources if os.path.normpath(s) != mmgr_path] # Verbose is the default for setuptools logging, but if it's on the command line, we take it # to mean that we should also be verbose. @@ -131,6 +142,12 @@ def get_compiler_type(compiler, check_unknown=True, output=False): be called cc or gcc. """ if debug: output=True + # MSVC's CCompiler subclass does not expose ``compiler_so`` (a Unix-only + # attribute). Detect it directly via ``compiler_type``. + if getattr(compiler, 'compiler_type', None) == 'msvc': + if output: + print('Compiler is MSVC.') + return 'msvc' cc = compiler.compiler_so[0] if cc == 'ccache': cc = compiler.compiler_so[1] @@ -254,10 +271,13 @@ def find_fftw_lib(output=False): if debug: output = True try_libdirs = [] - # Start with the explicit FFTW_DIR, if present. + # Start with the explicit FFTW_DIR, if present. Support both Unix + # ``/lib`` and conda-style ``/Library/lib`` layouts. if 'FFTW_DIR' in os.environ: - try_libdirs.append(os.environ['FFTW_DIR']) - try_libdirs.append(os.path.join(os.environ['FFTW_DIR'],'lib')) + fftw_root = os.environ['FFTW_DIR'] + try_libdirs.append(fftw_root) + try_libdirs.append(os.path.join(fftw_root, 'lib')) + try_libdirs.append(os.path.join(fftw_root, 'Library', 'lib')) # Add the python system library directory. try_libdirs.append(distutils.sysconfig.get_config_var('LIBDIR')) @@ -265,18 +285,27 @@ def find_fftw_lib(output=False): # If using Anaconda, add their lib dir in case fftw is installed there. # (With envs, this might be different than the sysconfig LIBDIR.) if 'CONDA_PREFIX' in os.environ: - try_libdirs.append(os.path.join(os.environ['CONDA_PREFIX'],'lib')) - - # Try some standard locations where things get installed - try_libdirs.extend(['/usr/local/lib', '/usr/lib']) - if sys.platform == "darwin": - try_libdirs.extend(['/sw/lib', '/opt/local/lib']) + conda_root = os.environ['CONDA_PREFIX'] + try_libdirs.append(os.path.join(conda_root, 'lib')) + # On Windows conda installs C libs under ``\Library\lib``. + try_libdirs.append(os.path.join(conda_root, 'Library', 'lib')) + + if IS_WINDOWS: + # vcpkg layout + if 'VCPKG_ROOT' in os.environ: + try_libdirs.append(os.path.join( + os.environ['VCPKG_ROOT'], 'installed', 'x64-windows', 'lib')) + else: + # Try some standard locations where things get installed + try_libdirs.extend(['/usr/local/lib', '/usr/lib']) + if sys.platform == "darwin": + try_libdirs.extend(['/sw/lib', '/opt/local/lib']) # Check the directories in LD_LIBRARY_PATH. This doesn't work on OSX >= 10.11 for path in ['LIBRARY_PATH', 'LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH']: if path in os.environ: - for dir in os.environ[path].split(':'): - try_libdirs.append(dir) + for d in os.environ[path].split(os.pathsep): + try_libdirs.append(d) # The user's home directory is often a good place to check. try_libdirs.append(os.path.join(os.path.expanduser("~"),"lib")) @@ -288,21 +317,34 @@ def find_fftw_lib(output=False): except ImportError: pass - if sys.platform == "darwin": - lib_ext = '.dylib' + if IS_WINDOWS: + # MSVC import library produced by conda-forge / vcpkg / fftw.org. + lib_names = ['fftw3.lib', 'libfftw3.lib', 'libfftw3-3.lib'] + elif sys.platform == "darwin": + lib_names = ['libfftw3.dylib'] else: - lib_ext = '.so' - name = 'libfftw3' + lib_ext - if output: print("Looking for ",name) + lib_names = ['libfftw3.so'] + if output: print("Looking for ", ' or '.join(lib_names)) tried_dirs = set() # Keep track, so we don't try the same thing twice. for dir in try_libdirs: - if dir == '': continue # This messes things up if it's in there. + if not dir: continue # Filters out '' and ``None`` (sysconfig may yield None on win32). if dir in tried_dirs: continue else: tried_dirs.add(dir) if not os.path.isdir(dir): continue - libpath = os.path.join(dir, name) - if not os.path.isfile(libpath): continue + for name in lib_names: + libpath = os.path.join(dir, name) + if os.path.isfile(libpath): + break + else: + continue if output: print(" ", dir, end='') + if IS_WINDOWS: + # On Windows the file we located is the import library, not the + # DLL. ``ctypes.cdll.LoadLibrary`` only loads runtime DLLs and + # would fail here, so just trust the path and let the linker + # use it. + if output: print(" (yes)") + return libpath try: lib = ctypes.cdll.LoadLibrary(libpath) if output: print(" (yes)") @@ -323,13 +365,19 @@ def find_fftw_lib(output=False): # If we didn't find it anywhere, but the user has set FFTW_DIR, trust it. if 'FFTW_DIR' in os.environ: - libpath = os.path.join(os.environ['FFTW_DIR'], name) + libpath = os.path.join(os.environ['FFTW_DIR'], lib_names[0]) print("WARNING:") - print("Could not find an installed fftw3 library named %s"%(name)) + print("Could not find an installed fftw3 library named %s"%(lib_names[0])) print("Trusting the provided FFTW_DIR=%s for the library location."%(libpath)) print("If this is incorrect, you may have errors later when linking.") return libpath + if IS_WINDOWS: + print("Could not find fftw3 library. On Windows, install fftw via conda-forge") + print("(``conda install -c conda-forge fftw``) or vcpkg, or set FFTW_DIR to a") + print("directory containing fftw3.lib (and fftw3.dll on PATH at runtime).") + raise OSError("fftw3 import library not found") + # Last ditch attempt. Use ctypes.util.find_library, which sometimes manages to find it # when the above attempts fail. try: @@ -371,21 +419,29 @@ def find_eigen_dir(output=False): # Add the python system include directory. try_dirs.append(distutils.sysconfig.get_config_var('INCLUDEDIR')) - # If using Anaconda, add their lib dir in case fftw is installed there. - # (With envs, this might be different than the sysconfig LIBDIR.) + # If using Anaconda, add their include dir in case eigen is installed there. + # (With envs, this might be different than the sysconfig INCLUDEDIR.) if 'CONDA_PREFIX' in os.environ: - try_dirs.append(os.path.join(os.environ['CONDA_PREFIX'],'lib')) - - # Some standard install locations: - try_dirs.extend(['/usr/local/include', '/usr/include']) - if sys.platform == "darwin": - try_dirs.extend(['/sw/include', '/opt/local/include']) + conda_root = os.environ['CONDA_PREFIX'] + try_dirs.append(os.path.join(conda_root, 'include')) + # Windows conda packages live under ``\Library\include``. + try_dirs.append(os.path.join(conda_root, 'Library', 'include')) + + if IS_WINDOWS: + if 'VCPKG_ROOT' in os.environ: + try_dirs.append(os.path.join( + os.environ['VCPKG_ROOT'], 'installed', 'x64-windows', 'include')) + else: + # Some standard install locations: + try_dirs.extend(['/usr/local/include', '/usr/include']) + if sys.platform == "darwin": + try_dirs.extend(['/sw/include', '/opt/local/include']) # Also if there is a C_INCLUDE_PATH, check those dirs. for path in ['C_INCLUDE_PATH']: if path in os.environ: - for dir in os.environ[path].split(':'): - try_dirs.append(dir) + for d in os.environ[path].split(os.pathsep): + try_dirs.append(d) # Finally, (last resort) check our own download of eigen. if os.path.isdir('downloaded_eigen'): @@ -496,6 +552,27 @@ def try_compile(cpp_code, compiler, cflags=[], lflags=[], prepend=None, check_wa with tempfile.NamedTemporaryFile(delete=False, suffix='.exe', dir=local_tmp) as exe_file: exe_name = exe_file.name + # MSVC's distutils CCompiler does not expose Unix-style ``compiler_so`` + # / ``linker_so`` lists; compose probe builds via the high-level API. + if getattr(compiler, 'compiler_type', None) == 'msvc': + try: + objects = compiler.compile([cpp_name], output_dir=local_tmp, + extra_postargs=list(cflags)) + exe_root = os.path.splitext(exe_name)[0] + compiler.link_executable(objects, exe_root, + extra_postargs=list(lflags), + target_lang='c++') + except Exception as e: + if debug: + print('MSVC compile/link probe failed: ', repr(e)) + return False + # Probe succeeded. Best-effort cleanup. + for f in [cpp_name, o_name, exe_name]: + if os.path.exists(f): + try: os.remove(f) + except OSError: pass + return True + # Try compiling with the given flags cc = [compiler.compiler_so[0]] if prepend: @@ -776,6 +853,8 @@ def _single_compile(obj): def fix_compiler(compiler, njobs): + is_msvc = getattr(compiler, 'compiler_type', None) == 'msvc' + # Remove any -Wstrict-prototypes in the compiler flags (since invalid for C++) try: compiler.compiler_so.remove("-Wstrict-prototypes") @@ -790,22 +869,27 @@ def fix_compiler(compiler, njobs): # Figure out what compiler it will use comp_type = get_compiler_type(compiler, output=True) - cc = compiler.compiler_so[0] - already_have_ccache = False - if cc == 'ccache': - already_have_ccache = True - cc = compiler.compiler_so[1] - if cc == comp_type: - print('Using compiler %s'%(cc)) + if is_msvc: + cc = 'msvc' + already_have_ccache = False + print('Using compiler MSVC') else: - print('Using compiler %s, which is %s'%(cc,comp_type)) + cc = compiler.compiler_so[0] + already_have_ccache = False + if cc == 'ccache': + already_have_ccache = True + cc = compiler.compiler_so[1] + if cc == comp_type: + print('Using compiler %s'%(cc)) + else: + print('Using compiler %s, which is %s'%(cc,comp_type)) # Make sure the compiler works with a simple c++ code if not try_cpp(compiler): # One failure mode is that sometimes there is a -B /path/to/compiler_compat # which can cause problems. If we get here, try removing that. success = False - if '-B' in compiler.linker_so: + if not is_msvc and '-B' in compiler.linker_so: for i in range(len(compiler.linker_so)): if (compiler.linker_so[i] == '-B' and 'compiler_compat' in compiler.linker_so[i+1]): @@ -815,66 +899,84 @@ def fix_compiler(compiler, njobs): break if not success: print("There seems to be something wrong with the compiler or cflags") - print(str(compiler.compiler_so)) + if not is_msvc: + print(str(compiler.compiler_so)) raise OSError("Compiler does not work for compiling C++ code") # Check if we can use ccache to speed up repeated compilation. - if not already_have_ccache and try_cpp(compiler, prepend='ccache'): + if (not is_msvc and not already_have_ccache and + try_cpp(compiler, prepend='ccache')): print('Using ccache') compiler.set_executable('compiler_so', ['ccache'] + compiler.compiler_so) - if njobs > 1: + if njobs > 1 and not IS_WINDOWS: # Global variable for tracking the number of jobs to use. # We can't pass this to parallel compile, since the signature is fixed. # So if using parallel compile, set this value to use within parallel compile. global glob_use_njobs glob_use_njobs = njobs compiler.compile = types.MethodType(parallel_compile, compiler) - - extra_cflags = copt[comp_type] - extra_lflags = lopt[comp_type] - - success = try_cpp14(compiler, extra_cflags, extra_lflags) - if not success: - # In case libc++ doesn't work, try letting the system use the default stdlib - try: - extra_cflags.remove('-stdlib=libc++') - extra_lflags.remove('-stdlib=libc++') - except (AttributeError, ValueError): - pass - else: - success = try_cpp14(compiler, extra_cflags, extra_lflags) + elif IS_WINDOWS and njobs > 1: + # MSVC drives parallel compilation via ``/MP`` rather than a Python + # multiprocessing pool; the monkey-patched ``parallel_compile`` above + # is built around the Unix one-source-at-a-time invocation pattern + # and currently misbehaves under MSVC. Stick to single-process + # compile here -- per-extension speedup can be regained later by + # adding ``/MP`` to the MSVC ``copt`` entry. + print('Note: forcing single-process compile on Windows.') + + extra_cflags = list(copt[comp_type]) + extra_lflags = list(lopt[comp_type]) + + if is_msvc: + # The Unix-style probe in try_cpp14 has been adapted via the MSVC + # branch in try_compile; trust MSVC for C++14 support. + success = True + else: + success = try_cpp14(compiler, extra_cflags, extra_lflags) + if not success: + # In case libc++ doesn't work, try letting the system use the default stdlib + try: + extra_cflags.remove('-stdlib=libc++') + extra_lflags.remove('-stdlib=libc++') + except (AttributeError, ValueError): + pass + else: + success = try_cpp14(compiler, extra_cflags, extra_lflags) if not success: print('The compiler %s with flags %s did not successfully compile C++14 code'% (cc, ' '.join(extra_cflags))) raise OSError("Compiler is not C++-14 compatible") - # Also see if adding -msse2 works (and doesn't give a warning) - if '-msse2' not in extra_cflags: - extra_cflags.append('-msse2') - if try_cpp14(compiler, extra_cflags, extra_lflags, check_warning=True): - print('Using cflag -msse2') - else: - print('warning with -msse2.') - extra_cflags.remove('-msse2') + if not is_msvc: + # Also see if adding -msse2 works (and doesn't give a warning). This flag + # is GCC/Clang-only; MSVC enables SSE2 by default on x64 builds. + if '-msse2' not in extra_cflags: + extra_cflags.append('-msse2') + if try_cpp14(compiler, extra_cflags, extra_lflags, check_warning=True): + print('Using cflag -msse2') + else: + print('warning with -msse2.') + extra_cflags.remove('-msse2') # If doing develop installation, it's important for the build directory to be before any # other directories. Particularly ones that might have another version of GalSim installed. # Otherwise the wrong library can be linked, which leads to errors. # So, make sure that the -Lbuild/... directive happens first among any -L directives in - # the link flags. - linker_so = compiler.linker_so - # Find the first -L flag among the current flags (if any) - for i, flag in enumerate(linker_so): - if flag.startswith('-L'): - print('Found link: ',i,flag) - break - else: - i = len(linker_so) - # Insert -Llib for any libs that are in build directory, to make sure they are first. - linker_so[i:i] = ['-L' + l for l in compiler.library_dirs if l.startswith('build')] - # Copy this list back to the compiler object - compiler.set_executable('linker_so', linker_so) + # the link flags. ``linker_so`` is a Unix-only attribute, so guard the rewrite. + if hasattr(compiler, 'linker_so'): + linker_so = list(compiler.linker_so) + # Find the first -L flag among the current flags (if any) + for i, flag in enumerate(linker_so): + if flag.startswith('-L'): + print('Found link: ',i,flag) + break + else: + i = len(linker_so) + # Insert -Llib for any libs that are in build directory, to make sure they are first. + linker_so[i:i] = ['-L' + l for l in compiler.library_dirs if l.startswith('build')] + # Copy this list back to the compiler object + compiler.set_executable('linker_so', linker_so) # Return the extra cflags, since those will be added to the build step in a different place. print('Using extra flags ',extra_cflags) @@ -1208,7 +1310,10 @@ def run(self): # If requested, also build the shared library. if int(os.environ.get('GALSIM_BUILD_SHARED', 0)): - self.run_command("build_shared_clib") + if IS_WINDOWS: + print('GALSIM_BUILD_SHARED is not supported on Windows yet; skipping.') + else: + self.run_command("build_shared_clib") if int(os.environ.get('GALSIM_RUN_TEST', 0)): self.run_command("run_cpp_test") @@ -1313,11 +1418,20 @@ def run(self): 'depends' : headers + inst, 'include_dirs' : ['include', 'include/galsim'], 'undef_macros' : undef_macros }) -ext=Extension("galsim._galsim", - py_sources, - depends = cpp_sources + headers + inst, - undef_macros = undef_macros, - extra_link_args = ["-lfftw3"]) +if IS_WINDOWS: + # MSVC link line uses ``libraries`` + ``library_dirs`` (populated by + # ``add_dirs`` via ``find_fftw_lib``). ``-lfftw3`` is GCC-only. + ext=Extension("galsim._galsim", + py_sources, + depends = cpp_sources + headers + inst, + undef_macros = undef_macros, + libraries = ['fftw3']) +else: + ext=Extension("galsim._galsim", + py_sources, + depends = cpp_sources + headers + inst, + undef_macros = undef_macros, + extra_link_args = ["-lfftw3"]) build_dep = ['setuptools>=38', 'pybind11>=2.2', 'numpy>=1.17'] run_dep = ['astropy', 'LSSTDESC.Coord'] @@ -1418,10 +1532,10 @@ def run(self): ) # Check that the path includes the directory where the scripts are installed. -real_env_path = [os.path.realpath(d) for d in os.environ['PATH'].split(':')] +real_env_path = [os.path.realpath(d) for d in os.environ['PATH'].split(os.pathsep)] if hasattr(dist,'script_install_dir'): print('scripts installed into ',dist.script_install_dir) - if (dist.script_install_dir not in os.environ['PATH'].split(':') and + if (dist.script_install_dir not in os.environ['PATH'].split(os.pathsep) and os.path.realpath(dist.script_install_dir) not in real_env_path): print('\nWARNING: The GalSim executables were installed in a directory not in your PATH') diff --git a/src/Image.cpp b/src/Image.cpp index 9d5464f108..f92fbd9900 100644 --- a/src/Image.cpp +++ b/src/Image.cpp @@ -733,7 +733,7 @@ void rfft(const BaseImage& in, ImageView > out, dbg<<"Start rfft\n"; dbg<<"self bounds = "<& in, ImageView out, bool shift_in, bool sh dbg<<"Start irfft\n"; dbg<<"self bounds = "<& in, ImageView > out, dbg<<"Start cfft\n"; dbg<<"self bounds = "< #include +#include +#else +#include +#include +#endif #include #include #include -#include #include // For memcpy #ifdef _OPENMP @@ -129,6 +134,14 @@ namespace galsim { void BaseDeviate::seedurandom() { +#ifdef _WIN32 + // Windows has no /dev/urandom; use std::random_device which delegates + // to the platform CSPRNG (CryptGenRandom / BCryptGenRandom on Windows + // CRTs). Same observable contract as the POSIX path: produce a + // single int worth of entropy and feed the Mersenne twister. + std::random_device rd; + _impl->_rng->seed(rd()); +#else // This implementation shamelessly taken from: // http://stackoverflow.com/questions/2572366/how-to-use-dev-random-or-urandom-in-c int randomData = open("/dev/urandom", O_RDONLY); @@ -144,13 +157,22 @@ namespace galsim { } close(randomData); _impl->_rng->seed(myRandomInteger); +#endif } void BaseDeviate::seedtime() { +#ifdef _WIN32 + // Match the POSIX path's observable behaviour: seed with the + // microsecond portion of the wall clock. + auto now = std::chrono::system_clock::now().time_since_epoch(); + auto us = std::chrono::duration_cast(now).count(); + _impl->_rng->seed(static_cast(us % 1000000)); +#else struct timeval tp; gettimeofday(&tp,NULL); _impl->_rng->seed(tp.tv_usec); +#endif } void BaseDeviate::seed(long lseed) diff --git a/src/SBInterpolatedImage.cpp b/src/SBInterpolatedImage.cpp index c92672fe06..fd64efa69a 100644 --- a/src/SBInterpolatedImage.cpp +++ b/src/SBInterpolatedImage.cpp @@ -200,7 +200,7 @@ namespace galsim { if (q2 > _nonzero_bounds.getYMax()) q2 = _nonzero_bounds.getYMax(); // We'll need these for each row. Save them. - double xwt[p2-p1+1]; + std::vector xwt(p2-p1+1); for (int p=p1, pp=0; p<=p2; ++p, ++pp) xwt[pp] = _xInterp.xval(p-x); double sum = 0.; @@ -427,7 +427,7 @@ namespace galsim { dbg<<"q range = "< xwt(p2-p1+1); for (int p=p1, pp=0; p<=p2; ++p, ++pp) xwt[pp] = _kInterp.xval(p-kx); std::complex sum = 0.; @@ -437,7 +437,7 @@ namespace galsim { dbg<<"kimage bounds = "<<_kimage->getBounds()< xsum = KValueInnerLoop(p2-p1+1,pwrap1,qwrap,No2,N,xwt,*_kimage); + std::complex xsum = KValueInnerLoop(p2-p1+1,pwrap1,qwrap,No2,N,xwt.data(),*_kimage); sum += xsum * _kInterp.xval(q-ky); } @@ -549,9 +549,9 @@ namespace galsim { // a given q is independent of y, so we save that as well. double x = x0; - double xwt[_xInterp.ixrange() * mm]; - double p1ar[mm]; - double p2ar[mm]; + std::vector xwt(_xInterp.ixrange() * mm); + std::vector p1ar(mm); + std::vector p2ar(mm); int k=0; for (int i=i1; i temp(mm); for (int j=j1; j _nonzero_bounds.getYMax()) q2 = _nonzero_bounds.getYMax(); - double xwt[p2-p1+1]; + std::vector xwt(p2-p1+1); for (int p=p1, pp=0; p<=p2; ++p, ++pp) { xwt[pp] = _xInterp.xval(p-x); } @@ -825,9 +825,9 @@ namespace galsim { // is that we need to wrap around the p,q values and handle the conjugation possibility // correctly. (cf. comments in kValue method.) kx = kx0; - double xwt[_kInterp.ixrange() * mm]; - double p1ar[mm]; - double p2ar[mm]; + std::vector xwt(_kInterp.ixrange() * mm); + std::vector p1ar(mm); + std::vector p2ar(mm); int k=0; for (int i=i1; i array on stack, so reinterpret_cast below. + std::vector temp(2*mm); // Backing storage for the complex view below; reinterpret_cast below. for (int j=j1; j xwt(p2-p1+1); for (int p=p1, pp=0; p<=p2; ++p, ++pp) xwt[pp] = _kInterp.xval(p-kx); std::complex sum = 0.; @@ -1448,7 +1448,7 @@ namespace galsim { dbg<<"kimage bounds = "<<_kimage.getBounds()< xsum = KValueInnerLoop(p2-p1+1,pwrap1,qwrap,No2,N,xwt,_kimage); + std::complex xsum = KValueInnerLoop(p2-p1+1,pwrap1,qwrap,No2,N,xwt.data(),_kimage); sum += xsum * _kInterp.xval(q-ky); } diff --git a/src/SBTransform.cpp b/src/SBTransform.cpp index ed84410151..964baf7c10 100644 --- a/src/SBTransform.cpp +++ b/src/SBTransform.cpp @@ -779,12 +779,12 @@ namespace galsim { ky0 *= ceny; dky *= ceny; - // Use the stack rather than the heap for these, since a bit faster and small - // enough that they should fit without any problem. - T xphase_kx[2*m]; - T xphase_ky[2*n]; - std::complex* phase_kx = reinterpret_cast*>(xphase_kx); - std::complex* phase_ky = reinterpret_cast*>(xphase_ky); + // VLAs are not portable (MSVC rejects them); use std::vector and + // .data() for the reinterpret view onto std::complex. + std::vector xphase_kx(2*m); + std::vector xphase_ky(2*n); + std::complex* phase_kx = reinterpret_cast*>(xphase_kx.data()); + std::complex* phase_ky = reinterpret_cast*>(xphase_ky.data()); fillphase_1d(phase_kx, m, kx0, dkx); fillphase_1d(phase_ky, n, ky0, dky); diff --git a/src/WCS.cpp b/src/WCS.cpp index e69a4261e0..ee3c5e693d 100644 --- a/src/WCS.cpp +++ b/src/WCS.cpp @@ -138,7 +138,7 @@ namespace galsim { int nblock = std::min(n, 256); xdbg<<"nblock = "< temp(nblock); if (abp) { dbg<<"Using abp\n"; const double* Ap = abp; @@ -150,8 +150,8 @@ namespace galsim { xdbg<<"v = "< "< "< A_dudx((nab-1)*(nab-1)); + std::vector A_dudy((nab-1)*(nab-1)); + std::vector B_dvdx((nab-1)*(nab-1)); + std::vector B_dvdy((nab-1)*(nab-1)); for (int i=1; i du(nblock); + std::vector dv(nblock); + std::vector dudx(nblock); + std::vector dudy(nblock); + std::vector dvdx(nblock); + std::vector dvdy(nblock); const int MAX_ITER = 10; bool not_converged = false; @@ -210,16 +210,16 @@ namespace galsim { dbg<<"n = "< dudx - Horner2D(x, y, n1, A_dudy, nab-1, nab-1, dudy, temp); // -> dudy - Horner2D(x, y, n1, B_dvdx, nab-1, nab-1, dvdx, temp); // -> dvdx - Horner2D(x, y, n1, B_dvdy, nab-1, nab-1, dvdy, temp); // -> dvdy + Horner2D(x, y, n1, A_dudx.data(), nab-1, nab-1, dudx.data(), temp.data()); // -> dudx + Horner2D(x, y, n1, A_dudy.data(), nab-1, nab-1, dudy.data(), temp.data()); // -> dudy + Horner2D(x, y, n1, B_dvdx.data(), nab-1, nab-1, dvdx.data(), temp.data()); // -> dvdx + Horner2D(x, y, n1, B_dvdy.data(), nab-1, nab-1, dvdy.data(), temp.data()); // -> dvdy xdbg<<"dudx = "<