diff --git a/.gitignore b/.gitignore index 11f91bc..6ff199f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,9 @@ openbt_pypkg/coverage.xml openbt_pypkg/htmlcov openbt_pypkg/src/openbt.egg-info openbt_pypkg/src/openbt/_version.py +openbt_pypkg/src/openbt/include/ +openbt_pypkg/src/openbt/lib/ + # Other files -.DS_Store +.DS_Store \ No newline at end of file diff --git a/docs/bibliography_cpp.rst b/docs/bibliography_cpp.rst deleted file mode 100644 index 203aa7f..0000000 --- a/docs/bibliography_cpp.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. raw:: latex - - \cleardoublepage - \begingroup - \renewcommand\chapter[1]{\endgroup} - \phantomsection - -Bibliography -============ - -.. bibliography:: references.bib - :style: plain - :keyprefix: cpp- diff --git a/docs/developer_environment.rst b/docs/developer_environment.rst new file mode 100644 index 0000000..6cbb816 --- /dev/null +++ b/docs/developer_environment.rst @@ -0,0 +1,236 @@ +.. _developer_env: + +Developer Environment +===================== + +This section is a repository of information that might be potentially useful to +developers. Note that information regarding intermediate files/caches that are +created automatically, which might cause issues during development and testing, +is split across sections. + +Eigen +----- +.. _Eigen: https://gitlab.com/libeigen/eigen + +Eigen_ is a header-only C++ template library for linear algebra. Being +header-only means there is no compiled library to link against, it is used +purely by including its headers directly into source files. + +Installation +~~~~~~~~~~~~ + +The |openbt| Meson build system satisfies the Eigen dependence automatically. +First, Meson uses different techniques to search for an existing Eigen +installation. If found, that installation is used for the build. If not found, +Meson falls back to the ``subprojects/eigen.wrap`` file, which instructs it to +download a pinned Eigen version automatically from Eigen's repository and use it +internally for that build. As a result, Eigen is always available to the build +regardless of whether it is preinstalled on the system. + +Developers using macOS who need to test the build system or who prefer to have a +system-wide installation can install Eigen |via| Homebrew: + +.. code-block:: console + + $ brew install eigen + +Meson Build +----------- +.. _Meson: https://mesonbuild.com +.. _ninja: https://ninja-build.org + +The |openbt| Python package uses the Meson_ build system together with its +ninja_ backend to compile the C++ command line tools during installation. +Please refer to the relevant installation instructions to determine if manual +installation of these tools is required for a particular task. + +Please refer to the documentation in ``tools/build_openbt_clt.sh`` for +information about using that tool, for an example of how to configure and use +the Meson build system, and for potential build difficulties (|eg| due to +intermediate and cached files). + +Build Process with Python +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Meson build is not invoked directly by developers working on or testing the +Python package. The build is triggered automatically when the |openbt| Python +package is installed |via| + +.. code-block:: console + + $ cd /path/to/OpenBT/openbt_pypkg + $ python -m pip install . + +or in editable mode |via| + +.. code-block:: console + + $ python -m pip install -e . + +It is also invoked automatically to build wheels. We generally refer to this +automated process as a "package build." + +Internally, ``setup.py`` defines a custom ``build_clt`` command that wipes and +rebuilds the Meson build directory ``openbt_pypkg/cpp/builddir`` from scratch on +every package build, forcing Meson to re-detect the compiler, MPI, and Eigen +installations rather than reusing stale detection results. Developers who need +the exact Meson invocation can inspect ``build_clt`` in ``setup.py`` directly. + +A successful package build creates the following files and directories: + +* ``openbt_pypkg/cpp/builddir/`` — Meson's working build directory. Build + output including object files are stored here. Since this directory is wiped + and recreated on every package build, it can be deleted safely at any time. + +* ``openbt_pypkg/src/openbt/_version.py`` — Written by ``setuptools_scm`` + from the current git tag, not by Meson. + +Note that while ``openbt_pypkg/cpp`` officially contains the package's C++ +source code and Meson build system, its contents simply alias the actual code +and build system defined at the root of the repository. Therefore, for example, +all intermediate and cached issues associated with the base folder also exist +for package builds. + +Editable Python package installations install build products, such as the +command line tools, directly in a developer's clone rather than inside the +Python execution environment (|eg| within the ``site-packages`` folder of a +virtual environment). These cached files, which can occasionally cause issues, +are + +* ``openbt_pypkg/src/openbt/{bin,include,lib}/`` — The install destination + populated by ``meson install``. This is the most problematic caching layer: + ``meson install`` overlays new files onto these directories but never removes + stale ones. If a binary is renamed, a tool is removed from the build, or + Eigen headers change, the old files persist silently. Consider deleting these + if the build produces unexpected behaviour. Note that, of these contents, + only a subset of the command line tools in ``bin`` is included in a package + build. See ``meson.build`` for the current list of built tools. + +* ``openbt_pypkg/src/openbt/include/eigen3/`` — Eigen headers installed + under the package prefix as a side effect of Eigen's own Meson install step, + regardless of whether Eigen came from the system or the bundled + ``subprojects/eigen.wrap``. These files are unimportant once the command + line tools are built and are not included in package distributions. + +* ``openbt_pypkg/src/openbt/lib/pkgconfig/eigen3.pc`` — A ``pkg-config`` + file for the installed Eigen, with its ``prefix`` pointing into + ``src/openbt/``, that is installed as a side effect. This file is unimportant + and is not included in package distributions. + + +Tox +--- +.. _tox setup: https://tox.wiki/en/latest/index.html + +Developers are free to setup whatever environment that they may need to +facilitate their work with the Python package. However, the package includes a +`tox setup`_, which developers can also use to automatically setup and manage +dedicated virtual environments for different predefined development tasks. Some +tasks are more broadly useful at the level of the whole repository since they +can, for instance, build the User Guides for all |openbt| tools. + +Development with |tox| +~~~~~~~~~~~~~~~~~~~~~~ + +The following is a rough guide to help install |tox| as a command line tool in +a dedicated, minimal virtual environment. |tox| is made available with +no need to manually activate its virtual environment. + +.. note:: + Developers that would like to use |tox| should, at the very least, learn + enough about it that they understand the difference between running ``tox`` + and ``tox -r``. Some potential issues are highlighted below. + +.. code-block:: console + + $ cd $HOME/local/venv + $ deactivate + $ /path/to/desired/python --version + $ /path/to/desired/python -m venv $HOME/local/venv/.toxbase + $ ./.toxbase/bin/python -m pip list + $ ./.toxbase/bin/python -m pip install --upgrade pip setuptools + $ ./.toxbase/bin/python -m pip install tox + $ ./.toxbase/bin/python -m pip list + $ ./.toxbase/bin/tox --version + +To avoid having to activate ``.toxbase`` every time we would like to work with +|tox|, we setup |tox| in ``PATH``. Note that developers can use this single +|tox| installation for multiple projects. Please replace ``.bash_profile`` +with the appropriate shell configuration file and tailor the following to your +needs. + +.. code-block:: console + + $ mkdir -p $HOME/local/bin + $ ln -s $HOME/local/venv/.toxbase/bin/tox $HOME/local/bin/tox + $ vi $HOME/.bash_profile (add $HOME/local/bin to PATH) + $ . $HOME/.bash_profile + $ which tox + $ tox --version + +No work will be carried out by default with the calls ``tox`` and ``tox -r``. + +Run the following from the directory hierarchy that contains the |openbt| +|tox| configuration file ``/path/to/OpenBT/openbt_pypkg/tox.ini`` to see the +full list of available environments and what each one does: + +.. code-block:: console + + $ tox list -v + +Two or more tasks can be executed in a single invocation, (|eg| ``tox -r -e +report,coverage``). Users needing ``pdf`` should note that |tox| does not +install ``make`` or a LaTeX distribution; those must be installed separately. + +The |tox| tool caches all of its virtual environments in ``openbt_pypkg/.tox/``. +Running ``tox -r -e `` forces a clean environment rebuild including +installation of (potentially more modern) dependencies and a full package build +from scratch. Happily, developers can activate and work directly in |tox|'s +cached virtual environments. + +Direct use of |tox| virtual environments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Many of the |tox| tasks will build the |openbt| binary automatically each time +they are run, which can significantly slow development work. In such cases, +developer productivity can benefit from creating a clean virtual environment for +their task using ``tox -r -e `` and subsequently loading and working in that +virtual environment directly. + +Developers can inspect ``tox.ini`` to see what commands are run by their task +and adapt these for their work. + +The following example shows how to run only a single test case using the +``coverage`` virtual environment setup by |tox|. + +.. code-block:: console + + $ cd /path/to/OpenBT/openbt_pypkg + $ tox -r -e coverage + $ . ./.tox/coverage/bin/activate + $ which python + $ python --version + $ python -m pip list + $ python -m pytest --pyargs openbt.tests.test_mixing + +Note that using the ``coverage`` virtual environment directly can be +particularly useful since the package is installed in editable mode and +therefore facilitates interactive development and testing of the Python code. + +The ``html`` environment can be activated directly in the same way to rebuild +documentation iteratively without paying the cost of a full package rebuild each +time: + +.. code-block:: console + + $ cd /path/to/OpenBT/openbt_pypkg + $ tox -r -e html + $ . ./.tox/html/bin/activate + $ which sphinx-build + $ sphinx-build -W -E -b html ../docs ../docs/build_html + +Caching +~~~~~~~ +As noted above, some |tox| tasks build the |openbt| package in editable mode. +They, therefore, can suffer from the potential caching issues mentioned above +for direct editable installations of the package. diff --git a/docs/examples_r.rst b/docs/examples_r.rst new file mode 100644 index 0000000..c78dea0 --- /dev/null +++ b/docs/examples_r.rst @@ -0,0 +1,93 @@ +Examples +======== +.. _Branin: https://www.sfu.ca/~ssurjano/branin.html + +To use |openbt| in R, install ``Ropenbt`` as described in :doc:`get_started_r`. +This example assumes that the command line tools were built with MPI support. + +Let's create a test function. A popular one is the Branin_ function: + +.. code-block:: r + + # Test Branin function, rescaled + braninsc <- function(xx) + { + x1 <- xx[1] + x2 <- xx[2] + + x1bar <- 15*x1 - 5 + x2bar <- 15 * x2 + + term1 <- x2bar - 5.1*x1bar^2/(4*pi^2) + 5*x1bar/pi - 6 + term2 <- (10 - 10/(8*pi)) * cos(x1bar) + + y <- (term1^2 + term2 - 44.81) / 51.95 + return(y) + } + + + # Simulate Branin data for testing + set.seed(99) + n=500 + p=2 + x = matrix(runif(n*p),ncol=p) + y=rep(0,n) + for(i in 1:n) y[i] = braninsc(x[i,]) + +And then we can load the ``Ropenbt`` package and fit a BART model. Here we set +the model type as ``model="bart"``, which ensures that we fit a homoscedastic BART +model. The number of MPI processes to use is specified as ``tc=4``. For a list +of all optional parameters, see ``args(openbt)``. + +.. code-block:: r + + library(Ropenbt) + fit=openbt(x,y,tc=4,model="bart",modelname="branin") + +Next we can construct predictions and make a simple plot. Here, we are +calculating the in-sample predictions since we passed the same ``x`` matrix to +the ``predict.openbt()`` function. + +.. code-block:: r + + # Calculate in-sample predictions + fitp=predict.openbt(fit,x,tc=4) + + # Make a simple plot + plot(y,fitp$mmean,xlab="observed",ylab="fitted") + abline(0,1) + +To save the model, use the ``openbt.save()`` function. Similarly, load the +model using ``openbt.load()``. Because the posterior can be large in +sample-based models such as these, the fitted model is saved in a compressed +file format with the extension ``.obt``. + +.. code-block:: r + + # Save fitted model as test.obt in the working directory + openbt.save(fit,"test") + + # Load fitted model to a new object. + fit2=openbt.load("test") + +The standard variable activity information, calculated as the proportion of +splitting rules involving each variable, can be computed using the +``vartivity.openbt()`` function. + +.. code-block:: r + + # Calculate variable activity information + fitv=vartivity.openbt(fit2) + + # Plot variable activity + plot(fitv) + +A more accurate alternative is to calculate the Sobol' indices. + +.. code-block:: r + + # Calculate Sobol' indices + fits=sobol.openbt(fit2) + fits$msi + fits$mtsi + fits$msij diff --git a/docs/get_started_r.rst b/docs/get_started_r.rst new file mode 100644 index 0000000..5ccc551 --- /dev/null +++ b/docs/get_started_r.rst @@ -0,0 +1,39 @@ +Getting Started with R +======================= +.. _remotes: https://remotes.r-lib.org + +Installed versions of the |openbt| R package, ``Ropenbt``, provide a front-end R +interface that wraps a dedicated set of |openbt| C++ command line tools. The +package locates and calls the already-built command line tools (such as +``openbtcli``) by first searching the folders specified in ``PATH``. If they +are not found, it searches the current working directory as a fallback. + +Follow the :doc:`get_started_cpp` guide to build, install, and test the tools +before continuing. + +Install Ropenbt +------------------------- +With the command line tools built, install the +``Ropenbt`` R interface directly from GitHub using the remotes_ package. First, make sure +``remotes`` is installed: + +.. code-block:: r + + install.packages("remotes") + +Now install ``Ropenbt`` directly from the codebase: + +.. code-block:: r + + remotes::install_github('https://github.com/bandframework/OpenBT', subdir='Ropenbt') + +Note that some ``Ropenbt`` package dependencies may also be installed. Since +``Ropenbt`` itself needs no compilation, this step is quick regardless of +platform. + +Testing +------- +The ``Ropenbt`` package does not currently ship a dedicated automated test suite +of its own. However, executing the full set of steps detailed in +:doc:`examples_r` is a reasonable smoke test that your installation is working +end to end. diff --git a/docs/git_workflow.rst b/docs/git_workflow.rst index e46a2b0..60c3fcd 100644 --- a/docs/git_workflow.rst +++ b/docs/git_workflow.rst @@ -1,7 +1,5 @@ Git Workflow ============ -Since we are currently standing this repository up, we are working with an -informal git workflow. A minimal set of rules are .. note:: @@ -10,6 +8,9 @@ informal git workflow. A minimal set of rules are which might result in unwanted side effects. Rather, a gatekeeper should resolve the conflicts in a local clone, merge locally, and push. +Since we are currently standing this repository up, we are working with an +informal git workflow. A minimal set of rules are + #. No one should make direct commits to the ``main`` branch. #. Each addition and change should be made on a dedicated feature branch that is based off of the latest commit on the ``main`` branch. Try to group related @@ -39,3 +40,58 @@ informal git workflow. A minimal set of rules are Developers are encouraged to create PRs early during branch development to begin and record a dialogue with potential reviewers in the PR. + +GitHub Actions +-------------- + +All of the following actions run automatically on every push and pull request to +``main``. A merge should only proceed once all actions pass. + +Documentation +~~~~~~~~~~~~~ + +* **Check Spelling** — Checks all files in the repository + for typographic errors using the ``typos`` tool with the ``typos.toml`` + configuration file. + +* **Check Links** — Checks all ``.rst`` and ``.md`` files for broken URLs using + the ``lychee`` tool. In addition to running on push and pull request, this + action runs on a regular schedule to catch links that break between + contributions. + +* **Build Sphinx Docs** — Builds the |openbt| documentation in both HTML and + PDF format using |tox|. The built documents are uploaded as a downloadable + artifact so that contributors can review rendered documentation without + needing a local build environment. + +Python Package Testing +~~~~~~~~~~~~~~~~~~~~~~ + +* **Test** |openbt| **Python Source Distribution** — The primary test action. Builds + a Python source distribution and tests it across a matrix of operating + systems, MPI implementations, and Python versions to validate broad + compatibility. This action additionally runs on published releases so that + the source distribution built and tested by the action, which is stored as an + artifact, can be manually uploaded to PyPI as the official release + distribution. + +* **Test** |openbt| **Developer-mode Installation** — Tests the editable installation + (``pip install -e .``) on a reduced matrix. MPI is intentionally installed + |via| |pip| rather than a system package manager to confirm that pip-installed + MPI implementations work correctly. + +* **Test** |openbt| **in Anaconda** — Tests installation inside a conda environment + across a matrix of operating systems and installs |via| |pip| a prebuilt + Open MPI installation included in a Python package. + +* **Measure** |openbt| **Python Coverage** — Runs the full Python test suite with + coverage measurement using |tox| and uploads the raw coverage file, XML + report, and HTML report as artifacts. + +C++ Tools Testing +~~~~~~~~~~~~~~~~~ + +* **Test** |openbt| **C++ Command Line Tools** — Builds and tests the C++ command + line tools directly across a matrix of operating systems and MPI implementations, independently of the Python package. Prints dynamic library + linkage information for each built binary so that developers can verify the + correct MPI implementation was linked. diff --git a/docs/index.rst b/docs/index.rst index fc41f5e..f9ddb99 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,11 +3,9 @@ Welcome to |openbt|'s Documentation! .. _Open MPI: https://www.open-mpi.org .. _MPICH: https://www.mpich.org .. _framework: https://bandframework.github.io -.. _Issue 35: https://github.com/bandframework/OpenBT/issues/35 .. _OpenBT repository: https://bitbucket.org/mpratola/openbt/src/master .. _OpenBTMixing repository: https://github.com/jcyannotty/OpenBT - .. image:: images/openbt_logo_rect.png :align: center :alt: OpenBT @@ -29,7 +27,7 @@ it can be built with MPI installed on a laptop using the system's package manager or with MPI installations on leadership class platforms and clusters that were installed by experts and optimized for their specific platform. -This repository was established by merging the contents of the original Bitbucket +This project was established by merging the contents of the original Bitbucket `OpenBT repository`_ with the `OpenBTMixing repository`_, which was based off of the former. It, therefore, will supersede those two repositories, which will be frozen. @@ -37,18 +35,20 @@ frozen. This repository and its contents are being established and developed as part of |band| framework_. -.. note:: - While an R wrapper does exist for the original |openbt| and |openbtmixing| - repositories, that functionality has not yet been included in this new, - combined repository (`Issue 35`_). - .. toctree:: :numbered: :maxdepth: 1 :caption: C++ User Guide: get_started_cpp - bibliography_cpp + +.. toctree:: + :numbered: + :maxdepth: 1 + :caption: R User Guide: + + get_started_r + examples_r .. toctree:: :numbered: @@ -67,6 +67,6 @@ This repository and its contents are being established and developed as part of contributing git_workflow documentation - tox_usage + developer_environment versioning release_procedure diff --git a/docs/tox_usage.rst b/docs/tox_usage.rst deleted file mode 100644 index 5e0a259..0000000 --- a/docs/tox_usage.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _developer_env: - -Developer Environment -===================== -.. _tox: https://tox.wiki/en/latest/index.html - -.. todo:: - Sarthak to write this diff --git a/openbt_pypkg/tox.ini b/openbt_pypkg/tox.ini index 60ca6f3..0f9f69e 100644 --- a/openbt_pypkg/tox.ini +++ b/openbt_pypkg/tox.ini @@ -8,7 +8,9 @@ requires = tox>=4 env_list = [testenv] -description = Run OpenBT's full test suite with or without coverage +description = + coverage: Run OpenBT's full test suite with coverage + nocoverage: Run OpenBT's full test suite without coverage passenv = COVERAGE_HTML COVERAGE_XML @@ -28,7 +30,10 @@ commands = coverage: coverage run --rcfile={toxinidir}/.coveragerc --data-file={env:COV_FILE} -m pytest ./src/openbt/tests [testenv:report] -description = Generate XML and HTML format coverage reports +description = Write coverage results to stdout as well as generate XML and HTML + format coverage reports. This is typically run after or at the same time as + the coverage task. See tox.ini for information on env vars that control + where the reports are written. depends = coverage deps = coverage skip_install = true @@ -38,8 +43,7 @@ commands = coverage report --data-file={env:COV_FILE} [testenv:check] -# The work done in this task does not alter any files. -description = Check code against typical Python standards +description = Check code against typical Python standards. This task does not alter any files. deps = setuptools flake8 @@ -54,8 +58,12 @@ deps = sphinx sphinxcontrib-bibtex sphinx_rtd_theme + # Uncomment the following dependence if optional live-reloading will be used in this task + #sphinx-autobuild commands = sphinx-build -W -E -b html {env:DOC_ROOT} {env:DOC_ROOT}/build_html + # The command below is for live-reloading of the documentation during development. Uncomment it if you want to use it. + #sphinx-autobuild -W -E -b html {env:DOC_ROOT} {env:DOC_ROOT}/build_html [testenv:pdf] description = Generate OpenBT PDF-format documentation diff --git a/tools/build_openbt_clt.sh b/tools/build_openbt_clt.sh index b5a58c3..e1292aa 100755 --- a/tools/build_openbt_clt.sh +++ b/tools/build_openbt_clt.sh @@ -12,6 +12,24 @@ # This script returns exit codes that should make it compatible with use in CI # build processes. # +# Intermediate & cached files +# --------------------------- +# This script has Meson create and use the /path/to/OpenBT/builddir folder for +# the build. Developers can use this script to create that folder and then use +# Meson manually with that folder to develop and test the code. Users could +# similarly use the contents of the script to guide custom builds. The Meson +# setup, compile, and install commands in the script might provide a good +# starting point for such efforts. +# +# While the /path/to/OpenBT/subprojects folder does contain necessary files +# under version control, it can also contain cached third-party dependencies +# such as Eigen's source code. The subprojects/packagecache folder can also +# contain cached files such as third-party dependence tarballs and patches. +# Please note that setting up the Meson build directory with the --clearcache +# flag does **not** remove such files. Rather, they intentionally persist +# across builds. Consider reviewing those contents if Meson uses Eigen versions +# or installations different from those intended. +# #####----- HARDCODED VALUES use_mpi=true