.. Copyright 2022 NWChemEx-Project
..
.. Licensed under the Apache License, Version 2.0 (the "License");
.. you may not use this file except in compliance with the License.
.. You may obtain a copy of the License at
..
.. http://www.apache.org/licenses/LICENSE-2.0
..
.. Unless required by applicable law or agreed to in writing, software
.. distributed under the License is distributed on an "AS IS" BASIS,
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
.. See the License for the specific language governing permissions and
.. limitations under the License.

***************************
Loading a Module Collection
***************************

The key piece of a module collection is the ``load_modules`` function. When a
user starts a run with PluginPlay one of the first things they do is initialize
a ``ModuleManager`` instance. The code to do this looks something like:

.. code-block:: c++

   // Initialize ModuleManager
   ModuleManager mm;
   library1::load_modules(mm);
   library2::load_modules(mm);

where ``load_modules(mm)`` calls load the module collections provided by the
various libraries.

Public API
==========

As far as the public API for ``load_modules`` goes, the declaration is simple:

.. literalinclude:: ../../../../tests/cxx/doc_snippets/load_modules.hpp
   :language: c++

In particular note that by forward declaring the ``load_modules`` function it is
not necessary for the user to know the types of your modules and more
importantly any libraries you use to implement them.

.. note::

   If your modules use property types defined elsewhere (such as in centralized
   community resources like NWChemEx/SimDE) and your
   module-specific inputs are standard C++ types (or types found in the
   property types) this is your entire public API!!!

Implementation
==============

The actual implementation of ``load_modules`` typically consists of two parts:
loading the modules and setting the default submodules.

Modules are loaded into the ``ModuleManager`` by calling ``add_module``. For
your convenience the ``ModuleManager`` has an overload of ``add_module`` which
takes a template type parameter that is the type of your module (as in the name
of the class which contains the algorithm) and a module key. The module key is
how users will refer to your module, *e.g.*, when they want to run your module
they will call ``ModuleManager::run_as`` providing your module's key. If your
module requires more detailed set-up other overloads exist that will bind to
existing instances.

Continuing with our electric field examples, adding our modules to the
``ModuleManager`` looks like:

.. literalinclude:: ../../../../tests/cxx/doc_snippets/load_modules.cpp
   :language: c++
   :lines: 17-27,30-32


Once you have added all your modules the next step is to set the default
submodules. In our examples, the ``ClassicalForce`` module needed a submodule
which can compute electric fields. Presently we have already loaded three such
modules; their keys are:

- "Coulomb's Law"
- "Coulomb's Law with screening"
- "Single-precision Coulomb's law"

If by default we want the ``ClassicalForce`` module we loaded under the key
"Force" to use a ``CoulombsLaw`` module we can accomplish this by:

.. literalinclude:: ../../../../tests/cxx/doc_snippets/load_modules.cpp
   :language: c++
   :lines: 29

.. note::

   It is not necessary to set all submodules in the ``load_modules`` function.
   In particular if your module depends on a property that none of your modules
   can compute you would not set that submodule. In this case, it will be the
   responsability of the caller to set the submodule.

The entire implementation of our ``load_modules`` function looks like:

.. literalinclude:: ../../../../tests/cxx/doc_snippets/load_modules.cpp
   :language: c++
