diff --git a/doc/sphinx/source/index.rst b/doc/sphinx/source/index.rst index c18d236..c7ad42e 100644 --- a/doc/sphinx/source/index.rst +++ b/doc/sphinx/source/index.rst @@ -1,188 +1,183 @@ .. Tamaas documentation master file, created by sphinx-quickstart on Mon Apr 29 18:08:33 2019. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Tamaas --- A blazingly fast rough contact library ================================================= Tamaas (from تماس meaning "contact" in Arabic and Farsi) is a high-performance rough-surface periodic contact code based on boundary and volume integral equations. The clever mathematical formulation of the underlying numerical methods (see e.g. `10.1007/s00466-017-1392-5 `_ and `arXiv:1811.11558 `_) allows the use of the fast-Fourier Transform, a great help in achieving peak performance: Tamaas is consistently **two orders of magnitude faster** (and lighter) than traditional FEM! Quickstart ---------- Here is a quick introduction to get you started with Tamaas. Installation ^^^^^^^^^^^^ First make sure the following dependencies are installed for Tamaas: - a **C++ compiler** with full **C++14** and **OpenMP** support - **SCons** (python build system) - **FFTW3** compiled with **OpenMP** support - **thrust** (1.9.2+) - **boost** (pre-processor) - **python 3+** (probably works with python 2, but it is not tested) with **numpy** - **pybind11** (included as submodule) - **expolit** (included as submodule) Optional dependencies are: - **scipy** (for nonlinear solvers) - **uvw** (for dumpers) - **googletest** and **pytest** (for tests) - **Doxygen** and **Sphinx** (for documentation) .. tip:: On a HPC environment, use the following variables to specify where the dependencies are located: - ``FFTW_ROOT`` - ``THRUST_ROOT`` - ``BOOST_ROOT`` - ``PYBIND11_ROOT`` - ``GTEST_ROOT`` .. note:: You can use the provided Dockerfile to build an image with the external dependencies installed. You should first clone the git submodules that are dependencies to tamaas (`expolit `_, `pybind11 `_ and `googletest `_):: git submodule update --init --recursive The build system uses `SCons `_. In order to compile Tamaas with the default options:: scons After compiling a first time, you can edit the compilation options in the file ``build-setup.conf``, or alternatively supply the options directly in the command line:: scons option=value [...] To get a list of **all** build options and their possible values, you can run ``scons -h``. You can run ``scons -H`` to see the SCons-specific options (among them ``-j n`` executes the build with ``n`` threads and ``-c`` cleans the build). Note that the build is aware of the ``CXX`` and ``CXXFLAGS`` environment variables. Once compiled, you can install the python module with:: scons install prefix=/your/prefix The above command automatically calls ``pip(3)`` if it is installed, and falls back on ``setuptools`` otherwise. If you do not want to install Tamaas, you can use the following command:: scons dev This creates a symlink in ``~/.local/lib//site-packages`` and is equivalent to ``pip(3) install -e`` or ``./setup.py develop``. You can check that everything is working fine with:: python3 -c 'import tamaas; print(tamaas)' -.. note:: When installing with ``scons install``, verify that the supplied - prefix lives in ``PYTHONPATH``. ``setuptools`` may complain if it is - not the case. You should not have to worry about ``/your/prefix/lib`` - being in ``LD_LIBRARY_PATH``, the RPaths are automatically set in the - compiled python module. Using Docker ............ The Tamaas repository provides a `Dockerfile` that describes an appropriate build environment. You can use it in the following way:: # Build the image, run it and mount the tamaas repository docker build -t tamaas_build . docker run -v $PWD:/app/tamaas -it tamaas_build bash # Once in the image shell: compile and install cd /app/tamaas scons scons dev The image also has some of the dependencies required to run the examples below (matplotlib, uvw). Running the contact pipe tools ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In the ``examples/pipe_tools`` folder, you will find three scripts that can be used to explore the mechanics of elastic rough contact: - ``surface`` generates randomly rough surfaces (see :doc:`rough_surfaces`) - ``contact`` solves a contact problem with a surface read from ``stdin`` (see :doc:`contact`) - ``plot`` simply plots the surface tractions and displacements read from ``stdin`` Here's a sample command line for you to try out:: ./surface --cutoffs 2 4 64 --size 512 512 --hurst 0.8 | ./contact 1 | ./plot Check out the help of each script for a description of the arguments. Library overview ---------------- Tamaas is mainly composed of three components: - Random surface generation procedures - Model state objects and operators - Contact solving procedures These parts are meant to be independent as well as inter-operable. The first one provides an interface to several stochastic surface generation algorithms described in :doc:`rough_surfaces`. The second provides an interface to a state object :py:class:`Model ` (and C++ class :cpp:class:`tamaas::Model`) as well as integral operators based on the state object (see :doc:`model`). Finally, the third part provides contact solving routines that make use of the integral operators for performance (see :doc:`contact`). Contribution ------------ You can contribute to Tamaas by reporting any bugs you find `here `_ if you have an account on `c4science `_. To contribute code to Tamaas, you can use `Arcanist `_ to send code differentials. To know if you break anything, you can run the tests with:: scons test Make sure you have `pytest `_ installed. .. toctree:: :maxdepth: 2 :caption: Table of Contents: ./rough_surfaces ./model ./contact ./api_reference Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` diff --git a/python/SConscript b/python/SConscript index e95f78f..f2f2a86 100644 --- a/python/SConscript +++ b/python/SConscript @@ -1,141 +1,144 @@ # -*- mode:python; coding: utf-8 -*- # vim: set ft=python: # @file # @section LICENSE # # Copyright (©) 2016-19 EPFL (École Polytechnique Fédérale de Lausanne), # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from __future__ import print_function from os.path import abspath, join from SCons.Script import Import, Split, Copy, Dir Import('main_env') # Pybind11 wrapper env_pybind = main_env.Clone(SHLIBPREFIX='') # Remove pedantic warnings cxx_flags = env_pybind['CXXFLAGS'] try: del cxx_flags[cxx_flags.index('-pedantic')] except ValueError: pass 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/compute.cpp wrap/test_features.cpp """) # Adding legacy wrap code if main_env['legacy_bem']: pybind_sources += ["wrap/bem.cpp"] # Building the pybind library tamaas_wrap = env_pybind.SharedLibrary( target='tamaas/_tamaas', source=pybind_sources, LIBS=['Tamaas'], ) # For some reason link happens too early Import('libTamaas') env_pybind.Depends(tamaas_wrap, libTamaas) # 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)) # Copying additional python files python_files = """ compute.py dumpers/__init__.py dumpers/_helper.py nonlinear_solvers/__init__.py """.split() targets = [tamaas_wrap] targets += [ copy_env.Command(join('tamaas', f), join(abspath(str(Dir('#python/tamaas'))), f), Copy("$TARGET", "$SOURCE")) for f in python_files ] targets.append(copy_env.Command('MANIFEST.in', '#python/MANIFEST.in', Copy("$TARGET", "$SOURCE"))) subst_env = env_pybind.Clone( PRINT_CMD_LINE_FUNC=main_env['gen_print']("Generating", "yellow", main_env), SUBST_DICT={ '@version@': '$version', '@authors@': str(copy_env['authors']), '@email@': '$email', # TODO change when issue with unicode fixed # '@copyright@': '$copyright, # '@maintainer@': '$maintainer', } ) subst_env.Tool('textfile') targets.append(subst_env.Substfile('setup.py.in')) targets.append(subst_env.Substfile('tamaas/__init__.py.in')) # Defining alias for python builds main_env.Alias('build-python', targets) # Checking if we can use pip to install (more convenient for end-user) conf = Configure(main_env, custom_tests={'CheckPythonModule': CheckPythonModule}) has_pip = conf.CheckPythonModule('pip') -conf.Finish() +install_env = conf.Finish() # Current build directory -main_env['PYDIR'] = Dir('.') +install_env['PYDIR'] = Dir('.') # Setting command line for installation if has_pip: - main_env['PYINSTALLCOM'] = '${py_exec} -m pip install $PYOPTIONS .' - main_env['PYDEVELOPCOM'] = '${py_exec} -m pip install $PYOPTIONS -e .' + install_env['PYINSTALLCOM'] = '${py_exec} -m pip install $PYOPTIONS .' + install_env['PYDEVELOPCOM'] = '${py_exec} -m pip install $PYOPTIONS -e .' else: - main_env['PYINSTALLCOM'] = '${py_exec} setup.py install $PYOPTIONS' - main_env['PYDEVELOPCOM'] = '${py_exec} setup.py develop $PYOPTIONS' + install_env['PYINSTALLCOM'] = '${py_exec} setup.py install $PYOPTIONS' + install_env['PYDEVELOPCOM'] = '${py_exec} setup.py develop $PYOPTIONS' + install_env['py_version'] = get_python_version(install_env) + install_env['ENV']['PYTHONPATH'] = \ + install_env.subst('${prefix}/lib/python${py_version}/site-packages') # Specify install target -python_install = main_env.Command( +python_install = install_env.Command( join('$prefix', 'dummy_target'), - targets, main_env['PYINSTALLCOM'], PYOPTIONS='--prefix ${prefix}', - chdir=main_env['PYDIR']) + targets, install_env['PYINSTALLCOM'], PYOPTIONS='--prefix ${prefix}', + chdir=install_env['PYDIR']) -python_install_dev = main_env.Command( +python_install_dev = install_env.Command( join('$prefix', 'dummy_target_local'), - targets, main_env['PYDEVELOPCOM'], PYOPTIONS='--user', - chdir=main_env['PYDIR']) + targets, install_env['PYDEVELOPCOM'], PYOPTIONS='--user', + chdir=install_env['PYDIR']) main_env.Alias('install-python', python_install) main_env.Alias('dev', python_install_dev) diff --git a/site_scons/site_init.py b/site_scons/site_init.py index 629d311..c72d405 100644 --- a/site_scons/site_init.py +++ b/site_scons/site_init.py @@ -1,111 +1,124 @@ # -*- coding: utf-8 -*- # @file # @section LICENSE # # Copyright (©) 2016-19 EPFL (École Polytechnique Fédérale de Lausanne), # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import subprocess import SCons from SCons.Script import Dir, Configure # ------------------------------------------------------------------------------ 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 = subprocess.check_output([env['py_exec'], "-c", versions_script], universal_newlines=True).split('\n') includes += [Dir(env['PYBIND11_ROOT'])] # Extension of shared library for python extension = subprocess.check_output([env['py_exec'] + '-config', "--extension-suffix"], universal_newlines=True).split('\n')[0] env['SHLIBSUFFIX'] = extension 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 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 # ------------------------------------------------------------------------------ def CheckPythonModule(context, module): """Checks the existence of a python module""" context.Message('Checking python module {}... '.format(module)) env = context.sconf.env command = [env.subst('${py_exec}'), '-c', 'import {}'.format(module)] context.Log('Executing external command: {}\n'.format(command)) try: subprocess.check_output(command, stderr=subprocess.STDOUT) result = True except subprocess.CalledProcessError as e: result = False context.Log(e.output + '\n') context.Result(result) return result # ------------------------------------------------------------------------------ def dummy_command(env, command, error_msg): """Creates a dummy scons command""" def print_error(*args, **kwargs): print(error_msg) def print_cmd(*args, **kwargs): pass comm = env.Command('#.phony_{}'.format(command), '', print_error, PRINT_CMD_LINE_FUNC=print_cmd) env.Alias(command, comm) + + +# ------------------------------------------------------------------------------ +def get_python_version(env): + versions_script = """ +from __future__ import print_function +from sysconfig import get_python_version +print(get_python_version())""" + version = subprocess.check_output([env['py_exec'], "-c", versions_script], + universal_newlines=True).replace('\n', + '') + print(version) + return version