{ "cells": [ { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# MueLu - Level containers" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "## Philosophy" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "- *MueLu* strictly splits data and algorithms.\n", "- Data is stored in data containers. There is one data container associated with each level. Therefore, the data container class is ```Level```.\n", "- The algorithms are implemented in ```Factory``` classes. Factory here, means, that input data is used and processed to produce output data. A factory can be understood as a data processing unit. It does not store any data itself." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "## Basics of the Level container" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Declare location of include headers " ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ ".I /opt/install/do-conf-ep-serial/include/" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ " Load Trilinos libraries" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ ".L libepetra" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ ".L libxpetra" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ ".L libmuelu" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ ".L libteuchoscore" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Include some standard header files to create a communicator and an ```Xpetra::Map```" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#include \"Kokkos_DefaultNode.hpp\"\n", "#include \"Epetra_SerialComm.h\"\n", "#include \"Teuchos_RCP.hpp\"\n", "#include \"Teuchos_DefaultSerialComm.hpp\"\n", "#include \"Xpetra_MapFactory.hpp\"\n", "#include \"Xpetra_Map.hpp\"" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Again, we use standard template parameters:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typedef double SC;\n", "typedef int LO;\n", "typedef int GO;\n", "typedef Kokkos::Compat::KokkosSerialWrapperNode EpetraNode;\n", "typedef EpetraNode NO;" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Let's create a ```MueLu::Level``` object:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#include \"MueLu_Level.hpp\"" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(MueLu::Level &) @0x7f27d0fa9018\n" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MueLu::Level l;" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "A ```MueLu::Level``` object is basically a data container. You can store (arbitrary) data in the level container given a (unique) name. To store data, you use the ```Set``` routine:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Set(\"MyInt\", 42);\n", "l.Set(\"MyDouble\", 37.88);\n" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "This also works for more complicated objects. Usually, you store ```RCP``` pointers to some linear algebra objects, such as matrices, vectors or just ```Xpetra::Map``` objects as shown next:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(Teuchos::RCP > &) @0x7f27d0fa9150\n" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Epetra_SerialComm Comm;\n", "Teuchos::RCP > comm = Xpetra::toXpetra(Comm);\n", "Teuchos::RCP> map = Xpetra::MapFactory::Build(Xpetra::UseEpetra, 10, 0, comm);" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Set(\"MyMap\", map);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The ```Level``` class has a print routine, that can be very useful for debugging. It prints a list with all data stored insided and some additional information. Please note, that you have to provide the ```MueLu::Extreme``` verbosity flag to print the list." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyMap NoFactory 0 User Map available \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.print(std::cout, MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Routines like ```IsAvailable``` allow you to check programmatically at runtime whether a variable is stored in the ```Level``` container:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(bool) true\n" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.IsAvailable(\"MyMap\");" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "To access data, you can use the ```Get``` data. It is templated on the data type." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(Teuchos::RCP > &) @0x7f27d0fa9168\n" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Teuchos::RCP> myMap = l.Get>>(\"MyMap\");" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " \n", " Number of Global Entries = 10\n", " Maximum of all GIDs = 9\n", " Minimum of all GIDs = 0\n", " Index Base = 0\n", " \n", "\n" ] }, { "data": { "text/plain": [ "(std::basic_ostream >::__ostream_type &) @0x7f27c8cee700\n" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "std::cout << *myMap << std::endl;" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Data, which is stored on the level class using the ```Set``` routine is not automatically freed after the ```Get``` call, as one can easily verify:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyMap NoFactory 0 User Map available \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.print(std::cout, MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "As you can see, the variable ```myMap``` is still contained in the list of data." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "You can explicitly remove data from the container by using the following ```Delete``` call." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Delete(\"MyMap\",MueLu::NoFactory::get());" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Printing out the content of ```l``` proofs that ```MyMap``` is not stored in the container any more." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.print(std::cout, MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "You may have noticed that we needed the ```MueLu::NoFactory::get()``` parameter in the ```Delete``` call. This leads us to the next step, discussing data dependencies and finally the Factory concept in *MueLu*." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "## What is ```MueLu::NoFactory```?" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "```MueLu::NoFactory``` means that the associated data has not been created by a so-called ```Factory```. In order to automatically manage and resolve data dependencies *MueLu* uses the so-called ```Factories```. ```Factory``` classes contain the algorithms: they require some algorithm-specific input data, process the input data and produce some output data. In contrast: the ```Level``` class is a pure container class, storing and providing data that is used by the ```Factory``` classes." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Please note: the naming ```Factory``` class might be misleading. It is not a ```Factory``` class in the sense of the ```Factory``` pattern to create new objects as it is used, e.g., in *Xpetra* (see, e.g., ```Xpetra::MapFactory```)." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Long in short: *MueLu* **strictly** separates data and algorithms. The data is stored in the ```Level``` container classes whereas data is processed in the ```Factory``` classes. The ```Factory``` classes get data from the ```Level``` classes and store newly generated data in the ```Level``` classes." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "## How can we declare data dependencies?" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Factory-generated data versus user data" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "To demonstrate the principle, let's define the most trivial ```Factory``` class, one can think of:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#include \"MueLu_SingleLevelFactoryBase.hpp\"\n", "using Teuchos::RCP;\n", "using MueLu::Level;\n", "class DummyFact : public MueLu::SingleLevelFactoryBase { \n", " virtual void DeclareInput(Level ¤tLevel) const {};\n", " virtual void Build(Level & currentLevel) const {};\n", "};" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "For now, the meaning of the empty routines ```DeclareInput``` and ```Build``` is not important.\n", "\n", "Next, we create two instances, that is, two different factories." ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(DummyFact &) @0x7f27d0fa92c0\n" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "DummyFact f1;\n", "DummyFact f2;" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Important is, that each factory has a unique memory adress, e.g." ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Memory adress of factory1: 0x7f27d0fa9180\n", "Memory adress of factory2: 0x7f27d0fa92c0\n" ] }, { "data": { "text/plain": [ "(std::basic_ostream >::__ostream_type &) @0x7f27c8cee700\n" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "std::cout << \"Memory adress of factory1: \" << &f1 << std::endl;\n", "std::cout << \"Memory adress of factory2: \" << &f2 << std::endl;" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The keypoint is to understand, that data in *MueLu* is uniquely described by the name **and** the generating factory. The generating factory itself is identified and referred to by its memory adress.\n", "\n", "This allows to store *different data* using the *same* variable name but a *different factory*." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Let's give an example:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "******* WARNING *******\n", "Level::Set: unable to store \"MyInt\" generated by factory 0x7f27d0fa9180 on level -1, as it has not been requested and no keep flags were set for it\n", "\n", "******* WARNING *******\n", "Level::Set: unable to store \"MyInt\" generated by factory 0x7f27d0fa92c0 on level -1, as it has not been requested and no keep flags were set for it\n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Set(\"MyInt\", 46, &f1);\n", "l.Set(\"MyInt\", 47, &f2);" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyInt 0x7f27d0fa9180 1 No unknown not available 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.print(std::cout,MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Obviously, storing data failed. In fact, data generated by a factory is only stored, if it has requested before.\n", "\n", "So, let's *request* the data named *MyInt* generated by *f1*:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyInt 0x7f27d0fa9180 1 No unknown not available 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Request(\"MyInt\", &f1);\n", "l.print(std::cout,MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The printout shows a variable *MyInt* generated by ```NoFactory``` from the beginning (with data $42$). There is a second *MyInt* generated by the adress associated with ```f1```. The variable is listed to be requested, but there is no data stored (```data not available```). Now, let's try to set the data:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyInt 0x7f27d0fa9180 1 No int 46 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Set(\"MyInt\", 46, &f1);\n", "l.print(std::cout,MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "That worked! Now we have two different variables *MyInt*. One generated by ```NoFactory``` (which corresponds to the user) with the value $42$ and one generated by ```f1``` with the value $46$." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Ok. Let's store another *MyInt* generated by ```f2```, just to test it:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyInt 0x7f27d0fa9180 1 No int 46 0xc2550f0 \n", " MyInt 0x7f27d0fa92c0 1 No int 47 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Request(\"MyInt\", &f2);\n", "l.Set(\"MyInt\", 47, &f2);\n", "l.print(std::cout,MueLu::Extreme);" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyInt 0x7f27d0fa9180 1 No int 46 0xc2550f0 \n", " MyInt 0x7f27d0fa92c0 1 No int 47 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int ret = l.Get(\"MyInt\", &f2);\n", "int ret2 = l.Get(\"MyInt\", &f2);\n", "int ret3 = l.Get(\"MyInt\", &f2);\n", "l.print(std::cout, MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "As you can see, we can access the data several times and it is not automatically freed. We can use ```Release``` to decrement the request counter. If it goes to zero, the data is deleted from the ```Level``` container. If it was a RCP pointer that runs out of scope, the underlying data is also automatically freed." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " MyDouble NoFactory 0 User double 37.8800 \n", " MyInt NoFactory 0 User int 42 \n", " MyInt 0x7f27d0fa9180 1 No int 46 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Release(\"MyInt\", &f2);\n", "l.print(std::cout, MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Long in short: the ```Request``` call increases the request counter, whereas the ```Release``` call decreases the request counter. If the request counter is zero the data is removed from the level container. Only data, which has been requested before (i.e., its request counter is larger than zero) can be stored.\n", "\n", "The only exception is user data (generated by ```NoFactory```). It can always be stored. User data has to be deleted using the ```Delete``` call." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "To clear all data from the level class the following commands would be necessary:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Release(\"MyInt\", &f1); // Release the data gen. by f1\n", "l.Delete(\"MyInt\", MueLu::NoFactory::get()); // Remove the 42 from l\n", "l.Delete(\"MyDouble\", MueLu::NoFactory::get());\n", "l.print(std::cout, MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The level container now should be empty." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Factory dependencies" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "#### The naive approach" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Let's implement a first non-trivial factory. That is, we have to provide a implementation for the ```DeclareInput``` and the ```Build``` routine. The following factory shall take a variable ```InputNumber``` of type ```int``` as input and store the square root of it in the level container using the variable name ```SquareRoot```.\n", "\n", "In the ```DeclareInput``` routine we have to declare all necessary input data. In our case this is the ```InputNumber``` variable, which is supposed to be provided by the user. In the ```Build``` routine we obtain the input data from the ```Level``` class, build the square root and store the result on the ```Level``` class.\n", "\n", "A naive implementation could look like follows:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class SquareRootFact : public MueLu::SingleLevelFactoryBase { \n", " public:\n", " virtual void DeclareInput(MueLu::Level ¤tLevel) const {\n", " currentLevel.DeclareInput(\"InputNumber\", MueLu::NoFactory::get(), this);\n", " };\n", " virtual void Build(MueLu::Level & currentLevel) const {\n", " // extract data from level\n", " double userInput = currentLevel.Get(\"InputNumber\");\n", " // do calculation, process data\n", " double result = sqrt(userInput);\n", " // store result in level container\n", " currentLevel.Set(\"SquareRoot\", result);\n", " };\n", "};" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Let's create an instance of the class:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(SquareRootFact &) @0x7f27d0fa9418\n" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "SquareRootFact sqFact;" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The ```Level``` class has a ```Request``` routine, which recursively makes sure that all necessary input data for the given factory is properly requested in the ```Level``` container:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " InputNumber NoFactory 1 No unknown not available 0x7f27d0fa9418 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Request(sqFact);\n", "l.print(std::cout, MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "In our case above call is not really necessary (but it does not really hurt either), since we only need user-provided data as input (```NoFactory```).\n", "\n", "Please note: we **never** call the ```DeclareInput``` routine of the Factory class directly (unless you are an absolute expert), since it contains some sophisticated logic to recursively resolve data dependencies. You always should think from the level perspective and call the member functions provided by the ```Level``` class." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Of course, we must not forget to set the input data:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Set(\"InputNumber\", 25);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Then, we can call the build routine and check the output" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " InputNumber NoFactory 1 User int 25 0x7f27d0fa9418 \n", " SquareRoot NoFactory 0 User double 5.0000 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sqFact.Build(l);\n", "l.print(std::cout,MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "It seems to work, but let's find a more elegant solution." ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.ExpertClear();" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "#### Use data dependencies between factories" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Usually, input data for a factory is provided by another factory (rather than the user). So, just for demonstration purposes, let's introduce a new factory ```DataFactory2``` which only stores a number in the level container. The implementation would be like this:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class DataFactory2 : public MueLu::SingleLevelFactoryBase { \n", " public:\n", " virtual void DeclareInput(MueLu::Level ¤tLevel) const {};\n", " virtual void Build(MueLu::Level & currentLevel) const {\n", " currentLevel.Set(\"Number\", 36.0, this);\n", " };\n", "};" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Please note the ```this``` pointer as third argument in the ```Set``` call. It means that the concrete instance of ```DataFactory2``` generated the variable ```Number```, that is stored in the ```Level``` container.\n", "\n", "Next, we create a ```SquareRootFact2``` factory, which expects the input variable ```Number``` from a factory which actually provides the data variable ```Number```. In the ```DeclareInput``` call as well as in the ```Get``` call in the ```Build``` routine, we use the ```GetFactory(\"Number\")``` routine, which basically returns the factory which is responsible to produce the variable ```Number```. In our case this will be an instance of ```DataFactory2```. We will see later how we declare the data dependency." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class SquareRootFact2 : public MueLu::SingleLevelFactoryBase { \n", " public:\n", " virtual void DeclareInput(MueLu::Level ¤tLevel) const {\n", " currentLevel.DeclareInput(\"Number\", GetFactory(\"Number\").get(), this);\n", " };\n", " virtual void Build(MueLu::Level & currentLevel) const {\n", " // extract data from level\n", " double userInput = currentLevel.Get(\"Number\", GetFactory(\"Number\").get());\n", " //double userInput = Get(currentLevel,\"Number\");\n", " // do calculation, process data\n", " double result = sqrt(userInput);\n", " // store result in level container\n", " currentLevel.Set(\"SquareRoot\", result, this);\n", " };\n", "};" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "We create an instance of both the ```DataFactory2``` and ```SquareRootFact2``` classes." ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(SquareRootFact2 &) @0x7f27d0fa96a0\n" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "DataFactory2 datFact;\n", "SquareRootFact2 sqFact2;" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Then, we declare the data dependencies between these two factories. In our case ```datFact``` is responsible to provide variable ```Number``` as input for factory ```sqFact2```. In other words: ```sqFact2``` requires ```Number``` generated by ```datFact```. That is, we set ```datFact``` as the generating factory for ```Number``` in ```sqFact2```. This is done by the ```SetFactory``` routine:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sqFact2.SetFactory(\"Number\", Teuchos::rcpFromRef(datFact));" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "To calculate the square root of ```Number``` we then *request* the result on the level class with the command" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.Request(\"SquareRoot\", &sqFact2);" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " Number 0x7f27d0fa9560 1 No unknown not available 0x7f27d0fa96a0 \n", " SquareRoot 0x7f27d0fa96a0 1 No unknown not available 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.print(std::cout,MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "As one can see, the ```Request``` call for ```SquareRoot``` automatically triggered an ```Request``` for ```Number```, since it is prerequisite to calculate the result.\n", "\n", "After all requests have (automatically) been resolved in a recursive fashion we are ready for the result." ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(double) 6.000000\n" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "double sqres = l.Get(\"SquareRoot\", &sqFact2);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Again, we do not call the ```Build``` routines directly, but just ask for the result. The ```Build``` routines are then automatically recursively called to produce the requested result.\n", "\n", "Note, you have to call ```Request(\"SquareRoot\",...)``` before the ```Get(\"SquareRoot\",...)``` call. Data, which has not been requested first, won't be calculated and nothing would happen.\n", "\n", "Next, we can look at the content of the level container. Obviously, it only contains the ```SquareRoot``` variable with the result $6$. The input data ```Number``` was only necessary to calculate the variable ```SquareRoot```. No other factory has requested ```Number```. Therefore, ```Number``` has automatically been freed and removed from the container.\n", "\n", "The result ```SquareRoot``` is stored on the level class as we've requested it by our ```Request``` call." ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "LevelID = -1\n", " data name gen. factory addr. req keep type data req'd by \n", " -------------------- ------------------ ----- ----- --------------- -------------- --------------------\n", " SquareRoot 0x7f27d0fa96a0 1 No double 6.0000 0xc2550f0 \n" ] }, { "data": { "text/plain": [ "(void) @0x7ffcffc83ef0\n" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.print(std::cout,MueLu::Extreme);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Of course, the ```Build``` routines are only called if we try to get data from the level container, which is not available, yet. Once it has been calculated, we can extract it as often we want (as long as we do not release the data) without the data being recalculated." ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(double) 6.000000\n" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "double sqres2 = l.Get(\"SquareRoot\", &sqFact2);" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "#### A slightly more elegant implementation" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The ```Get``` and ```Set``` calls can be written a little bit more elegant using the ```Get``` and ```Set``` functions of the ```Factory``` class. In the following example, the commented lines are equivalent with the new commands below." ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class DataFactory3 : public MueLu::SingleLevelFactoryBase { \n", " public:\n", " virtual void DeclareInput(MueLu::Level ¤tLevel) const {};\n", " virtual void Build(MueLu::Level & currentLevel) const {\n", " //currentLevel.Set(\"Number\", 36.0, this);\n", " Set(currentLevel, \"Number\", 36.0);\n", " };\n", "};\n", "\n", "class SquareRootFact3 : public MueLu::SingleLevelFactoryBase { \n", " public:\n", " virtual void DeclareInput(MueLu::Level ¤tLevel) const {\n", " //currentLevel.DeclareInput(\"Number\", GetFactory(\"Number\").get(), this);\n", " Input(currentLevel,\"Number\");\n", " };\n", " virtual void Build(MueLu::Level & currentLevel) const {\n", " // extract data from level\n", " //double userInput = currentLevel.Get(\"Number\", GetFactory(\"Number\").get());\n", " double userInput = Get(currentLevel,\"Number\");\n", " // do calculation, process data\n", " double result = sqrt(userInput);\n", " // store result in level container\n", " //currentLevel.Set(\"SquareRoot\", result, this);\n", " Set(currentLevel,\"SquareRoot\", result);\n", " };\n", "};\n" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The following list might help to understand the different syntax of the ```Level``` and ```Factory``` calls. Note, that ```Factory``` internally always uses ```GetFactory``` to determine the associated generating factory for the data variables.\n", "\n", "| Level class | Factory class |\n", "|-------------|---------------|\n", "| Level::DeclareInput(\"VariableName\", FactoryPtr, GeneratingFactoryPtr) | Factory::Input(Level, \"VariableName\") |\n", "| Level::Get(\"VariableName\", FactoryPtr) | Factory::Get(Level, \"VariableName\") |\n", "| Level::Set(\"VariableName\", FactoryPtr) | Factory::Set(Level, \"VariableName\") |" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [ { "data": { "text/plain": [ "(double) 6.000000\n" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "DataFactory3 datFact3;\n", "SquareRootFact3 sqFact3;\n", "sqFact3.SetFactory(\"Number\", Teuchos::rcpFromRef(datFact3));\n", "l.Request(\"SquareRoot\", &sqFact3);\n", "l.Get(\"SquareRoot\", &sqFact3);" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "C++11", "language": "", "name": "cling-cpp11" }, "language_info": { "codemirror_mode": "text/x-c++src", "file_extension": ".c++", "mimetype": " text/x-c++src", "name": "c++" } }, "nbformat": 4, "nbformat_minor": 0 }