diff --git a/.github/workflows/gh_pages.yml b/.github/workflows/gh_pages.yml
new file mode 100644
index 00000000..f9a57b93
--- /dev/null
+++ b/.github/workflows/gh_pages.yml
@@ -0,0 +1,127 @@
+# Build and deploy documentation to GitHub Pages
+name: GitHub Pages
+
+on: [ push, pull_request ]
+
+env:
+ DEFAULT_BRANCH: "release"
+
+jobs:
+ build-and-deploy:
+ name: Build and deploy to gh-pages
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ lfs: true
+
+ - name: Debugging information
+ run: |
+ echo "github.ref:" ${{github.ref}}
+ echo "github.event_name:" ${{github.event_name}}
+ echo "github.head_ref:" ${{github.head_ref}}
+ echo "github.base_ref:" ${{github.base_ref}}
+ set -x
+ git rev-parse --abbrev-ref HEAD
+ git branch
+ git branch -a
+ git remote -v
+ python -V
+ pip list --not-required
+ pip list
+
+ # Clone and set up the old gh-pages branch
+ - name: Clone old gh-pages
+ if: ${{ github.event_name == 'push' }}
+ run: |
+ set -x
+ git fetch
+ ( git branch gh-pages remotes/origin/gh-pages && git clone . --branch=gh-pages _gh-pages/ ) || mkdir _gh-pages
+ rm -rf _gh-pages/.git/
+ mkdir -p _gh-pages/branch/
+
+ # If a push and default branch, copy build to _gh-pages/ as the "main"
+ # deployment.
+ - name: Build and copy documentation (default branch)
+ if: |
+ contains(github.event_name, 'push') &&
+ contains(github.ref, env.DEFAULT_BRANCH)
+ run: |
+ set -x
+ mkdir -p _build/html/versions
+
+ # create two copies of the documentation
+ # 1. the frozen version, represented as vX.X in the version switcher
+ docker build -t musica -f docker/Dockerfile.docs .
+ id=$(docker create musica)
+ docker cp $id:/build/docs/sphinx tmpdocs
+ docker rm -v $id
+ version=$(sed -nr "s/^release = f'v(.+)\{suffix\}'.*$/\1/p" docs/source/conf.py)
+ mv tmpdocs _build/html/versions/${version}
+
+ # 2. stable, represented as vX.X (stable) in the version switcher
+ # edit conf.py to produce a version string that looks like vX.X (stable)
+ docker build -t musica -f docker/Dockerfile.docs --build-arg SUFFIX=" (stable)" .
+ id=$(docker create musica)
+ docker cp $id:/build/docs/sphinx tmpdocs
+ docker rm -v $id
+ mv tmpdocs _build/html/versions/stable
+ # Delete everything under _gh-pages/ that is from the
+ # primary branch deployment. Excludes the other branches
+ # _gh-pages/branch-* paths, and not including
+ # _gh-pages itself.
+ find _gh-pages/ -mindepth 1 ! -path '_gh-pages/branch*' ! -path '_gh-pages/versions*' -delete
+ rsync -a _build/html/versions/stable/* _gh-pages/
+ mkdir -p _gh-pages/versions
+ rsync -a _build/html/versions/* _gh-pages/versions
+ # mv docs/switcher.json _gh-pages
+
+ # If a push and not on default branch, then copy the build to
+ # _gh-pages/branch/$brname (transforming '/' into '--')
+ - name: Build and copy documentation (branch)
+ if: |
+ contains(github.event_name, 'push') &&
+ !contains(github.ref, env.DEFAULT_BRANCH)
+ run: |
+ set -x
+ docker build -t musica -f docker/Dockerfile.docs .
+ id=$(docker create musica)
+ docker cp $id:/build/docs/sphinx tmpdocs
+ docker rm -v $id
+ brname="${{github.ref}}"
+ brname="${brname##refs/heads/}"
+ brdir=${brname//\//--} # replace '/' with '--'
+ rm -rf _gh-pages/branch/${brdir}
+ rsync -a tmpdocs/ _gh-pages/branch/${brdir}
+
+ # Go through each branch in _gh-pages/branch/, if it's not a
+ # ref, then delete it.
+ - name: Delete old feature branches
+ if: ${{ github.event_name == 'push' }}
+ run: |
+ set -x
+ for brdir in `ls _gh-pages/branch/` ; do
+ brname=${brdir//--/\/} # replace '--' with '/'
+ if ! git show-ref remotes/origin/$brname ; then
+ echo "Removing $brdir"
+ rm -r _gh-pages/branch/$brdir/
+ fi
+ done
+
+ # Add the .nojekyll file
+ - name: nojekyll
+ if: ${{ github.event_name == 'push' }}
+ run: |
+ touch _gh-pages/.nojekyll
+
+ # Deploy
+ # https://github.com/peaceiris/actions-gh-pages
+ - name: Deploy
+ uses: peaceiris/actions-gh-pages@v3
+ if: ${{ github.event_name == 'push' }}
+ with:
+ publish_branch: gh-pages
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: _gh-pages/
+ force_orphan: true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a69d73e8..7f7a21b6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,7 @@ option(MUSICA_ENABLE_TESTS "Builds tests that ensures each enabled MUSICA compon
option(MUSICA_ENABLE_MPI "Enable MPI parallel support" OFF)
option(MUSICA_ENABLE_OPENMP "Enable OpemMP support" OFF)
option(MUSICA_ENABLE_MEMCHECK "Enable memory checking" OFF)
+option(MUSICA_BUILD_DOCS "Build the documentation" OFF)
cmake_dependent_option(
MUSICA_ENABLE_TUVX "Builds TUV-x, a photolysis calculator library" ON "MUSICA_BUILD_FORTRAN_INTERFACE" OFF)
@@ -91,6 +92,10 @@ endif()
include(dependencies)
+if(MUSICA_BUILD_DOCS)
+ add_subdirectory(docs)
+endif()
+
################################################################################
# Tests
if(MUSICA_ENABLE_TESTS)
diff --git a/docker/Dockerfile.docs b/docker/Dockerfile.docs
new file mode 100644
index 00000000..b3cc510e
--- /dev/null
+++ b/docker/Dockerfile.docs
@@ -0,0 +1,33 @@
+FROM fedora:37
+
+RUN dnf -y update \
+ && dnf -y install \
+ doxygen \
+ gcc-c++ \
+ gcc \
+ gdb \
+ git \
+ cmake \
+ make \
+ lcov \
+ valgrind \
+ python3 \
+ python3-pip \
+ && dnf clean all
+
+COPY . /musica/
+
+RUN pip3 install -r /musica/docs/requirements.txt
+
+ARG SUFFIX=""
+ENV SWITCHER_SUFFIX=$SUFFIX
+
+RUN echo "The suffix is '$SWITCHER_SUFFIX'"
+
+RUN mkdir /build \
+ && cd /build \
+ && cmake -D MUSICA_BUILD_DOCS=ON \
+ /musica \
+ && make docs
+
+WORKDIR /build
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644
index 00000000..5e14eef1
--- /dev/null
+++ b/docs/CMakeLists.txt
@@ -0,0 +1,20 @@
+################################################################################
+# Sphinx
+
+set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/source)
+set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx)
+set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html)
+
+add_custom_command(
+ OUTPUT ${SPHINX_INDEX_FILE} __fake_file_to_ensure_this_always_run
+ COMMAND
+ ${SPHINX_EXECUTABLE} -b html
+ ${SPHINX_SOURCE} ${SPHINX_BUILD}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py
+ COMMENT "Generating documentation with Sphinx"
+ # run this command each time. This way we don't have to keep track of each individual rst file
+ BuildDocs
+)
+
+add_custom_target(docs ALL DEPENDS ${SPHINX_INDEX_FILE} Doxygen)
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000..d0c3cbf1
--- /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/make.bat b/docs/make.bat
new file mode 100644
index 00000000..747ffb7b
--- /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
+
+%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.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "" goto help
+
+%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 00000000..b86ccb7c
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,5 @@
+sphinx
+sphinx-book-theme
+sphinx-copybutton
+sphinx-design
+sphinxcontrib-bibtex
diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css
new file mode 100644
index 00000000..c51b21d1
--- /dev/null
+++ b/docs/source/_static/custom.css
@@ -0,0 +1,41 @@
+.sd-card-img-top {
+ width: 33% !important;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 10px;
+}
+
+.download-div {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ margin-bottom: 1rem;
+}
+
+.download-button {
+ display: inline-block;
+ padding: 10px 20px;
+ background-color: #3498db;
+ color: white;
+ border: none;
+ border-radius: 5px;
+ text-align: center;
+ text-decoration: none;
+ font-size: 16px;
+ cursor: pointer;
+ transition: background-color 0.3s;
+}
+
+.transparent-image > img {
+ background-color: unset !important;
+}
+
+.download-button:hover {
+ background-color: #2980b9;
+}
+
+blockquote {
+ padding: unset;
+ border-left: unset;
+}
\ No newline at end of file
diff --git a/docs/source/_static/favicon/favicon.ico b/docs/source/_static/favicon/favicon.ico
new file mode 100644
index 00000000..7905e965
Binary files /dev/null and b/docs/source/_static/favicon/favicon.ico differ
diff --git a/docs/source/_static/index_api.svg b/docs/source/_static/index_api.svg
new file mode 100644
index 00000000..1851b2d7
--- /dev/null
+++ b/docs/source/_static/index_api.svg
@@ -0,0 +1,97 @@
+
+
+
+
\ No newline at end of file
diff --git a/docs/source/_static/index_contribute.svg b/docs/source/_static/index_contribute.svg
new file mode 100644
index 00000000..eb06c21c
--- /dev/null
+++ b/docs/source/_static/index_contribute.svg
@@ -0,0 +1,76 @@
+
+
+
+
\ No newline at end of file
diff --git a/docs/source/_static/index_getting_started.svg b/docs/source/_static/index_getting_started.svg
new file mode 100644
index 00000000..1f3eda8b
--- /dev/null
+++ b/docs/source/_static/index_getting_started.svg
@@ -0,0 +1,66 @@
+
+
+
+
\ No newline at end of file
diff --git a/docs/source/_static/index_user_guide.svg b/docs/source/_static/index_user_guide.svg
new file mode 100644
index 00000000..b3742e0c
--- /dev/null
+++ b/docs/source/_static/index_user_guide.svg
@@ -0,0 +1,67 @@
+
+
+
+
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 00000000..29217117
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,75 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+import datetime
+sys.path.insert(0, os.path.abspath('.'))
+
+# -- Project information -----------------------------------------------------
+
+project = 'MUSICA'
+copyright = f'2024-{datetime.datetime.now().year}, NCAR/UCAR'
+author = 'NCAR/UCAR'
+
+suffix = ''
+# the suffix is required. This is controlled by the dockerfile that builds the docs
+release = f'0.0.0'
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx_copybutton',
+ 'sphinx_design',
+ 'sphinxcontrib.bibtex',
+]
+
+bibtex_bibfiles = ['references.bib']
+suppress_warnings = ["bibtex.missing_field"]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'pydata_sphinx_theme'
+
+html_theme_options = {
+ "external_links": [],
+ "github_url": "https://github.com/NCAR/musica",
+ "navbar_end": ["version-switcher", "navbar-icon-links"],
+ "pygment_light_style": "tango",
+ "pygment_dark_style": "monokai"
+}
+
+html_css_files = [
+ 'custom.css'
+]
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+html_favicon = '_static/favicon/favicon.ico'
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 00000000..e1de8b76
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,54 @@
+.. musica documentation HTML titles
+..
+.. # (over and under) for module headings
+.. = for sections
+.. - for subsections
+.. ^ for subsubsections
+.. ~ for subsubsubsections
+.. " for paragraphs
+
+==================================
+Welcome to MUSICA's documentation!
+==================================
+
+.. grid:: 1 1 2 2
+ :gutter: 2
+
+ .. grid-item-card:: Getting started
+ :img-top: _static/index_getting_started.svg
+ :link: getting_started
+ :link-type: doc
+
+ Check out the getting started guide to build and install musica.
+
+ .. grid-item-card:: User guide
+ :img-top: _static/index_user_guide.svg
+ :link: user_guide/index
+ :link-type: doc
+
+ .. grid-item-card:: API reference
+ :img-top: _static/index_api.svg
+ :link: api/index
+ :link-type: doc
+
+ .. grid-item-card:: Contributors guide
+ :img-top: _static/index_contribute.svg
+ :link: contributing/index
+ :link-type: doc
+
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+.. getting_started
+.. user_guide/index
+.. api/index
+.. contributing/index
+.. citing_and_bibliography/index
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`