diff --git a/SConstruct b/SConstruct index f714fcf..787cc53 100644 --- a/SConstruct +++ b/SConstruct @@ -1,315 +1,318 @@ # ------------------------------------------------------------------------------ # Imports # ------------------------------------------------------------------------------ from __future__ import print_function import os from os.path import join, abspath, basename from version import write_info_file # ------------------------------------------------------------------------------ EnsurePythonVersion(2, 7) EnsureSConsVersion(2, 4) # ------------------------------------------------------------------------------ # Helper functions # ------------------------------------------------------------------------------ def detect_fftw(env): """Detect fftw on clusters""" fftw_include = "" fftw_library = "" # If FFTW is provided by module system (on clusters) if 'FFTW_ROOT' in env['ENV']: fftw_include = join(env['ENV']['FFTW_ROOT'], 'include') fftw_library = join(env['ENV']['FFTW_ROOT'], 'lib') # Setting up FFTW env['FFTW_LIBRARY_WISH'] = ['main', 'omp'] env['FFTW_INCLUDE_DIR'] = fftw_include env['FFTW_LIBRARY_DIR'] = fftw_library env.Tool(fftw) # ------------------------------------------------------------------------------ def detect_cuda(env): """Detect cuda on clusters""" if 'CUDA_ROOT' in env['ENV']: env['CUDA_TOOLKIT_PATH'] = env['ENV']['CUDA_ROOT'] else: env['CUDA_TOOLKIT_PATH'] = '/opt/cuda' env['CUDA_COMPONENTS'] = ['cufft'] env['CUDA_ARCH_FLAG'] = '-arch=sm_60' colors = env['COLOR_DICT'] if not env['verbose']: env['NVCCCOMSTR'] = env['SHCXXCOMSTR'] env['SHLINKCOMSTR'] = u'{0}[Linking (cuda)] {1}$TARGET{2}'.format(colors['purple'], colors['blue'], colors['end']) env.AppendUnique(CXXFLAGS="-expt-extended-lambda") # experimental lambda support env.AppendUnique(CXXFLAGS="-expt-relaxed-constexpr") # experimental lambda support if env['build_type'] == 'debug': env.AppendUnique(CXXFLAGS="-G") env.Tool('nvcc') # ------------------------------------------------------------------------------ def detect_boost(env): """Detect boost on clusters""" if 'BOOST_ROOT' in env['ENV']: env['BOOST_INCLUDE_DIR'] = join(env['ENV']['BOOST_ROOT'], 'include') env.Tool(boost) # ------------------------------------------------------------------------------ def detect_thrust(env): """Detect cuda on clusters""" if 'CUDA_ROOT' in env['ENV']: env['THRUST_INCLUDE_DIR'] = join(env['ENV']['CUDA_ROOT'], 'include') else: env['THRUST_INCLUDE_DIR'] = '/opt/cuda/include' if basename(env['CXX']) == "clang++": env.AppendUnique(CXXFLAGS=["-Wno-unused-local-typedef"]) env.Tool(thrust) # ------------------------------------------------------------------------------ def detect_dependencies(env): """Detect all dependencies""" detect_fftw(env) detect_boost(env) detect_thrust(env) # Activate cuda if needed if env['backend'] == 'cuda': detect_cuda(env) # ------------------------------------------------------------------------------ def gen_print(action_string, color_string, env): """Generic function for creating pretty compile output""" if env['verbose']: return None def print_fun(command, target, source, env): colors = env['COLOR_DICT'] print("{}[{}] {}{}".format(colors[color_string], action_string, colors['end'], target[0])) return print_fun # ------------------------------------------------------------------------------ # Main compilation # ------------------------------------------------------------------------------ # Compilation colors colors = { 'cyan': '\033[96m', 'purple': '\033[95m', 'blue': '\033[94m', 'green': '\033[92m', 'yellow': '\033[93m', 'red': '\033[91m', 'end': '\033[0m' } # Inherit all environment variables (for CXX detection, etc.) main_env = Environment(ENV=os.environ) main_env['COLOR_DICT'] = colors # Compiler detection compiler_default = 'g++' if 'CXX' in os.environ: compiler_default = os.environ['CXX'] print("Detected default compiler {} from environment".format(compiler_default)) # Build variables vars = Variables('build-setup.conf') vars.Add(EnumVariable('build_type', 'Build type', 'release', allowed_values=('release', 'profiling', 'debug'), ignorecase=2)) vars.Add(EnumVariable('backend', 'Thrust backend', 'omp', allowed_values=('omp', 'cuda'), ignorecase=2)) vars.Add(EnumVariable('sanitizer', 'Sanitizer type', 'none', allowed_values=('none', 'memory', 'leaks', 'address'), ignorecase=2)) vars.Add('prefix', 'Prefix where to install', '/usr/local') vars.Add('CXX', 'Compiler', compiler_default) vars.Add('py_exec', 'Python executable', 'python') # Cosmetic vars.Add(BoolVariable('verbose', 'Activate verbosity', False)) vars.Add(BoolVariable('color', 'Color the non-verbose compilation output', False)) # Tamaas components vars.Add(BoolVariable('build_doc', 'Build documentation', False)) vars.Add(BoolVariable('build_tests', 'Build test suite', False)) vars.Add(BoolVariable('build_python', 'Build python wrapper', False)) # Dependencies vars.Add(BoolVariable('use_googletest', 'Build tests using GTest', False)) vars.Update(main_env) Help(vars.GenerateHelpText(main_env)) # Save all options, not just those that differ from default with open('build-setup.conf', 'w') as setup: for key in vars.keys(): setup.write("{} = '{}'\n".format(key, main_env[key])) main_env['should_configure'] = not main_env.GetOption('clean') and not main_env.GetOption('help') build_type = main_env['build_type'] build_dir = 'build-' + main_env['build_type'] if main_env['should_configure']: print("Building in " + build_dir) verbose = main_env['verbose'] # Remove colors if not set if not main_env['color']: for key in colors: colors[key] = '' # Setting object suffix main_env['SHOBJSUFFIX'] = '.o' if not verbose: main_env['SHCXXCOMSTR'] = u'{0}[Compiling ($SHCXX)] {1}$SOURCE'.format(colors['green'], colors['end']) main_env['SHLINKCOMSTR'] = u'{0}[Linking] {1}$TARGET'.format(colors['purple'], colors['end']) # Include paths main_env.AppendUnique(CPPPATH=['#/src', '#/src/core', '#/src/bem', '#/src/surface', '#/src/python', '#/src/percolation', '#/src/model', '#/src/solvers', '#/src/gpu', '#/python']) # Changing the shared object extension main_env['SHOBJSUFFIX'] = '.o' # Back to gcc if cuda is activated if main_env['backend'] == "cuda": main_env['CXX'] = "g++" # OpenMP flags - compiler dependent omp_libs = { "g++": ["gomp"], "c++": ["gomp"], "clang++": [], "icpc": [] } omp_flags = { "g++": ["-fopenmp"], "c++": ["-fopenmp"], "clang++": ["-fopenmp=libomp"], "icpc": ["-qopenmp"] } omp_lib = omp_libs[main_env['CXX']] omp_flag = omp_flags[main_env['CXX']] main_env.AppendUnique(LIBS=omp_lib) main_env.AppendUnique(LINKFLAGS=omp_flag) # Flags and options main_env.AppendUnique(CXXFLAGS=['-std=c++11', '-Wall', omp_flag]) if main_env['backend'] == 'omp': main_env.AppendUnique(CPPDEFINES=["THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_OMP"]) elif main_env['backend'] == 'cuda': main_env.AppendUnique(CPPDEFINES=["THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CUDA"]) main_env.AppendUnique(CPPDEFINES=['USE_CUDA']) +if main_env['build_python']: + main_env.AppendUnique(CPPDEFINES=['USE_PYTHON']) + # Adding compile flags defined in evironment if 'CXXFLAGS' in os.environ: main_env.AppendUnique(CXXFLAGS=Split(os.environ['CXXFLAGS'])) if build_type == 'debug': main_env.AppendUnique(CPPDEFINES=['TAMAAS_DEBUG']) # Compilation flags cxxflags_dict = { "debug": Split("-g -O0"), "profiling": Split("-g -pg -O2 -fno-omit-frame-pointer"), "release": Split("-O3") } # Link flags for shared libs shlinkflags_dict = { "debug": Split(""), "profiling": ['-pg'], "release": [] } if main_env['sanitizer'] != 'none': if main_env['backend'] == 'cuda': print("Sanitizers with cuda are not yet supported!") Exit(1) cxxflags_dict[build_type].append('-fsanitize={}'.format(main_env['sanitizer'])) shlinkflags_dict[build_type].append('-fsanitize={}'.format(main_env['sanitizer'])) main_env.AppendUnique(CXXFLAGS=cxxflags_dict[build_type]) main_env.AppendUnique(SHLINKFLAGS=shlinkflags_dict[build_type]) main_env.AppendUnique(LINKFLAGS=shlinkflags_dict[build_type]) main_env['LIBPATH'] = [abspath(join(build_dir, 'src'))] main_env['RPATH'] = "$LIBPATH" if main_env['should_configure']: detect_dependencies(main_env) # Writing information file write_info_file("src/tamaas_info.cpp") # Saving the env file env_content = """export PYTHONPATH=$PYTHONPATH:{0}/python export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{0}/src """ def write_env_file(target, source, env): """Builder to write content to file""" with open(str(target[0]), 'w') as env_file: env_file.write(env_content.format(abspath(build_dir))) main_env['gen_print'] = gen_print env_file_env = main_env.Clone(PRINT_CMD_LINE_FUNC=gen_print("Writing", "cyan", main_env)) # Need to have a command and manage tamaas_environement.sh as target because # the build directory does not always exist env_file_env.Command(join(build_dir, 'tamaas_environement.sh'), None, write_env_file) Export('main_env') # Building subdirs def subdir(dir): return SConscript(join(dir, 'SConscript'), variant_dir=join(build_dir, dir), duplicate=True) # Building Tamaas library subdir('src') # Building Tamaas extra components for dir in ['python', 'tests', 'doc']: if main_env['build_{}'.format(dir)] and not main_env.GetOption('help'): subdir(dir) diff --git a/python/SConscript b/python/SConscript index 558466b..a3ddd05 100644 --- a/python/SConscript +++ b/python/SConscript @@ -1,55 +1,34 @@ from __future__ import print_function import os from os.path import abspath, basename -from subprocess import check_output, STDOUT import re Import('main_env') # Pybind11 wrapper env_pybind = main_env.Clone(SHLIBPREFIX='') - -# Run code below to get versions from user preference and not scons -versions_script = """ -from __future__ import print_function -import distutils.sysconfig as dsys -from numpy.distutils.misc_util import get_numpy_include_dirs as numpy_dirs - -print(dsys.get_python_inc()) -for d in numpy_dirs(): - print(d)""" - -includes = check_output([main_env['py_exec'], "-c", versions_script], - universal_newlines=True).split('\n') - -includes += [Dir('#third-party/pybind11/include')] - -# Extension of shared library for python -extension = check_output([main_env['py_exec'] + '-config', "--extension-suffix"], - universal_newlines=True).split('\n')[0] -env_pybind.AppendUnique(CPPPATH=includes) env_pybind.Tool(pybind11) pybind_sources = Split(""" tamaas_module.cpp wrap/core.cpp wrap/percolation.cpp wrap/surface.cpp wrap/model.cpp wrap/solvers.cpp wrap/bem.cpp """) # Building the pybind library env_pybind.SharedLibrary( - target='tamaas/_tamaas' + extension, + target='tamaas/_tamaas', source=pybind_sources, LIBS=['Tamaas'], RPATH=[abspath('../src')] ) # Copying the __init__.py file with extra python classes copy_env = env_pybind.Clone( PRINT_CMD_LINE_FUNC=main_env['gen_print']("Copying", "red", main_env)) copy_env.Command("tamaas/__init__.py", "#/python/tamaas.py", Copy("$TARGET", "$SOURCE")) diff --git a/site_scons/site_init.py b/site_scons/site_init.py index 7a33330..3536579 100644 --- a/site_scons/site_init.py +++ b/site_scons/site_init.py @@ -1,101 +1,123 @@ from SCons.Script import * from os.path import * +from subprocess import check_output, STDOUT import os def fftw(env): """A Tool to search for fftw headers and libraries""" if env.GetOption('clean'): return env.SetDefault(FFTW_VERSION='3') env.SetDefault(FFTW_LIBRARY_WISH=[]) if 'FFTW_INCLUDE_DIR' in env: env.AppendUnique(CPPPATH=env['FFTW_INCLUDE_DIR']) if 'FFTW_LIBRARY_DIR' in env: env.AppendUnique(LIBPATH=env['FFTW_LIBRARY_DIR']) version = env['FFTW_VERSION'] if version == "2": lib_names = {'main': 'fftw'} inc_names = ['fftw.h'] else: lib_names = {'main': 'fftw3', 'thread': 'fftw3_threads', 'omp': 'fftw3_omp'} inc_names = ['fftw3.h'] try: libs = [lib_names[i] for i in env['FFTW_LIBRARY_WISH']] except: raise SCons.Errors.StopError( 'Incompatible wishlist {0} from version {1}'.format( env['FFTW_LIBRARY_WISH'], env['FFTW_VERSION'])) env.AppendUnique(LIBS=libs) if version == "2": env.Append(LIBS='m') conf = Configure(env) if not conf.CheckLibWithHeader(libs, inc_names, 'c++'): raise SCons.Errors.StopError( 'Failed to find libraries {0} or ' 'headers {1}.'.format(str(lib_names), str(inc_names))) env = conf.Finish() def boost(env): """A tool to confugure for boost""" if env.GetOption('clean'): return if 'BOOST_INCLUDE_DIR' in env: env.AppendUnique(CPPPATH=env['BOOST_INCLUDE_DIR']) conf = Configure(env) if not conf.CheckCXXHeader('boost/preprocessor/seq.hpp'): raise SCons.Errors.StopError( 'Failed to find Boost header') env = conf.Finish() def pybind11(env): """A tool to configure pybind11""" if env.GetOption('clean'): return + # Run code below to get versions from user preference and not scons + versions_script = """ +from __future__ import print_function +import distutils.sysconfig as dsys +from numpy.distutils.misc_util import get_numpy_include_dirs as numpy_dirs + +print(dsys.get_python_inc()) +for d in numpy_dirs(): + print(d)""" + + includes = check_output([env['py_exec'], "-c", versions_script], + universal_newlines=True).split('\n') + + includes += [Dir('#third-party/pybind11/include')] + + # Extension of shared library for python + extension = check_output([env['py_exec'] + '-config', "--extension-suffix"], + universal_newlines=True).split('\n')[0] + env['SHLIBSUFFIX'] = extension + '.so' + env.AppendUnique(CPPPATH=includes) + conf = Configure(env) if not conf.CheckCXXHeader('pybind11/pybind11.h'): raise SCons.Errors.StopError( 'Failed to find pybind11 header\n' + "Run 'git submodule update --init --recursive third-party/pybind11'") env = conf.Finish() def gtest(env): """A tool to configure GoogleTest""" if env.GetOption('clean'): return conf = Configure(env) if not conf.CheckCXXHeader('gtest/gtest.h'): raise SCons.Errors.StopError( 'Failed to find GoogleTest header\n' + "Run 'git submodule update --init --recursive third-party/googletest'") env = conf.Finish() def thrust(env): """A tool to confugure for thrust""" if env.GetOption('clean'): return if 'THRUST_INCLUDE_DIR' in env: env.AppendUnique(CPPPATH=env['THRUST_INCLUDE_DIR']) conf = Configure(env) if not conf.CheckCXXHeader('thrust/version.h'): raise SCons.Errors.StopError( 'Failed to find Thrust library') env = conf.Finish() diff --git a/src/bem/bem_fft_base.cpp b/src/bem/bem_fft_base.cpp index 8de76d4..838ec4f 100644 --- a/src/bem/bem_fft_base.cpp +++ b/src/bem/bem_fft_base.cpp @@ -1,199 +1,200 @@ /** * @file * * @author Guillaume Anciaux * * @section LICENSE * * Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas 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. * * Tamaas 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 Tamaas. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "bem_fft_base.hh" /* -------------------------------------------------------------------------- */ #include "bem_meta_functional.hh" #include "elastic_energy_functional.hh" #include "fft_plan_manager.hh" #include "surface_statistics.hh" +#include "types.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /* -------------------------------------------------------------------------- */ BemFFTBase::BemFFTBase(Surface& p) : BemInterface(p), functional(new MetaFunctional(*this)), surface_tractions(p.size(), p.getL()), surface_displacements(p.size(), p.getL()), surface_spectral_input(p.size(), p.getL()), surface_spectral_output(p.size(), p.getL()), surface_spectral_influence_disp(p.size(), p.getL()), true_displacements(p.size(), p.getL()), old_displacements(p.size(), p.getL()), gap(p.size(), p.getL()), e_star(std::nan("")), tmp_coeff(1. / M_PI) { // this->setNumberOfThreads(this->nthreads); max_iterations = 5000; dump_freq = 100; this->functional->addFunctionalTerm(new ElasticEnergyFunctional(*this)); std::cerr << this << " is setting up the surfaces"; std::cerr << &p << " has size " << p.size() << std::endl; } /* -------------------------------------------------------------------------- */ BemFFTBase::~BemFFTBase() { FFTPlanManager::get().clean(); } /* -------------------------------------------------------------------------- */ const Surface& BemFFTBase::getTractions() const { return surface_tractions; } /* -------------------------------------------------------------------------- */ const Surface& BemFFTBase::getDisplacements() const { return surface_displacements; } /* -------------------------------------------------------------------------- */ const Surface& BemFFTBase::getSpectralInfluenceOverDisplacement() { return surface_spectral_influence_disp; } /* -------------------------------------------------------------------------- */ void BemFFTBase::setEffectiveModulus(Real e_star) { this->e_star = e_star; this->computeSpectralInfluenceOverDisplacement(); } /* -------------------------------------------------------------------------- */ Real BemFFTBase::getEffectiveModulus() { return this->e_star; } /* -------------------------------------------------------------------------- */ void BemFFTBase::computeSpectralInfluenceOverDisplacement() { // if (std::isnan(tmp_coeff)) SURFACE_FATAL("constant tmp_coeff is nan"); // if (std::isnan(e_star)) SURFACE_FATAL("constant e_star is nan"); const Real L = surface.getL(); auto wavevectors = FFTransform::computeFrequencies( surface_spectral_influence_disp.sizes()); auto inf_it = surface_spectral_influence_disp.begin(), inf_begin = surface_spectral_influence_disp.begin(); auto end = wavevectors.end(2); //#pragma omp parallel for firstprivate(inf_it) for (auto it = wavevectors.begin(2); it < end; ++it) { inf_it = inf_begin; inf_it += it - wavevectors.begin(2); VectorProxy q_vec(&(*it), 2); q_vec *= 2 * M_PI / L; Real q = q_vec.l2norm(); // Influence function *inf_it = 2. / (q * e_star); } surface_spectral_influence_disp(0) = 0.; } /* -------------------------------------------------------------------------- */ void BemFFTBase::computeDisplacementsFromTractions() { this->applyInfluenceFunctions(surface_tractions, surface_displacements); } /* -------------------------------------------------------------------------- */ void BemFFTBase::computeTractionsFromDisplacements() { this->applyInverseInfluenceFunctions(surface_displacements, surface_tractions); } /* -------------------------------------------------------------------------- */ void BemFFTBase::applyInfluenceFunctions(Surface& input, Surface& output) { FFTransform& plan1 = FFTPlanManager::get().createPlan(input, surface_spectral_output); plan1.forwardTransform(); surface_spectral_output *= surface_spectral_influence_disp; FFTransform& plan2 = FFTPlanManager::get().createPlan(output, surface_spectral_output); plan2.backwardTransform(); } /* -------------------------------------------------------------------------- */ void BemFFTBase::applyInverseInfluenceFunctions(Surface& input, Surface& output) { FFTransform& plan1 = FFTPlanManager::get().createPlan(input, surface_spectral_output); plan1.forwardTransform(); surface_spectral_output /= surface_spectral_influence_disp; surface_spectral_output(0) = 0; FFTransform& plan2 = FFTPlanManager::get().createPlan(output, surface_spectral_output); plan2.backwardTransform(); } /* -------------------------------------------------------------------------- */ void BemFFTBase::computeGaps() { UInt size = surface.size(); #pragma omp parallel for for (UInt i = 0; i < size * size; i++) { gap(i) = true_displacements(i) - surface(i); } } /* -------------------------------------------------------------------------- */ void BemFFTBase::computeTrueDisplacements() { this->true_displacements = this->surface_displacements; UInt n = surface.size(); UInt size = n * n; Real shift = 1e300; for (UInt i = 0; i < size; ++i) { if (surface_displacements(i) - shift - surface(i) < 0.) { shift = surface_displacements(i) - surface(i); } } for (UInt i = 0; i < size; ++i) { true_displacements(i) = surface_displacements(i) - shift; } } /* -------------------------------------------------------------------------- */ void BemFFTBase::addFunctional(Functional* new_funct) { this->functional->addFunctionalTerm(new_funct); } /* -------------------------------------------------------------------------- */ __END_TAMAAS__ diff --git a/src/core/fftransform.hh b/src/core/fftransform.hh index dfd2ba4..a22890c 100644 --- a/src/core/fftransform.hh +++ b/src/core/fftransform.hh @@ -1,121 +1,115 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * * Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas 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. * * Tamaas 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 Tamaas. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef FFTRANSFORM_HH #define FFTRANSFORM_HH /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "grid_hermitian.hh" #include "tamaas.hh" -#include "types.hh" +#include "static_types.hh" #include /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /* -------------------------------------------------------------------------- */ /** * @brief Generic class for FFT interface wrapping */ template class FFTransform { public: /// Constructor FFTransform(Grid& real, GridHermitian& spectral); /// Destructor virtual ~FFTransform(); public: /// Perform FFT virtual void forwardTransform() = 0; /// Perform IFFT virtual void backwardTransform() = 0; /// Normalize the real surface after backward transform virtual void normalize(); public: /// Fill a grid with modevectors: boolean if grid has hermitian dimensions template static Grid computeFrequencies(const std::array& sizes); protected: Grid& real; GridHermitian& spectral; }; /* -------------------------------------------------------------------------- */ template template Grid FFTransform::computeFrequencies(const std::array& sizes) { // If hermitian is true, we suppose the dimensions of freq are // reduced based on hermitian symetry and that it has dim components auto& n = sizes; Grid freq(n, dim); - std::array tuple{{0}}; - -#pragma omp parallel for firstprivate(tuple) - for (auto it = freq.begin(dim); it < freq.end(dim); ++it) { - VectorProxy wavevector(&(*it), dim); - UInt index = freq.getNbPoints() - (freq.end(dim) - it); - - /// Computing tuple from index - for (UInt d = dim - 1; d > 0; d--) { - tuple[d] = index % n[d]; - index -= tuple[d]; - index /= n[d]; - } - - tuple[0] = index; - - UInt dmax = dim; - - if (hermitian) { - dmax = dim - 1; - wavevector(dim - 1) = tuple[dim - 1]; - } - - for (UInt d = 0; d < dmax; d++) { - T td = tuple[d]; - T nd = n[d]; - T q = (tuple[d] <= n[d] / 2) ? td : td - nd; - wavevector(d) = q; - } - } + constexpr UInt dmax = dim - static_cast(hermitian); + + Loop::stridedLoop( + [dmax, &n](StaticVector&& wavevector, UInt index) { + std::array tuple{{0}}; + /// Computing tuple from index + for (Int d = dim - 1; d >= 0; d--) { + tuple[d] = index % n[d]; + index -= tuple[d]; + index /= n[d]; + } + + if (hermitian) + wavevector(dim - 1) = tuple[dim - 1]; + + for (UInt d = 0; d < dmax; d++) { + // Type conversion + T td = tuple[d]; + T nd = n[d]; + T q = (tuple[d] < n[d] / 2) ? td : td - nd; + wavevector(d) = q; + } + }, + freq, Loop::range(freq.getNbPoints())); return freq; } /* -------------------------------------------------------------------------- */ __END_TAMAAS__ /* -------------------------------------------------------------------------- */ #endif // FFTRANSFORM_HH diff --git a/src/core/grid_base.hh b/src/core/grid_base.hh index 6b91019..0d17874 100644 --- a/src/core/grid_base.hh +++ b/src/core/grid_base.hh @@ -1,317 +1,298 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * * Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas 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. * * Tamaas 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 Tamaas. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __GRID_BASE_HH__ #define __GRID_BASE_HH__ /* -------------------------------------------------------------------------- */ #include "array.hh" #include "iterator.hh" #include "loop.hh" #include "tamaas.hh" #include #include #include #include /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ -/// Namespace for view index classes -namespace view { -/// Index class -struct index { - index(Int i = -1) : i(i) {} - Int i; -}; - -/// Blocked index class -struct blocked : public index { - blocked(Int i) : index(i) {} -}; - -/// Free index class -struct free : public index { - free() : index(-1) {} -}; -} // namespace view - /** * @brief Dimension agnostic grid with components stored per points */ template class GridBase { public: /// Constructor by default GridBase() = default; /// Copy constructor GridBase(const GridBase& o) : data(o.data), nb_components(o.nb_components), offset(o.offset) {} /// Move constructor (transfers data ownership) GridBase(GridBase&& o) : data(std::move(o.data)), nb_components(std::exchange(o.nb_components, 1)), offset(std::exchange(o.offset, 0)) {} /// Destructor virtual ~GridBase() = default; /* ------------------------------------------------------------------------ */ /* Iterator class */ /* ------------------------------------------------------------------------ */ public: using iterator = iterator_::iterator; using const_iterator = iterator_::iterator; public: /// Get grid dimension virtual UInt getDimension() const { return 1; } /// Get internal data pointer (const) const T* getInternalData() const { return this->data.data(); } /// Get internal data pointer (non-const) T* getInternalData() { return this->data.data(); } /// Get number of components UInt getNbComponents() const { return nb_components; } /// Set number of components void setNbComponents(UInt n) { nb_components = n; } /// Get offset UInt getOffset() const { return offset; } /// Get total size virtual UInt dataSize() const { return this->data.size(); } /// Get number of points UInt getNbPoints() const { return this->dataSize() / this->getNbComponents(); } /// Set components void uniformSetComponents(const GridBase& vec); /* ------------------------------------------------------------------------ */ /* Iterator methods */ /* ------------------------------------------------------------------------ */ virtual iterator begin(UInt n = 1) { return iterator(this->getInternalData() + this->offset, 0, n); } virtual iterator end(UInt n = 1) { return iterator(this->getInternalData() + this->offset, this->dataSize(), n); } virtual const_iterator begin(UInt n = 1) const { return const_iterator(this->getInternalData() + this->offset, 0, n); } virtual const_iterator end(UInt n = 1) const { return const_iterator(this->getInternalData() + this->offset, this->dataSize(), n); } /* ------------------------------------------------------------------------ */ /* Operators */ /* ------------------------------------------------------------------------ */ inline T& operator()(UInt i) { return this->data[i]; } inline const T& operator()(UInt i) const { return this->data[i]; } #define VEC_OPERATOR(op) \ template \ GridBase& operator op(const GridBase& other) VEC_OPERATOR(+=); VEC_OPERATOR(*=); VEC_OPERATOR(-=); VEC_OPERATOR(/=); #undef VEC_OPERATOR template T dot(const GridBase& other) const; #define SCALAR_OPERATOR(op) GridBase& operator op(const T& e) SCALAR_OPERATOR(+=); SCALAR_OPERATOR(*=); SCALAR_OPERATOR(-=); SCALAR_OPERATOR(/=); SCALAR_OPERATOR(=); #undef SCALAR_OPERATOR GridBase& operator=(const GridBase& o); /* ------------------------------------------------------------------------ */ /* Min/max */ /* ------------------------------------------------------------------------ */ T min() const; T max() const; T sum() const; T mean() const { return sum() / static_cast(dataSize()); } T var() const; /* ------------------------------------------------------------------------ */ /* Move/Copy */ /* ------------------------------------------------------------------------ */ public: template void copy(const GridBase& other) { data = other.data; nb_components = other.nb_components; offset = other.offset; } template void move(GridBase&& other) { data = std::move(other.data); nb_components = std::exchange(other.nb_components, 1); offset = std::exchange(other.offset, 0); } GridBase& wrap(GridBase& o) { data.wrap(o.data); nb_components = o.nb_components; offset = o.offset; return *this; } GridBase& wrap(const GridBase& o) { data.wrap(o.data); nb_components = o.nb_components; offset = o.offset; return *this; } protected: Array data; UInt nb_components = 1; UInt offset = 0; }; /* -------------------------------------------------------------------------- */ template void GridBase::uniformSetComponents(const GridBase& vec) { if (!(vec.dataSize() == this->nb_components)) TAMAAS_EXCEPTION("Cannot set grid field with values of vector"); auto begin_it(begin()); auto end_it(end()); // silencing nvcc warnings #pragma omp parallel for for (auto it = begin(); it < end_it; ++it) { UInt i = it - begin_it; *it = vec.data[i % this->nb_components]; } } /* -------------------------------------------------------------------------- */ #define SCALAR_OPERATOR_IMPL(op) \ template \ inline GridBase& GridBase::operator op(const T& e) { \ Loop::loop([e] CUDA_LAMBDA(T& val) { val op e; }, *this); \ return *this; \ } SCALAR_OPERATOR_IMPL(+=); SCALAR_OPERATOR_IMPL(*=); SCALAR_OPERATOR_IMPL(-=); SCALAR_OPERATOR_IMPL(/=); SCALAR_OPERATOR_IMPL(=); #undef SCALAR_OPERATOR_IMPL /* -------------------------------------------------------------------------- */ #define VEC_OPERATOR_IMPL(op) \ template \ template \ inline GridBase& GridBase::operator op(const GridBase& other) { \ TAMAAS_ASSERT(other.dataSize() == this->dataSize(), \ "surface size does not match"); \ Loop::loop([] CUDA_LAMBDA(T& x, const T1& y) { x op y; }, *this, other); \ return *this; \ } VEC_OPERATOR_IMPL(+=); VEC_OPERATOR_IMPL(-=); VEC_OPERATOR_IMPL(*=); VEC_OPERATOR_IMPL(/=); #undef VEC_OPERATOR /* -------------------------------------------------------------------------- */ template GridBase& GridBase::operator=(const GridBase& o) { this->copy(o); return *this; } /* -------------------------------------------------------------------------- */ using op = operation; template inline T GridBase::min() const { // const auto id = [] CUDA_LAMBDA (const T&x){return x;}; return Loop::reduce([] CUDA_LAMBDA(const T& x) { return x; }, *this); } /* -------------------------------------------------------------------------- */ template inline T GridBase::max() const { return Loop::reduce([] CUDA_LAMBDA(const T& x) { return x; }, *this); } /* -------------------------------------------------------------------------- */ template inline T GridBase::sum() const { return Loop::reduce([] CUDA_LAMBDA(const T& x) { return x; }, *this); } /* -------------------------------------------------------------------------- */ template inline T GridBase::var() const { const T mu = mean(); const T var = Loop::reduce( [mu] CUDA_LAMBDA(const T& x) { return (x - mu) * (x - mu); }, *this); return var / (dataSize() - 1); } /* -------------------------------------------------------------------------- */ template template T GridBase::dot(const GridBase& other) const { return Loop::reduce( [] CUDA_LAMBDA(const T& x, const T1& y) { return x * y; }, *this, other); } __END_TAMAAS__ #endif // __GRID_BASE_HH__ diff --git a/src/core/grid_tmpl.hh b/src/core/grid_tmpl.hh index abaf75e..2f17992 100644 --- a/src/core/grid_tmpl.hh +++ b/src/core/grid_tmpl.hh @@ -1,173 +1,170 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * * Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas 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. * * Tamaas 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 Tamaas. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __GRID_TMPL_HH__ #define __GRID_TMPL_HH__ /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "tamaas.hh" __BEGIN_TAMAAS__ template template void Grid::init(const T1& n, UInt nb_components) { std::copy(n.begin(), n.end(), this->n.begin()); this->nb_components = nb_components; this->resize(this->n); } /* -------------------------------------------------------------------------- */ template inline UInt Grid::computeSize() const { UInt size = 1; for (UInt i = 0; i < dim; i++) size *= n[i]; size *= this->nb_components; return size; } /* -------------------------------------------------------------------------- */ template template inline UInt Grid::unpackOffset(UInt offset, UInt index_pos, UInt index, T1... rest) const { offset += index * strides[index_pos]; return unpackOffset(offset, index_pos + 1, rest...); // tail-rec bb } template template inline UInt Grid::unpackOffset(UInt offset, UInt index_pos, UInt index) const { return offset + index * strides[index_pos]; } template template inline T& Grid::operator()(T1... args) { /// Checking access integrity constexpr UInt nargs = sizeof...(T1); static_assert(nargs == dim + 1 || nargs == 1 || nargs == dim, "number of arguments in operator() does not match dimension"); constexpr UInt start = (nargs == 1) ? dim : 0; UInt offset = unpackOffset(this->offset, start, args...); return this->data[offset]; } template template inline const T& Grid::operator()(T1... args) const { /// Checking access integrity constexpr UInt nargs = sizeof...(T1); static_assert(nargs == dim + 1 || nargs == 1 || nargs == dim, "number of arguments in operator() does not match dimension"); constexpr UInt start = (nargs == 1) ? dim : 0; UInt offset = unpackOffset(this->offset, start, args...); return this->data[offset]; } /* -------------------------------------------------------------------------- */ template inline UInt Grid::computeOffset(std::array tuple) const { UInt offset = this->offset; - for (UInt i = 0; i < dim + 1; i++) { - offset += tuple[i] * strides[i]; - } - - return offset; + return std::inner_product(tuple.begin(), tuple.end(), strides.begin(), + offset); } template inline T& Grid::operator()(std::array tuple) { UInt offset = computeOffset(tuple); return this->data[offset]; } template inline const T& Grid:: operator()(std::array tuple) const { UInt offset = computeOffset(tuple); return this->data[offset]; } /* -------------------------------------------------------------------------- */ template Grid& Grid::operator=(const Grid& other) { this->copy(other); return *this; } template Grid& Grid::operator=(Grid& other) { this->copy(other); return *this; } template Grid& Grid::operator=(Grid&& other) { this->move(std::forward>(other)); return *this; } /* -------------------------------------------------------------------------- */ template template void Grid::copy(const Grid& other) { GridBase::copy(other); this->n = other.n; this->strides = other.strides; } template template void Grid::move(Grid&& other) { GridBase::move(std::forward>(other)); this->n = std::move(other.n); this->strides = std::move(other.strides); } /* -------------------------------------------------------------------------- */ /* Stream operator */ /* -------------------------------------------------------------------------- */ template inline std::ostream& operator<<(std::ostream& stream, const Grid& _this) { _this.printself(stream); return stream; } __END_TAMAAS__ /* -------------------------------------------------------------------------- */ #endif // __GRID_TMPL_HH__ diff --git a/src/core/grid_view.hh b/src/core/grid_view.hh index 9bbe3d7..966c300 100644 --- a/src/core/grid_view.hh +++ b/src/core/grid_view.hh @@ -1,244 +1,113 @@ /** * @file * * @author Lucas Frérot * * @section LICENSE * * Copyright (©) 2016 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Tamaas 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. * * Tamaas 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 Tamaas. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __GRID_VIEW_HH__ #define __GRID_VIEW_HH__ /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "tamaas.hh" #include /* -------------------------------------------------------------------------- */ __BEGIN_TAMAAS__ /* -------------------------------------------------------------------------- */ /** * @brief View type on grid - * /!\ iterators do not work on this type of grid - * + * This is a view on a *contiguous* chunk of data defined by a grid */ template