\( \usepackage{euler} % must be loaded before fontspec for the whole doc (below); this must be kept for pngmath, however \usepackage{hyperref} \usepackage{amsmath} \usepackage{amsbsy} %\usepackage{mathabx} \usepackage{underscore} \usepackage[all]{xy} % Metadata of the pdf output \hypersetup{pdftitle={Yade Documentation}} \hypersetup{pdfauthor={Smilauer, V., et al.}} \hypersetup{pdfkeywords={Discrete element method, granular materials, contact law, hydromechanical coupling}} % symbols \renewcommand{\mat}{\boldsymbol} \renewcommand{\vec}{\boldsymbol} \renewcommand{\tens}{\boldsymbol} %normalized and locfram here \def\normalized#1{\widehat{#1}} \def\locframe#1{\widetilde{#1}} % timestep \def\Dt{\Delta t} \def\Dtcr{\Dt_{\rm cr}} % algorithm complexity \def\bigO#1{{\mathcal{O}(#1)}} % variants for greek symbols \let\epsilon\varepsilon \let\theta\vartheta \let\phi\varphi % shorthands \let\sig\sigma \let\eps\epsilon % variables at different points of time \def\prev#1{#1^-} \def\pprev#1{#1^\ominus} \def\curr#1{#1^{\circ}} \def\nnext#1{#1^\oplus} \def\next#1{#1^+} % shorthands for geometry \def\currn{\curr{\vec{n}}} \def\currC{\curr{\vec{C}}} \def\uT{\vec{u}_T} \def\curruT{\curr{\vec{u}}_T} \def\prevuT{\prev{\vec{u}}_T} \def\currn{\curr{\vec{n}}} \def\prevn{\prev{\vec{n}}} % motion \def\pprevvel{\pprev{\dot{\vec{u}}}} \def\nnextvel{\nnext{\dot{\vec{u}}}} \def\curraccel{\curr{\ddot{\vec{u}}}} \def\prevpos{\prev{\vec{u}}} \def\currpos{\curr{\vec{u}}} \def\nextpos{\next{\vec{u}}} \def\curraaccel{\curr{\dot{\vec{\omega}}}} \def\pprevangvel{\pprev{\vec{\omega}}} \def\nnextangvel{\nnext{\vec{\omega}}} \def\loccurr#1{\curr{\locframe{#1}}} \def\numCPU{n_{\rm cpu}} \DeclareMathOperator{\Align}{Align} \DeclareMathOperator{\sign}{sgn} % sorting algorithms \def\isleq#1{\currelem{#1}\ar@/^/[ll]^{\leq}} \def\isnleq#1{\currelem{#1}\ar@/^/[ll]^{\not\leq}} \def\currelem#1{\fbox{$#1$}} \def\sortSep{||} \def\sortInv{\hbox{\phantom{||}}} \def\sortlines#1{\xymatrix@=3pt{#1}} \def\crossBound{||\mkern-18mu<} \)

# Source code for yade.libVersions

    # encoding: utf-8
    """
    The ``yade.libVersions`` module tracks versions of all libraries it was compiled with. Example usage is as follows::

       from yade.libVersions import *
       if(getVersion('cgal') > (4,9,0)):
          …
       else:
          …

    To obtain a list of all libraries use the function :yref:`yade.libVersions.printAllVersions`.

    All libraries listed in :ref:`prerequisites<prerequisites>` are detected by this module.

    .. note:: If we need a version of some library not listed in :ref:`prerequisites<prerequisites>`, then it must also be added to :ysrc:`that list<doc/sphinx/installation.rst>`.

    When adding a new version please have a look at these three files:

    1. :ysrc:`py/_libVersions.cpp`: detection of versions from ``#include`` files by C++.
    2. :ysrc:`py/libVersions.py.in`: python module which is constructed by cmake during compilation. All ``*.in`` files are processed by cmake.
    3. :ysrc:`cMake/FindMissingVersions.cmake`: forced detection of library with undetectable version.

    .. hint:: The safest way to compare versions is to use builtin python tuple comparison e.g. ``if(cgalVer > (4,9,0) and cgalVer < (5,1,1)):``.
    """

    # all C++ functions are accessible now:
    from yade._libVersions import *
    import yade.config

    def getArchitecture():
       """
       :return: string containing processor architecture name, as reported by ``uname -m`` call or from ``CMAKE_HOST_SYSTEM_PROCESSOR`` cmake variable.
       """
       return 'amd64'

    def getLinuxVersion():
       """
       :return: string containing linux release and version, preferably the value of ``PRETTY_NAME`` from file ``/etc/os-release``.
       """
       ret=""
       try:
          import os
          listDir = os.listdir("/etc")
          once = ("os-release" in listDir)
          for f in listDir:
             if((once and f=="os-release") or ((not once) and f.endswith("elease"))):
                with open(os.path.join("/etc", f), 'r') as fin:
                   lines=""
                   for line in fin:
                      if(line.startswith("PRETTY_NAME")):
                         try:
                            ret=(line.split('"')[1])
                         except Exception as e:
                            ret=(line)
                         break
                      lines+=line
                   if(ret==""): ret=("\n"+lines)
       except Exception as e:
          print("Error: cannot find file /etc/os-release. Caught exception:",e)
       if(ret==""): ret="Unknown"
       return ret

    def getVersion(libName):
       """
       This function returns the tuple ``(major, minor, patchlevel)`` with library version number. The ``yade --test`` in file :ysrc:`py/tests/libVersions.py` tests that this
       version is the same as detected by cmake and C++. If only one of those could detect the library version, then this number is used.

       :param string libName: the name of the library

       :return: tuple in format ``(major, minor, patchlevel)`` if ``libName`` exists. Otherwise it returns ``None``.

       .. note:: library openblas has no properly defined version in header files, this function will return ``(0,0,0)`` for openblas. Parsing the version string would be unreliable. The mpi version detected by cmake sometimes is different than version detected by C++, this needs further investigation.
       """
       cppVer   = getAllVersionsCpp()
       cmakeVer = getAllVersionsCmake()
       if(libName == 'openblas'):
          print("Warning: openblas has no properly defined version in header files, the obtained version is ",cppVer[libName])
       if((libName == 'mpi' ) and (cppVer[libName][0] != cmakeVer[libName][0])):
          print('\033[91m'+" Warning: mpi versions are different. Can you help with file py/libVersions.py.in?"+'\033[0m')
          print("C++ is: " , cppVer[libName], " and cmake is: ",cmakeVer[libName], ", will return the C++ one.")
       if((libName in cppVer) and (len(cppVer[libName])==2)):
          return cppVer[libName][0]
       if((libName in cmakeVer) and (len(cmakeVer[libName])==2)):
          return cmakeVer[libName][0]
       #raise RuntimeError("Could not find library version of ",libName)
       return None

    def getAllVersionsCmake():
       """
       This function returns library versions as provided by cmake during compilation.

       :return: dictionary in following format: ``{ "libName" : [ (major, minor, patchlevel) , "versionString" ] }``

       As an example the dict below reflects what libraries this documentation was compiled with (here are only those detected by `CMAKE <https://cmake.org>`_):

       .. ipython::

          In [1]: from yade.libVersions import *

          In [1]: getAllVersionsCmake()

       .. note:: Please add here detection of other libraries when yade starts using them or if you discover how to extract from cmake a version which I didn't add here.

       """

       ret={}
       def addVer(name,v1,v2,v3,ver):
          try:
             ret.update({ name : [ ( int(v1) , int(v2) , int(v3) ) , ver ]})
          except:
             pass
       # 0.cmake
       addVer("cmake",'4','3','4','4.3.4')
       # 1. compiler
       try:
          addVer('compiler'  ,'15.3.0'.split('.')[0],'15.3.0'.split('.')[1],'15.3.0'.split('.')[2],'/usr/bin/x86_64-linux-gnu-g++ 15.3.0')
       except:
          pass
       addVer("clang",'','','','')
       # 2. boost
       addVer("boost",'1','90','0','1.90.0')
       # 3. qt
       addVer("qt"   ,'','','','..')
       # 4. freeglut
       addVer("freeglut" ,'3','0','0','3.0.0')
       try:
          glutVerStr=''
          glutVerNum=glutVerStr.split('.')
          addVer("glut", glutVerNum[0] , glutVerNum[1] , glutVerNum[2] , glutVerStr )
       except:
          pass
       # 5. qglviewer  - I don't know how to detect it
       # 6. python
       addVer("python",'3','14','6','3.14.6')
       # 7. matplotlib
       addVer("matplotlib" ,'','','', '3.10.7+dfsg1')
       # 8. eigen
       addVer("eigen" ,'3','4','0','3.4.0')
       # 9. gdb        - I don't know how to detect it
       # 10. sqlite3   - I don't know how to detect it
       # 11. loki      - I don't know how to detect it
       # 12. vtk
       addVer("vtk"   ,'9','5','2','9.5.2')
       # 13. cgal
       addVer("cgal"  ,'','','','')
       # 14. suitesparse
       addVer("suitesparse",'','','','')
       # 15. openblas  - I don't know how to detect it
       # 16. metis     - I don't know how to detect it
       # 17. mpi       - This one is based on https://cmake.org/cmake/help/v3.10/module/FindMPI.html
       addVer("mpi"   ,'3','1','0', '3.1')
       # 18. numpy
       addVer("numpy" ,'2','4','4', '2.4.4')
       # Note: these below are getting the version currently installed, not the one with which yade was compiled. Maybe this will need to be changed.
       # 19. ipython
       addVer("ipython" ,'9','11','0', '9.11.0')
       # 20. sphinx,
       addVer("sphinx" ,'9','1','0', '9.1.0')
       # 21. clp
       # Note: this can be fixed in the same way as forced detection of freeglut, with file cMake/FindMissingVersions.cmake
       addVer("clp",'','','','')
       addVer("coinutils",'','','','')
       # 22. PyMPI
       addVer("mpi4py" ,'4','1','1', '4.1.1')
       # 23. MPFR
       addVer("mpfr",'4','2','2','4.2.2')
       addVer("mpc",'1','3','1','1.3.1')
       # 24. mpmath
       # a simple check of mpmath is a following python command:
       # import mpmath ; mpmath.mp.dps=50 ; mpmath.acos(0)
       try:
          addVer("mpmath",'1.4.1'.split('.')[0],'1.4.1'.split('.')[1],'1.4.1'.split('.')[2],'1.4.1')
       except:
          pass
       # 25. tkinter
       addVer("tkinter" ,'8','6','0', '8.6')
       # 26. pygraphviz
       addVer("pygraphviz" ,'1','14','0', '1.14')
       # 27. Xlib
       addVer("Xlib" ,'0','33','0', '(0,33)')

       return ret

    def printAllVersions(rstFormat=False):
       """
       This function prints a nicely formatted table with library versions.

       :param bool rstFormat: whether to print table using the reStructuredText formatting. Defaults to ``False`` and prints using `Gitlab markdown rules <https://gitlab.com/help/user/markdown>`_ so that it is easy to paste into gitlab discussions.

       As an example the table below actually reflects with what libraries this documentation was compiled:

       .. ipython::

          In [1]: printAllVersions()

       .. note:: For convenience at startup ``from yade.libVersions import printAllVersions`` is executed, so that this function is readily accessible.

       """

       # there will be three columns: library , cmake , C++
       headers  = ["library","cmake","C++"]
       longest  = [None,None,None]
       cmakeVer = getAllVersionsCmake()
       cppVer   = getAllVersionsCpp()
       namesSet = set()
       for i in range(3): longest[i] = len(headers[i])
       for key,val in cmakeVer.items():
          longest[0] = max(longest[0],len(key))
          if(len(val)==2):
             namesSet.add(key)
             longest[1] = max(longest[1],len(val[1]))
       for key,val in cppVer.items():
          longest[0] = max(longest[0],len(key))
          if(len(val)==2):
             namesSet.add(key)
             longest[2] = max(longest[2],len(val[1]))

       for i in range(3): longest[i]+=2

       sep = '| '+'-'*longest[0]+' | '+'-'*longest[1]+' | '+'-'*longest[2]+' |\n'
       lines="|"
       if(rstFormat):
          sep = '+-'+'-'*longest[0]+'-+-'+'-'*longest[1]+'-+-'+'-'*longest[2]+'-+'
          lines = sep+'\n|'
       # nice python formatting guide: https://pyformat.info/
       for i in range(3):
          lines +=" "+(('{:'+str(longest[i])+'}').format(headers[i]))+" |"
       lines+='\n'
       if(rstFormat):
          lines += sep.replace('-','=')+'\n'
       else:
          lines += sep
       for libName in sorted(namesSet):
          lines+="| "+(('{:'+str(longest[0])+'}').format(libName))+" |"
          if (libName in cmakeVer) and (len(cmakeVer[libName])==2):
             lines+=" "+(('{:'+str(longest[1])+'}').format(cmakeVer[libName][1]))+" |"
          else:
             lines+=" "+(('{:'+str(longest[1])+'}').format(' '                 ))+" |"
          if (libName in cppVer) and (len(cppVer[libName])==2):
             lines+=" "+(('{:'+str(longest[2])+'}').format(cppVer[libName][1]  ))+" |"
          else:
             lines+=" "+(('{:'+str(longest[2])+'}').format(' '                 ))+" |"
          lines+='\n'
          if(rstFormat):
             lines+= sep+'\n'

       if(rstFormat==False): print("\n```")
       #print("Yade revision  : ",yade.config.revision)
       print("Yade version   : ",yade.config.version)
       #print("Yade prefix    : ",yade.config.prefix)
       #print("Yade suffix    : ",yade.config.suffix)
       feats = ""
       for f in yade.config.features: feats+=" "+f
       print("Yade features  :",feats)
       # print yade config dir relative to
       confD = yade.config.confDir
       try:
          import os
          confD = "~/"+os.path.relpath(yade.config.confDir,os.environ['HOME'])
       except Exception as e:
          pass
       print("Yade config dir: ",confD)
       print("Yade precision :  "+str(yade.math.getDigits2(1))+" bits, "+str(yade.math.getDigits10(1))+" decimal places, with"+("" if yade.config.highPrecisionMpmath else "out")+" mpmath, "+yade.config.highPrecisionName)
       if(len(yade.math.getRealHPCppDigits10()) > 1):
          print("Yade RealHP<…> :  "+str(yade.math.getRealHPCppDigits10())+" decimal digits in C++, "+str(yade.math.getRealHPPythonDigits10())+" decimal digits accessible from python")
       if(rstFormat==False): print("```")
       print("\nLibraries used :\n")
       print(lines)
       if(rstFormat==False): print("```")
       print("Linux version  :  "+str(getLinuxVersion()))
       print("Architecture   :  "+str(getArchitecture()))
       try:
          print("Little endian  :  "+str(yade.math.isThisSystemLittleEndian()))
       except Exception as e:
          print("Little endian  :  unknown")
       if(rstFormat==False): print("```")
       print("")

    def getAllVersions(rstFormat=False):
       """
       :return: ``str`` - this function returns the result of :yref:`printAllVersions(rstFormat)<yade.libVersions.printAllVersions>` call inside a string variable.
       """
       import sys,io
       origStdOut = sys.stdout
       newStdOut  = io.StringIO()
       sys.stdout = newStdOut
       printAllVersions(rstFormat)
       sys.stdout = origStdOut
       return newStdOut.getvalue()

    """
    GITLAB format:

    | header 1 | header 2 |
    | -------- | -------- |
    | cell 1   | cell 2   |
    | cell 3   | cell 4   |

    reStructuredText format:

    +----------+----------+
    | header 1 | header 2 |
    +==========+==========+
    | cell 1   | cell 2   |
    +----------+----------+
    | cell 3   | cell 4   |
    +----------+----------+
    """