diff --git a/CODE-OF-CONDUCT.rst b/CODE-OF-CONDUCT.rst new file mode 100644 index 00000000..dc08e37d --- /dev/null +++ b/CODE-OF-CONDUCT.rst @@ -0,0 +1,9 @@ +Code of Conduct +--------------- + +Everyone participating in this project is governed by the CSDMS `Code of Conduct`_. +By participating, you are expected to uphold this code. + +.. Links + +.. _Code of Conduct: https://github.com/csdms/project/blob/main/CODE-OF-CONDUCT.md diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d0c3cbf1..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# 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 deleted file mode 100644 index 6247f7e2..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@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/source/_static/babelizer-bmi-example-c.png b/docs/source/_static/babelizer-bmi-example-c.png deleted file mode 100644 index 3dc74e8a..00000000 Binary files a/docs/source/_static/babelizer-bmi-example-c.png and /dev/null differ diff --git a/docs/source/babel_heatc.toml b/docs/source/babel_heatc.toml index c6f3786f..4054b80c 100644 --- a/docs/source/babel_heatc.toml +++ b/docs/source/babel_heatc.toml @@ -1,10 +1,13 @@ -[library] -[library.HeatModel] +# See https://babelizer.readthedocs.io/ for more information + +# Describe the library being wrapped. +[library.HeatC] language = "c" library = "bmiheatc" header = "bmi_heat.h" entry_point = "register_bmi_heat" +# Describe compiler options need to build the library being wrapped. [build] undef_macros = [] define_macros = [] @@ -13,17 +16,26 @@ library_dirs = [] include_dirs = [] extra_compile_args = [] +# Describe the newly wrapped package. [package] name = "pymt_heatc" -requirements = [""] +requirements = [] [info] github_username = "pymt-lab" package_author = "csdms" package_author_email = "csdms@colorado.edu" -package_license = "MIT" -summary = "PyMT plugin for the C heat model" +package_license = "MIT License" +summary = "PyMT component for the C heat model" [ci] -python_version = ["3.9"] -os = ["linux", "mac", "windows"] +python_version = [ + "3.10", + "3.11", + "3.12", +] +os = [ + "linux", + "mac", + "windows", +] diff --git a/docs/source/babel_heatf.toml b/docs/source/babel_heatf.toml index 678ee596..e9511e28 100644 --- a/docs/source/babel_heatf.toml +++ b/docs/source/babel_heatf.toml @@ -1,9 +1,13 @@ -[library.HeatModel] +# See https://babelizer.readthedocs.io/ for more information + +# Describe the library being wrapped. +[library.HeatF] language = "fortran" library = "bmiheatf" header = "" entry_point = "bmi_heat" +# Describe compiler options need to build the library being wrapped. [build] undef_macros = [] define_macros = [] @@ -12,17 +16,26 @@ library_dirs = [] include_dirs = [] extra_compile_args = [] +# Describe the newly wrapped package. [package] name = "pymt_heatf" -requirements = [""] +requirements = [] [info] github_username = "pymt-lab" package_author = "csdms" package_author_email = "csdms@colorado.edu" package_license = "MIT License" -summary = "PyMT plugin for the Fortran heat model" +summary = "PyMT component for the Fortran heat model" [ci] -python_version = ["3.9"] -os = ["linux", "mac", "windows"] +python_version = [ + "3.10", + "3.11", + "3.12", +] +os = [ + "linux", + "mac", + "windows", +] diff --git a/docs/source/code-of-conduct.rst b/docs/source/code-of-conduct.rst new file mode 100644 index 00000000..d16993ad --- /dev/null +++ b/docs/source/code-of-conduct.rst @@ -0,0 +1 @@ +.. include:: ../../CODE-OF-CONDUCT.rst diff --git a/docs/source/environment.yml b/docs/source/environment-c.yml similarity index 56% rename from docs/source/environment.yml rename to docs/source/environment-c.yml index 05796077..414e07b9 100644 --- a/docs/source/environment.yml +++ b/docs/source/environment-c.yml @@ -1,5 +1,5 @@ -# A conda environment file for the babelizer example -name: wrap +# A conda environment file for the babelizer C example +name: wrap-c channels: - conda-forge dependencies: @@ -10,3 +10,5 @@ dependencies: - c-compiler - bmi-c - babelizer + - bmi-tester + - pymt>=1.3 diff --git a/docs/source/environment-fortran.yml b/docs/source/environment-fortran.yml index 6bfd6118..903c569d 100644 --- a/docs/source/environment-fortran.yml +++ b/docs/source/environment-fortran.yml @@ -1,5 +1,5 @@ # A conda environment file for the babelizer Fortran example -name: wrap +name: wrap-f channels: - conda-forge dependencies: @@ -10,3 +10,5 @@ dependencies: - fortran-compiler - bmi-fortran - babelizer + - bmi-tester + - pymt>=1.3 diff --git a/docs/source/example.rst b/docs/source/example-c.rst similarity index 51% rename from docs/source/example.rst rename to docs/source/example-c.rst index 78977ae9..ebdf256c 100644 --- a/docs/source/example.rst +++ b/docs/source/example-c.rst @@ -9,16 +9,14 @@ To simplify package management in the example, we'll use :term:`conda`. We'll also use :term:`git` to obtain the model source code. -This is a somewhat long example. -To break it up, -here are the steps we'll take: +Here are the steps we'll take to complete this example: #. Create a :term:`conda environment` that includes software to compile the model and wrap it with the *babelizer* #. Clone the `bmi-example-c`_ repository from GitHub and build the *heat* model from source #. Create a *babelizer* input file describing the *heat* model -#. Run the *babelizer* to generate Python bindings, then build the bindings +#. Run the *babelizer* to generate a Python package, then build and install the package #. Show the *heat* model running in Python through *pymt* Before we begin, @@ -26,18 +24,21 @@ create a directory to hold our work: .. code:: bash - $ mkdir build && cd build + mkdir example-c && cd example-c This directory is a starting point; -we'll make new directories under it as we proceed through the example. -In the end, -the directory structure under ``build`` should look like that in Figure 1. +we'll add files and directories to it as we proceed through the example. +The final directory structure of ``example-c`` should look similar to that below. -.. figure:: _static/babelizer-bmi-example-c.png - :align: center - :alt: Directory structure after completing example +.. code:: bash + + example-c/ + ├── babel_heatc.toml + ├── bmi-example-c/ + ├── environment-c.yml + ├── pymt_heatc/ + └── test/ - Figure 1: Directory structure after completing example. Set up a conda environment -------------------------- @@ -45,17 +46,18 @@ Set up a conda environment Start by setting up a :term:`conda environment` that includes the *babelizer*, as well as a toolchain to build and install the model. The necessary packages are listed in the conda environment file -:download:`environment.yml`: +:download:`environment-c.yml`: -.. include:: environment.yml +.. include:: environment-c.yml :literal: -:download:`Download ` this file -and create the new environment with: +:download:`Download ` this file +and place it in the ``example-c`` directory you created above. +Create the new environment with: .. code:: bash - $ conda env create --file=environment.yml + conda env create --file environment-c.yml When this command completes, activate the environment @@ -63,25 +65,26 @@ activate the environment .. code:: bash - $ conda activate wrap + conda activate wrap-c -The *wrap* environment now contains all the dependencies needed +The *wrap-c* environment now contains all the dependencies needed to build, install, and wrap the *heat* model. Build the *heat* model from source ---------------------------------- -Clone the `bmi-example-c`_ repository from GitHub: +From the ``example-c`` directory, +clone the `bmi-example-c`_ repository from GitHub: .. code:: bash - $ git clone https://github.com/csdms/bmi-example-c + git clone https://github.com/csdms/bmi-example-c There are general `instructions`_ in the repository for building and installing this package on Linux, macOS, and Windows. We'll augment those instructions -with the note that we're installing into the *wrap* conda environment, +with the note that we're installing into the *wrap-c* conda environment, so the ``CONDA_PREFIX`` environment variable should be used to specify the install path. @@ -93,17 +96,17 @@ use these commands to build and install the *heat* model: .. code:: bash - $ cd bmi-example-c - $ mkdir _build && cd _build - $ cmake .. -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX - $ make install + cd bmi-example-c + mkdir build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX + make install Verify the install by testing for the existence of the header of the library containing the compiled *heat* model: .. code:: bash - $ test -f $CONDA_PREFIX/include/bmi_heat.h ; echo $? + test -f $CONDA_PREFIX/include/bmi_heat.h ; echo $? A return of zero indicates success. @@ -111,112 +114,74 @@ Windows ....... Building on Windows requires -Microsoft Visual Studio 2017 or Microsoft Build Tools for Visual Studio 2017. +Microsoft Visual Studio 2019 or Microsoft Build Tools for Visual Studio 2019. To build and install the *heat* model, the following commands must be run in a `Developer Command Prompt`_: -.. code:: +.. code:: bat - > cd bmi-example-c - > mkdir _build && cd _build - > cmake .. ^ - -G "NMake Makefiles" ^ - -DCMAKE_INSTALL_PREFIX=%CONDA_PREFIX% ^ - -DCMAKE_BUILD_TYPE=Release - > cmake --build . --target install --config Release + cd bmi-example-c + mkdir build && cd build + cmake .. ^ + -G "NMake Makefiles" ^ + -DCMAKE_INSTALL_PREFIX=%CONDA_PREFIX% ^ + -DCMAKE_BUILD_TYPE=Release + cmake --build . --target install --config Release Verify the install by testing for the existence of the header of the library containing the compiled *heat* model: -.. code:: +.. code:: bat - > if not exist %LIBRARY_INC%\\bmi_heat.h exit 1 + if not exist %LIBRARY_INC%\\bmi_heat.h exit 1 -Create the *babelizer* input file ---------------------------------- +Create a *babelizer* configuration file +--------------------------------------- -The *babelizer* input file provides information to the *babelizer* +A *babelizer* configuration file provides information to the *babelizer* about the model to be wrapped. -The input file is created with the ``babelize generate`` subcommand. - -Return to our initial ``build`` directory and call ``babelize generate`` with: -.. code:: bash - - $ cd ../.. - $ babelize generate \ - --package=pymt_heatc \ - --summary="PyMT plugin for the C heat model" \ - --language=c \ - --library=bmiheatc \ - --header=bmi_heat.h \ - --entry-point=register_bmi_heat \ - --name=HeatModel \ - --requirement="" > babel_heatc.toml +Typically, we would use the ``babelize sample-config`` command +to create a sample configuration file, which could then be edited. +However, to simplify this example, we have provided a completed +configuration file for the *heat* model. +:download:`Download ` the file +:download:`babel_heatc.toml` and copy it to the ``example-c`` directory. -In this call, -the *babelizer* will also fill in default values; -e.g., author name, author email, GitHub username, and license. - -The resulting file, :download:`babel_heatc.toml`, -will look something like this: +The configuration file looks like this: .. include:: babel_heatc.toml :literal: -For more information on the entries and sections of the *babelizer* input file, +For more information on the entries and sections of the *babelizer* configuration file, see `Input file <./readme.html#input-file>`_. Wrap the model with the *babelizer* ----------------------------------- -Generate Python bindings for the model with the ``babelize init`` subcommand: +From the ``example-c`` directory, +generate a Python package for the model with the ``babelize init`` command: .. code:: bash - $ babelize init babel_heatc.toml + babelize init babel_heatc.toml The results are placed in a new directory, ``pymt_heatc``, under the current directory. -.. code:: bash +Build and install the wrapped model +................................... - $ ls -aF pymt_heatc - ./ MANIFEST.in recipe/ - ../ Makefile requirements-build.txt - .git/ README.rst requirements-library.txt - .github/ babel.toml requirements-testing.txt - .gitignore docs/ requirements.txt - CHANGES.rst meta/ setup.cfg - CREDITS.rst pymt_heatc/ setup.py - LICENSE pyproject.toml - -Before we can build the Python bindings, -we must ensure that the dependencies required by the toolchain, -as well as any required by the model, -as specified in the *babelizer* input file (none in this case), -are satisfied. - -Change to the ``pymt_heatc`` directory and install dependencies -into the conda environment: +Change to the ``pymt_heatc`` directory, +then build and install the Python package with *pip*: .. code:: bash - $ cd pymt_heatc - $ conda install -c conda-forge \ - --file=requirements-build.txt \ - --file=requirements-testing.txt \ - --file=requirements-library.txt \ - --file=requirements.txt + cd pymt_heatc + pip install ."[dev]" -Now build the Python bindings with: - -.. code:: bash - - $ make install - -This command sets off a long list of messages, +The ``pip install`` command sets off a long list of messages, at the end of which you'll hopefully see: .. code:: bash @@ -224,31 +189,39 @@ at the end of which you'll hopefully see: Successfully installed pymt-heatc Pause a moment to see what we've done. -Change back to the initial ``build`` directory, +Change back to the initial ``example-c`` directory, make a new ``test`` directory, and change to it: .. code:: bash - $ cd .. - $ mkdir test && cd test + cd .. + mkdir test && cd test -Start a Python session and try the following commands: +Start a Python session (e.g., run ``python``) and try the following commands: .. code:: python - >>> from pymt_heatc import HeatModel - >>> m = HeatModel() - >>> print(m.get_component_name()) + from pymt_heatc import HeatC + m = HeatC() + m.get_component_name() + +You should see: + +.. code:: bash + The 2D Heat Equation We've imported the *heat* model, written in C, into Python! -Exit the Python session. +Exit the Python session (e.g. type ``exit()``). + +Test the BMI +............ At this point, -it's a good idea to run the *bmi-tester* (`GitHub repo `_) +it's a good idea to run the *bmi-tester* (`documentation `_) over the model. The *bmi-tester* exercises each BMI method exposed through Python, ensuring it works correctly. @@ -260,16 +233,16 @@ Create a configuration file for *heat* at the command line with: .. code:: bash - $ echo "1.5, 8.0, 6, 5" > config.txt + echo "1.5, 8.0, 6, 5" > config.txt -or download the file :download:`config.txt ` -(making sure to place it in the ``test`` directory). +or download the file :download:`config.txt `, +making sure to place it in the ``test`` directory. -Run the *bmi-tester*: +From the ``test`` directory, run the *bmi-tester*: .. code:: bash - $ bmi-test pymt_heatc:HeatModel --config-file=config.txt --root-dir=. -vvv + bmi-test pymt_heatc:HeatC --config-file=config.txt --root-dir=. -vvv This command sets off a long list of messages, ending with @@ -281,15 +254,15 @@ ending with if everything has been built correctly. -Add metadata to make a *pymt* component ---------------------------------------- +Make a *pymt* component +----------------------- The final step in wrapping the *heat* model is to add metadata used by the `Python Modeling Tool`_, *pymt*. CSDMS develops a set of standards, the `CSDMS Model Metadata`_, that provides a detailed and formalized description of a model. -The metadata allow *heat* to be run and and :term:`coupled ` +The metadata allow *heat* to be run and be :term:`coupled ` with other models that expose a BMI and have been similarly wrapped with the *babelizer*. @@ -297,61 +270,79 @@ Recall the *babelizer* outputs the wrapped *heat* model to the directory ``pymt_heatc``. Under this directory, the *babelizer* created a directory for *heat* model metadata, -``meta/HeatModel``. +``meta/HeatC``. Change back to the ``pymt_heatc`` directory and view the current metadata: .. code:: bash - $ cd ../pymt_heatc - $ ls meta/HeatModel/ + cd ../pymt_heatc + ls meta/HeatC/ + +which gives: + +.. code:: bash + api.yaml The file ``api.yaml`` is automatically generated by the *babelizer*. To complete the description of the *heat* model, other metadata files are needed, including: -* :download:`info.yaml ` -* :download:`run.yaml ` -* a :download:`templated model configuration file ` -* :download:`parameters.yaml ` +* :download:`info.yaml ` +* :download:`run.yaml ` +* a :download:`templated model configuration file ` +* :download:`parameters.yaml ` `Descriptions`_ of these files and their roles are given in the CSDMS Model Metadata repository. Download each of the files using the links in the list above -and place them in the ``pymt_heatc/meta/HeatModel`` directory +and place them in the ``pymt_heatc/meta/HeatC`` directory alongside ``api.yaml``. - -Next, install *pymt*: +The structure of the ``meta`` directory should look like: .. code:: bash - $ conda install -c conda-forge pymt + meta/ + └── HeatC/ + ├── api.yaml + ├── heat.txt + ├── info.yaml + ├── parameters.yaml + └── run.yaml -Then start a Python session and show that the *heat* model +Run the babelized model in *pymt* +................................... + +Start a Python session and show that the *heat* model can be called through *pymt*: .. code:: python - >>> from pymt.models import HeatModel - >>> m = HeatModel() - >>> print(m.name) + from pymt.models import HeatC + m = HeatC() + m.name + +You should see: + +.. code:: bash + The 2D Heat Equation A longer example, -:download:`pymt_heatc_ex.py `, +:download:`pymt_heatc_ex.py `, is included in the documentation. For easy viewing, it's reproduced here verbatim: -.. include:: examples/pymt_heatc_ex.py +.. include:: examples/c/pymt_heatc_ex.py :literal: -:download:`Download ` this Python script, +:download:`Download ` this Python script, then run it with: .. code:: bash - $ python pymt_heatc_ex.py + python pymt_heatc_ex.py Summary @@ -361,7 +352,7 @@ Using the *babelizer*, we wrapped the *heat* model, which is written in C. It can now be called as a *pymt* component in Python. The steps for wrapping a model with the *babelizer* outlined in this example -can also be applied to models written in C++ and Fortran. +can also be applied to models written in C++ and `Fortran`_. .. @@ -370,7 +361,8 @@ can also be applied to models written in C++ and Fortran. .. _bmi-example-c: https://github.com/csdms/bmi-example-c .. _instructions: https://github.com/csdms/bmi-example-c/blob/master/README.md .. _Developer Command Prompt: https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs -.. _bmi-tester: https://github.com/csdms/bmi-tester +.. _bmi-tester: https://bmi-tester.readthedocs.io .. _Python Modeling Tool: https://pymt.readthedocs.io .. _CSDMS Model Metadata: https://github.com/csdms/model_metadata .. _Descriptions: https://github.com/csdms/model_metadata/blob/develop/README.rst +.. _Fortran: example-fortran.html diff --git a/docs/source/example-fortran.rst b/docs/source/example-fortran.rst index 536ce84e..0d2c3c56 100644 --- a/docs/source/example-fortran.rst +++ b/docs/source/example-fortran.rst @@ -9,16 +9,14 @@ To simplify package management in the example, we'll use :term:`conda`. We'll also use :term:`git` to obtain the model source code. -This is a somewhat long example. -To break it up, -here are the steps we'll take: +Here are the steps we'll take to complete this example: #. Create a :term:`conda environment` that includes software to compile the model and wrap it with the *babelizer* #. Clone the `bmi-example-fortran`_ repository from GitHub and build the *heat* model from source #. Create a *babelizer* input file describing the *heat* model -#. Run the *babelizer* to generate Python bindings, then build the bindings +#. Run the *babelizer* to generate a Python package, then build and install the package #. Show the *heat* model running in Python through *pymt* Before we begin, @@ -26,24 +24,20 @@ create a directory to hold our work: .. code:: bash - $ mkdir build && cd build + $ mkdir example-f && cd example-f This directory is a starting point; -we'll make new directories under it as we proceed through the example. -In the end, -the first level of the directory structure under ``build`` should look like this: +we'll add files and directories to it as we proceed through the example. +The final directory structure of ``example-c`` should look similar to that below. -.. code:: +.. code:: bash - . + example-f/ ├── babel_heatf.toml - ├── bmi-example-fortran - │ └── ... + ├── bmi-example-fortran/ ├── environment-fortran.yml - ├── pymt_heatf - │ └── ... - └── test - └── ... + ├── pymt_heatf/ + └── test/ Set up a conda environment -------------------------- @@ -57,11 +51,12 @@ The necessary packages are listed in the conda environment file :literal: :download:`Download ` this file -and create the new environment with: +and place it in the ``example-f`` directory you created above. +Create the new environment with: .. code:: bash - $ conda env create --file=environment-fortran.yml + conda env create --file environment-fortran.yml When this command completes, activate the environment @@ -69,20 +64,21 @@ activate the environment .. code:: bash - $ conda activate wrap + conda activate wrap-f -The *wrap* environment now contains all the dependencies needed +The *wrap-f* environment now contains all the dependencies needed to build, install, and wrap the *heat* model. Build the *heat* model from source ---------------------------------- -Clone the `bmi-example-fortran`_ repository from GitHub: +From the ``example-f`` directory, +clone the `bmi-example-fortran`_ repository from GitHub: .. code:: bash - $ git clone https://github.com/csdms/bmi-example-fortran + git clone https://github.com/csdms/bmi-example-fortran There are general `instructions`_ in the repository for building and installing this package on Linux, macOS, and Windows. @@ -93,14 +89,13 @@ should be used to specify the install path. Note that if you build the model with the `Fortran Package Manager `_ -(fpm), you will end up with a static library (`.a` on Unix, `.lib` on +(*fpm*), you will end up with a static library (`.a` on Unix, `.lib` on Windows) instead of the dynamic library (`.so` on Unix, `.dll` on Windows) that the CMake build creates. We are aware of issues linking to the compiler runtime libraries from this static library, and for this reason we recommend using the CMake build routine, as detailed below. - Linux and macOS ............... @@ -109,17 +104,17 @@ use these commands to build and install the *heat* model: .. code:: bash - $ cd bmi-example-fortran - $ mkdir _build && cd _build - $ cmake .. -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX - $ make install + cd bmi-example-fortran + mkdir build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX + make install Verify the install by testing for the existence of the module file of the library containing the compiled *heat* model: .. code:: bash - $ test -f $CONDA_PREFIX/include/bmiheatf.mod ; echo $? + test -f $CONDA_PREFIX/include/bmiheatf.mod ; echo $? A return of zero indicates success. @@ -134,25 +129,24 @@ Building the *heat* model on Windows requires either: * Microsoft Visual Studio 2017 or later, or Microsoft Build Tools for Visual Studio 2017 or later, in which case the following instructions should be followed. -Open the `Developer Command Prompt`_ and run: +Open a `Developer Command Prompt`_ and run: -.. code:: +.. code:: bat - > cd bmi-example-fortran - > mkdir _build - > cd _build - > cmake .. ^ - -G "NMake Makefiles" ^ - -DCMAKE_INSTALL_PREFIX=%CONDA_PREFIX% ^ - -DCMAKE_BUILD_TYPE=Release - > cmake --build . --target install --config Release + cd bmi-example-fortran + mkdir build && cd build + cmake .. ^ + -G "NMake Makefiles" ^ + -DCMAKE_INSTALL_PREFIX=%CONDA_PREFIX% ^ + -DCMAKE_BUILD_TYPE=Release + cmake --build . --target install --config Release Verify the install by testing for the existence of the module file of the library containing the compiled *heat* model: -.. code:: +.. code:: bat - > if exist %CONDA_PREFIX%\include\bmiheatf.mod echo File exists + if exist %CONDA_PREFIX%\include\bmiheatf.mod echo File exists Note that on Windows systems, the conda package we specified called `fortran-compiler` installs a fairly old version of the Flang @@ -170,126 +164,93 @@ that uses them, to avoid incompatibility issues, and so if you choose a different compiler than provided by `fortran-compiler`, you will likely have to compile the BMI bindings with this compiler as well. +Create a *babelizer* configuration file +--------------------------------------- -Create the *babelizer* input file ---------------------------------- - -The *babelizer* input file provides information to the *babelizer* +A *babelizer* configuration file provides information to the *babelizer* about the model to be wrapped. -The input file is created with the ``babelize generate`` subcommand. - -Return to our initial ``build`` directory and call ``babelize generate`` with: - -.. code:: bash - - $ cd ../.. - $ babelize generate \ - --package=pymt_heatf \ - --summary="PyMT plugin for the Fortran heat model" \ - --language=fortran \ - --library=bmiheatf \ - --entry-point=bmi_heat \ - --name=HeatModel \ - --requirement="" > babel_heatf.toml -In this call, -the *babelizer* will also fill in default values; -e.g., author name, author email, GitHub username, and license. +Typically, we would use the ``babelize sample-config`` command +to create a sample configuration file, which could then be edited. +However, to simplify this example, we have provided a completed +configuration file for the *heat* model. +:download:`Download ` the file +:download:`babel_heatf.toml` and copy it to the ``example-f`` directory. -The resulting file, :download:`babel_heatf.toml`, -will look something like this: +The configuration file looks like this: .. include:: babel_heatf.toml :literal: -For more information on the entries and sections of the *babelizer* input file, +For more information on the entries and sections of the *babelizer* configuration file, see `Input file <./readme.html#input-file>`_. Wrap the model with the *babelizer* ----------------------------------- -Generate Python bindings for the model with the ``babelize init`` subcommand: +From the ``example-f`` directory, +generate a Python package for the model with the ``babelize init`` command: .. code:: bash - $ babelize init babel_heatf.toml + babelize init babel_heatf.toml The results are placed in a new directory, ``pymt_heatf``, under the current directory. -.. code:: bash - - $ ls -aF pymt_heatf - ./ .gitignore recipe/ - ../ LICENSE requirements-build.txt - babel.toml Makefile requirements-library.txt - CHANGES.rst MANIFEST.in requirements-testing.txt - CREDITS.rst meta/ requirements.txt - docs/ pymt_heatf/ setup.cfg - .git/ pyproject.toml setup.py - .github/ README.rst - -Before we can build the Python bindings, -we must ensure that the dependencies required by the toolchain, -as well as any required by the model, -as specified in the *babelizer* input file (none in this case), -are satisfied. - -Change to the ``pymt_heatf`` directory and install dependencies -into the conda environment: - -.. code:: bash +Build and install the wrapped model +................................... - $ cd pymt_heatf - $ conda install -c conda-forge \ - --file=requirements-build.txt \ - --file=requirements-testing.txt \ - --file=requirements-library.txt \ - --file=requirements.txt - -Now build the Python bindings with: +Change to the ``pymt_heatf`` directory, +then build and install the Python package with *pip*: .. code:: bash - $ make install + cd pymt_heatf + pip install ."[dev]" -This command sets off a long list of messages, +The ``pip install`` command sets off a long list of messages, at the end of which you'll hopefully see: .. code:: bash - Successfully installed pymt-heatf-0.1 - -Internally, this uses `pip` to install the Python -package in editable mode. + Successfully installed pymt_heatf Pause a moment to see what we've done. -Change back to the initial ``build`` directory, +Change back to the initial ``example-f`` directory, make a new ``test`` directory, and change to it: .. code:: bash - $ cd .. - $ mkdir test && cd test + cd .. + mkdir test && cd test -Start a Python session (e.g. run ``python``) and try the following commands: +Start a Python session (e.g., run ``python``) and try the following commands: .. code:: python - >>> from pymt_heatf import HeatModel - >>> m = HeatModel() - >>> m.get_component_name() - 'The 2D Heat Equation' + from pymt_heatf import HeatF + m = HeatF() + m.get_component_name() + +You should see: + +.. code:: bash + + The 2D Heat Equation We've imported the *heat* model, written in Fortran, into Python! -Exit the Python session (e.g. type ``exit()``) +Exit the Python session (e.g. type ``exit()``). + +Test the BMI +............ At this point, -it's a good idea to run the *bmi-tester* (`GitHub repo `_) +it's a good idea to run the *bmi-tester* (`documentation `_) over the model. The *bmi-tester* exercises each BMI method exposed through Python, ensuring it works correctly. @@ -301,16 +262,16 @@ Create a configuration file for *heat* at the command line with: .. code:: bash - $ echo "1.5, 8.0, 6, 5" > config.txt + echo "1.5, 8.0, 6, 5" > config.txt -or download the file :download:`config.txt ` -(making sure to place it in the ``test`` directory). +or download the file :download:`config.txt `, +making sure to place it in the ``test`` directory. -Run the *bmi-tester*: +From the ``test`` directory, run the *bmi-tester*: .. code:: bash - $ bmi-test pymt_heatf:HeatModel --config-file=config.txt --root-dir=. -vvv + bmi-test pymt_heatf:HeatF --config-file=config.txt --root-dir=. -vvv This command sets off a long list of messages, ending with @@ -322,8 +283,8 @@ ending with if everything has been built correctly. -Add metadata to make a *pymt* component ---------------------------------------- +Make a *pymt* component +----------------------- The final step in wrapping the *heat* model is to add metadata used by the `Python Modeling Tool`_, *pymt*. @@ -338,14 +299,19 @@ Recall the *babelizer* outputs the wrapped *heat* model to the directory ``pymt_heatf``. Under this directory, the *babelizer* created a directory for *heat* model metadata, -``meta/HeatModel``. +``meta/HeatF``. Change back to the ``pymt_heatf`` directory and view the current metadata: .. code:: bash - $ cd ../pymt_heatf - $ ls meta/HeatModel/ + cd ../pymt_heatf + ls meta/HeatModel/ + +which gives: + +.. code:: bash + api.yaml The file ``api.yaml`` is automatically generated by the *babelizer*. @@ -360,47 +326,53 @@ other metadata files are needed, including: `Descriptions`_ of these files and their roles are given in the CSDMS Model Metadata repository. Download each of the files using the links in the list above -and place them in the ``pymt_heatf/meta/HeatModel`` directory +and place them in the ``pymt_heatf/meta/HeatF`` directory alongside ``api.yaml``. - -Next, install *pymt*: +The structure of the ``meta`` directory should look like: .. code:: bash - $ conda install -c conda-forge pymt + meta/ + └── HeatF/ + ├── api.yaml + ├── heat.txt + ├── info.yaml + ├── parameters.yaml + └── run.yaml -Then start a Python session and show that the *heat* model +Run the babelized model in *pymt* +................................... + +Start a Python session and show that the *heat* model can be called through *pymt*: .. code:: python - >>> from pymt.models import HeatModel - >>> m = HeatModel() - >>> m.name - 'The 2D Heat Equation' + from pymt.models import HeatF + m = HeatF() + m.name + +You should see: + +.. code:: bash + + The 2D Heat Equation A longer example, -:download:`pymt_heatc_ex.py `, +:download:`pymt_heatf_ex.py `, is included in the documentation. For easy viewing, it's reproduced here verbatim: -.. include:: examples/pymt_heatc_ex.py +.. include:: examples/fortran/pymt_heatf_ex.py :literal: -:download:`Download ` this Python script, +:download:`Download ` this Python script, make sure we're still in the `test` directory we just created, then run it with: .. code:: bash - $ python pymt_heatc_ex.py - -Note that here we are actually running the Python script that -was developed for the :doc:`C example `, not Fortran. -That is one of the powerful things about wrapping your -BMI-enabled model and accessing it via PyMT - it provides a -standardised interface, regardless of the underlying model -and the language it was written in. + python pymt_heatf_ex.py Summary @@ -410,7 +382,7 @@ Using the *babelizer*, we wrapped the *heat* model, which is written in Fortran. It can now be called as a *pymt* component in Python. The steps for wrapping a model with the *babelizer* outlined in this example -can also be applied to models written in C (:doc:`see the example `) +can also be applied to models written in C (:doc:`see the example `) and C++. @@ -420,7 +392,7 @@ and C++. .. _bmi-example-fortran: https://github.com/csdms/bmi-example-fortran .. _instructions: https://github.com/csdms/bmi-example-c/blob/master/README.md .. _Developer Command Prompt: https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs -.. _bmi-tester: https://github.com/csdms/bmi-tester +.. _bmi-tester: https://bmi-tester.readthedocs.io .. _Python Modeling Tool: https://pymt.readthedocs.io .. _CSDMS Model Metadata: https://github.com/csdms/model_metadata .. _Descriptions: https://github.com/csdms/model_metadata/blob/develop/README.rst diff --git a/docs/source/examples/c/config.txt b/docs/source/examples/c/config.txt new file mode 120000 index 00000000..f1a6cc6c --- /dev/null +++ b/docs/source/examples/c/config.txt @@ -0,0 +1 @@ +../config.txt \ No newline at end of file diff --git a/docs/source/examples/heat.txt b/docs/source/examples/c/heat.txt similarity index 100% rename from docs/source/examples/heat.txt rename to docs/source/examples/c/heat.txt diff --git a/docs/source/examples/heatc_ex.py b/docs/source/examples/c/heatc_ex.py similarity index 94% rename from docs/source/examples/heatc_ex.py rename to docs/source/examples/c/heatc_ex.py index d6c31f23..5dae9948 100644 --- a/docs/source/examples/heatc_ex.py +++ b/docs/source/examples/c/heatc_ex.py @@ -1,14 +1,14 @@ -"""An example of running the heatc model through its BMI.""" +"""An example of running the C heat model through its BMI.""" import numpy as np -from pymt_heatc import HeatModel +from pymt_heatc import HeatC config_file = "config.txt" np.set_printoptions(formatter={"float": "{: 6.1f}".format}) # Instatiate an initialize the model. -m = HeatModel() +m = HeatC() print(m.get_component_name()) m.initialize(config_file) diff --git a/docs/source/examples/info.yaml b/docs/source/examples/c/info.yaml similarity index 100% rename from docs/source/examples/info.yaml rename to docs/source/examples/c/info.yaml diff --git a/docs/source/examples/parameters.yaml b/docs/source/examples/c/parameters.yaml similarity index 100% rename from docs/source/examples/parameters.yaml rename to docs/source/examples/c/parameters.yaml diff --git a/docs/source/examples/pymt_heatc_ex.py b/docs/source/examples/c/pymt_heatc_ex.py old mode 100755 new mode 100644 similarity index 94% rename from docs/source/examples/pymt_heatc_ex.py rename to docs/source/examples/c/pymt_heatc_ex.py index 85f27694..09490235 --- a/docs/source/examples/pymt_heatc_ex.py +++ b/docs/source/examples/c/pymt_heatc_ex.py @@ -1,9 +1,9 @@ -"""Run the heat model in pymt.""" +"""Run the C heat model in pymt.""" -from pymt.models import HeatModel +from pymt.models import HeatC # Instantiate the component and get its name. -m = HeatModel() +m = HeatC() print(m.name) # Call setup, then initialize the model. diff --git a/docs/source/examples/run.yaml b/docs/source/examples/c/run.yaml similarity index 100% rename from docs/source/examples/run.yaml rename to docs/source/examples/c/run.yaml diff --git a/docs/source/examples/fortran/config.txt b/docs/source/examples/fortran/config.txt new file mode 120000 index 00000000..f1a6cc6c --- /dev/null +++ b/docs/source/examples/fortran/config.txt @@ -0,0 +1 @@ +../config.txt \ No newline at end of file diff --git a/docs/source/examples/fortran/heatf_ex.py b/docs/source/examples/fortran/heatf_ex.py new file mode 100644 index 00000000..661a59e1 --- /dev/null +++ b/docs/source/examples/fortran/heatf_ex.py @@ -0,0 +1,67 @@ +"""An example of running the Fortran heat model through its BMI.""" + +import numpy as np +from pymt_heatf import HeatF + +config_file = "config.txt" +np.set_printoptions(formatter={"float": "{: 6.1f}".format}) + + +# Instatiate and initialize the model. +m = HeatF() +print(m.get_component_name()) +m.initialize(config_file) + +# List the model's exchange items. +print("Input vars:", m.get_input_var_names()) +print("Output vars:", m.get_output_var_names()) + +# Get the grid_id for the plate_surface__temperature variable. +var_name = "plate_surface__temperature" +print(f"Variable {var_name}") +grid_id = m.get_var_grid(var_name) +print(" - grid id:", grid_id) + +# Get grid and variable info for plate_surface__temperature. +print(" - grid type:", m.get_grid_type(grid_id)) +grid_rank = m.get_grid_rank(grid_id) +print(" - rank:", grid_rank) +grid_shape = np.empty(grid_rank, dtype=np.int32) +m.get_grid_shape(grid_id, grid_shape) +print(" - shape:", grid_shape) +grid_size = m.get_grid_size(grid_id) +print(" - size:", grid_size) +grid_spacing = np.empty(grid_rank, dtype=np.float64) +m.get_grid_spacing(grid_id, grid_spacing) +print(" - spacing:", grid_spacing) +grid_origin = np.empty(grid_rank, dtype=np.float64) +m.get_grid_origin(grid_id, grid_origin) +print(" - origin:", grid_origin) +print(" - variable type:", m.get_var_type(var_name)) +print(" - units:", m.get_var_units(var_name)) +print(" - itemsize:", m.get_var_itemsize(var_name)) +print(" - nbytes:", m.get_var_nbytes(var_name)) + +# Get the initial temperature values. +val = np.empty(grid_shape, dtype=np.float64) +m.get_value(var_name, val) +print(" - initial values (gridded):") +print(val.reshape(np.roll(grid_shape, 1))) + +# Get time information from the model. +print("Start time:", m.get_start_time()) +print("End time:", m.get_end_time()) +print("Current time:", m.get_current_time()) +print("Time step:", m.get_time_step()) +print("Time units:", m.get_time_units()) + +# Advance the model by one time step. +m.update() +print("Updated time:", m.get_current_time()) + +# Advance the model until a later time. +m.update_until(5.0) +print("Later time:", m.get_current_time()) + +# Finalize the model. +m.finalize() diff --git a/docs/source/examples/fortran/pymt_heatf_ex.py b/docs/source/examples/fortran/pymt_heatf_ex.py new file mode 100644 index 00000000..91678b43 --- /dev/null +++ b/docs/source/examples/fortran/pymt_heatf_ex.py @@ -0,0 +1,61 @@ +"""Run the Fortran heat model in pymt.""" + +from pymt.models import HeatF + +# Instantiate the component and get its name. +m = HeatF() +print(m.name) + +# Call setup, then initialize the model. +args = m.setup(".") +m.initialize(*args) + +# List the model's exchange items. +print("Number of input vars:", len(m.input_var_names)) +for var in m.input_var_names: + print(f" - {var}") +print("Number of output vars:", len(m.output_var_names)) +for var in m.output_var_names: + print(f" - {var}") + +# Get variable info. +var_name = m.output_var_names[0] +print(f"Variable {var_name}") +print(" - variable type:", m.var_type(var_name)) +print(" - units:", m.var_units(var_name)) +print(" - itemsize:", m.var_itemsize(var_name)) +print(" - nbytes:", m.var_nbytes(var_name)) +print(" - location:", m.var_location(var_name)) + +# Get grid info for variable. +grid_id = m.var_grid(var_name) +print(" - grid id:", grid_id) +print(" - grid type:", m.grid_type(grid_id)) +print(" - rank:", m.grid_ndim(grid_id)) +print(" - size:", m.grid_node_count(grid_id)) +print(" - shape:", m.grid_shape(grid_id)) + +# Get time information from the model. +print("Start time:", m.start_time) +print("End time:", m.end_time) +print("Current time:", m.time) +print("Time step:", m.time_step) +print("Time units:", m.time_units) + +# Get the initial values of the variable. +print(f"Get values of {var_name}...") +val = m.var[var_name].data +print(f" - values at time {m.time}:") +print(val) + +# Advance the model by one time step. +m.update() +print("Update: current time:", m.time) + +# Advance the model until a later time. +m.update_until(5.0) +print("Update: current time:", m.time) + +# Finalize the model. +m.finalize() +print("Done.") diff --git a/docs/source/index.rst b/docs/source/index.rst index dedebede..0a025055 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -40,7 +40,7 @@ User Guide readme cli - example + example-c example-fortran glossary @@ -66,6 +66,7 @@ Additional Information authors changelog contributing + code-of-conduct license Help diff --git a/news/97.doc b/news/97.doc new file mode 100644 index 00000000..e9fc43e7 --- /dev/null +++ b/news/97.doc @@ -0,0 +1,3 @@ + +Updated the C and Fortran examples in the docs for configuration and API +changes in the *babelizer*. diff --git a/news/97.misc.1 b/news/97.misc.1 new file mode 100644 index 00000000..ccba3e7c --- /dev/null +++ b/news/97.misc.1 @@ -0,0 +1,2 @@ + +Added a document linking to the CSDMS Code of Conduct. diff --git a/news/97.misc.2 b/news/97.misc.2 new file mode 100644 index 00000000..cc671173 --- /dev/null +++ b/news/97.misc.2 @@ -0,0 +1,3 @@ + +Removed the Sphinx makefiles from the ``docs`` directory in favor of the *nox* +``build-docs`` session.