diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb4baf6..df6a83d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,3 +57,13 @@ jobs: python -c "import libMobility" python -c "from libMobility import DPStokes, PSE, NBody, SelfMobility" + - name: Install docs dependencies + run: | + pip install -r docs/requirements.txt + shell: bash -el {0} + + - name: Build Sphinx Documentation + run: | + cd docs + make html + shell: bash -el {0} diff --git a/.gitignore b/.gitignore index 96ca043..5068655 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ cpp/example .\#* temp *_init_* -*.o \ No newline at end of file +*.o +build +docs/source/generated \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 7050eef..28b036c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "third_party/uammd"] path = third_party/uammd - url = git@github.com:/raulppelaez/uammd + url = https://github.com/raulppelaez/uammd [submodule "third_party/LanczosAlgorithm"] path = third_party/LanczosAlgorithm - url = git@github.com:Raulppelaez/LanczosAlgorithm + url = https://github.com/Raulppelaez/LanczosAlgorithm diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..0dce193 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,21 @@ +version: "2" + +submodules: + include: all + recursive: true + +build: + os: "ubuntu-22.04" + tools: + python: "mambaforge-22.9" + jobs: + post_create_environment: + - pip install -r docs/requirements.txt + - cmake -DCMAKE_INSTALL_PREFIX=$(which pip | rev | cut -d/ -f3- | rev) . && make -j4 all install + +conda: + environment: environment.yml + + +sphinx: + configuration: docs/source/conf.py diff --git a/README.md b/README.md index 2d3cdd8..a3b099b 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,8 @@ This repository contains several GPU solvers that can compute the action of the In particular, given a group of forces, $\boldsymbol{F}$ , acting on a group of positions, $\boldsymbol{X}$, the libMobility solvers can compute: -$$d\boldsymbol{X} = \boldsymbol{\mathcal{M}}\boldsymbol{F} + \text{prefactor}\sqrt{2T\boldsymbol{\mathcal{M}}}d\boldsymbol{W}$$ +$$d\boldsymbol{X} = \boldsymbol{\mathcal{M}}\boldsymbol{F}dt + \text{prefactor}\sqrt{2T\boldsymbol{\mathcal{M}}}d\boldsymbol{W}$$ - Where dX are the linear displacements, prefactor is an user provided prefactor and dW is a collection of i.i.d Weinner processes. T is the temperature (really $k_B T$). Finally $\boldsymbol{\mathcal{M}}$ represents the mobility tensor. Each solver in libMobility allows to compute either the deterministic term, the stochastic term, or both at the same time. @@ -18,7 +17,7 @@ Some of the solvers have different functionalities than the others. For instance ## How this repository is organized -The directory **solvers** contains a subfolder for each module. Each module exists on a different git repository (and included here as a submodule). Besides the submodule repo, the folder for each solver contains a wrapper to the afforementioned repository that allows to use it under a common interface. +The directory **solvers** contains a subfolder for each module. The folder for each solver the implementation of the libMobility interface for that solver. The directory **python** contains the file libMobility.py, which can be imported giving access to all the compiled modules. The directory **cpp** contains an example usage of the C++ interface to the modules. The directory **include** contains the C++ base class and utilities used to construct the modules. @@ -31,18 +30,17 @@ Each solver provides the following set of functions (called the same in C++ and * **setParameters[SolverName]([extra parameters])**: Some modules might need special parameters, in these instances this function must also be called. Check the README for each module and its mobility.h file. * **setPositions(positions)**: Sets the positions to compute the mobility of. * **Mdot(forces, result)**: Computes the deterministic hydrodynamic displacements, i.e applies the mobility operator. - * **sqrtMdotW(result, prefactor = 1)**: Computes the stochastic displacements and multiplies them by the provided prefactor. -!--- Donev: If prefactor=0 do nothing ---> - * **hydrodynamicVelocities(forces = null, torques = null, result, prefactor = 1)**: Equivalent to calling Mdot followed by sqrtMdotW (some algorithms might benefit from doing these operations together, e.g., solvers based on fluctuating hydrodynamics). -!--- Donev: default value of prefactor should be 0. This function is confusing with regards to the torques. NOTE: I only later saw torques were removed from mobility.h... I assume what you mean here is that stochastic increments are only computed for linear velocity, and if torques are provided only the deterministic term is provided? If you mean that M in the case of torques is the combined force-torque mobility, then forces and torques should be in one vector called "applied". There has to be consistency between result and input and cleared up. I have a strong feeling I wrote this comment already but not sure you ever saw it or never looked at my last round of comments. ---> + * **sqrtMdotW(result, prefactor = 1)**: Computes the stochastic displacements and multiplies them by the provided prefactor. The computation will be skipped if prefactor is 0. + + * **hydrodynamicVelocities(forces = null, result, prefactor = 1)**: Equivalent to calling Mdot followed by sqrtMdotW (some algorithms might benefit from doing these operations together, e.g., solvers based on fluctuating hydrodynamics). + * **clean()**: Cleans any memory allocated by the module. The initialization function must be called again in order to use the module again. -The many examples in this repository offer more insight about the interface and how to use them. See cpp/example.cpp or python/example.py. See solvers/NBody for an example of a module implementation. Even though the algorithm behind it is quite convoluted, the files in this directory are short and simple, since they are only a thin wrapper to the actual algorithm, located under BatchedNBodyRPY there. +The many examples in this repository offer more insight about the interface and how to use them. See cpp/example.cpp or python/example.py. An equal sign denotes defaults. ### Data format -Positions, forces, torques and the results provided by the functions are packed in a 3*numberParticles contiguos array containing ```[x_1, y_1, z_1, x_2,...z_N]``` . +Positions, forces, and the results provided by the functions are packed in a 3*numberParticles contiguous array containing ```[x_1, y_1, z_1, x_2,...z_N]```. -!--- Donev: This is not clear if both forces and torques are provided as input. What is the format of result? 6*N or 2*3*N? ---> ### Parameters The valid parameters accepted by the interface are: @@ -56,15 +54,15 @@ An equal sign denotes default values. ### Configuration parameters At contruction, solvers must be provided with the following information: - * **periodicityX**, **periodicityY**, **periodicityZ**: The periodicity, can any of "periodic", "open", "single_wall", "two_walls", "unspecified". + * **periodicityX**, **periodicityY**, **periodicityZ**: The periodicity, can be any of "periodic", "open", "single_wall", "two_walls", "unspecified". The solvers constructor will check the provided configuration and throw an error if something invalid is requested of it (for instance, the PSE solver will complain if open boundaries are chosen). ## How to use this repo -Some solvers might be included as a git submodule (So that each solver has its own, separated, repository). Be sure to clone this repository recursively (using ```git clone --recurse```). +Be sure to clone this repository recursively (using ```git clone --recurse```). -After compilation (see below) you will have all the tools mentioned above available for each solver. Note that it is not required to compile all modules, only the ones you need (so you do not need to worry about dependencies of unused solvers). +After compilation (see below) you will have all the tools mentioned above available for each solver. ## Compilation @@ -115,7 +113,7 @@ will provide more in depth information about the solver. In order to use a module called SolverName, the header solvers/SolverName/mobility.h must be included. If the module has been compiled correctly the definitions required for the functions in mobility.h will be available at solvers/SolverName/mobility.so. -An example is available in cpp/example.cpp and the accompanying Makefile. +An example is available in cpp/example.cpp. ## Adding a new solver Solvers must be added following the ```libmobility::Mobility``` directives (see include/MobilityInterface). This C++ base class joins every solver under a common interface. When the C++ interface is prepared, the python bindings can be added automagically by using ```pythonify.h``` (a tool under MobilityInterface). @@ -124,8 +122,6 @@ Solvers are exposed to Python and C++ via a single class that inherits from ```l A new solver must add a directory under the "solvers", which must be the name that both the python and C++ classes. -Under the directory proper to this new module, the repository containing the solver can be added as a submodule. - Besides the folder containing the repository, inside the solver directory a series of files (and only these files) must exist (additional files might be placed under an "extra" directory inside the solver directory). These files are: * **mobility.h**: Must include ```MobilityInterface.h``` and define a single class, named as the directory for the solver, that inherits the ```libmobility::Mobility``` base class. For instance, in solvers/NBody/mobility.h we have: ```c++ @@ -134,7 +130,7 @@ Besides the folder containing the repository, inside the solver directory a seri ... ``` Every pure virtual function in ```libmobility::Mobility``` must be overriden and defined. See more about the mobility interface in include/MobilityInterface. -mobility.h can include and make use of any existent utilities/files from the solvers repository. + * **python_wrapper.cpp**: This file must provide the python bindings for the class in mobility.h. If this class follows the ```libmobility::Mobility``` correctly, this file can in general be quite simple, having only a single line using the ```MOBILITY_PYTHONIFY``` utility in include/MobilityInterface/pythonify.h. See solvers/NBody/python_wrapper.cpp for an example. In the case of a module being python only (or in general not providing a correct child of ```libmobility::Mobility```), python_wrapper.cpp might be ommited, but a file called [solver].py must exist instead, providing a python class that is compatible with ```libmobility::Mobility``` (so that the user can write ```from solver import *``` and get a class, called "solver" that adheres to the libmobility requirements). * **CMakeLists.txt**: This must contain rules to create the shared library for the particular solver and its python wrapper. The solver library should be called "lib[Solver].so", while the python library should be called "[Solver].[Python_SOABI].so" with the correct extension suffix. See one of the available CMakeLists.txt for an example. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/style.css b/docs/_static/style.css new file mode 100644 index 0000000..2580b00 --- /dev/null +++ b/docs/_static/style.css @@ -0,0 +1,59 @@ +@import 'theme.css'; + +.rst-content dl:not(.docutils) dt:first-child { + margin-top: 0; +} + +.rst-content dl:not(.docutils) dl dt { + margin-bottom: 4px; + border: none; + border-left: solid 3px #ccc; + background: #f0f0f0; + color: #555; +} + +.rst-content dl table, +.rst-content dl ul, +.rst-content dl ol, +.rst-content dl p { + margin-bottom: 8px !important; +} + +.rst-content dl:not(.docutils) dt { + display: table; + margin: 6px 0; + font-size: 90%; + line-height: normal; + background: #e7f2fa; + color: #2980B9; + border-top: solid 3px #6ab0de; + padding: 6px; + position: relative; +} + +html.writer-html5 .rst-content dl.field-list { + display: initial; +} + +html.writer-html5 .rst-content dl.field-list>dd, +html.writer-html5 .rst-content dl.field-list>dt { + margin-bottom: 4px; + padding-left: 6px; +} + +p { + line-height: 20px; + font-size: 14px; +} + +html.writer-html5 .rst-content dl.field-list>dt:after { + content: initial; +} + +dt.field-even { + text-transform: uppercase; +} + +dt.field-odd { + text-transform: uppercase; +} diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..6247f7e --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..8b776d3 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,5 @@ +sphinx==7.2.6 +sphinx-rtd-theme==1.3.0 +sphinxcontrib-autoprogram==0.1.8 +sphinxcontrib-napoleon==0.7 +gitpython diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 0000000..8747416 --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,10 @@ +API Reference +============= + +.. autosummary:: + :toctree: generated + :recursive: + + libMobility + + diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..a1afd58 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,85 @@ +# Configuration file for the Sphinx documentation builder. +project = "libMobility" +author = "RaulPPelaez" + +import git +import sys +import os + + +def get_latest_git_tag(repo_path="."): + repo = git.Repo(repo_path) + tags = sorted(repo.tags, key=lambda t: t.commit.committed_datetime) + return tags[-1].name if tags else None + + +current_tag = get_latest_git_tag("../../") +sys.path.append(os.path.abspath("./extensions")) +if current_tag is None: + current_tag = "master" +release = current_tag +version = current_tag + +# -- General configuration +extensions = [ + "sphinx.ext.duration", + "sphinx.ext.doctest", + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinxcontrib.autoprogram", + "customsig", +] +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_init_with_doc = False +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = True +napoleon_use_admonition_for_notes = True +napoleon_use_admonition_for_references = True +napoleon_use_ivar = True +napoleon_use_param = True +napoleon_use_rtype = True +napoleon_preprocess_types = True +napoleon_type_aliases = None +napoleon_attr_annotations = True +autosummary_ignore_module_all = False + +intersphinx_mapping = { + "python": ("https://docs.python.org/3/", None), + "torch": ("https://pytorch.org/docs/stable/", None), + "sphinx": ("https://www.sphinx-doc.org/en/master/", None), + "pybind11": ("https://pybind11.readthedocs.io/en/stable/", None), +} +intersphinx_disabled_domains = ["std"] + +templates_path = ["_templates"] + +# -- Options for HTML output + +html_theme = "sphinx_rtd_theme" + +# -- Options for EPUB output +epub_show_urls = "footnote" + +autoclass_content = "both" +autodoc_typehints = "none" +autodoc_inherit_docstrings = False +sphinx_autodoc_typehints = True +html_show_sourcelink = True +autodoc_default_options = { + "members": True, + "member-order": "bysource", + "exclude-members": "__weakref__", + "undoc-members": False, + "show-inheritance": True, + "inherited-members": False, +} +# Exclude all torchmdnet.datasets.*.rst files in source/generated/ +html_static_path = ["../_static"] +html_css_files = [ + "style.css", +] diff --git a/docs/source/extensions/customsig.py b/docs/source/extensions/customsig.py new file mode 100644 index 0000000..ad8c77e --- /dev/null +++ b/docs/source/extensions/customsig.py @@ -0,0 +1,43 @@ +# This file is a Sphinx extension that modifies the signature of functions/methods/classes +# Pybind11 generates signatures in the first line of the docstring, it includes type hints and other redundant information that we put in the docstring itself. + +from sphinx.application import Sphinx +import logging +import re + + +def setup(app: Sphinx): + app.connect("autodoc-process-signature", process_signature) + + +def modify_signature(signature): + # Remove the class method references (e.g., self: ...) + modified = re.sub(r"\s*self:\s*[\w\.]+\s*,?\s*", "", signature) + + # Remove the type hints from the parameters + modified = re.sub(r":\s*[\w\.\[\]]+", "", modified) + + # Simplify numpy array default values to be just empty + modified = re.sub(r"array\(\[\],\s*dtype=[\w]+\)", "", modified) + + # Remove any trailing equals signs that now lead nowhere + modified = re.sub(r"=\s*,", ",", modified) + modified = re.sub(r"=\s*\)", ")", modified) + + # Remove extra spaces around parameters + modified = re.sub(r"\s*,\s*", ", ", modified) + modified = re.sub(r"\s*\(", "(", modified) + modified = re.sub(r"\s*\)", ")", modified) + + return modified + + +def process_signature(app, what, name, obj, options, signature, return_annotation): + if what in ["function", "method", "class"] and signature: + original_signature = signature + signature = modify_signature(signature) + return_annotation = None # Clear the return annotation if needed + logging.info( + f"Modified {name} signature from {original_signature} to {signature}" + ) + return (signature, return_annotation) diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..47dc7cb --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,20 @@ +Welcome to the libMobility Documentation! +========================================= + + + +.. toctree:: + :hidden: + + installation + usage + solvers + api + +.. + Indices and tables + ================== + + * :ref:`genindex` + * :ref:`modindex` + * :ref:`search` diff --git a/docs/source/installation.rst b/docs/source/installation.rst new file mode 100644 index 0000000..fcb7d22 --- /dev/null +++ b/docs/source/installation.rst @@ -0,0 +1,32 @@ +Installation +============ + +We recommend working with a `conda `_ environment. The file ``environment.yml`` contains the necessary dependencies to compile and use the library. + +You can create the environment with: + +.. code-block:: shell + + $ conda env create -f environment.yml + +Then, activate the environment with: + +.. code-block:: shell + + $ conda activate libmobility + +CMake is used for compilation, you can compile and install everything with: + +.. code-block:: shell + + $ mkdir build && cd build + $ cmake -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX .. + $ make all install + +It is advisable to install the library in the conda environment, so that the python bindings are available. The environment variable ``$CONDA_PREFIX`` is set to the root of the conda environment. + +After compilation, the python bindings will be available in the conda environment under the name ``libMobility``. See :ref:`usage` for more information. + +The following variables are available to customize the compilation process: + +- ``DOUBLEPRECISION``: If this variable is defined, libMobility is compiled in double precision (single by default). diff --git a/docs/source/solvers.rst b/docs/source/solvers.rst new file mode 100644 index 0000000..be5fe45 --- /dev/null +++ b/docs/source/solvers.rst @@ -0,0 +1,48 @@ +.. _solvers: +Available solvers +================= + +The following solvers are available in libMobility. + +Self Mobility +------------- +This module neglects hydrodynamic interactions and simply sets :math:`\boldsymbol{\mathcal{M} }= \frac{1}{6\pi\eta a} \mathbb{I}`. + +.. autoclass:: libMobility.SelfMobility + :members: + :inherited-members: + :no-index: + +Positively Split Ewald (PSE) +---------------------------- + +This module computes the RPY mobility in triply periodic boundaries using Ewald splitting with the Positively Split Ewald method. + + +.. autoclass:: libMobility.PSE + :members: + :inherited-members: + :no-index: + + + + +NBody +----- + +This module computes the RPY mobility in open boundaries using an :math:`O(N^2)` algorithm. + +.. autoclass:: libMobility.NBody + :members: + :inherited-members: + :no-index: + +Doubly Periodic Stokes (DPStokes) +--------------------------------- + +This module computes hydrodynamic interactions in a doubly periodic environment. + +.. autoclass:: libMobility.DPStokes + :members: + :inherited-members: + :no-index: diff --git a/docs/source/usage.rst b/docs/source/usage.rst new file mode 100644 index 0000000..dc8c7a7 --- /dev/null +++ b/docs/source/usage.rst @@ -0,0 +1,72 @@ +Usage +----- + +libMobility offers a set of solvers to compute the hydrodynamic displacements of particles in a fluid under different constraints and boundary conditions. The solvers are written in C++ and wrapped in Python. + +In particular, libMobility solvers can compute the different elements in the right hand side of the following stochastic differential equation: + +.. math:: + + d\boldsymbol{X} = \boldsymbol{\mathcal{M}}\boldsymbol{F}dt + \text{prefactor}\sqrt{2T\boldsymbol{\mathcal{M}}}d\boldsymbol{W} + +.. hint:: See the :ref:`solvers` section for a list of available solvers. + + +The libMobility interface +~~~~~~~~~~~~~~~~~~~~~~~~~ + +All solvers present the same set of methods, which are used to set the parameters of the solver, initialize it, and compute the different terms in the equation above. + +As an example, the :py:mod:`libMobility.SelfMobility` solver has the following API: + +.. autoclass:: libMobility.SelfMobility + :members: + :inherited-members: + :no-index: + + + +Example +~~~~~~~ + +The following example shows how to use the :py:class:`libMobility.SelfMobility` solver to compute the different terms in the equation above. + +A libMobility solver is initialized in three steps: + +1. Creation of the solver object, specifying the periodicity of the system. + + +2. Setting the parameters proper to the solver. + + +3. Initialization of the solver with global the parameters. + +.. code:: python + + + import numpy as np + import libMobility + + numberParticles = 3 + Solver = libMobility.SelfMobility + precision = np.float32 if Solver.precision=="float" else np.float64 + pos = np.random.rand(3*numberParticles).astype(precision) + force = np.ones(3*numberParticles).astype(precision) + result = np.zeros(3*numberParticles).astype(precision) + + # The solver will fail if it is not compatible with the provided periodicity + nb = Solver(periodicityX='open',periodicityY='open',periodicityZ='open') + # Other solvers might need an intermediate step here to provide some extra parameters: + # nb.setParameters(parameter1 = 1, ...) + nb.initialize(temperature=1.0, viscosity = 1/(6*np.pi), + hydrodynamicRadius = 1.0, + numberParticles = numberParticles) + nb.setPositions(pos) + nb.Mdot(forces = force, result = result) + print(f"{numberParticles} particles located at ( X Y Z ): {pos}") + print("Forces:", force) + print("M*F:", result) + # result = prefactor*sqrt(2*temperature*M)*dW + nb.sqrtMdotW(prefactor = 1.0, result = result) + print("sqrt(2*T*M)*N(0,1):", result) + nb.clean() diff --git a/include/MobilityInterface/pythonify.h b/include/MobilityInterface/pythonify.h index bbaa979..6398f68 100644 --- a/include/MobilityInterface/pythonify.h +++ b/include/MobilityInterface/pythonify.h @@ -31,6 +31,96 @@ inline auto createConfiguration(std::string perx, std::string pery, std::string return conf; } +const char *constructor_docstring = R"pbdoc( +Initialize the module with a given set of periodicity conditions. + +Each periodicity condition can be one of the following: + - open: No periodicity in the corresponding direction. + - unspecified: The periodicity is not specified. + - single_wall: The system is bounded by a single wall in the corresponding direction. + - two_walls: The system is bounded by two walls in the corresponding direction. + - periodic: The system is periodic in the corresponding direction. + +Parameters +---------- +periodicityX : str + Periodicity condition in the x direction. +periodicityY : str + Periodicity condition in the y direction. +periodicityZ : str + Periodicity condition in the z direction. +)pbdoc"; + +const char *initialize_docstring = R"pbdoc( +Initialize the module with a given set of parameters. + +Parameters +---------- +temperature : float + Temperature of the system in energy units (i.e. kT). +viscosity : float + Viscosity of the fluid. +hydrodynamicRadius : float + Hydrodynamic radius of the particles. +numberParticles : int + Number of particles in the system. +)pbdoc"; + +const char *mdot_docstring = R"pbdoc( +Computes the product of the Mobility matrix with a group of forces, :math:`\boldsymbol{\mathcal{M}}\boldsymbol{F}`. + +It is required that :py:mod:`setPositions` has been called before calling this function. +Both inputs must have precision given by the precision attribute of the module. +Both inputs must have size 3*N, where N is the number of particles. +The arrays are ordered as :code:`[f0x, f0y, f0z, f1x, f1y, f1z, ...]`. + +Parameters +---------- +forces : array_like, + Forces acting on the particles. +result : array_like, + Where the result will be stored. +)pbdoc"; + +const char *sqrtMdotW_docstring = R"pbdoc( +Computes the stochastic contribution, :math:`\text{prefactor}\sqrt{2T\boldsymbol{\mathcal{M}}}d\boldsymbol{W}`, where :math:`\boldsymbol{\mathcal{M}}` is the mobility matrix and :math:`d\boldsymbol{W}` is a Wiener process. + +It is required that :py:mod:`setPositions` has been called before calling this function. +Both inputs must have precision given by the precision attribute of the module. +Both inputs must have size 3*N, where N is the number of particles. +The arrays are ordered as :code:`[f0x, f0y, f0z, f1x, f1y, f1z, ...]`. + +Parameters +---------- +result : array_like, + Where the result will be stored. The result will have the same format as the forces array. +prefactor : float, optional + Prefactor to multiply the result by. Default is 1.0. +)pbdoc"; + + + +const char *hydrodynamicvelocities_docstring = R"pbdoc( +Computes the hydrodynamic (deterministic and stochastic) velocities. + +.. math:: + \boldsymbol{\mathcal{M}}\boldsymbol{F} + \text{prefactor}\sqrt{2T\boldsymbol{\mathcal{M}}}d\boldsymbol{W} + +If the forces are ommited only the stochastic part is computed. +If the temperature is zero the stochastic part is ommited. +Calling this function is equivalent to calling :py:mod:`Mdot` and :py:mod:`sqrtMdotW` in sequence, but in some solvers this can be done more efficiently. + +Parameters +---------- +forces : array_like, optional + Forces acting on the particles. +result : array_like + Where the result will be stored. +prefactor : float, optional + Prefactor to multiply the result by. Default is 1.0. +)pbdoc"; + + #define xMOBILITY_PYTHONIFY(MODULENAME, EXTRACODE, documentation) \ PYBIND11_MODULE(MODULENAME, m){ \ using real = libmobility::real; \ @@ -39,7 +129,7 @@ inline auto createConfiguration(std::string perx, std::string pery, std::string auto solver = py::class_(m, MOBILITYSTR(MODULENAME), documentation); \ solver.def(py::init([](std::string perx, std::string pery, std::string perz){ \ return std::unique_ptr(new MODULENAME(createConfiguration(perx, pery, perz))); }), \ - "Class constructor.", "periodicityX"_a, "periodicityY"_a, "periodicityZ"_a). \ + constructor_docstring, "periodicityX"_a, "periodicityY"_a, "periodicityZ"_a). \ def("initialize", [](MODULENAME &myself, real T, real eta, real a, int N){ \ Parameters par; \ par.temperature = T; \ @@ -48,7 +138,7 @@ inline auto createConfiguration(std::string perx, std::string pery, std::string par.numberParticles = N; \ myself.initialize(par); \ }, \ - "Initialize the module with a given set of parameters.", \ + initialize_docstring, \ "temperature"_a, "viscosity"_a, \ "hydrodynamicRadius"_a, \ "numberParticles"_a). \ @@ -58,20 +148,20 @@ inline auto createConfiguration(std::string perx, std::string pery, std::string def("Mdot", [](MODULENAME &myself, pyarray forces, pyarray result){\ auto f = forces.size()?forces.data():nullptr; \ myself.Mdot(f, result.mutable_data());}, \ - "Computes the product of the RPY Mobility matrix with a group of forces.", \ + mdot_docstring, \ "forces"_a = pyarray(), "result"_a). \ def("sqrtMdotW", [](MODULENAME &myself, pyarray result, libmobility::real prefactor){ \ myself.sqrtMdotW(result.mutable_data(), prefactor);}, \ - "Computes the stochastic contribution, sqrt(2*T*M) dW, where M is the mobility and dW is a Weiner process.", \ + sqrtMdotW_docstring, \ "result"_a = pyarray(), "prefactor"_a = 1.0). \ def("hydrodynamicVelocities", [](MODULENAME &myself, pyarray forces,\ pyarray result, libmobility::real prefactor){ \ auto f = forces.size()?forces.data():nullptr; \ myself.hydrodynamicVelocities(f, result.mutable_data(), prefactor);}, \ - "Computes the hydrodynamic (deterministic and stochastic) velocities. If the forces are ommited only the stochastic part is computed. If the temperature is zero (default) the stochastic part is ommited. The result is equivalent to calling Mdot followed by stochasticDisplacements.", \ + hydrodynamicvelocities_docstring, \ "forces"_a = pyarray(), "result"_a = pyarray(), "prefactor"_a = 1). \ def("clean", &MODULENAME::clean, "Frees any memory allocated by the module."). \ - def_property_readonly_static("precision", [](py::object){return MODULENAME::precision;}, "Compilation precision, a string holding either float or double."); \ + def_property_readonly_static("precision", [](py::object){return MODULENAME::precision;}, R"pbdoc(Compilation precision, a string holding either float or double.)pbdoc"); \ EXTRACODE\ } #define MOBILITY_PYTHONIFY(MODULENAME, documentationPrelude) xMOBILITY_PYTHONIFY(MODULENAME,; ,documentationPrelude) diff --git a/solvers/DPStokes/python_wrapper.cpp b/solvers/DPStokes/python_wrapper.cpp index c3f61e5..3792578 100644 --- a/solvers/DPStokes/python_wrapper.cpp +++ b/solvers/DPStokes/python_wrapper.cpp @@ -1,6 +1,68 @@ /*Raul P. Pelaez 2022. Python wrapper for the DPStokes module -*/ -#include"mobility.h" + */ +#include "mobility.h" #include +using DPStokesParameters = uammd_dpstokes::PyParameters; +static const char *docstring = R"pbdoc( +In the Doubly periodic Stokes geometry (DPStokes), an incompressible fluid exists in a domain which is periodic in the plane and open (or walled) in the third direction. -MOBILITY_PYTHONIFY(DPStokes, "This module computes hydrodynamic interactions in a doubly periodic environment"); +Parameters +---------- +dt : float + The time step. +viscosity : float + The viscosity of the fluid. +Lx : float + The box size in the x direction. +Ly : float + The box size in the y direction. +zmin : float + The minimum value of the z coordinate. +zmax : float + The maximum value of the z coordinate. +w : float + The support of the particle force spreading kernel. +w_d : float + The support of the dipole force spreading kernel. +hydrodynamicRadius : float + The hydrodynamic radius of the particle. +beta : float + The width of the Exponential of the Semicircle (ES) particle force spreading kernel. +beta_d : float + The width of the Exponential of the Semicircle (ES) particle dipole spreading kernel. +alpha : float + Distance normalization factor for the particle force spreading kernel. +alpha_d : float + Distance normalization factor for the dipole force spreading kernel. +mode : str + The wall mode. Options are 'slit', 'bottom' and 'nowall'. +)pbdoc"; + +MOBILITY_PYTHONIFY_WITH_EXTRA_CODE( + DPStokes, + solver.def( + "setParameters", + [](DPStokes &self, real dt, real viscosity, real Lx, real Ly, real zmin, + real zmax, real w, real w_d, real hydrodynamicRadius, real beta, + real beta_d, real alpha, real alpha_d, std::string mode) { + DPStokesParameters params; + params.dt = dt; + params.viscosity = viscosity; + params.Lx = Lx; + params.Ly = Ly; + params.zmin = zmin; + params.zmax = zmax; + params.w = w; + params.w_d = w_d; + params.hydrodynamicRadius = hydrodynamicRadius; + params.beta = beta; + params.beta_d = beta_d; + params.alpha = alpha; + params.alpha_d = alpha_d; + params.mode = mode; + self.setParametersDPStokes(params); + }, + "dt"_a, "viscosity"_a, "Lx"_a, "Ly"_a, "zmin"_a, "zmax"_a, "w"_a, + "w_d"_a, "hydrodynamicRadius"_a, "beta"_a, "beta_d"_a, "alpha"_a, + "alpha_d"_a, "mode"_a);, + docstring); diff --git a/solvers/NBody/python_wrapper.cpp b/solvers/NBody/python_wrapper.cpp index 7580d35..c9b5dd4 100644 --- a/solvers/NBody/python_wrapper.cpp +++ b/solvers/NBody/python_wrapper.cpp @@ -16,7 +16,7 @@ namespace nbody_rpy{ } MOBILITY_PYTHONIFY_WITH_EXTRA_CODE(NBody, - solver.def("setParametersNBody", + solver.def("setParameters", [](NBody &myself, std::string algo, int NBatch, int NperBatch){ myself.setParametersNBody({nbody_rpy::string2NBodyAlgorithm(algo), NBatch, NperBatch}); diff --git a/solvers/PSE/python_wrapper.cpp b/solvers/PSE/python_wrapper.cpp index d967c72..0236433 100644 --- a/solvers/PSE/python_wrapper.cpp +++ b/solvers/PSE/python_wrapper.cpp @@ -1,11 +1,35 @@ -#include"mobility.h" +#include "mobility.h" #include +static const char *docstringSetParameters = R"pbdoc( + Set the parameters for the PSE solver. -MOBILITY_PYTHONIFY_WITH_EXTRA_CODE(PSE, - solver.def("setParametersPSE", - [](PSE &self, real psi, real Lx, real Ly, real Lz, real shearStrain){ - self.setParametersPSE({psi, Lx, Ly, Lz, shearStrain}); - }, - "psi"_a, "Splitting parameter", "Lx"_a, "Ly"_a, "Lz"_a, "shearStrain"_a);, - "This module computes the RPY mobility in triply periodic boundaries using Ewald splitting in the GPU."); + Parameters + ---------- + psi : float + The Splitting parameter. + Lx : float + The box size in the x direction. + Ly : float + The box size in the y direction. + Lz : float + The box size in the z direction. + shearStrain : float + The shear strain. + )pbdoc"; + +static const char *docstring = R"pbdoc( +This module computes the RPY mobility in triply periodic boundaries using Ewald splitting with the Positively Split Ewald method.)pbdoc"; + +MOBILITY_PYTHONIFY_WITH_EXTRA_CODE( + PSE, + solver.def( + "setParametersPSE", + [](PSE &self, real psi, real Lx, real Ly, real Lz, real shearStrain) { + self.setParametersPSE({psi, Lx, Ly, Lz, shearStrain}); + }, + docstringSetParameters, + "psi"_a, "Lx"_a, + "Ly"_a, "Lz"_a, + "shearStrain"_a); + , docstring); diff --git a/solvers/SelfMobility/python_wrapper.cpp b/solvers/SelfMobility/python_wrapper.cpp index 8b3d51f..f6b2681 100644 --- a/solvers/SelfMobility/python_wrapper.cpp +++ b/solvers/SelfMobility/python_wrapper.cpp @@ -4,7 +4,7 @@ #include MOBILITY_PYTHONIFY_WITH_EXTRA_CODE(SelfMobility, - solver.def("setParametersSelfMobility", + solver.def("setParameters", [](SelfMobility &self, real parameter){ self.setParametersSelfMobility(parameter); }, "parameter"_a, "Some example parameter");,