diff --git a/doc/dev-doc/CMakeLists.txt b/doc/dev-doc/CMakeLists.txt index fa0806a02..182240509 100644 --- a/doc/dev-doc/CMakeLists.txt +++ b/doc/dev-doc/CMakeLists.txt @@ -1,183 +1,187 @@ # set(DOXYGEN_INPUT_DOX ${CMAKE_CURRENT_BINARY_DIR}/akantu.dox) # set(DOXYGEN_XML_DIR ${CMAKE_CURRENT_BINARY_DIR}/xml) # set(DOXYGEN_OUTPUT ${DOXYGEN_XML_DIR}/index.xml) # configured documentation tools and intermediate build results set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build") # Sphinx cache with pickled ReST documents set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") # HTML output directory set(SPHINX_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/html") set(SPHINX_OUTPUT "${SPHINX_HTML_DIR}/index.html") set(SPHINX_INPUT "${CMAKE_CURRENT_BINARY_DIR}/conf.py") # # ---------------------------------------------------------------------------- # # # Doxygen # # # ---------------------------------------------------------------------------- # # find_package(Doxygen REQUIRED) # set(DOXYGEN_WARNINGS NO) # set(DOXYGEN_QUIET YES) # if(CMAKE_VERBOSE_MAKEFILE) # set(DOXYGEN_WARNINGS YES) # set(DOXYGEN_QUIET NO) # endif(CMAKE_VERBOSE_MAKEFILE) # package_get_all_source_files( # AKANTU_LIBRARY_SRCS # AKANTU_LIBRARY_PUBLIC_HDRS # AKANTU_LIBRARY_PRIVATE_HDRS # ) # package_get_all_include_directories( # _akantu_include_dirs # ) # package_get_all_external_informations( # PRIVATE_INCLUDE AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR # INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR # LIBRARIES AKANTU_EXTERNAL_LIBRARIES # ) # list(APPEND _akantu_include_dirs # ${AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR} # ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR} # ${PROJECT_BINARY_DIR}/src) # file(STRINGS ${PROJECT_SOURCE_DIR}/.clang-format AKANTU_TAB_SIZE # REGEX "^TabWidth: *([0-9]*)" # ) # string(REGEX REPLACE ".*([0-9]+)" "\\1" AKANTU_TAB_SIZE "${AKANTU_TAB_SIZE}") # if (CMAKE_VERSION VERSION_GREATER 3.9.5) # #set(DOXYGEN_WARNINGS YES) # #set(DOXYGEN_QUIET NO) # set(DOXYGEN_STRIP_FROM_PATH ${PROJECT_SOURCE_DIR}) # set(DOXYGEN_STRIP_FROM_INC_PATH ${PROJECT_SOURCE_DIR}) # set(DOXYGEN_TAB_SIZE ${AKANTU_TAB_SIZE}) # set(DOXYGEN_ALIASES # "rst=\\verbatim embed:rst" # "endrst=\\endverbatim" # ) # set(DOXYGEN_WARN_IF_UNDOCUMENTED NO) # set(DOXYGEN_WARN_IF_DOC_ERROR NO) # set(DOXYGEN_WARN_AS_ERROR NO) # set(DOXYGEN_EXCLUDE "${PROJECT_SOURCE_DIR}/src/common/aka_fwd.hh") # set(DOXYGEN_RECURSIVE YES) # set(DOXYGEN_EXCLUDE # "aka_named_argument.hh" # ) # set(DOXYGEN_EXAMPLE_PATH "${PROJECT_SOURCE_DIR}/examples") # set(DOXYGEN_EXAMPLE_RECURSIVE YES) # set(DOXYGEN_SOURCE_BROWSER NO) # set(DOXYGEN_CLANG_ASSISTED_PARSING NO) # #set(DOXYGEN_CLANG_OPTIONS ) # set(DOXYGEN_CLANG_DATABASE_PATH ${CMAKE_BINARY_DIR}) # set(DOXYGEN_USE_MATHJAX YES) # set(DOXYGEN_GENERATE_HTML NO) # set(DOXYGEN_GENERATE_HTMLHELP NO) # set(DOXYGEN_GENERATE_LATEX NO) # set(DOXYGEN_GENERATE_XML YES) # set(DOXYGEN_XML_OUTPUT xml) # set(DOXYGEN_ENABLE_PREPROCESSING YES) # set(DOXYGEN_MACRO_EXPANSION YES) # set(DOXYGEN_INCLUDE_PATH ${_akantu_include_dirs}) # set(DOXYGEN_PREDEFINED # ${AKANTU_DEFINITIONS} # "DOXYGEN" # # "AKANTU_TO_IMPLEMENT()=" # # "DECLARE_NAMED_ARGUMENT()=" # # "OPTIONAL_NAMED_ARGUMENT(n, v)=v" # # "REQUIRED_NAMED_ARGUMENT(n)=" # ) # set(DOXYGEN_COLLABORATION_GRAPH NO) # set(DOXYGEN_UML_LOOK YES) # set(DOXYGEN_TEMPLATE_RELATIONS YES) # set(DOXYGEN_CALL_GRAPH YES) # set(DOXYGEN_CALLER_GRAPH YES) # set(DOXYGEN_DOT_GRAPH_MAX_NODES 500) # set(DOXYGEN_SHOW_FILES NO) # set(DOXYGEN_LOOKUP_CACHE_SIZE 9) # set(_SRCS # ${PROJECT_BINARY_DIR}/src/aka_config.hh # ${PROJECT_BINARY_DIR}/src/aka_element_classes_info.hh # ${AKANTU_LIBRARY_SRCS} # ${AKANTU_LIBRARY_PUBLIC_HDRS} # ${AKANTU_LIBRARY_PRIVATE_HDRS} # ) # list(REMOVE_ITEM _SRCS # "${PROJECT_SOURCE_DIR}/src/common/aka_named_argument.hh") # doxygen_add_docs(doxygen-doc # ${_SRCS} # USE_STAMP_FILE # COMMENT "Building XML documentation with Doxygen in ${DOXYGEN_XML_DIR}" # ) # else() # string(REGEX REPLACE ";" " " AKANTU_DOXYGEN_DEFINTIONS "${AKANTU_DEFINITIONS};DOXYGEN") # string(REGEX REPLACE ";" " " AKANTU_DOXYGEN_INCLUDE_DIRS "${_akantu_include_dirs}") # make_directory(${DOXYGEN_XML_DIR}) # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/akantu.dox.in # ${DOXYGEN_INPUT_DOX} # ) # add_custom_command( # OUTPUT ${DOXYGEN_OUTPUT} # COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_INPUT_DOX} # DEPENDS ${DOXYGEN_INPUT_DOX} # COMMENT "Building XML documentation with Doxygen in ${DOXYGEN_XML_DIR}" # ) # add_custom_target(doxygen-doc ALL # DEPENDS ${DOXYGEN_OUTPUT} # ) # endif() # ---------------------------------------------------------------------------- # # Sphinx # # ---------------------------------------------------------------------------- # find_package(Sphinx REQUIRED) set(SPHINX_VERBOSE_FLAG "-q") if(CMAKE_VERBOSE_MAKEFILE) set(SPHINX_VERBOSE_FLAG) endif(CMAKE_VERBOSE_MAKEFILE) -set(AKANTU_IN_READTHEDOC FALSE) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/conf.py" "${SPHINX_INPUT}" @ONLY) +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/manual/manual-bibliography.bib" + "${CMAKE_CURRENT_BINARY_DIR}/manual/manual-bibliography.bib" + COPYONLY) + set(SPHINX_PARALLEL_FLAG) if (SPHINX_VERSION VERSION_GREATER_EQUAL 1.7.0) set(SPHINX_PARALLEL_FLAG -j auto) endif() set(_sphinx_command ${SPHINX_BUILD_EXECUTABLE} ${SPHINX_PARALLEL_FLAG} ${SPHINX_VERBOSE_FLAG} -b html -c "${CMAKE_CURRENT_BINARY_DIR}" -d "${SPHINX_CACHE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" "${SPHINX_HTML_DIR}" ) file(GLOB_RECURSE _SPHINX_SRCS "*.rst") add_custom_command( OUTPUT ${SPHINX_OUTPUT} COMMAND ${_sphinx_command} DEPENDS ${SPHINX_INPUT} ${_SPHINX_SRCS} COMMENT "Building HTML documentation with Sphinx in ${SPHINX_HTML_DIR}" ) add_custom_target(sphinx-doc ALL DEPENDS ${SPHINX_OUTPUT}) diff --git a/doc/dev-doc/akantu.dox.j2 b/doc/dev-doc/akantu.dox.j2 index c55a9d2b4..6a0439dbe 100644 --- a/doc/dev-doc/akantu.dox.j2 +++ b/doc/dev-doc/akantu.dox.j2 @@ -1,47 +1,47 @@ PROJECT_NAME = Akantu PROJECT_NUMBER = {{ akantu_version }} STRIP_FROM_PATH = {{ akantu_source_path }} STRIP_FROM_INC_PATH = {{ akantu_source_path }} TAB_SIZE = 4 ALIASES = "rst=\verbatim embed:rst" \ "endrst=\endverbatim" QUIET = NO WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = NO WARN_AS_ERROR = NO INPUT = {{ akantu_source_path }}/src FILE_PATTERNS = *.c *.cc *.hh *.py EXCLUDE = {{ akantu_source_path }}/src/common/aka_fwd.hh RECURSIVE = YES EXAMPLE_PATH = {{ akantu_source_path }}/examples EXAMPLE_RECURSIVE = YES SOURCE_BROWSER = NO GENERATE_HTML = NO GENERATE_HTMLHELP = NO USE_MATHJAX = YES GENERATE_LATEX = NO GENERATE_XML = YES XML_OUTPUT = xml ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES PREDEFINED = DOXYGEN DOXYGEN_INCLUDE_PATH = {{ akantu_source_path }}/src/common \ {{ akantu_source_path }}/src/fe_engine \ {{ akantu_source_path }}/src/mesh \ {{ akantu_source_path }}/src/model +PREDEFINED = "AKANTU_GET_MACRO(name, value, type) = type get##name() const;" \ + "AKANTU_GET_MACRO_NOT_CONST(name, value, type) = type get##name();" EXPAND_AS_DEFINED = __BEGIN_AKANTU__ \ __END_AKANTU__ \ __BEGIN_AKANTU_DUMPER__ \ __END_AKANTU_DUMPER__ \ AKANTU_SET_MACRO \ - AKANTU_GET_MACRO \ - AKANTU_GET_MACRO_NOT_CONST \ AKANTU_GET_MACRO_DEREF_PTR \ AKANTU_GET_MACRO_BY_ELEMENT_TYPE \ AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST COLLABORATION_GRAPH = NO UML_LOOK = YES TEMPLATE_RELATIONS = YES CALL_GRAPH = YES CALLER_GRAPH = YES LOOKUP_CACHE_SIZE = 0 diff --git a/doc/dev-doc/conf.py b/doc/dev-doc/conf.py index 1dec5e888..d7b77b805 100644 --- a/doc/dev-doc/conf.py +++ b/doc/dev-doc/conf.py @@ -1,334 +1,334 @@ # -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os import shutil import jinja2 import git import re import subprocess # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Number figures numfig = True # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'sphinxcontrib.bibtex', 'breathe', ] read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True' if read_the_docs_build: akantu_path = "." akantu_source_path = "../../" else: akantu_path = "@CMAKE_CURRENT_BINARY_DIR@" akantu_source_path = "@CMAKE_SOURCE_DIR@" # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['CMakeLists.txt', 'manual/appendix/elements.rst', 'manual/appendix/material-parameters.rst', 'manual/constitutive-laws.rst', 'manual/new-constitutive-laws.rst'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' primary_domain = 'cpp' highlight_language = 'cpp' bibtex_bibfiles = ['manual/manual-bibliography.bib'] # -- Project information ----------------------------------------------------- project = 'Akantu' copyright = '2021 EPFL (Ecole Polytechnique Fédérale de Lausanne)' + \ ' Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)' author = 'Nicolas Richart' with open(os.path.join(akantu_source_path, 'VERSION'), 'r') as fh: version_file = fh.readlines() file_release = version_file[0].strip() try: tag_prefix = 'v' git_repo = git.Repo(akantu_source_path) git_describe = git_repo.git.describe('--tags', '--dirty', '--always', '--long', '--match', '{}*'.format(tag_prefix)) print("GIT Describe: {}".format(git_describe)) # git describe to PEP404 version describe_matches = re.search( (r'^{}(?P.+?)' + r'(?:-(?P\d+)-g(?P[0-9a-f]+)' + r'(?:-(?Pdirty))?)?$').format(tag_prefix), git_describe) if describe_matches: describe_matches = describe_matches.groupdict() - release = 'v' + describe_matches['version'] + release = describe_matches['version'] if describe_matches['distance']: release += '.' if '+' in release else '+' release += '{distance}.{sha}'.format(**describe_matches) if describe_matches['dirty']: release += '.dirty' else: count = git_repo.git.rev_list('HEAD', '--count') describe_matches = re.search( (r'^(?P[0-9a-f]+)' + r'(?:-(?Pdirty))?$').format(tag_prefix), git_describe).groupdict() - release = 'v{}.{}+{}'.format(file_release, count, - describe_matches['sha']) + release = '{}.{}+{}'.format(file_release, count, + describe_matches['sha']) except git.InvalidGitRepositoryError: - release = 'v' + file_release + release = file_release -version = re.sub(r'^v([0-9]+)\.([0-9+]).*', - r'v\1.\2', +version = re.sub(r'^([0-9]+)\.([0-9+]).*', + r'\1.\2', release) print('Release: {} - Version: {}'.format(release, version)) # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # if read_the_docs_build: html_theme = 'default' else: html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] html_logo = '_static/logo_only_akantu.svg' # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} html_sidebars = { '**': [ 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', ]} math_eqref_format = "Eq. {number}" # MathJax configuration if not read_the_docs_build: mathjax_config = { 'extensions': [ "tex2jax.js", "siunitx.js" ], 'TeX': { 'Macros': { 'st': [r'\mathrm{#1}', 1], 'mat': [r'\mathbf{#1}', 1], 'half': [r'\frac{1}{2}', 0], }, 'extensions': ["AMSmath.js", "AMSsymbols.js", "sinuitx.js"], }, } else: mathjax3_config = { 'tex': { 'macros': { 'st': [r'\mathrm{#1}', 1], 'mat': [r'\mathbf{#1}', 1], 'half': [r'\frac{1}{2}', 0], }, 'packages': ['base', 'ams'], }, 'loader': { 'load': ['[tex]/ams'] }, } # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'Akantudoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': r'''\usepackage{amsmath}''', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'Akantu.tex', 'Akantu Documentation', 'Nicolas Richart', 'manual'), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'akantu', 'Akantu Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'Akantu', 'Akantu Documentation', author, 'Akantu', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project epub_author = author epub_publisher = author epub_copyright = copyright # The unique identifier of the text. This can be a ISBN number # or the project homepage. # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- j2_args = {} if read_the_docs_build: j2_template_path = '.' else: j2_template_path = '@CMAKE_CURRENT_SOURCE_DIR@' os.makedirs(os.path.join(akantu_path, '_static'), exist_ok=True) shutil.copyfile( os.path.join('@CMAKE_CURRENT_SOURCE_DIR@', html_logo), os.path.join(akantu_path, html_logo)) j2_args = { 'akantu_source_path': akantu_source_path, 'akantu_version': version.replace('v', ''), } print(akantu_path) j2_env = jinja2.Environment( loader=jinja2.FileSystemLoader(j2_template_path), undefined=jinja2.DebugUndefined) j2_template = j2_env.get_template('akantu.dox.j2') with open(os.path.join(akantu_path, 'akantu.dox'), 'w') as fh: fh.write(j2_template.render(j2_args)) subprocess.run(['doxygen', 'akantu.dox'], cwd=akantu_path) # print("akantu_path = '{}'".format(akantu_path)) breathe_projects = {"Akantu": os.path.join(akantu_path, "xml")} breathe_default_project = "Akantu" breathe_default_members = ('members', 'undoc-members') breathe_implementation_filename_extensions = ['.c', '.cc', '.cpp'] breathe_show_enumvalue_initializer = True # -- Options for intersphinx extension --------------------------------------- intersphinx_mapping = { 'numpy': ('https://docs.scipy.org/doc/numpy/', None), 'scipy': ('https://docs.scipy.org/doc/scipy/reference', None), } diff --git a/doc/dev-doc/manual/heattransfermodel.rst b/doc/dev-doc/manual/heattransfermodel.rst index 38f14392b..ec4fba797 100644 --- a/doc/dev-doc/manual/heattransfermodel.rst +++ b/doc/dev-doc/manual/heattransfermodel.rst @@ -1,169 +1,169 @@ Heat Transfer Model =================== The heat transfer model is a specific implementation of the :cpp:class:`Model ` interface dedicated to handle the dynamic heat equation. Theory ------ The strong form of the dynamic heat equation can be expressed as .. math:: \rho c_v \dot{T} + \nabla \cdot \vec{\kappa} \nabla T = b with :math:`T` the scalar temperature field, :math:`c_v` the specific heat capacity, :math:`\rho` the mass density, :math:`\mat{\kappa}` the conductivity tensor, and :math:`b` the heat generation per unit of volume. The discretized weak form with a finite number of elements is .. math:: \forall i \quad \sum_j \left( \int_\Omega \rho c_v N_j N_i d\Omega \right) \dot{T}_j - \sum_j \left( \int_\Omega \vec{\kappa} \nabla N_j \nabla N_i d\Omega \right) T_j = - \int_{\Gamma} N_i \vec{q} \cdot \vec{n} d\Gamma + \int_\Omega b N_i d\Omega with :math:`i` and :math:`j` the node indices, :math:`\vec{n}` the normal field to the surface :math:`\Gamma = \partial \Omega`. To simplify, we can define the capacity and the conductivity matrices as .. math:: C_{ij} = \int_\Omega \rho c_v N_j N_i d\Omega \qquad \textrm{and} \qquad K_{ij} = - \int_\Omega \vec{\kappa} \nabla N_j \nabla N_i d\Omega and the system to solve can be written .. math:: \mat{C} \cdot \vec{\dot{T}} = \vec{Q}^{\text{ext}} -\mat{K} \cdot \vec{T}~, with :math:`\vec{Q}^{\text{ext}}` the consistent heat generated. Using the Heat Transfer Model ----------------------------- A material file name has to be provided during initialization. Currently, the :cpp:class:`HeatTransferModel ` object uses dynamic analysis with an explicit time integration scheme. It can simply be created like this .. code-block:: c++ HeatTransferModel model(mesh, spatial_dimension); while an existing mesh has been used (see \ref{sect:common:mesh}). Then the model object can be initialized with: .. code-block:: c++ model.initFull() This function will load the material properties, and allocate / initialize the nodes and element :cpp:class:`Arrays ` More precisely, the heat transfer model contains 4 :cpp:class:`Arrays `: - **temperature** contains the nodal temperature :math:`T` (zero by default after the initialization). - **temperature_rate** contains the variations of temperature :math:`\dot{T}` (zero by default after the initialization). - **blocked_dofs** contains a Boolean value for each degree of freedom specifying whether the degree is blocked or not. A Dirichlet boundary condition (:math:`T_d`) can be prescribed by setting the **blocked_dofs** value of a degree of freedom to ``true``. The **temperature** and the **temperature_rate** are computed for all degrees of freedom where the **blocked_dofs** value is set to ``false``. For the remaining degrees of freedom, the imposed values (zero by default after initialization) are kept. - **external_heat_rate** contains the external heat generations. :math:`\vec{Q^{ext}}` on the nodes. - **internal_heat_rate** contains the internal heat generations. :math:`\vec{Q^{int}} = -\mat{K} \cdot \vec{T}` on the nodes. Only a single material can be specified on the domain. A material text file (*e.g.* material.dat) provides the material properties as follows: -.. code-block:: +.. code-block:: python model heat_transfer_model [ capacity = %\emph{XXX}% density = %\emph{XXX}% conductivity = [%\emph{XXX}% ... %\emph{XXX}%] ] where the ``capacity`` and ``density`` are scalars, and the ``conductivity`` is specified as a :math:`3\times 3` tensor. Explicit Dynamic ---------------- The explicit time integration scheme in ``Akantu`` uses a lumped capacity matrix :math:`\mat{C}` (reducing the computational cost, see Chapter :ref:`sect-smm`). This matrix is assembled by distributing the capacity of each element onto its nodes. Therefore, the resulting :math:`\mat{C}` is a diagonal matrix stored in the ``capacity`` :cpp:class:`Array ` of the model. .. code-block:: c++ model.assembleCapacityLumped(); .. note:: Currently, only the explicit time integration with lumped capacity matrix is implemented within ``Akantu``. The explicit integration scheme is *Forward Euler* :cite:`curnier92a`. - Predictor: :math:`\vec{T}_{n+1} = \vec{T}_{n} + \Delta t \dot{\vec{T}}_{n}` - Update residual: :math:`\vec{R}_{n+1} = \left( \vec{Q^{ext}_{n+1}} - \vec{K}\vec{T}_{n+1} \right)` - Corrector : :math:`\dot{\vec{T}}_{n+1} = \mat{C}^{-1} \vec{R}_{n+1}` The explicit integration scheme is conditionally stable. The time step has to be smaller than the stable time step, and it can be obtained in ``Akantu`` as follows: .. code-block:: c++ time_step = model.getStableTimeStep(); The stable time step is defined as: .. math:: \Delta t_{\st{crit}} = 2 \Delta x^2 \frac{\rho c_v}{\mid\mid \mat{\kappa} \mid\mid^\infty} :label: eqn:htm:explicit:stabletime where :math:`\Delta x` is the characteristic length (*e.g* the in-radius in the case of linear triangle element), :math:`\rho` is the density, :math:`\mat{\kappa}` is the conductivity tensor, and :math:`c_v` is the specific heat capacity. It is necessary to impose a time step which is smaller than the stable time step, for instance, by multiplying the stable time step by a safety factor smaller than one. .. code-block:: c++ const Real safety_time_factor = 0.1; Real applied_time_step = time_step * safety_time_factor; model.setTimeStep(applied_time_step); The following loop allows, for each time step, to update the ``temperature``, ``residual`` and ``temperature_rate`` fields following the previously described integration scheme. .. code-block:: c++ for (UInt s = 1; (s-1)*applied_time_step < total_time; ++s) { model.solveStep(); } An example of explicit dynamic heat propagation is presented in ``examples/heat_transfer/explicit_heat_transfer.cc``. This example consists of a square 2D plate of :math:`1 \text{m}^2` having an initial temperature of :math:`100 \text{K}` everywhere but a none centered hot point maintained at :math:`300 \text{K}`. :numref:`fig:htm:explicit:dynamic-1` presents the geometry of this case. The material used is a linear fictitious elastic material with a density of :math:`8940 \text{kg}/\text{m}^3`, a conductivity of :math:`401 \text{W}/\text{m}/\text{K}` and a specific heat capacity of :math:`385 \text{J}/\text{K}/\text{kg}`. The time step used is :math:`0.12 \text{s}`. .. _fig:htm:explicit:dynamic-1: .. figure:: figures/hot-point-1.png :align: center Initial temperature field .. _fig:htm:explicit:dynamic-2: .. figure:: figures/hot-point-2.png :align: center Temperature field after 15000 time steps = 30 minutes. The lines represent iso-surfaces. diff --git a/doc/dev-doc/manual/io.rst b/doc/dev-doc/manual/io.rst index 6b14473cf..307eaba2f 100644 --- a/doc/dev-doc/manual/io.rst +++ b/doc/dev-doc/manual/io.rst @@ -1,272 +1,271 @@ .. _sect-io: Input/Output ============ Input file ---------- The text input file of a simulation should be precised using the method :cpp:func:`initialize ` which will instantiate the static :cpp:class:`Parser ` object of ``Akantu``. This section explains how to manipulate at :cpp:class:`Parser ` objects to input data in ``Akantu``. Akantu Parser ~~~~~~~~~~~~~ ``Akantu`` file parser has a tree organization. - :cpp:class:`Parser `, the root of the tree, can be accessed using:: auto & parser = getStaticParser(); - :cpp:class:`ParserSection `, branch of the tree, - contains map a of sub-sections (:cpp:enum:`SectionType - `, :cpp:class:`ParserSection `) + contains map a of sub-sections (:cpp:enum:`ParserType + `, :cpp:class:`ParserSection `) and a :cpp:class:`ParserSection * ` pointing to the parent section. The user section of the input file can directly be accessed by:: const auto & usersect = getUserParser(); - :cpp:class:`ParserParameter `, the leaf of the tree, carries data of the input file which can be cast to the correct type with the assignment operator:: Real mass = usersect.getParameter("mass"); or used directly within an expression Grammar ~~~~~~~ The structure of text input files consists of different sections containing a list of parameters. As example, the file parsed in the previous section will look like:: user parameters [ mass = 10.5 ] Basically every standard arithmetic operations can be used inside of input files as well as the constant ``pi`` and ``e`` and the exponent operator ``^``. Operations between :cpp:class:`ParserParameter ` are also possible with the convention that only parameters of the current and the parent sections are available. :cpp:class:`Vector ` and :cpp:class:`Matrix ` can also be read according to the ``NumPy`` :cite:`numpy` writing convention (a.e. cauchy_stress_tensor = [[:math:`\sigma_{xx}`, :math:`\sigma_{xy}`],[:math:`\sigma_{yx}`,\ :math:`\sigma_{yy}`]]). An example illustrating how to parse the following input file can be found in ``example\io\parser\example_parser.cc``:: user parameters [ spatial_dimension = 2 mesh_file = swiss_cheese.msh inner_holes = holes outter_crust = crust lactostatic_p = 30e3 stress = [[lactostatic_p, 0 ], [0, lactostatic_p]] max_nb_iterations = 100 precision = 1e-9 ] .. _sect-io-material: Material section ~~~~~~~~~~~~~~~~ The input file should also be used to specify material characteristics (constitutive behavior and material properties). The dedicated material section is then read by :cpp:func:`initFull ` method of :cpp:class:`SolidMechanicsModel ` which initializes the different materials specified with the following convention:: material constitutive_law [ name = value rho = value ... ] where *constitutive_law* is the adopted constitutive law, followed by the material properties listed one by line in the bracket (*e.g.*, ``name`` and density :math:``rho``. Some constitutive laws can also have an *optional flavor*. More information can be found in sections relative to material :ref:`sect-smm-cl`. Output data ----------- Generic data ~~~~~~~~~~~~ In this section, we address ways to get the internal data in human-readable formats. The models in ``Akantu`` handle data associated to the mesh, but this data can be split into several :cpp:class:`Arrays `. For example, the data stored per element type in a :cpp:class:`ElementTypeMapArray ` is composed of as many :cpp:class:`Arrays ` as types in the mesh. In order to get this data in a visualization software, the models contain a object to dump ``VTK`` files. These files can be visualized in software such as ``ParaView`` :cite:`paraview`, ``ViSit`` :cite:`visit` or ``Mayavi`` :cite:`mayavi`. The internal dumper of the model can be configured to specify which data fields are to be written. This is done with the :cpp:func:`addDumpField ` method. By default all the files are generated in a folder called ``paraview/``:: model.setBaseName("output"); // prefix for all generated files model.addDumpField("displacement"); model.addDumpField("stress"); ... model.dump() The fields are dumped with the number of components of the memory. For example, in 2D, the memory has :cpp:class:`Vectors ` of 2 components, or the :math:`2^{nd}` order tensors with :math:`2\times2` components. This memory can be dealt with :cpp:func:`addDumpFieldVector ` which always dumps :cpp:class:`Vectors ` with 3 components or :cpp:func:`addDumpFieldTensor ` which dumps :math:`2^{nd}` order tensors with :math:`3\times3` components respectively. The routines :cpp:func:`addDumpFieldVector ` and :cpp:func:`addDumpFieldTensor ` were introduced because of ``ParaView`` which mostly manipulate 3D data. Those fields which are stored by quadrature point are modified to be seen in the ``VTK`` file as elemental data. To do this, the default is to average the values of all the quadrature points. The list of fields depends on the models (for :cpp:class:`SolidMechanicsModel ` see table :ref:`tab-io-smm-field-list`. -.. container:: - :name: tab-io-smm-field-list +.. _tab-io-smm-field-list: - .. table:: List of dumpable fields for :cpp:class:`SolidMechanicsModel `. +.. table:: List of dumpable fields for :cpp:class:`SolidMechanicsModel `. ====================== ================ ================= key type support ====================== ================ ================= displacement ``Vector`` nodes mass ``Vector`` nodes velocity ``Vector`` nodes acceleration ``Vector`` nodes force ``Vector`` nodes residual ``Vector`` nodes increment ``Vector`` nodes blocked_dofs ``Vector`` nodes partitions ``Real`` elements material_index variable elements strain ``Matrix`` quadrature points Green strain ``Matrix`` quadrature points principal strain ``Vector`` quadrature points principal Green strain ``Vector`` quadrature points grad_u ``Matrix`` quadrature points stress ``Matrix`` quadrature points Von Mises stress ``Real`` quadrature points material_index variable quadrature points ====================== ================ ================= Cohesive elements’ data ~~~~~~~~~~~~~~~~~~~~~~~ Cohesive elements and their relative data can be easily dumped thanks to a specific dumper contained in :cpp:class:`SolidMechanicsModelCohesive `. In order to use it, one has just to add the string ``cohesive elements`` when calling each method already illustrated. Here is an example on how to dump displacement and damage:: model.addDumpFieldVectorToDumper("cohesive elements", "displacement"); model.addDumpFieldToDumper("cohesive elements", "damage"); model.dump("cohesive elements"); Fragmentation data ^^^^^^^^^^^^^^^^^^ Whenever the :cpp:class:`SolidMechanicsModelCohesive ` is used, it is possible to dump additional data about the fragments that get formed in the simulation both in serial and parallel. This task is carried out by the :cpp:class:`FragmentManager ` class, that takes care of computing the following quantities for each fragment: - index; - mass; - moments of inertia; - velocity; - number of elements. These computations can be realized at once by calling the function :cpp:class:`computeAllData `, or individually by calling the other public functions of the class. The data can be dumped to be visualized in ``ParaView``, or can be accessed within the simulation. An example of usage is: At the end of this example the velocities of the fragments are accessed with a reference to a :cpp:class:`const Array\ `. The size of this array is the number of fragments, and its number of components is the spatial dimension in this case. Advanced dumping ~~~~~~~~~~~~~~~~ Arbitrary fields ^^^^^^^^^^^^^^^^ In addition to the predetermined fields from the models and materials, the user can add any data to a dumper as long as the support is the same. That is to say data that have the size of the full mesh on if the dumper is dumping the mesh, or of the size of an element group if it is a filtered dumper. For this the easiest is to use the “external” fields register functions The simple case force nodal and elemental data are to pass directly the data container itself if it as the good size. - For nodal fields: It is assumed that the array as the same size as the number of nodes in the mesh - For elemental fields: It is assumed that the arrays in the map have the same sizes as the element numbers in the mesh for element types of dimension ``spatial_dimension``. If some changes have to be applied on the data as for example a padding for ``ParaView`` vectors, this can be done by using the field interface. All these functions use the default dumper registered in the mesh but also have the ``ToDumper`` variation with the dumper name specified. For example: An example of code presenting this interface is present in the ``examples/io/dumper``. This interface is part of the :cpp:class:`Dumpable ` class from which the :cpp:class:`Mesh ` inherits. Creating a new dumper ^^^^^^^^^^^^^^^^^^^^^ You can also create you own dumpers, ``Akantu`` uses a third-party library in order to write the output files, ``IOHelper``. ``Akantu`` supports the ``ParaView`` format and a Text format defined by ``IOHelper``. This two files format are handled by the classes :cpp:class:`DumperParaview ` and :cpp:class:`DumperText `. In order to use them you can instantiate on of this object in your code. This dumper have a simple interface. You can register a mesh :cpp:func:`registerMesh `, :cpp:func:`registerFilteredMesh ` or a field, :cpp:class:`registerField `. An example of code presenting this low level interface is present in the ``examples/io/dumper``. The different types of :cpp:class:`Field ` that can be created are present in the source folder ``src/io/dumper``. diff --git a/doc/dev-doc/manual/structuralmechanicsmodel.rst b/doc/dev-doc/manual/structuralmechanicsmodel.rst index 92a8c3f40..516d72fdd 100644 --- a/doc/dev-doc/manual/structuralmechanicsmodel.rst +++ b/doc/dev-doc/manual/structuralmechanicsmodel.rst @@ -1,214 +1,214 @@ Structural Mechanics Model ========================== Static structural mechanics problems can be handled using the class :cpp:class:`StructuralMechanicsModel `. So far, ``Akantu`` provides 2D and 3D Bernoulli beam elements :cite:`frey2009`. This model is instantiated for a given :cpp:class:`Mesh `, as for the :cpp:class:`SolidMechanicsModel `. The model will create its own :cpp:class:`FEEngine ` object to compute the interpolation, gradient, integration and assembly operations. The :cpp:class:`StructuralMechanicsModel ` constructor is called in the following way: .. code-block:: c++ StructuralMechanicsModel model(mesh, spatial_dimension); where ``mesh`` is a :cpp:class:`Mesh ` object defining the structure for which the equations of statics are to be solved, and ``spatial_dimension`` is the dimensionality of the problem. If ``spatial_dimension`` is omitted, the problem is assumed to have the same dimensionality as the one specified by the mesh. .. warning:: Dynamic computations are not supported to date. .. note:: Structural meshes are created and loaded - with ``_miot_gmsh_struct`` instead of ``_miot_gmsh`` (cf. :ref:`loading mesh`) + with ``_miot_gmsh_struct`` instead of ``_miot_gmsh`` (cf. :ref:`loading_mesh`) .. code-block:: c++ Mesh mesh; mesh.read("structural_mesh.msh", _miot_gmsh_struct); This model contains at least the following :cpp:class:`Arrays `: - **blocked_dofs** contains a Boolean value for each degree of freedom specifying whether that degree is blocked or not. A Dirichlet boundary condition can be prescribed by setting the **blocked_dofs** value of a degree of freedom to ``true``. The **displacement** is computed for all degrees of freedom for which the **blocked_dofs** value is set to ``false``. For the remaining degrees of freedom, the imposed values (zero by default after initialization) are kept. - **displacement_rotation** contains the generalized displacements (*i.e.* displacements and rotations) of all degrees of freedom. It can be either a computed displacement for free degrees of freedom or an imposed displacement in case of blocked ones (:math:`\vec{u}` in the following). - **external_force** contains the generalized external forces (forces and moments) applied to the nodes (:math:`\vec{f_{\st{ext}}}` in the following). - **internal_force** contains the generalized internal forces (forces and moments) applied to the nodes (:math:`\vec{f_{\st{int}}}` in the following). An example to help understand how to use this model will be presented in the next section. .. _sec:structMechMod:setup: Model Setup ----------- Initialization `````````````` The easiest way to initialize the structural mechanics model is: .. code-block:: c++ model.initFull(); The method :cpp:class:`initFull ` computes the shape functions, initializes the internal vectors mentioned above and allocates the memory for the stiffness matrix, unlike the solid mechanics model, its default argument is ``_static``. Material properties are defined using the :cpp:class:`StructuralMaterial ` structure described in :numref:`tab-structmechmod-strucmaterial`. Such a definition could, for instance, look like .. code-block:: c++ StructuralMaterial mat1; mat.E=3e10; mat.I=0.0025; mat.A=0.01; .. _tab-structmechmod-strucmaterial: .. table:: Material properties for structural elements defined in the class :cpp:class:`StructuralMaterial `. :align: center ====== ====== Field Description ====== ====== ``E`` Young's modulus ``A`` Cross section area ``I`` Second cross sectional moment of inertia (for 2D elements) ``Iy`` ``I`` around beam :math:`y`--axis (for 3D elements) ``Iz`` ``I`` around beam :math:`z`--axis (for 3D elements) ``GJ`` Polar moment of inertia of beam cross section (for 3D elements) ====== ====== Materials can be added to the model's ``element_material`` vector using .. code-block:: c++ model.addMaterial(mat1); They are successively numbered and then assigned to specific elements. .. code-block:: c++ for (UInt i = 0; i < nb_element_mat_1; ++i) { model.getElementMaterial(_bernoulli_beam_2)(i,0) = 1; } .. _sect:structMechMod:boundary: Setting Boundary Conditions ``````````````````````````` As explained before, the Dirichlet boundary conditions are applied through the array **blocked_dofs**. Two options exist to define Neumann conditions. If a nodal force is applied, it has to be directly set in the array **force_momentum**. For loads distributed along the beam length, the method :cpp:class:`computeForcesFromFunction ` integrates them into nodal forces. The method takes as input a function describing the distribution of loads along the beam and a functor :cpp:class:`BoundaryFunctionType ` specifing if the function is expressed in the local coordinates (``_bft_traction_local``) or in the global system of coordinates (``_bft_traction``). .. code-block:: c++ static void lin_load(double * position, double * load, Real * normal, UInt surface_id){ memset(load,0,sizeof(Real)*3); load[1] = position[0]*position[0]-250; } int main(){ ... model.computeForcesFromFunction<_bernoulli_beam_2>(lin_load, _bft_traction_local); ... } .. _sect:structMechMod:static: Static Analysis --------------- The :cpp:class:`StructuralMechanicsModel ` class can perform static analyses of structures. In this case, the equation to solve is the same as for the :cpp:class:`SolidMechanicsModel ` used for static analyses .. math:: \mat{K} \vec{u} = \vec{f_{\st{ext}}}~, :label: eqn-structmechmod-static where :math:`\mat{K}` is the global stiffness matrix, :math:`\vec{u}` the generalized displacement vector and :math:`\vec{f_{\st{ext}}}` the vector of generalized external forces applied to the system. To solve such a problem, the static solver of the :cpp:class:`StructuralMechanicsModel ` object is used. First a model has to be created and initialized. .. code-block:: c++ StructuralMechanicsModel model(mesh); model.initFull(); - :cpp:func:`model.initFull ` initializes all internal vectors to zero. Once the model is created and initialized, the boundary conditions can be set as explained in Section :ref:`sect:structMechMod:boundary`. Boundary conditions will prescribe the external forces or moments for the free degrees of freedom :math:`\vec{f_{\st{ext}}}` and displacements or rotations for the others. To completely define the system represented by equation (:eq:`eqn-structmechmod-static`), the global stiffness matrix :math:`\mat{K}` must be assembled. .. code-block:: c++ model.assembleStiffnessMatrix(); The computation of the static equilibrium is performed using the same Newton-Raphson algorithm as described in Section~\ref{sect:smm:static}. \note{To date, :cpp:class:`StructuralMechanicsModel ` handles only constitutively and geometrically linear problems, the algorithm is therefore guaranteed to converge in two iterations.} .. code-block:: c++ model.solveStep(); - :cpp:func:`model.solveStep ` solves the :eq:`eqn-structmechmod-static`. The **increment** vector of the model will contain the new increment of displacements, and the **displacement_rotation** vector is also updated to the new displacements. At the end of the analysis, the final solution is stored in the **displacement_rotation** vector. A full example of how to solve a structural mechanics problem is presented in the code ``example/structural_mechanics/bernoulli_beam_2_example.cc``. This example is composed of a 2D beam, clamped at the left end and supported by two rollers as shown in :numref:`fig-structmechmod-exam1-1`. The problem is defined by the applied load :math:`q=6 \text{\kN/m}`, moment :math:`\bar{M} = 3.6 \text{kN m}`, moments of inertia :math:`I_1 = 250\,000 \text{cm}^4` and :math:`I_2 = 128\,000 \text{cm}^4` and lengths :math:`L_1 = 10\text{m}` and :math:`L_2 = 8\text{m}`. The resulting rotations at node two and three are :math:`\varphi_2 = 0.001\,167` and :math:`\varphi_3 = -0.000\,771`. .. _fig-structmechmod-exam1-1: .. figure:: figures/beam_example.svg :align: center 2D beam example diff --git a/doc/dev-doc/reference.rst b/doc/dev-doc/reference.rst index d82c91a6d..5dd7a26e6 100644 --- a/doc/dev-doc/reference.rst +++ b/doc/dev-doc/reference.rst @@ -1,118 +1,118 @@ .. _reference: Reference --------- Common `````` .. doxygenfunction:: akantu::initialize(const std::string &input_file, int &argc, char **&argv) .. doxygenfunction:: akantu::initialize(int &argc, char **&argv) .. doxygentypedef:: akantu::UInt .. doxygentypedef:: akantu::Int .. doxygentypedef:: akantu::Real .. doxygenenum:: akantu::ElementType .. doxygenenum:: akantu::ModelType .. doxygenenum:: akantu::AnalysisMethod .. doxygenenum:: akantu::SolveConvergenceCriteria .. doxygenclass:: akantu::ArrayBase .. doxygenclass:: akantu::ArrayDataLayer .. doxygenclass:: akantu::Array .. doxygenclass:: akantu::ElementTypeMapArray .. doxygenclass:: akantu::Vector .. doxygenclass:: akantu::Matrix Mesh ```` .. doxygenclass:: akantu::Mesh .. doxygenclass:: akantu::FEEngine .. doxygenclass:: akantu::Element .. doxygenclass:: akantu::GroupManager .. doxygenclass:: akantu::ElementGroup .. doxygenclass:: akantu::NodeGroup Models `````` Common ...... .. doxygenclass:: akantu::BC::Dirichlet::FixedValue .. doxygenclass:: akantu::BC::Dirichlet::FlagOnly .. doxygenclass:: akantu::BC::Dirichlet::IncrementValue .. doxygenclass:: akantu::BC::Neumann::FromHigherDim .. doxygenclass:: akantu::BC::Neumann::FromSameDim .. doxygenclass:: akantu::BoundaryCondition .. doxygenclass:: akantu::BoundaryConditionFunctor .. doxygenclass:: akantu::EventHandlerManager .. doxygenclass:: akantu::Model .. doxygenclass:: akantu::NonLocalManagerCallback Solvers ....... .. doxygenclass:: akantu::ModelSolver .. doxygenclass:: akantu::DOFManager .. doxygenclass:: akantu::NonLinearSolver .. doxygenclass:: akantu::NonLinearSolverNewtonRaphson Solid Mechanics Model ..................... .. doxygenclass:: akantu::SolidMechanicsModel .. doxygenclass:: akantu::SolidMechanicsModelOptions .. doxygenclass:: akantu::MaterialSelector .. doxygenclass:: akantu::MeshDataMaterialSelector .. doxygenclass:: akantu::Material .. doxygenclass:: akantu::InternalField Solid Mechanics Model Cohesive .............................. .. doxygenclass:: akantu::SolidMechanicsModelCohesive .. doxygenclass:: akantu::FragmentManager Heat Transfer Model ................... .. doxygenclass:: akantu::HeatTransferModel Phase Field Model ................... .. doxygenclass:: akantu::PhaseFieldModel .. doxygenclass:: akantu::PhaseField Structural Mechanics Model .......................... .. doxygenclass:: akantu::StructuralMaterial .. doxygenclass:: akantu::StructuralMechanicsModel Coupler Solid PhaseField ........................ .. doxygenclass:: akantu::CouplerSolidPhaseField Synchronizers ````````````` .. doxygenclass:: akantu::DataAccessor Input/Output ```````````` .. doxygenclass:: akantu::Dumpable .. doxygenclass:: akantu::DumperIOHelper .. doxygenclass:: akantu::DumperParaview .. doxygenclass:: akantu::DumperText -.. doxygenclass:: akantu::Field +.. doxygenclass:: akantu::dumpers::Field .. doxygenclass:: akantu::Parser .. doxygenclass:: akantu::ParserParameter .. doxygenclass:: akantu::ParserSection -.. doxygenenum:: akantu::SectionType +.. doxygenenum:: akantu::ParserType diff --git a/src/io/parser/parser.hh b/src/io/parser/parser.hh index 3297fc68c..8789424f9 100644 --- a/src/io/parser/parser.hh +++ b/src/io/parser/parser.hh @@ -1,514 +1,539 @@ /** * @file parser.hh * * @author Nicolas Richart * * @date creation: Wed Nov 13 2013 * @date last modification: Fri Dec 08 2017 * * @brief File parser interface * * * Copyright (©) 2014-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_random_generator.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef AKANTU_PARSER_HH_ #define AKANTU_PARSER_HH_ namespace akantu { #if !defined(DOXYGEN) // clang-format off #define AKANTU_SECTION_TYPES \ (cohesive_inserter) \ (contact) \ (embedded_interface) \ (friction) \ (global) \ (heat) \ (integration_scheme) \ (material) \ (phasefield) \ (mesh) \ (model) \ (model_solver) \ (neighborhood) \ (neighborhoods) \ (non_linear_solver) \ (non_local) \ (rules) \ (solver) \ (time_step_solver) \ (user) \ (weight_function) \ (not_defined) // clang-format on /// Defines the possible section types AKANTU_CLASS_ENUM_DECLARE(ParserType, AKANTU_SECTION_TYPES) AKANTU_CLASS_ENUM_OUTPUT_STREAM(ParserType, AKANTU_SECTION_TYPES) AKANTU_CLASS_ENUM_INPUT_STREAM(ParserType, AKANTU_SECTION_TYPES) +#else +enum class ParserType { + cohesive_inserter, + contact, + embedded_interface, + friction, + global, + heat, + integration_scheme, + material, + phasefield, + mesh, + model, + model_solver, + neighborhood, + neighborhoods, + non_linear_solver, + non_local, + rules, + solver, + time_step_solver, + user, + weight_function, + not_defined +}; #endif /// Defines the possible search contexts/scopes (for parameter search) enum ParserParameterSearchCxt { _ppsc_current_scope = 0x1, _ppsc_parent_scope = 0x2, _ppsc_current_and_parent_scope = 0x3 }; /* ------------------------------------------------------------------------ */ /* Parameters Class */ /* ------------------------------------------------------------------------ */ class ParserSection; /// @brief The ParserParameter objects represent the end of tree branches as /// they /// are the different informations contained in the input file. class ParserParameter { public: ParserParameter() : name(std::string()), value(std::string()), dbg_filename(std::string()) { } ParserParameter(const std::string & name, const std::string & value, const ParserSection & parent_section) : parent_section(&parent_section), name(name), value(value), dbg_filename(std::string()) {} ParserParameter(const ParserParameter & param) = default; virtual ~ParserParameter() = default; /// Get parameter name const std::string & getName() const { return name; } /// Get parameter value const std::string & getValue() const { return value; } /// Set info for debug output void setDebugInfo(const std::string & filename, UInt line, UInt column) { dbg_filename = filename; dbg_line = line; dbg_column = column; } template inline operator T() const; // template inline operator Vector() const; // template inline operator Matrix() const; /// Print parameter info in stream void printself(std::ostream & stream, __attribute__((unused)) unsigned int indent = 0) const { stream << name << ": " << value << " (" << dbg_filename << ":" << dbg_line << ":" << dbg_column << ")"; } private: void setParent(const ParserSection & sect) { parent_section = § } friend class ParserSection; private: /// Pointer to the parent section const ParserSection * parent_section{nullptr}; /// Name of the parameter std::string name; /// Value of the parameter std::string value; /// File for debug output std::string dbg_filename; /// Position of parameter in parsed file UInt dbg_line, dbg_column; }; /* ------------------------------------------------------------------------ */ /* Sections Class */ /* ------------------------------------------------------------------------ */ /// ParserSection represents a branch of the parsing tree. class ParserSection { public: using SubSections = std::multimap; using Parameters = std::map; private: using const_section_iterator_ = SubSections::const_iterator; public: /* ------------------------------------------------------------------------ */ /* SubSection iterator */ /* ------------------------------------------------------------------------ */ /// Iterator on sections class const_section_iterator { public: using iterator_category = std::forward_iterator_tag; using value_type = ParserSection; using pointer = ParserSection *; using reference = ParserSection &; const_section_iterator() = default; const_section_iterator(const const_section_iterator_ & it) : it(it) {} const_section_iterator(const const_section_iterator & other) = default; const_section_iterator & operator=(const const_section_iterator & other) = default; const ParserSection & operator*() const { return it->second; } const ParserSection * operator->() const { return &(it->second); } bool operator==(const const_section_iterator & other) const { return it == other.it; } bool operator!=(const const_section_iterator & other) const { return it != other.it; } const_section_iterator & operator++() { ++it; return *this; } const_section_iterator operator++(int) { const_section_iterator tmp = *this; operator++(); return tmp; } private: const_section_iterator_ it; }; /* ------------------------------------------------------------------------ */ /* Parameters iterator */ /* ------------------------------------------------------------------------ */ /// Iterator on parameters class const_parameter_iterator { public: const_parameter_iterator(const const_parameter_iterator & other) = default; const_parameter_iterator(const Parameters::const_iterator & it) : it(it) {} const_parameter_iterator & operator=(const const_parameter_iterator & other) { if (this != &other) { it = other.it; } return *this; } const ParserParameter & operator*() const { return it->second; } const ParserParameter * operator->() { return &(it->second); }; bool operator==(const const_parameter_iterator & other) const { return it == other.it; } bool operator!=(const const_parameter_iterator & other) const { return it != other.it; } const_parameter_iterator & operator++() { ++it; return *this; } const_parameter_iterator operator++(int) { const_parameter_iterator tmp = *this; operator++(); return tmp; } private: Parameters::const_iterator it; }; /* ---------------------------------------------------------------------- */ ParserSection() : name(std::string()) {} ParserSection(const std::string & name, ParserType type) : name(name), type(type) {} ParserSection(const std::string & name, ParserType type, const std::string & option, const ParserSection & parent_section) : parent_section(&parent_section), name(name), type(type), option(option) {} ParserSection(const ParserSection & section) : parent_section(section.parent_section), name(section.name), type(section.type), option(section.option), parameters(section.parameters), sub_sections_by_type(section.sub_sections_by_type) { setChldrenPointers(); } ParserSection & operator=(const ParserSection & other) { if (&other != this) { parent_section = other.parent_section; name = other.name; type = other.type; option = other.option; parameters = other.parameters; sub_sections_by_type = other.sub_sections_by_type; setChldrenPointers(); } return *this; } virtual ~ParserSection(); virtual void printself(std::ostream & stream, unsigned int indent = 0) const; /* ---------------------------------------------------------------------- */ /* Creation functions */ /* ---------------------------------------------------------------------- */ public: ParserParameter & addParameter(const ParserParameter & param); ParserSection & addSubSection(const ParserSection & section); protected: /// Clean ParserSection content void clean() { parameters.clear(); sub_sections_by_type.clear(); } private: void setChldrenPointers() { for (auto && param_pair : this->parameters) { param_pair.second.setParent(*this); } for (auto && sub_sect_pair : this->sub_sections_by_type) { sub_sect_pair.second.setParent(*this); } } /* ---------------------------------------------------------------------- */ /* Accessors */ /* ---------------------------------------------------------------------- */ public: class SubSectionsRange : public std::pair { public: SubSectionsRange(const const_section_iterator & first, const const_section_iterator & second) : std::pair(first, second) {} auto begin() { return this->first; } auto end() { return this->second; } }; /// Get begin and end iterators on subsections of certain type auto getSubSections(ParserType type = ParserType::_not_defined) const { if (type != ParserType::_not_defined) { auto range = sub_sections_by_type.equal_range(type); return SubSectionsRange(range.first, range.second); } return SubSectionsRange(sub_sections_by_type.begin(), sub_sections_by_type.end()); } /// Get number of subsections of certain type UInt getNbSubSections(ParserType type = ParserType::_not_defined) const { if (type != ParserType::_not_defined) { return this->sub_sections_by_type.count(type); } return this->sub_sections_by_type.size(); } /// Get begin and end iterators on parameters auto getParameters() const { return std::pair( parameters.begin(), parameters.end()); } /* ---------------------------------------------------------------------- */ /// Get parameter within specified context const ParserParameter & getParameter( const std::string & name, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { Parameters::const_iterator it; if ((search_ctx & _ppsc_current_scope) != 0) { it = parameters.find(name); } if (it == parameters.end()) { if ((search_ctx & _ppsc_parent_scope) != 0 and parent_section != nullptr) { return parent_section->getParameter(name, search_ctx); } AKANTU_SILENT_EXCEPTION( "The parameter " << name << " has not been found in the specified context"); } return it->second; } /* ------------------------------------------------------------------------ */ /// Get parameter within specified context, with a default value in case the /// parameter does not exists template T getParameter( const std::string & name, const T & default_value, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { try { T tmp = this->getParameter(name, search_ctx); return tmp; } catch (debug::Exception &) { return default_value; } } /* ------------------------------------------------------------------------ */ /// Check if parameter exists within specified context bool hasParameter( const std::string & name, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { Parameters::const_iterator it; if ((search_ctx & _ppsc_current_scope) != 0) { it = parameters.find(name); } if (it == parameters.end()) { if ((search_ctx & _ppsc_parent_scope) != 0 and parent_section != nullptr) { return parent_section->hasParameter(name, search_ctx); } return false; } return true; } /* -------------------------------------------------------------------------- */ /// Get value of given parameter in context template T getParameterValue( const std::string & name, ParserParameterSearchCxt search_ctx = _ppsc_current_scope) const { const ParserParameter & tmp_param = getParameter(name, search_ctx); T t = tmp_param; return t; } /* -------------------------------------------------------------------------- */ /// Get section name std::string getName() const { return name; } /// Get section type ParserType getType() const { return type; } /// Get section option std::string getOption(const std::string & def = "") const { return (not option.empty()) ? option : def; } protected: void setParent(const ParserSection & sect) { parent_section = § } /* ---------------------------------------------------------------------- */ /* Members */ /* ---------------------------------------------------------------------- */ private: /// Pointer to the parent section const ParserSection * parent_section{nullptr}; /// Name of section std::string name; /// Type of section, see AKANTU_SECTION_TYPES ParserType type{ParserType::_not_defined}; /// Section option std::string option; /// Map of parameters in section Parameters parameters; /// Multi-map of subsections SubSections sub_sections_by_type; }; /* ------------------------------------------------------------------------ */ /* Parser Class */ /* ------------------------------------------------------------------------ */ /// Root of parsing tree, represents the global ParserSection class Parser : public ParserSection { public: Parser() : ParserSection("global", ParserType::_global) {} void parse(const std::string & filename); std::string getLastParsedFile() const; static bool isPermissive() { return permissive_parser; } public: /// Parse real scalar static Real parseReal(const std::string & value, const ParserSection & section); /// Parse real vector static Vector parseVector(const std::string & value, const ParserSection & section); /// Parse real matrix static Matrix parseMatrix(const std::string & value, const ParserSection & section); /// Parse real random parameter static RandomParameter parseRandomParameter(const std::string & value, const ParserSection & section); protected: /// General parse function template static T parseType(const std::string & value, Grammar & grammar); protected: // friend class Parsable; static bool permissive_parser; std::string last_parsed_file; }; inline std::ostream & operator<<(std::ostream & stream, const ParserParameter & _this) { _this.printself(stream); return stream; } inline std::ostream & operator<<(std::ostream & stream, const ParserSection & section) { section.printself(stream); return stream; } } // namespace akantu namespace std { template <> struct iterator_traits<::akantu::Parser::const_section_iterator> { using iterator_category = input_iterator_tag; using value_type = ::akantu::ParserParameter; using difference_type = ptrdiff_t; using pointer = const ::akantu::ParserParameter *; using reference = const ::akantu::ParserParameter &; }; } // namespace std #include "parser_tmpl.hh" #endif /* AKANTU_PARSER_HH_ */