From c2506c9fb249d29643cb96f18b43616d8af75268 Mon Sep 17 00:00:00 2001 From: Tor Harald Sandve Date: Wed, 6 Mar 2013 10:17:27 +0100 Subject: [PATCH] code is now included using \snippet. Apparently this looks better with the new Doxygen version. The HTML_EXTRA_STYLESHEET is now used rather then the HTML_STYLESHEET in order to include used-defined styles for the same reason --- Documentation/Doxylocal | 15 +- Documentation/style.css | 826 +----------------------------- tutorials/generate_doc_figures.py | 9 +- tutorials/tutorial1.cpp | 62 ++- tutorials/tutorial2.cpp | 95 ++-- tutorials/tutorial3.cpp | 136 +++-- tutorials/tutorial4.cpp | 230 ++++++--- 7 files changed, 364 insertions(+), 1009 deletions(-) diff --git a/Documentation/Doxylocal b/Documentation/Doxylocal index ec2fdef5..c3b62bdd 100644 --- a/Documentation/Doxylocal +++ b/Documentation/Doxylocal @@ -44,11 +44,12 @@ IMAGE_PATH = @PROJECT_SOURCE_DIR@/@doxy_dir@/Figure LAYOUT_FILE = @PROJECT_SOURCE_DIR@/@doxy_dir@/DoxygenLayout.xml -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. -HTML_STYLESHEET = style.css +HTML_EXTRA_STYLESHEET = style.css diff --git a/Documentation/style.css b/Documentation/style.css index 0daa3a98..0877f331 100644 --- a/Documentation/style.css +++ b/Documentation/style.css @@ -1,835 +1,11 @@ -/* The standard CSS for doxygen */ - +/* Userspesific CSS for doxygen */ body, table, div, p, dl { font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; font-size: 16px; } - -/* @group Heading Levels */ - h1 { - font-size: 150%; -} - -.title { - font-size: 150%; - font-weight: bold; - margin: 10px 2px; -} - -h2 { font-size: 120%; } -h3 { - font-size: 100%; -} -dt { - font-weight: bold; -} - -div.multicol { - -moz-column-gap: 1em; - -webkit-column-gap: 1em; - -moz-column-count: 3; - -webkit-column-count: 3; -} - -p.startli, p.startdd, p.starttd { - margin-top: 2px; -} - -p.endli { - margin-bottom: 0px; -} - -p.enddd { - margin-bottom: 4px; -} - -p.endtd { - margin-bottom: 2px; -} - -/* @end */ - -caption { - font-weight: bold; -} - -span.legend { - font-size: 70%; - text-align: center; -} - -h3.version { - font-size: 90%; - text-align: center; -} - -div.qindex, div.navtab{ - background-color: #EBEFF6; - border: 1px solid #A3B4D7; - text-align: center; - margin: 2px; - padding: 2px; -} - -div.qindex, div.navpath { - width: 100%; - line-height: 140%; -} - -div.navtab { - margin-right: 15px; -} - -/* @group Link Styling */ - -a { - color: #3D578C; - font-weight: normal; - text-decoration: none; -} - -.contents a:visited { - color: #4665A2; -} - -a:hover { - text-decoration: underline; -} - -a.qindex { - font-weight: bold; -} - -a.qindexHL { - font-weight: bold; - background-color: #9CAFD4; - color: #ffffff; - border: 1px double #869DCA; -} - -.contents a.qindexHL:visited { - color: #ffffff; -} - -a.el { - font-weight: bold; -} - -a.elRef { -} - -a.code { - color: #4665A2; -} - -a.codeRef { - color: #4665A2; -} - -/* @end */ - -dl.el { - margin-left: -1cm; -} - -.fragment { - font-family: monospace, fixed; - font-size: 105%; -} - -pre.fragment { - border: 1px solid #C4CFE5; - background-color: #FBFCFD; - padding: 4px 6px; - margin: 4px 8px 4px 2px; - overflow: auto; - word-wrap: break-word; - font-size: 9pt; - line-height: 125%; -} - -div.ah { - background-color: black; - font-weight: bold; - color: #ffffff; - margin-bottom: 3px; - margin-top: 3px; - padding: 0.2em; - border: solid thin #333; - border-radius: 0.5em; - -webkit-border-radius: .5em; - -moz-border-radius: .5em; - box-shadow: 2px 2px 3px #999; - -webkit-box-shadow: 2px 2px 3px #999; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; - background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); - background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); -} - -div.groupHeader { - margin-left: 16px; - margin-top: 12px; - font-weight: bold; -} - -div.groupText { - margin-left: 16px; - font-style: italic; -} - -body { - background: white; - color: black; - margin: 0; -} - -div.contents { - margin-top: 10px; - margin-left: 10px; - margin-right: 5px; -} - -td.indexkey { - background-color: #EBEFF6; - font-weight: bold; - border: 1px solid #C4CFE5; - margin: 2px 0px 2px 0; - padding: 2px 10px; -} - -td.indexvalue { - background-color: #EBEFF6; - border: 1px solid #C4CFE5; - padding: 2px 10px; - margin: 2px 0px; -} - -tr.memlist { - background-color: #EEF1F7; -} - -p.formulaDsp { - text-align: center; -} - -img.formulaDsp { - -} - -img.formulaInl { - vertical-align: middle; -} - -div.center { - text-align: center; - margin-top: 0px; - margin-bottom: 0px; - padding: 0px; -} - -div.center img { - border: 0px; -} - -address.footer { - text-align: right; - padding-right: 12px; -} - -img.footer { - border: 0px; - vertical-align: middle; -} - -/* @group Code Colorization */ - -span.keyword { - color: #008000 -} - -span.keywordtype { - color: #604020 -} - -span.keywordflow { - color: #e08000 -} - -span.comment { - color: #800000 -} - -span.preprocessor { - color: #806020 -} - -span.stringliteral { - color: #002080 -} - -span.charliteral { - color: #008080 -} - -span.vhdldigit { - color: #ff00ff -} - -span.vhdlchar { - color: #000000 -} - -span.vhdlkeyword { - color: #700070 -} - -span.vhdllogic { - color: #ff0000 -} - -/* @end */ - -/* -.search { - color: #003399; - font-weight: bold; -} - -form.search { - margin-bottom: 0px; - margin-top: 0px; -} - -input.search { - font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #e8eef2; -} -*/ - -td.tiny { - font-size: 75%; -} - -.dirtab { - padding: 4px; - border-collapse: collapse; - border: 1px solid #A3B4D7; -} - -th.dirtab { - background: #EBEFF6; - font-weight: bold; -} - -hr { - height: 0px; - border: none; - border-top: 1px solid #4A6AAA; -} - -hr.footer { - height: 1px; -} - -/* @group Member Descriptions */ - -table.memberdecls { - border-spacing: 0px; - padding: 0px; -} - -.mdescLeft, .mdescRight, -.memItemLeft, .memItemRight, -.memTemplItemLeft, .memTemplItemRight, .memTemplParams { - background-color: #F9FAFC; - border: none; - margin: 4px; - padding: 1px 0 0 8px; -} - -.mdescLeft, .mdescRight { - padding: 0px 8px 4px 8px; - color: #555; -} - -.memItemLeft, .memItemRight, .memTemplParams { - border-top: 1px solid #C4CFE5; -} - -.memItemLeft, .memTemplItemLeft { - white-space: nowrap; -} - -.memItemRight { - width: 100%; -} - -.memTemplParams { - color: #4665A2; - white-space: nowrap; -} - -/* @end */ - -/* @group Member Details */ - -/* Styles for detailed member documentation */ - -.memtemplate { - font-size: 80%; - color: #4665A2; - font-weight: normal; - margin-left: 9px; -} - -.memnav { - background-color: #EBEFF6; - border: 1px solid #A3B4D7; - text-align: center; - margin: 2px; - margin-right: 15px; - padding: 2px; -} - -.mempage { - width: 100%; -} - -.memitem { - padding: 0; - margin-bottom: 10px; - margin-right: 5px; -} - -.memname { - white-space: nowrap; - font-weight: bold; - margin-left: 6px; -} - -.memproto { - border-top: 1px solid #A8B8D9; - border-left: 1px solid #A8B8D9; - border-right: 1px solid #A8B8D9; - padding: 6px 0px 6px 0px; - color: #253555; - font-weight: bold; - text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); - /* opera specific markup */ - box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - border-top-right-radius: 8px; - border-top-left-radius: 8px; - /* firefox specific markup */ - -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - -moz-border-radius-topright: 8px; - -moz-border-radius-topleft: 8px; - /* webkit specific markup */ - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - -webkit-border-top-right-radius: 8px; - -webkit-border-top-left-radius: 8px; - background-image:url('nav_f.png'); - background-repeat:repeat-x; - background-color: #E2E8F2; - -} - -.memdoc { - border-bottom: 1px solid #A8B8D9; - border-left: 1px solid #A8B8D9; - border-right: 1px solid #A8B8D9; - padding: 2px 5px; - background-color: #FBFCFD; - border-top-width: 0; - /* opera specific markup */ - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; - box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - /* firefox specific markup */ - -moz-border-radius-bottomleft: 8px; - -moz-border-radius-bottomright: 8px; - -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); - /* webkit specific markup */ - -webkit-border-bottom-left-radius: 8px; - -webkit-border-bottom-right-radius: 8px; - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); -} - -.paramkey { - text-align: right; -} - -.paramtype { - white-space: nowrap; -} - -.paramname { - color: #602020; - white-space: nowrap; -} -.paramname em { - font-style: normal; -} - -.params, .retval, .exception, .tparams { - border-spacing: 6px 2px; -} - -.params .paramname, .retval .paramname { - font-weight: bold; - vertical-align: top; -} - -.params .paramtype { - font-style: italic; - vertical-align: top; -} - -.params .paramdir { - font-family: "courier new",courier,monospace; - vertical-align: top; -} - - - - -/* @end */ - -/* @group Directory (tree) */ - -/* for the tree view */ - -.ftvtree { - font-family: sans-serif; - margin: 0px; -} - -/* these are for tree view when used as main index */ - -.directory { - font-size: 9pt; - font-weight: bold; - margin: 5px; -} - -.directory h3 { - margin: 0px; - margin-top: 1em; - font-size: 11pt; -} - -/* -The following two styles can be used to replace the root node title -with an image of your choice. Simply uncomment the next two styles, -specify the name of your image and be sure to set 'height' to the -proper pixel height of your image. -*/ - -/* -.directory h3.swap { - height: 61px; - background-repeat: no-repeat; - background-image: url("yourimage.gif"); -} -.directory h3.swap span { - display: none; -} -*/ - -.directory > h3 { - margin-top: 0; -} - -.directory p { - margin: 0px; - white-space: nowrap; -} - -.directory div { - display: none; - margin: 0px; -} - -.directory img { - vertical-align: -30%; -} - -/* these are for tree view when not used as main index */ - -.directory-alt { - font-size: 100%; - font-weight: bold; -} - -.directory-alt h3 { - margin: 0px; - margin-top: 1em; - font-size: 11pt; -} - -.directory-alt > h3 { - margin-top: 0; -} - -.directory-alt p { - margin: 0px; - white-space: nowrap; -} - -.directory-alt div { - display: none; - margin: 0px; -} - -.directory-alt img { - vertical-align: -30%; -} - -/* @end */ - -div.dynheader { - margin-top: 8px; -} - -address { - font-style: normal; - color: #2A3D61; -} - -table.doxtable { - border-collapse:collapse; -} - -table.doxtable td, table.doxtable th { - border: 1px solid #2D4068; - padding: 3px 7px 2px; -} - -table.doxtable th { - background-color: #374F7F; - color: #FFFFFF; - font-size: 110%; - padding-bottom: 4px; - padding-top: 5px; - text-align:left; -} - -.tabsearch { - top: 0px; - left: 10px; - height: 36px; - background-image: url('tab_b.png'); - z-index: 101; - overflow: hidden; - font-size: 13px; -} - -.navpath ul -{ - font-size: 11px; - background-image:url('tab_b.png'); - background-repeat:repeat-x; - height:30px; - line-height:30px; - color:#8AA0CC; - border:solid 1px #C2CDE4; - overflow:hidden; - margin:0px; - padding:0px; -} - -.navpath li -{ - list-style-type:none; - float:left; - padding-left:10px; - padding-right:15px; - background-image:url('bc_s.png'); - background-repeat:no-repeat; - background-position:right; - color:#364D7C; -} - -.navpath li.navelem a -{ - height:32px; - display:block; - text-decoration: none; - outline: none; -} - -.navpath li.navelem a:hover -{ - color:#6884BD; -} - -.navpath li.footer -{ - list-style-type:none; - float:right; - padding-left:10px; - padding-right:15px; - background-image:none; - background-repeat:no-repeat; - background-position:right; - color:#364D7C; - font-size: 8pt; -} - - -div.summary -{ - float: right; - font-size: 8pt; - padding-right: 5px; - width: 50%; - text-align: right; -} - -div.summary a -{ - white-space: nowrap; -} - -div.ingroups -{ - font-size: 8pt; - padding-left: 5px; - width: 50%; - text-align: left; -} - -div.ingroups a -{ - white-space: nowrap; -} - -div.header -{ - background-image:url('nav_h.png'); - background-repeat:repeat-x; - background-color: #F9FAFC; - margin: 0px; - border-bottom: 1px solid #C4CFE5; -} - -div.headertitle -{ - padding: 5px 5px 5px 10px; -} - -dl -{ - padding: 0 0 0 10px; -} - -dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug -{ - border-left:4px solid; - padding: 0 0 0 6px; -} - -dl.note -{ - border-color: #D0C000; -} - -dl.warning, dl.attention -{ - border-color: #FF0000; -} - -dl.pre, dl.post, dl.invariant -{ - border-color: #00D000; -} - -dl.deprecated -{ - border-color: #505050; -} - -dl.todo -{ - border-color: #00C0E0; -} - -dl.test -{ - border-color: #3030E0; -} - -dl.bug -{ - border-color: #C08050; -} - -#projectlogo -{ - text-align: center; - vertical-align: bottom; - border-collapse: separate; -} - -#projectlogo img -{ - border: 0px none; -} - -#projectname -{ - font: 300% Tahoma, Arial,sans-serif; - margin: 0px; - padding: 2px 0px; -} - -#projectbrief -{ - font: 120% Tahoma, Arial,sans-serif; - margin: 0px; - padding: 0px; -} - -#projectnumber -{ - font: 50% Tahoma, Arial,sans-serif; - margin: 0px; - padding: 0px; -} - -#titlearea -{ - padding: 0px; - margin: 0px; - width: 100%; - border-bottom: 1px solid #5373B4; -} - -.image -{ - text-align: center; -} - -.dotgraph -{ - text-align: center; -} - -.mscgraph -{ - text-align: center; -} - -.caption -{ - font-weight: bold; -} diff --git a/tutorials/generate_doc_figures.py b/tutorials/generate_doc_figures.py index 70c77338..7afe8b51 100755 --- a/tutorials/generate_doc_figures.py +++ b/tutorials/generate_doc_figures.py @@ -38,7 +38,7 @@ collected_garbage_file = [] if not isdir(figure_path): mkdir(figure_path) - +## [tutorial1] # tutorial 1 data_file_name = join(tutorial_data_path, "tutorial1.vtu") # grid = servermanager.sources.XMLUnstructuredGridReader(FileName = data_file_name) @@ -60,7 +60,9 @@ camera.SetFocalPoint(1.5, 1.5, 1) Render() WriteImage(join(figure_path, "tutorial1.png")) Hide(grid) +## [tutorial1] +## [tutorial2] # tutorial 2 data_file_name = join(tutorial_data_path, "tutorial2.vtu") grid = XMLUnstructuredGridReader(FileName = data_file_name) @@ -83,7 +85,9 @@ camera.SetFocalPoint(20, 20, 0.5) Render() WriteImage(join(figure_path, "tutorial2.png")) Hide(grid) +## [tutorial2] +## [tutorial3] # tutorial 3 for case in range(0,20): data_file_name = join(tutorial_data_path, "tutorial3-"+"%(case)03d"%{"case": case}+".vtu") @@ -110,7 +114,9 @@ for case in cases: Render() WriteImage(join(figure_path, "tutorial3-"+case+".png")) Hide(grid) +## [tutorial3] +## [tutorial4] # tutorial 4 for case in range(0,20): data_file_name = join(tutorial_data_path, "tutorial4-"+"%(case)03d"%{"case": case}+".vtu") @@ -137,6 +143,7 @@ for case in cases: Render() WriteImage(join(figure_path, "tutorial4-"+case+".png")) Hide(grid) +## [tutorial4] # remove temporary files for f in collected_garbage_file: diff --git a/tutorials/tutorial1.cpp b/tutorials/tutorial1.cpp index 71cf6699..a0ef22c0 100644 --- a/tutorials/tutorial1.cpp +++ b/tutorials/tutorial1.cpp @@ -23,31 +23,25 @@ #endif // HAVE_CONFIG_H /// \page tutorial1 A simple cartesian grid -/// This tutorial explains how to construct a simple cartesian grid, +/// This tutorial explains how to construct a simple Cartesian grid, /// and we will take a look at some output facilities. /// \page tutorial1 -/// \section commentedsource1 Program walkthrough. +/// \section commentedsource1 Program walk-through. /// All headers from opm-core are found in the opm/core/ directory. /// Some important headers are at the root, other headers are found /// in subdirectories. -#include -#include -#include -#include -#include -#include +/// \snippet tutorial1.cpp including headers -/** -\code +/// \internal [including headers] #include #include #include #include #include #include -\endcode -*/ +/// \internal [including headers] +/// \endinternal // ----------------- Main program ----------------- @@ -55,18 +49,22 @@ int main() { /// \page tutorial1 /// We set the number of blocks in each direction. - /// \code + /// \snippet tutorial1.cpp num blocks + /// \internal [num blocks] int nx = 4; int ny = 3; int nz = 2; - /// \endcode + /// \internal [num blocks] + /// \endinternal /// The size of each block is 1m x 1m x 1m. The default units are always the /// standard units (SI). But other units can easily be dealt with, see Opm::unit. - /// \code + /// \snippet tutorial1.cpp dim + /// \internal [dim] double dx = 1.0; double dy = 1.0; double dz = 1.0; - /// \endcode + /// \internal [dim] + /// \endinternal /// \page tutorial1 /// In opm-core, grid information is accessed via the UnstructuredGrid data structure. /// This data structure has a pure C API, including helper functions to construct and @@ -74,29 +72,38 @@ int main() /// which is a C++ class that wraps the UnstructuredGrid and takes care of /// object lifetime issues. /// One of the constructors of the class Opm::GridManager takes nx, ny, nz, dx, dy, dz - /// and construct the corresponding cartesian grid. - /// \code + /// and construct the corresponding Cartesian grid. + /// \snippet tutorial1.cpp grid manager + /// \internal [grid manager] Opm::GridManager grid(nx, ny, nz, dx, dy, dz); - /// \endcode + /// \internal [grid manager] + /// \endinternal /// \page tutorial1 /// We open an output file stream for the output - /// \code + /// \snippet tutorial1.cpp output stream + /// \internal [output stream] std::ofstream vtkfile("tutorial1.vtu"); - /// \endcode + /// \internal [output stream] + /// \endinternal /// \page tutorial1 /// The Opm::writeVtkData() function writes a grid together with /// data to a stream. Here, we just want to visualize the grid. We /// construct an empty Opm::DataMap object, which we send to /// Opm::writeVtkData() together with the grid - /// \code + /// \snippet tutorial1.cpp data map + /// \internal [data map] Opm::DataMap dm; - /// \endcode + /// \internal [data map] + /// \endinternal /// \page tutorial1 /// Call Opm::writeVtkData() to write the output file. - /// \code + /// \snippet tutorial1.cpp write vtk + /// \internal [write vtk] Opm::writeVtkData(*grid.c_grid(), dm, vtkfile); + /// \internal [write vtk] + /// \endinternal } -/// \endcode + /// \page tutorial1 /// We read the vtu output file in \a Paraview and obtain the following grid. /// \image html tutorial1.png @@ -105,3 +112,8 @@ int main() /// \section completecode1 Complete source code: /// \include tutorial1.cpp +/// \page tutorial1 +/// \details +/// \section pythonscript1 Python script to generate figures: +/// \snippet generate_doc_figures.py tutorial1 + diff --git a/tutorials/tutorial2.cpp b/tutorials/tutorial2.cpp index e0f32344..9271633e 100644 --- a/tutorials/tutorial2.cpp +++ b/tutorials/tutorial2.cpp @@ -24,7 +24,7 @@ /// \f${\bf u}\f$ denotes the velocity and \f$p\f$ the pressure. The permeability tensor is /// given by \f$K\f$ and \f$\mu\f$ denotes the viscosity. /// -/// We solve the flow equations for a cartesian grid and we set the source term +/// We solve the flow equations for a Cartesian grid and we set the source term /// \f$q\f$ be zero except at the left-lower and right-upper corner, where it is equal /// with opposite sign (inflow equal to outflow). @@ -49,28 +49,33 @@ #include /// \page tutorial2 -/// \section commentedcode2 Program walkthrough. -/// \code +/// \section commentedcode2 Program walk-through. +/// + int main() { - /// \endcode + /// \page tutorial2 - /// We construct a cartesian grid - /// \code + /// We construct a Cartesian grid + /// \snippet tutorial2.cpp cartesian grid + /// \internal [cartesian grid] int dim = 3; int nx = 40; int ny = 40; int nz = 1; Opm::GridManager grid(nx, ny, nz); - /// \endcode + /// \internal [cartesian grid] + /// \endinternal /// \page tutorial2 /// \details We access the unstructured grid through /// the pointer given by \c grid.c_grid(). For more details on the /// UnstructuredGrid data structure, see grid.h. - /// \code + /// \snippet tutorial2.cpp access grid + /// \internal [access grid] int num_cells = grid.c_grid()->number_of_cells; int num_faces = grid.c_grid()->number_of_faces; - /// \endcode + /// \internal [access grid] + /// endinternal /// \page tutorial2 @@ -80,90 +85,107 @@ int main() /// The header contains support /// for common units and prefixes, in the namespaces Opm::unit /// and Opm::prefix. - /// \code + /// \snippet tutorial2.cpp fluid + /// \internal [fluid] using namespace Opm::unit; using namespace Opm::prefix; int num_phases = 1; std::vector mu(num_phases, 1.0*centi*Poise); std::vector rho(num_phases, 1000.0*kilogram/cubic(meter)); - /// \endcode + /// \internal [fluid] + /// \endinternal /// \page tutorial2 /// \details /// We define a permeability equal to 100 mD. - /// \code + /// \snippet tutorial2.cpp perm + /// \internal [perm] double k = 100.0*milli*darcy; - /// \endcode - /// \page tutorial2 - /// \details + /// \internal [perm] + /// \endinternal /// \page tutorial2 /// \details /// We set up a simple property object for a single-phase situation. - /// \code + /// \snippet tutorial2.cpp single-phase property + /// \internal [single-phase property] Opm::IncompPropertiesBasic props(1, Opm::SaturationPropsBasic::Constant, rho, mu, 1.0, k, dim, num_cells); - /// \endcode + /// \internal [single-phase property] + /// /endinternal /// \page tutorial2 /// \details /// We take UMFPACK as the linear solver for the pressure solver /// (this library has therefore to be installed). - /// \code + /// \snippet tutorial2.cpp linsolver + /// \internal [linsolver] Opm::LinearSolverUmfpack linsolver; - /// \endcode - /// \page tutorial2 + /// \internal [linsolver] + /// \endinternal - /// \endcode /// \page tutorial2 /// We define the source term. - /// \code + /// \snippet tutorial2.cpp source + /// \internal [source] std::vector src(num_cells, 0.0); src[0] = 100.; src[num_cells-1] = -100.; - /// \endcode + /// \internal [source] + /// \endinternal + /// \page tutorial2 /// \details We set up the boundary conditions. /// By default, we obtain no-flow boundary conditions. - /// \code + /// \snippet tutorial2.cpp boundary + /// \internal [boundary] Opm::FlowBCManager bcs; - /// \endcode + /// \internal [boundary] + /// \endinternal /// We set up a pressure solver for the incompressible problem, /// using the two-point flux approximation discretization. The /// null pointers correspond to arguments for gravity, wells and /// boundary conditions, which are all defaulted (to zero gravity, /// no wells, and no-flow boundaries). - /// \code + /// \snippet tutorial2.cpp tpfa + /// \internal [tpfa] Opm::IncompTpfa psolver(*grid.c_grid(), props, linsolver, NULL, NULL, src, NULL); - + /// \internal [tpfa] + /// \endinternal + /// \page tutorial2 /// We declare the state object, that will contain the pressure and face /// flux vectors we are going to compute. The well state /// object is needed for interface compatibility with the /// solve() method of class /// Opm::IncompTPFA. - /// \code + /// \snippet tutorial2.cpp state + /// \internal [state] Opm::TwophaseState state; state.pressure().resize(num_cells, 0.0); state.faceflux().resize(num_faces, 0.0); state.saturation().resize(num_cells, 1.0); Opm::WellState well_state; - /// \endcode + /// \internal [state] + /// \endinternal /// \page tutorial2 /// We call the pressure solver. /// The first (timestep) argument does not matter for this /// incompressible case. - /// \code + /// \snippet tutorial2.cpp pressure solver + /// \internal [pressure solver] psolver.solve(1.0*day, state, well_state); - /// \endcode + /// \internal [pressure solver] + /// \endinternal /// \page tutorial2 /// We write the results to a file in VTK format. /// The data vectors added to the Opm::DataMap must /// contain cell data. They may be a scalar per cell /// (pressure) or a vector per cell (cell_velocity). - /// \code + /// \snippet tutorial2.cpp write output + /// \internal [write output] std::ofstream vtkfile("tutorial2.vtu"); Opm::DataMap dm; dm["pressure"] = &state.pressure(); @@ -171,8 +193,10 @@ int main() Opm::estimateCellVelocity(*grid.c_grid(), state.faceflux(), cell_velocity); dm["velocity"] = &cell_velocity; Opm::writeVtkData(*grid.c_grid(), dm, vtkfile); + /// \internal [write output] + /// \endinternal } -/// \endcode + /// \page tutorial2 /// We read the vtu output file in \a Paraview and obtain the following pressure /// distribution. \image html tutorial2.png @@ -181,3 +205,8 @@ int main() /// \page tutorial2 /// \section completecode2 Complete source code: /// \include tutorial2.cpp + +/// \page tutorial2 +/// \details +/// \section pythonscript2 python script to generate figures: +/// \snippet generate_doc_figures.py tutorial2 diff --git a/tutorials/tutorial3.cpp b/tutorials/tutorial3.cpp index a9c1d446..9cab2345 100644 --- a/tutorials/tutorial3.cpp +++ b/tutorials/tutorial3.cpp @@ -89,15 +89,19 @@ /// \page tutorial3 +/// \section commentedsource1 Program walk-through. /// \details /// Main function -/// \code +/// \snippet tutorial3.cpp main +/// \internal [main] int main () { - /// \endcode + /// \internal [main] + /// \endinternal + /// \page tutorial3 /// \details - /// We define the grid. A cartesian grid with 400 cells, + /// We define the grid. A Cartesian grid with 400 cells, /// each being 10m along each side. Note that we treat the /// grid as 3-dimensional, but have a thickness of only one /// layer in the Z direction. @@ -105,7 +109,8 @@ int main () /// The Opm::GridManager is responsible for creating and destroying the grid, /// the UnstructuredGrid data structure contains the actual grid topology /// and geometry. - /// \code + /// \snippet tutorial3.cpp grid + /// \internal [grid] int nx = 20; int ny = 20; int nz = 1; @@ -116,7 +121,8 @@ int main () GridManager grid_manager(nx, ny, nz, dx, dy, dz); const UnstructuredGrid& grid = *grid_manager.c_grid(); int num_cells = grid.number_of_cells; - /// \endcode + /// \internal [grid] + /// \endinternal /// \page tutorial3 /// \details @@ -128,7 +134,8 @@ int main () /// available for use, however. They are stored as constants in /// the Opm::unit namespace, while prefixes are in the Opm::prefix /// namespace. See Units.hpp for more. - /// \code + /// \snippet tutorial3.cpp set properties + /// \internal [set properties] int num_phases = 2; using namespace Opm::unit; using namespace Opm::prefix; @@ -136,139 +143,173 @@ int main () std::vector viscosity(num_phases, 1.0*centi*Poise); double porosity = 0.5; double permeability = 10.0*milli*darcy; - /// \endcode + /// \internal [set properties] + /// \endinternal /// \page tutorial3 /// \details We define the relative permeability function. We use a basic fluid /// description and set this function to be linear. For more realistic fluid, the /// saturation function may be interpolated from experimental data. - /// \code + /// \snippet tutorial3.cpp relperm + /// \internal [relperm] SaturationPropsBasic::RelPermFunc rel_perm_func = SaturationPropsBasic::Linear; - /// \endcode + /// \internal [relperm] + /// \endinternal /// \page tutorial3 /// \details We construct a basic fluid and rock property object /// with the properties we have defined above. Each property is /// constant and hold for all cells. - /// \code + /// \snippet tutorial3.cpp properties + /// \internal [properties] IncompPropertiesBasic props(num_phases, rel_perm_func, density, viscosity, porosity, permeability, grid.dimensions, num_cells); - /// \endcode + /// \internal [properties] + /// \endinternal /// \page tutorial3 /// \details Gravity parameters. Here, we set zero gravity. - /// \code + /// \snippet tutorial3.cpp gravity + /// \internal [gravity] const double *grav = 0; std::vector omega; - /// \endcode + /// \internal [gravity] + /// \endinternal /// \page tutorial3 /// \details We set up the source term. Positive numbers indicate that the cell is a source, /// while negative numbers indicate a sink. - /// \code + /// \snippet tutorial3.cpp source + /// \internal [source] std::vector src(num_cells, 0.0); src[0] = 1.; src[num_cells-1] = -1.; - /// \endcode + /// \internal [source] + /// \endinternal /// \page tutorial3 /// \details We set up the boundary conditions. Letting bcs be empty is equivalent /// to no-flow boundary conditions. - /// \code + /// \snippet tutorial3.cpp boundary + /// \internal [boundary] FlowBCManager bcs; - /// \endcode + /// \internal [boundary] + /// \endinternal /// \page tutorial3 /// \details We may now set up the pressure solver. At this point, /// unchanging parameters such as transmissibility are computed /// and stored internally by the IncompTpfa class. The null pointer /// constructor argument is for wells, which are not used in this tutorial. - /// \code + /// \snippet tutorial3.cpp pressure solver + /// \internal [pressure solver] LinearSolverUmfpack linsolver; IncompTpfa psolver(grid, props, linsolver, grav, NULL, src, bcs.c_bcs()); - /// \endcode + /// \internal [pressure solver] + /// \endinternal /// \page tutorial3 /// \details We set up a state object for the wells. Here, there are /// no wells and we let it remain empty. - /// \code + /// \snippet tutorial3.cpp well + /// \internal [well] WellState well_state; - /// \endcode + /// \internal [well] + /// \endinternal /// \page tutorial3 /// \details We compute the pore volume - /// \code + /// \snippet tutorial3.cpp pore volume + /// \internal [pore volume] std::vector porevol; Opm::computePorevolume(grid, props.porosity(), porevol); - /// \endcode + /// \internal [pore volume] + /// \endinternal /// \page tutorial3 /// \details Set up the transport solver. This is a reordering implicit Euler transport solver. - /// \code + /// \snippet tutorial3.cpp transport solver + /// \internal [transport solver] const double tolerance = 1e-9; const int max_iterations = 30; Opm::TransportModelTwophase transport_solver(grid, props, tolerance, max_iterations); - /// \endcode + /// \internal [transport solver] + /// \endinternal /// \page tutorial3 /// \details Time integration parameters - /// \code + /// \snippet tutorial3.cpp time parameters + /// \internal [time parameters] const double dt = 0.1*day; const int num_time_steps = 20; - /// \endcode + /// \internal [time parameters] + /// \endinternal /// \page tutorial3 /// \details We define a vector which contains all cell indexes. We use this /// vector to set up parameters on the whole domain. - /// \code + /// \snippet tutorial3.cpp cell indexes + /// \internal [cell indexes] std::vector allcells(num_cells); for (int cell = 0; cell < num_cells; ++cell) { allcells[cell] = cell; } - /// \endcode + /// \internal [cell indexes] + /// \endinternal /// \page tutorial3 /// \details /// We set up a two-phase state object, and - /// initialise water saturation to minimum everywhere. - /// \code + /// initialize water saturation to minimum everywhere. + /// \snippet tutorial3.cpp two-phase state + /// \internal [two-phase state] TwophaseState state; state.init(grid, 2); state.setFirstSat(allcells, props, TwophaseState::MinSat); - /// \endcode + /// \internal [two-phase state] + /// \endinternal /// \page tutorial3 /// \details This string stream will be used to construct a new /// output filename at each timestep. - /// \code + /// \snippet tutorial3.cpp output stream + /// \internal [output stream] std::ostringstream vtkfilename; - /// \endcode + /// \internal [output stream] + /// \endinternal /// \page tutorial3 /// \details Loop over the time steps. - /// \code + /// \snippet tutorial3.cpp time loop + /// \internal [time loop] for (int i = 0; i < num_time_steps; ++i) { - /// \endcode - /// \page tutorial3 + /// \internal [time loop] + /// \endinternal + - /// \endcode /// \page tutorial3 /// \details Solve the pressure equation - /// \code + /// \snippet tutorial3.cpp solve pressure + /// \internal [solve pressure] psolver.solve(dt, state, well_state); - /// \endcode + /// \internal [solve pressure] + /// \endinternal + /// \page tutorial3 /// \details Solve the transport equation. - /// \code + /// \snippet tutorial3.cpp transport solve + /// \internal [transport solve] transport_solver.solve(&state.faceflux()[0], &porevol[0], &src[0], dt, state.saturation()); - /// \endcode + /// \internal [transport solve] + /// \endinternal /// \page tutorial3 /// \details Write the output to file. - /// \code + /// \snippet tutorial3.cpp write output + /// \internal [write output] vtkfilename.str(""); vtkfilename << "tutorial3-" << std::setw(3) << std::setfill('0') << i << ".vtu"; std::ofstream vtkfile(vtkfilename.str().c_str()); @@ -278,7 +319,8 @@ int main () Opm::writeVtkData(grid, dm, vtkfile); } } -/// \endcode +/// \internal [write output] +/// \endinternal @@ -304,4 +346,8 @@ int main () /// \details /// \section completecode3 Complete source code: /// \include tutorial3.cpp -/// \include generate_doc_figures.py + +/// \page tutorial3 +/// \details +/// \section pythonscript3 python script to generate figures: +/// \snippet generate_doc_figures.py tutorial3 diff --git a/tutorials/tutorial4.cpp b/tutorials/tutorial4.cpp index d90ce978..6e45cd0b 100644 --- a/tutorials/tutorial4.cpp +++ b/tutorials/tutorial4.cpp @@ -46,18 +46,22 @@ #include /// \page tutorial4 Well controls - +/// This tutorial explains how to construct an example with wells /// \page tutorial4 +/// \section commentedsource1 Program walk-through. /// \details /// Main function -/// \code +/// \snippet tutorial4.cpp main +/// \internal[main] int main () { - /// \endcode + /// \internal[main] + /// \endinternal /// \page tutorial4 /// \details - /// We define the grid. A cartesian grid with 1200 cells. - /// \code + /// We define the grid. A Cartesian grid with 1200 cells. + /// \snippet tutorial4.cpp cartesian grid + /// \internal[cartesian grid] int dim = 3; int nx = 20; int ny = 20; @@ -69,126 +73,162 @@ int main () GridManager grid_manager(nx, ny, nz, dx, dy, dz); const UnstructuredGrid& grid = *grid_manager.c_grid(); int num_cells = grid.number_of_cells; - /// \endcode + /// \internal[cartesian grid] + /// \endinternal /// \page tutorial4 /// \details /// We define the properties of the fluid.\n /// Number of phases. - /// \code + /// \snippet tutorial4.cpp Number of phases + /// \internal[Number of phases] int num_phases = 2; using namespace unit; using namespace prefix; - /// \endcode + /// \internal[Number of phases] + /// \endinternal + /// \page tutorial4 /// \details density vector (one component per phase). - /// \code + /// \snippet tutorial4.cpp density + /// \internal[density] std::vector rho(2, 1000.); - /// \endcode + /// \internal[density] + /// \endinternal + /// \page tutorial4 /// \details viscosity vector (one component per phase). - /// \code + /// \snippet tutorial4.cpp viscosity + /// \internal[viscosity] std::vector mu(2, 1.*centi*Poise); - /// \endcode + /// \internal[viscosity] + /// \endinternal + /// \page tutorial4 /// \details porosity and permeability of the rock. - /// \code + /// \snippet tutorial4.cpp rock + /// \internal[rock] double porosity = 0.5; double k = 10*milli*darcy; - /// \endcode + /// \internal[rock] + /// \endinternal /// \page tutorial4 /// \details We define the relative permeability function. We use a basic fluid /// description and set this function to be linear. For more realistic fluid, the /// saturation function is given by the data. - /// \code + /// \snippet tutorial4.cpp relative permeability + /// \internal[relative permeability] SaturationPropsBasic::RelPermFunc rel_perm_func = SaturationPropsBasic::Linear; - /// \endcode + /// \internal[relative permeability] + /// \endinternal /// \page tutorial4 /// \details We construct a basic fluid with the properties we have defined above. /// Each property is constant and hold for all cells. - /// \code + /// \snippet tutorial4.cpp fluid properties + /// \internal[fluid properties] IncompPropertiesBasic props(num_phases, rel_perm_func, rho, mu, porosity, k, dim, num_cells); - /// \endcode + /// \internal[fluid properties] + /// \endinternal /// \page tutorial4 /// \details Gravity parameters. Here, we set zero gravity. - /// \code + /// \snippet tutorial4.cpp Gravity + /// \internal[Gravity] const double *grav = 0; std::vector omega; - /// \endcode + /// \internal[Gravity] + /// \endinternal /// \page tutorial4 /// \details We set up the source term. Positive numbers indicate that the cell is a source, /// while negative numbers indicate a sink. - /// \code + /// \snippet tutorial4.cpp source + /// \internal[source] std::vector src(num_cells, 0.0); src[0] = 1.; src[num_cells-1] = -1.; - /// \endcode + /// \internal[source] + /// \endinternal /// \page tutorial4 /// \details We compute the pore volume - /// \code + /// \snippet tutorial4.cpp pore volume + /// \internal[pore volume] std::vector porevol; Opm::computePorevolume(grid, props.porosity(), porevol); - /// \endcode + /// \internal[pore volume] + /// \endinternal /// \page tutorial4 /// \details Set up the transport solver. This is a reordering implicit Euler transport solver. - /// \code + /// \snippet tutorial4.cpp transport solver + /// \internal[transport solver] const double tolerance = 1e-9; const int max_iterations = 30; Opm::TransportModelTwophase transport_solver(grid, props, tolerance, max_iterations); - /// \endcode + /// \internal[transport solver] + /// \endinternal /// \page tutorial4 /// \details Time integration parameters - /// \code + /// \snippet tutorial4.cpp Time integration + /// \internal[Time integration] double dt = 0.1*day; int num_time_steps = 20; - /// \endcode + /// \internal[Time integration] + /// \endinternal /// \page tutorial4 /// \details We define a vector which contains all cell indexes. We use this /// vector to set up parameters on the whole domains. + /// \snippet tutorial4.cpp cell indexes + /// \internal[cell indexes] std::vector allcells(num_cells); for (int cell = 0; cell < num_cells; ++cell) { allcells[cell] = cell; } + /// \internal[cell indexes] + /// \endinternal /// \page tutorial4 /// \details We set up the boundary conditions. Letting bcs empty is equivalent /// to no flow boundary conditions. - /// \code + /// \snippet tutorial4.cpp boundary + /// \internal[boundary] FlowBCManager bcs; - /// \endcode + /// \internal[boundary] + /// \endinternal /// \page tutorial4 /// \details /// We set up a two-phase state object, and /// initialise water saturation to minimum everywhere. - /// \code + /// \snippet tutorial4.cpp two-phase state + /// \internal[two-phase state] TwophaseState state; state.init(grid, 2); state.setFirstSat(allcells, props, TwophaseState::MinSat); - /// \endcode + /// \internal[two-phase state] + /// \endinternal /// \page tutorial4 /// \details This string will contain the name of a VTK output vector. - /// \code + /// \snippet tutorial4.cpp VTK output + /// \internal[VTK output] std::ostringstream vtkfilename; - /// \endcode - + /// \internal[VTK output] + /// \endinternal /// \page tutorial4 /// To create wells we need an instance of the PhaseUsage-object - /// \code + /// \snippet tutorial4.cpp PhaseUsage-object + /// \internal[PhaseUsage-object] PhaseUsage phase_usage; phase_usage.num_phases = num_phases; phase_usage.phase_used[BlackoilPhases::Aqua] = 1; @@ -197,44 +237,54 @@ int main () phase_usage.phase_pos[BlackoilPhases::Aqua] = 0; phase_usage.phase_pos[BlackoilPhases::Liquid] = 1; - /// \endcode + /// \internal[PhaseUsage-object] + /// \endinternal /// \page tutorial4 /// \details This will contain our well-specific information - /// \code + /// \snippet tutorial4.cpp well_collection + /// \internal[well_collection] WellCollection well_collection; - /// \endcode + /// \internal[well_collection] + /// \endinternal /// \page tutorial4 /// \details Create the production specification for our top well group. /// We set a target limit for total reservoir rate, and set the controlling /// mode of the group to be controlled by the reservoir rate. - /// \code + /// \snippet tutorial4.cpp production specification + /// \internal[production specification] ProductionSpecification well_group_prod_spec; well_group_prod_spec.reservoir_flow_max_rate_ = 0.1; well_group_prod_spec.control_mode_ = ProductionSpecification::RESV; - /// \endcode + /// \internal[production specification] + /// \endinternal /// \page tutorial4 /// \details Create our well group. We hand it an empty injection specification, /// as we don't want to control its injection target. We use the shared_ptr-type because that's /// what the interface expects. The first argument is the (unique) name of the group. - /// \code + /// \snippet tutorial4.cpp injection specification + /// \internal[injection specification] std::tr1::shared_ptr well_group(new WellsGroup("group", well_group_prod_spec, InjectionSpecification(), phase_usage)); - /// \endcode + /// \internal[injection specification] + /// \endinternal /// \page tutorial4 /// \details We add our well_group to the well_collection - /// \code + /// \snippet tutorial4.cpp well_collection + /// \internal[well_collection] well_collection.addChild(well_group); - /// \endcode + /// \internal[well_collection] + /// \endinternal /// \page tutorial4 /// \details Create the production specification and Well objects (total 4 wells). We set all our wells to be group controlled. /// We pass in the string argument \C "group" to set the parent group. - /// \code + /// \snippet tutorial4.cpp create well objects + /// \internal[create well objects] const int num_wells = 4; for (int i = 0; i < num_wells; ++i) { std::stringstream well_name; @@ -246,20 +296,24 @@ int main () well_collection.addChild(well_leaf_node, "group"); } - /// \endcode + /// \internal[create well objects] + /// \endinternal /// \page tutorial4 /// \details Now we create the C struct to hold our wells (this is to interface with the solver code). For now we - /// \code + /// \snippet tutorial4.cpp well struct + /// \internal[well struct] Wells* wells = create_wells(num_phases, num_wells, num_wells /*number of perforations. We'll only have one perforation per well*/); - /// \endcode + /// \internal[well struct] + /// \endinternal /// /// \page tutorial4 /// \details We need to add each well to the C API. /// To do this we need to specify the relevant cells the well will be located in (\C well_cells). - /// \code + /// \snippet tutorial4.cpp well cells + /// \internal[well cells] for (int i = 0; i < num_wells; ++i) { const int well_cells = i*nx; const double well_index = 1; @@ -268,87 +322,112 @@ int main () add_well(PRODUCER, 0, 1, NULL, &well_cells, &well_index, well_name.str().c_str(), wells); } - /// \endcode + /// \internal[well cells] + /// \endinternal /// \page tutorial4 /// \details We need to make the well collection aware of our wells object - /// \code + /// \snippet tutorial4.cpp set well pointer + /// \internal[set well pointer] well_collection.setWellsPointer(wells); - /// \endcode + /// \internal[set well pointer] + /// \endinternal + /// \page tutorial4 /// We're not using well controls, just group controls, so we need to apply them. - /// \code + /// \snippet tutorial4.cpp apply group controls + /// \internal[apply group controls] well_collection.applyGroupControls(); - ///\endcode + /// \internal[apply group controls] + /// \endinternal /// \page tutorial4 /// \details We set up necessary information for the wells - /// \code + /// \snippet tutorial4.cpp init wells + /// \internal[init wells] WellState well_state; well_state.init(wells, state); std::vector well_resflowrates_phase; std::vector well_surflowrates_phase; std::vector fractional_flows; - /// \endcode + /// \internal[init wells] + /// \endinternal /// \page tutorial4 /// \details We set up the pressure solver. - /// \code + /// \snippet tutorial4.cpp pressure solver + /// \internal[pressure solver] LinearSolverUmfpack linsolver; IncompTpfa psolver(grid, props, linsolver, grav, wells, src, bcs.c_bcs()); - /// \endcode + /// \internal[pressure solver] + /// \endinternal /// \page tutorial4 /// \details Loop over the time steps. - /// \code + /// \snippet tutorial4.cpp time loop + /// \internal[time loop] for (int i = 0; i < num_time_steps; ++i) { - /// \endcode + /// \internal[time loop] + /// \endinternal /// \page tutorial4 /// \details We're solving the pressure until the well conditions are met /// or until we reach the maximum number of iterations. - /// \code + /// \snippet tutorial4.cpp well iterations + /// \internal[well iterations] const int max_well_iterations = 10; int well_iter = 0; bool well_conditions_met = false; while (!well_conditions_met) { - /// \endcode + /// \internal[well iterations] + /// \endinternal /// \page tutorial4 /// \details Solve the pressure equation - /// \code + /// \snippet tutorial4.cpp pressure solve + /// \internal[pressure solve] psolver.solve(dt, state, well_state); - - /// \endcode + /// \internal[pressure solve] + /// \endinternal + /// \page tutorial4 /// \details We compute the new well rates. Notice that we approximate (wrongly) surfflowsrates := resflowsrate + /// \snippet tutorial4.cpp compute well rates + /// \internal[compute well rates] Opm::computeFractionalFlow(props, allcells, state.saturation(), fractional_flows); Opm::computePhaseFlowRatesPerWell(*wells, well_state.perfRates(), fractional_flows, well_resflowrates_phase); Opm::computePhaseFlowRatesPerWell(*wells, well_state.perfRates(), fractional_flows, well_surflowrates_phase); - /// \endcode + /// \internal[compute well rates] + /// \endinternal /// \page tutorial4 /// \details We check if the well conditions are met. + /// \snippet tutorial4.cpp check well conditions + /// \internal[check well conditions] well_conditions_met = well_collection.conditionsMet(well_state.bhp(), well_resflowrates_phase, well_surflowrates_phase); ++well_iter; if (!well_conditions_met && well_iter == max_well_iterations) { THROW("Conditions not met within " << max_well_iterations<< " iterations."); } } - /// \endcode + /// \internal[check well conditions] + /// \endinternal /// \page tutorial4 /// \details Transport solver /// \TODO We must call computeTransportSource() here, since we have wells. - /// \code + /// \snippet tutorial4.cpp tranport solver + /// \internal[tranport solver] transport_solver.solve(&state.faceflux()[0], &porevol[0], &src[0], dt, state.saturation()); - /// \endcode + /// \internal[tranport solver] + /// \endinternal /// \page tutorial4 /// \details Write the output to file. - /// \code + /// \snippet tutorial4.cpp write output + /// \internal[write output] vtkfilename.str(""); vtkfilename << "tutorial4-" << std::setw(3) << std::setfill('0') << i << ".vtu"; std::ofstream vtkfile(vtkfilename.str().c_str()); @@ -360,7 +439,8 @@ int main () destroy_wells(wells); } -/// \endcode +/// \internal[write output] +/// \endinternal @@ -386,4 +466,8 @@ int main () /// \details /// \section completecode4 Complete source code: /// \include tutorial4.cpp -/// \include generate_doc_figures.py + +/// \page tutorial4 +/// \details +/// \section pythonscript4 python script to generate figures: +/// \snippet generate_doc_figures.py tutorial4