diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 289f60a326383531a37df6dfae73d35a4e6be81b..de7611c0c0a0971b99879ed3b669d0e7de1e0def 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,10 +18,11 @@ build_windows:
         - mkdir build
         - cd build
         - '$env:path += ";C:\Program Files\cmake\bin"'
-        - cmake .. -G "Visual Studio 15 2017" -A x64 -D MAiNGO_use_mpi=FALSE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=TRUE -D MAiNGO_build_parser=TRUE -D MAiNGO_build_shared_c_api=TRUE
+        - cmake .. -G "Visual Studio 15 2017" -A x64 -D MAiNGO_use_mpi=FALSE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=TRUE -D MAiNGO_build_parser=TRUE -D MAiNGO_build_shared_c_api=TRUE -D MAiNGO_use_knitro=FALSE
         - cmake --build . --config Release -j4
         - move Release/maingo-test-problems.exe Release/maingo-test-problems-sequential.exe
-        - cmake .. -G "Visual Studio 15 2017" -A x64 -D MAiNGO_use_mpi=TRUE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=FALSE -D MAiNGO_build_parser=FALSE -D MAiNGO_build_shared_c_api=FALSE -D MAiNGO_use_melon=FALSE
+        - move Release/unit-test-maingo.exe Release/unit-test-maingo-sequential.exe
+        - cmake .. -G "Visual Studio 15 2017" -A x64 -D MAiNGO_use_mpi=TRUE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=FALSE -D MAiNGO_build_parser=FALSE -D MAiNGO_build_shared_c_api=FALSE -D MAiNGO_use_melon=FALSE -D MAiNGO_use_knitro=FALSE
         - cmake --build . --config Release -j4
         - move Release/maingo-test-problems.exe Release/maingo-test-problems-parallel.exe
         - cd ..
@@ -42,7 +43,7 @@ test_windows:
         - maingo
     script:
         - cd build\Release
-        - .\unit-test-maingo.exe
+        - .\unit-test-maingo-sequential.exe
         - .\maingo-test-problems-sequential.exe
         - mpiexec -n 4 maingo-test-problems-parallel.exe
         - .\test-c-api-maingo.exe
@@ -65,16 +66,17 @@ build_linux:
     script:
         - mkdir build
         - cd build
-        - cmake -S .. -D MAiNGO_use_mpi=FALSE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=TRUE -D MAiNGO_build_parser=TRUE -D MAiNGO_build_shared_c_api=TRUE
+        - cmake -S .. -D MAiNGO_use_mpi=FALSE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=TRUE -D MAiNGO_build_parser=TRUE -D MAiNGO_build_shared_c_api=TRUE -D MAiNGO_use_knitro=FALSE
         - make -j4
         - mv maingo-test-problems maingo-test-problems-sequential
-        - cmake -S .. -D MAiNGO_use_mpi=TRUE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=FALSE -D MAiNGO_build_parser=FALSE -D MAiNGO_build_shared_c_api=FALSE -D MAiNGO_use_melon=FALSE
+        - mv unit-test-maingo unit-test-maingo-sequential
+        - cmake -S .. -D MAiNGO_use_mpi=TRUE -D MAiNGO_build_test=TRUE -D MAiNGO_build_python_interface=FALSE -D MAiNGO_build_parser=FALSE -D MAiNGO_build_shared_c_api=FALSE -D MAiNGO_use_melon=FALSE -D MAiNGO_use_knitro=FALSE
         - make -j4
         - mv maingo-test-problems maingo-test-problems-parallel
         - cd ..
     artifacts:
         paths:
-            - build/unit-test-maingo
+            - build/unit-test-maingo-sequential
             - build/maingo-test-problems-sequential
             - build/maingo-test-problems-parallel
             - build/libmaingo-c-api.so
@@ -92,7 +94,7 @@ test_linux:
     script:
         - module load /opt/intel/oneapi/modulefiles/mpi/latest
         - cd build
-        - ./unit-test-maingo
+        - ./unit-test-maingo-sequential
         - ./maingo-test-problems-sequential
         - mpiexec -n 4 ./maingo-test-problems-parallel
         - ./test-c-api-maingo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6c000ce3bc5e2b72a73cfb955c387634b1302e2..0991349bcf3d8027a239640dc2089be56750069e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,7 @@ set(MAiNGO_use_growing_datasets FALSE CACHE BOOL "Build MAiNGO with growing data
 set(MAiNGO_build_python_interface FALSE CACHE BOOL "Build the Python package 'maingopy' that allows to call MAiNGO from Python.")
 set(MAiNGO_build_standalone FALSE CACHE BOOL "Build MAiNGOcpp executable as standalone solver with problem.h.")
 set(MAiNGO_build_shared_c_api FALSE CACHE BOOL "Build library version of MAiNGO with parser callable from C.")
+set(MAiNGO_use_gcov FALSE CACHE BOOL "Instrument the code for code coverage with gcov (only for compatible compilers)")
 if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
     set(MAiNGO_build_parser TRUE CACHE BOOL "Build MAiNGO executable with parser.")
     set(MAiNGO_build_test TRUE CACHE BOOL "Build MAiNGO test cases.")
@@ -84,7 +85,7 @@ endif()
 if(MAiNGO_use_cplex)
     # cplex has to be linked first, since on Linux/MacOS, it comes as a static library that contains BLAS etc.
     # if linking it after our blas, this will result in multiply defined symbols
-    target_link_libraries(maingo-core PRIVATE cplex)
+    target_link_libraries(maingo-core PUBLIC cplex)
 endif()
 target_link_libraries(maingo-core
     PUBLIC
@@ -110,7 +111,7 @@ if(MAiNGO_use_melon)
 endif()
 if(MAiNGO_use_knitro)
     # knitro always needs to be linked after all other math-related libraries because of incompatibility with several math routines
-    target_link_libraries(maingo-core PRIVATE knitro)
+    target_link_libraries(maingo-core PUBLIC knitro)
 endif()
 if(MAiNGO_use_mpi)
     find_package(MPI REQUIRED QUIET)
@@ -122,6 +123,19 @@ if(MAiNGO_use_growing_datasets)
     message("Growing datasets will be used. See documentation for changes in model setup.")
     target_compile_definitions(maingo-core PUBLIC HAVE_GROWING_DATASETS) # Define pre-processor variable HAVE_GROWING_DATASETS
 endif()
+if(MAiNGO_use_gcov)
+    # Enable coverage report with gcov only for compilers that support it
+    target_compile_options(maingo-core PRIVATE
+                            $<$<CXX_COMPILER_ID:GNU>:--coverage>
+                            $<$<CXX_COMPILER_ID:AppleClang>:--coverage>
+                            $<$<CXX_COMPILER_ID:Clang>:--coverage>
+                           )
+    target_link_options(maingo-core PUBLIC
+                            $<$<CXX_COMPILER_ID:GNU>:--coverage>
+                            $<$<CXX_COMPILER_ID:AppleClang>:--coverage>
+                            $<$<CXX_COMPILER_ID:Clang>:--coverage>
+                       )
+endif()
 
 
 #----------------- If this is the top level, include dependencies  --------------------
diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt
index b7214787153f384d944a572518d53c778a51e84a..f24e732a548d900f7014c491aeb2395bf138e150 100644
--- a/ReleaseNotes.txt
+++ b/ReleaseNotes.txt
@@ -1,3 +1,13 @@
+Release version 0.7.3 (April 11th, 2024):
+    - Documentation & Testing:
+        - Updated MAiNGO documentation
+        - Added new unit tests and test cases
+    - Bugfixes:
+        - Various bug fixes
+    - Third-party libraries:
+	- Added support for newer CPLEX versions up to 22.1.1
+	- Upgraded to Pybind11 version 2.12.0
+
 Release version 0.7.2 (October 31th, 2023):
     - Bugfixes:
         - Fixed minor bug in algorithm for large parameter estimation problems
diff --git a/cmake/MAiNGOsourceFiles.cmake b/cmake/MAiNGOsourceFiles.cmake
index c15607ed8c0c64eb16d7a317c7393e2d9450762d..5c25be170cdb2a0237d18fbae5f408198a09f8b4 100644
--- a/cmake/MAiNGOsourceFiles.cmake
+++ b/cmake/MAiNGOsourceFiles.cmake
@@ -1,6 +1,8 @@
 set(MAiNGO_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src)
 set(MAiNGO_SRC
     ${MAiNGO_SOURCE_DIR}/bab.cpp
+    ${MAiNGO_SOURCE_DIR}/constraint.cpp
+    ${MAiNGO_SOURCE_DIR}/decayingProbability.cpp
     ${MAiNGO_SOURCE_DIR}/getTime.cpp
     ${MAiNGO_SOURCE_DIR}/ipoptProblem.cpp
     ${MAiNGO_SOURCE_DIR}/knitroProblem.cpp
@@ -14,6 +16,8 @@ set(MAiNGO_SRC
     ${MAiNGO_SOURCE_DIR}/logger.cpp
     ${MAiNGO_SOURCE_DIR}/MAiNGO.cpp
     ${MAiNGO_SOURCE_DIR}/MAiNGOevaluationFunctions.cpp
+    ${MAiNGO_SOURCE_DIR}/MAiNGOException.cpp
+    ${MAiNGO_SOURCE_DIR}/MAiNGOgetOption.cpp
     ${MAiNGO_SOURCE_DIR}/MAiNGOgetterFunctions.cpp
     ${MAiNGO_SOURCE_DIR}/MAiNGOmodelEpsCon.cpp
     ${MAiNGO_SOURCE_DIR}/MAiNGOprintingFunctions.cpp
@@ -22,6 +26,7 @@ set(MAiNGO_SRC
     ${MAiNGO_SOURCE_DIR}/MAiNGOtoOtherLanguage.cpp
     ${MAiNGO_SOURCE_DIR}/MAiNGOwritingFunctions.cpp
     ${MAiNGO_SOURCE_DIR}/pointIsWithinNodeBounds.cpp
+    ${MAiNGO_SOURCE_DIR}/outputVariable.cpp
     ${MAiNGO_SOURCE_DIR}/ubp.cpp
     ${MAiNGO_SOURCE_DIR}/ubpClp.cpp
     ${MAiNGO_SOURCE_DIR}/ubpCplex.cpp
@@ -46,8 +51,21 @@ endif()
 
 if(MAiNGO_build_test)
     set(MAiNGO_UNIT_TEST_SRC
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testBab.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testConstraint.cpp
         ${PROJECT_SOURCE_DIR}/tests/unitTests/testDecayingProbability.cpp
         ${PROJECT_SOURCE_DIR}/tests/unitTests/testLogger.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGO.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOException.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOevaluationFunctions.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOgetterFunctions.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOmodelEpsCon.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOprintingFunctions.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOreadSettings.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOsetAndGetOption.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOtoOtherLanguage.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testMAiNGOwritingFunctions.cpp
+        ${PROJECT_SOURCE_DIR}/tests/unitTests/testOutputVariable.cpp
         ${PROJECT_SOURCE_DIR}/tests/unitTests/testPointIsWithinNodeBounds.cpp
     )
 endif()
\ No newline at end of file
diff --git a/cmake/MAiNGOversion.cmake b/cmake/MAiNGOversion.cmake
index 9d405c5ed7656085717a2020ac8d070543d8e36e..8007a621ccf8ebfa30fa6697d9ddd9a8c0cc58ef 100644
--- a/cmake/MAiNGOversion.cmake
+++ b/cmake/MAiNGOversion.cmake
@@ -1,3 +1,3 @@
 set(MAiNGO_VERSION
-0.7.2
+0.7.3
 )
diff --git a/dep/cplex b/dep/cplex
index 1d4f489ea22949f22e9413ece215492ac7fabe8e..0d6dddd2a0968138bf2c92ba84deea1fdcc4c802 160000
--- a/dep/cplex
+++ b/dep/cplex
@@ -1 +1 @@
-Subproject commit 1d4f489ea22949f22e9413ece215492ac7fabe8e
+Subproject commit 0d6dddd2a0968138bf2c92ba84deea1fdcc4c802
diff --git a/dep/knitro b/dep/knitro
index 27856c391a5c09c7a133decab958ec40453dffcd..52c2c9e44278e093436a87a0782bc5c513984046 160000
--- a/dep/knitro
+++ b/dep/knitro
@@ -1 +1 @@
-Subproject commit 27856c391a5c09c7a133decab958ec40453dffcd
+Subproject commit 52c2c9e44278e093436a87a0782bc5c513984046
diff --git a/dep/libale b/dep/libale
index 49bacdeaa0ae4c2236d01a65c8b31f87a8576926..556283a03859824a6a826b793779bff50700cb66 160000
--- a/dep/libale
+++ b/dep/libale
@@ -1 +1 @@
-Subproject commit 49bacdeaa0ae4c2236d01a65c8b31f87a8576926
+Subproject commit 556283a03859824a6a826b793779bff50700cb66
diff --git a/dep/melon b/dep/melon
index 74856516f95e94fc0b517c9ebba985f4f1c92b09..f81eca75e67c88be3cdc5c30844f95be9a58d6e9 160000
--- a/dep/melon
+++ b/dep/melon
@@ -1 +1 @@
-Subproject commit 74856516f95e94fc0b517c9ebba985f4f1c92b09
+Subproject commit f81eca75e67c88be3cdc5c30844f95be9a58d6e9
diff --git a/dep/mumps b/dep/mumps
index 8d03311bd66b2bee39a8db75e68bf822b02952c9..3a701c82b245067a3ba473f3b710892f8a1b4c0c 160000
--- a/dep/mumps
+++ b/dep/mumps
@@ -1 +1 @@
-Subproject commit 8d03311bd66b2bee39a8db75e68bf822b02952c9
+Subproject commit 3a701c82b245067a3ba473f3b710892f8a1b4c0c
diff --git a/dep/pybind11 b/dep/pybind11
index 8dcced29ae4c7654c25bc50742a72556ee3ae36c..19a6b9f4efb569129c878b7f8db09132248fbaa1 160000
--- a/dep/pybind11
+++ b/dep/pybind11
@@ -1 +1 @@
-Subproject commit 8dcced29ae4c7654c25bc50742a72556ee3ae36c
+Subproject commit 19a6b9f4efb569129c878b7f8db09132248fbaa1
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 7079f9632f85cd6c0b8a4bc6c7dc1fa91a8eafd6..a628c242d1752772888462c25496f2d6d87dd2c2 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -1581,7 +1581,7 @@ FORMULA_TRANSPARENT    = YES
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-USE_MATHJAX            = NO
+USE_MATHJAX            = YES
 
 # When MathJax is enabled you can set the default output format to be used for
 # the MathJax output. See the MathJax site (see:
diff --git a/doc/manual.dox b/doc/manual.dox
index 8644b33d251e9217dc437218d30198e9da3d4159..9d00bff590987be09e8946d7462163bb06747bb6 100644
--- a/doc/manual.dox
+++ b/doc/manual.dox
@@ -11,8 +11,8 @@
 
 /**
 @mainpage McCormick-based Algorithm for mixed-integer Nonlinear Global Optimization
-@authors Dominik Bongartz, Jaromił Najman, Susanne Sass, Alexander Mitsos
-@date 2017-2021
+@authors Dominik Bongartz, Jaromił Najman, Susanne Sass, Clara Witte, Alexander Mitsos
+@date 2017-2024
 
 Thank you for using the beta version of MAiNGO! If you have any issues, concerns, or comments, please communicate them using the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo/-/issues">"Issues" functionality in GitLab</a> or send an e-mail to MAiNGO@avt.rwth-aachen.de
 
@@ -42,7 +42,7 @@ MAiNGO has been successfully applied to multiple flowsheet-optimization problems
 MAiNGO holds specialized relaxations for functions found in the field of chemical engineering (<a href="https://www.sciencedirect.com/science/article/pii/B9780444634283502721">Najman & Mitsos 2016</a>,
  <a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019</a>,
  <a href="https://link.springer.com/article/10.1007/s11081-020-09502-1">Bongartz et al. 2020</a>).
-All implemented special intrinsic functions can be found in `doc/implementedFunctions/Implemented_functions.pdf` in the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo">MAiNGO git repository</a>.
+All implemented special intrinsic functions can be found in the @ref function_library or `doc/implementedFunctions/Implemented_functions.pdf` in the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo">MAiNGO git repository</a>.
 
 @subsection MeLOn_examples Example Applications with Machine-Learning models (MeLOn)
 
@@ -56,7 +56,7 @@ MAiNGO and MeLOn have already been used for optimization problems with artificia
 Machine-learning models have also been combined with mechanistic process models for various applications including membrane science
 (<a href="https://www.sciencedirect.com/science/article/pii/S0376738818324293">Rall et al. 2019</a>,
 <a href="https://doi.org/10.1016/j.memsci.2020.117860">Rall et al. 2020a</a>,
-<a href="https://doi.org/10.1016/j.memsci.2020.117860">Rall et al. 2020b</a>, ), energy process optimization
+<a href="https://doi.org/10.1016/j.memsci.2020.117860">Rall et al. 2020b</a>), energy process optimization
 (<a href="https://www.sciencedirect.com/science/article/abs/pii/S009813541830886X">Schweidtmann et al. 2019</a>,
  <a href="https://www.sciencedirect.com/science/article/pii/B9780128186343501570">Schweidtmann et al. 2019</a>,
  <a href="https://www.sciencedirect.com/science/article/pii/B9780128185971500680">Huster et al. 2019a</a>,
@@ -66,7 +66,7 @@ Machine-learning models have also been combined with mechanistic process models
 
 @subsection cite How to Cite MAiNGO
 
-If you use MAiNGO, please cite the latest MAiNGO report:<br>
+If you use MAiNGO, please cite the MAiNGO report:<br>
 Bongartz, D., Najman, J., Sass, S. and Mitsos, A., MAiNGO - <b>M</b>cCormick-based <b>A</b>lgorithm for mixed-<b>i</b>nteger <b>N</b>onlinear <b>G</b>lobal <b>O</b>ptimization.
 Technical Report, Process Systems Engineering (AVT.SVT), RWTH Aachen University (2018). <a href="http://permalink.avt.rwth-aachen.de/?id=729717">http://permalink.avt.rwth-aachen.de/?id=729717</a>.
 
@@ -77,12 +77,11 @@ This manual is divided in the following sections:
 - \subpage install
 - \subpage writing_problem
 - \subpage maingo_output
+- \subpage maingo_settings
 - \subpage algorithm
-- \subpage parallel_version
-- \subpage growing_datasets
 - \subpage special_uses
-- \subpage maingo_in_your_software
-- \subpage maingo_settings
+- \subpage embedded
+- \subpage contrib
 - \subpage faq
 - \subpage bib
 
@@ -90,13 +89,13 @@ This manual is divided in the following sections:
 
 @section get_maingo Obtaining MAiNGO
 
-MAiNGO can be obtained from the git repository on the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo.git">MAiNGO GitLab page</a> or - if you plan to use it from Python - via the [maingopy package on PyPI](https://pypi.org/project/maingopy).
-To acess the full functionality of MAiNGO, we recommend obtaining the code via git  and following the instructions below, in particular because we use submodules for dependencies.
+MAiNGO can be obtained from the git repository on the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo.git">MAiNGO GitLab page</a>, - if you plan to use it from Python - via the [maingopy package on PyPI](https://pypi.org/project/maingopy) or - if you plan to use it within JuMP - via the Julia's package manager Pkg.
+To acess the full functionality of MAiNGO, we recommend obtaining the code via git and following the instructions below, in particular because we use submodules for dependencies.
 It is possible to download MAiNGO as a zipped folder from the GitLab page, but when doing so all dependencies need to be downloaded separately.
-The maingopy package on PyPI provides both source and pre-compiled binary distributions. Note that by default these will not have all features of the version available via git (e.g., MPI parallelization, or the optional closed-source dependencies KNITRO and CPLEX).
+The maingopy package on PyPI provides both source and pre-compiled binary distributions. Note that by default, packages obtained via PypI or   will not have all features of the version available via git (e.g., MPI parallelization, or the optional closed-source dependencies KNITRO and CPLEX).
 
 
-@subsection get_maingo_git Via git
+@subsection get_maingo_git Via git - Built from source
 
 To obtain MAiNGO via git, first clone the MAiNGO repository via
 \code{.sh}
@@ -137,6 +136,23 @@ If you want to use these features, you should obtain the MAiNGO code via git as
 
 If you obtain the binary distribution of <tt>maingopy</tt> from PyPI, there is no need to compile anything and you can skip the following steps and directly proceed with \ref executing_maingo_python "executing MAiNGO to solve an example problem" or \ref modeling_cpp_python "writing you own optimization problems".
 
+@subsection get_maingo_pkg Via Pkg - Julia's package manager 
+
+If you plan to use MAiNGO within JuMP, you can also obtain MAiNGO from Julia's package manager Pkg. To install the MAiNGO Package in Julia, run the following code:
+\code{.sh}
+import Pkg;
+Pkg.add("MAiNGO")
+\endcode
+Precompiled binaries will be automatically be installed from the <tt> MAiNGO_jll </tt> package.
+Note that the following features are *not* available in the MAiNGO package available via Pkg:
+- the MPI parallelization of MAiNGO
+- the C++ API, text-based model parser of MAiNGO and Pyhton API
+- the subsolvers CPLEX and KNITRO
+
+If you want to use these features, you should obtain the MAiNGO code via git as described above. This also enables you to build a version that can use CPLEX and KNITRO if you have them installed on your system.
+
+If you obtain the binary distribution of <tt>MAiNGO_jll</tt> from Pkg, there is no need to compile anything and you can skip the following steps and directly proceed with \ref executing_maingo_JuMP "executing MAiNGO via JuMP".
+
 
 @section req_software Required Software
 
@@ -146,7 +162,7 @@ Building MAiNGO requires the following software that is not provided when obtain
 - On Windows: Windows SDK 10.0.2 or later (https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/)
 - A Fortran Compiler (Linux & MacOS only; for Windows, we supply pre-compiled versions of all Fortran dependencies)
 
-CPLEX 12.8 or 12.9 and Knitro 11.0.1 are optional subsolvers that are also not provided with MAiNGO.
+CPLEX 12.10, 20.1 or 22.1 and Knitro 11.0.1 are optional subsolvers that are also not provided with MAiNGO.
 They are not required for using MAiNGO, but they can improve computational performance.
 CMake will automatically detect whether you have CPLEX/Knitro installed on your system or not. If you installed CPLEX or Knitro in a non-default path, it may be neccessary to adapt the paths in the corresponding CMakeLists.txt files at <tt>dep/knitro</tt> and <tt>dep/cplex</tt>.
 Note that the version of MAiNGO distributed via the [maingopy package](https://pypi.org/project/maingopy) cannot use CPLEX or Knitro, even if you have them installed on your system.
@@ -271,7 +287,9 @@ The easiest way to ensure that <tt>maingopy</tt> is found is to place the script
 So for the example, just copy <tt>examples/01_BasicExample/examplePythonInterface.py</tt> to your build directory and execute it there.
 If you obtained the <tt>maingopy</tt> package from PyPI, it should be found automatically regardless of where you execute the script.
 
+@subsection executing_maingo_JuMP Solving problems via JuMP
 
+To use MAiNGO in JumP, MAiNGO must either be installed using the \ref get_maingo_pkg "Julia's package manager Pkg" or \ref get_maingo_git "via git" and built it from source. To call MAiNGO from within JuMP, see the documentation in the Github repository of the [Julia wrapper to use MAiNGO with JuMP](https://github.com/MAiNGO-github/MAiNGO.jl).
 
 \page writing_problem Modeling in MAiNGO
 
@@ -458,7 +476,7 @@ Additionally, user-defined function symbols can be defined similarly to definiti
 ALE permits the usage of functions in definitions, assignments, functions, or expressions.
 As such, they can be used to write reduced-space formulations procedurally.
 
-For a complete list of implemented intrinsic functions beyond the standard functions (exp(), log(), sin(), asin(), etc.), refer to doc/implementedFunctions/Implemented_functions.pdf in the [MAiNGO](https://git.rwth-aachen.de/avt-svt/public/maingo) git repository.
+For a complete list of implemented intrinsic functions beyond the standard functions (exp(), log(), sin(), asin(), etc.), refer to the @ref function_library or doc/implementedFunctions/Implemented_functions.pdf in the [MAiNGO](https://git.rwth-aachen.de/avt-svt/public/maingo) git repository.
 The definition of user-defined functions is also possible.
 Please refer to the README.md of [libALE](https://git.rwth-aachen.de/avt-svt/public/libale) for further information on user-defined functions and additional intrinsic functions provided by libALE.
 
@@ -549,7 +567,7 @@ Your specialization of the MAiNGOmodel class needs to implement at least the fol
 
 Within the evaluate function, you can do almost any type of computation (including calling other functions / libraries), as long as they are implemented with mc::FFVar.
 However, it is not allowed to use loops with a number of iteration not known a priori (such as, e.g., solving a nonlinear equation system), and to use conditional statements that depend on variables (and the resulting code will not compile, since comparison operations are not defined for mc::FFVar).
-For a list of intrinsic functions supported by MAiNGO, refer to the documentation at <tt>doc/implementedFunctions/Implemented_functions.pdf</tt> in the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo">MAiNGO git repository</a>.
+For a list of intrinsic functions supported by MAiNGO, refer to the @ref function_library or <tt>doc/implementedFunctions/Implemented_functions.pdf</tt> in the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo">MAiNGO git repository</a>.
 
 If your model does contain equations that would require iterative solution, you need to leave appropriate optimization variables and equations to the optimizer instead
 (cf. <a href="https://link.springer.com/article/10.1007/s10898-017-0547-4">Bongartz & Mitsos 2017a</a>).
@@ -569,7 +587,7 @@ spurious behavior of the optimization process.
 You may add \ref maingo.OutputVariable "OutputVariables" to the <tt>output</tt> vector in the \ref maingo.EvaluationContainer "EvaluationContainer". This can be used to compute and return information that is not needed during the optimization
 but that you are interested in at the optimal solution.
 
-If you are using the <tt>squash_node</tt> function, it is neccessary to introduce appropriate squash inequalities to maintain correctness of the optimization problem. For more information refer to
+If you are using the <tt>squash_node</tt> function, it is neccessary to introduce appropriate squash inequalities to maintain correctness of the optimization problem. For more information refer to the @ref function_library or
 <tt>doc/implementedFunctions/Implemented_functions.pdf</tt>.
 
 @section c_api C API
@@ -577,11 +595,940 @@ If you are using the <tt>squash_node</tt> function, it is neccessary to introduc
 MAiNGO has a basic C API that enables the solution of a problem defined by a C-style character array in \ref modeling_ALE "ALE syntax". The C API consists in the function \ref solve_problem_from_ale_string_with_maingo.
 Please refer to the documentation of this function for details.
 
+@section modeling_JuMP Modeling via JuMP
+
+How to set up a model in JuMP is explained in the [JuMP documentation](https://jump.dev/JuMP.jl/stable/manual/models/). Then select MAiNGO as the optimizer in JuMP. 
+
 @section parsing_gams Parsing GAMS Files
 
 We also provide a tool for parsing GAMS convert files to ALE problem.txt or MAiNGO problem.h files. For detailed description please refer to <tt>utilities/MAiNGO_Reader_Writer/</tt> and the
 documentation found therein.
 
+@section function_library Library of Functions
+
+This section summarizes non-elementary intrinsic functions currently implemented
+in  MAiNGO. Elementary instrinsic denotes
+functions such as addition, multiplication, division, exp, \f$ x^n \f$. The latter can be found in
+the documentation of MC++. Using the non-elementary intrinsic functions (as opposed to
+implementing them by hand in the model using elementary functions) will in most cases
+result in tighter relaxations. In most cases, the \ref modeling_ALE "ALE syntax" is also supported in `C++` and Python.
+
+@subsection simple_func Simple Functions 
+
+<details>
+    <summary> <tt> sqr(x) </tt> </summary>
+    <table>
+        <tr><td> <b> Form: </b>                             <td> \f$ x^2 \f$
+        <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> sqr(x) </tt>
+        <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> sqr(x) </tt>
+        <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> sqr(x) </tt>
+        <tr><td> <b> Domain: </b>                           <td> \f$ ℝ \f$
+    </table>
+<br>
+</details>
+
+<details>
+  <summary> <tt> xlog(x)</tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ x \cdot \log(x) \f$
+    <tr><td  rowspan="2"> <b> How to call in </b> <tt> C++ </tt>: <td> <tt> xlog(x) </tt>
+    <tr>                                                          <td>  <tt> xlogx(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt> xlogx(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt> xlog(x) </tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ x>0 \f$
+    </table>
+   <br>
+</details>
+
+<details>
+  <summary> <tt> xexpy(x,y) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ \exp(x) \cdot y \f$
+    <tr><td  rowspan="2"> <b> How to call in </b> <tt> C++ </tt>: <td> <tt> expx_times_y(x,y) </tt>
+    <tr>                                                          <td> <tt> xexpy(y,x) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt> xexpy(y,x) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt> xexpy(y,x) </tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ ℝ^2 \f$
+    <tr><td> <b> Remarks: </b>                                    <td> The formula can be found in <a href="https://link.springer.com/article/10.1007/s10107-011-0496-5">Khajavirad & Sahinidis 2013</a>. <br>
+                                                                  Note that in <tt> C++ </tt>-syntax, the ordering of the variables is swapped in the first command.
+    </table>
+   <br>
+</details>
+
+<details>
+  <summary> <tt> sum_div(vars, coeff) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td colspan="2"> \f$ \frac{a_1 \cdot x}{a_2 \cdot x + \sum b_i \cdot y_i}  \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> sum_div(vars, coeff) </tt> <td> Where <tt> vars </tt> is a vector of size <i>n</i> and <tt> coeff </tt> is a vector <br>
+                                                        of size <i>n+1</i>. It is <tt> coeff[0] </tt> = \f$ a_1 \f$, <tt> coeff[1] </tt> \f$ = a_2 \f$, <br>
+                                                        <tt> coeff[2] </tt> \f$ = b_1 \f$, <tt> coeff[3] </tt> \f$ = b_2 \f$, . . .
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td colspan="2"> <tt> sum_div(x, y1,..., yn, a1, a2, b1,..., bn) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td colspan="2"> <tt> sum_div(vars, coeff) </tt>
+    <tr><td> <b> Domain: </b>                           <td colspan="2"> <tt> vars </tt> \f$ = (x,\boldsymbol{y}) \in ℝ^{n}_{>0} \f$ , \f$ a_i, b_i \in ℝ_{>0} \f$
+    <tr><td> <b> Remarks: </b>                          <td colspan="2"> The idea and derivation of the formula for 2D can be found in Section 2 <br>
+                                                        of <a href="https://link.springer.com/book/10.1007/978-1-4757-3532-1">Tawarmalani & Sahinidis 2002</a> or in <a href="https://link.springer.com/article/10.1023/A:1011233805045">Tawarmalani & Sahinidis 2001</a>.
+    </table>
+   <br>
+</details>
+
+<details>
+  <summary> <tt> xlog_sum(vars, coeff) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td colspan="2"> \f$ x \cdot \log(a \cdot x + \sum b_i \cdot y_i)  \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> xlog_sum(vars, coeff) </tt> <td> Where <tt> vars </tt> is a vector of size <i>n</i> and <tt> coeff </tt> <br>
+                                                        is a vector of size <i>n</i>. It is <tt> coeff[0] </tt> = \f$ a \f$, <br>
+                                                        <tt> coeff[1] </tt> \f$ = b_1 \f$, <tt> coeff[2] </tt> \f$ = b_2 \f$,. . .
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td colspan="2"> <tt> xlog_sum(x, y1,..., yn, a1, b1,..., bn) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td colspan="2"> <tt> xlog_sum(vars, coeff) </tt>
+    <tr><td> <b> Domain: </b>                           <td colspan="2"> <tt> vars </tt> \f$ = (x,\boldsymbol{y}) \in ℝ^{n}_{>0} \f$ , \f$ a_i, b_i \in ℝ_{>0} \f$
+    <tr><td> <b> Remarks: </b>                          <td colspan="2"> The idea and derivation of the formula for 2D can be <br>
+                                                        found in <a href="https://www.sciencedirect.com/science/article/abs/pii/S009813541930331X">Najman et al. 2019a</a>.
+    </table>
+   <br>
+</details>
+
+<details>
+  <summary> <tt> xexpax(x,a) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ x \cdot exp(a \cdot x)  \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> xexpax(x,a) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> xexpax(x,a) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> xexpax(x,a) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ ℝ \f$
+    <tr><td> <b> Remarks: </b>                          <td> <i>a</i> is a constant. More details can be found in <a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019b</a>.
+    </table>
+   <br>
+</details>
+
+<details>
+  <summary> Euclidian Norm </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \sqrt{x^2 + y^2}  \f$
+    <tr><td rowspan = "2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt> euclidean_norm_2d(x,y) </tt>
+    <tr>                                                            <td> <tt> norm2(x,y) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt> norm2(x,y) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:             <td> <tt> euclidean_norm_2d(x,y) </tt>
+    <tr><td> <b> Domain: </b>                                       <td> \f$ ℝ^2 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> This function is convex and not differentiable at \f$ x = y = 0 \f$.
+    </table>
+   <br>
+</details>
+ 
+<details>
+  <summary> Error Function </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \frac{1}{\sqrt{\pi}} \int_{-x}^{x} \exp(-t^2) \, dt \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> erf(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> erf(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> erf(x) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ ℝ \f$
+    </table>
+   <br>
+</details>
+
+<details>
+  <summary> Complementary Error Function </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ 1 - \frac{1}{\sqrt{\pi}} \int_{-x}^{x} \exp(-t^2) \, dt \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> erfc(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> erfc(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> erfc(x) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ ℝ \f$
+    </table>
+ <br>
+</details>
+
+<details>
+  <summary> <tt> xabsx(x) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ |x| \cdot x \f$
+    <tr><td rowspan = "2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt> fabsx_times_x(x) </tt>
+    <tr>                                                            <td> <tt> xabsx(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt> xabsx(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:             <td> <tt> fabsx_times_x(x) </tt>
+    <tr><td> <b> Domain: </b>                                       <td> \f$ ℝ \f$
+    </table>
+ <br>
+</details>
+
+<details>
+  <summary> <tt> regnormal(x,a,b) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \frac{x}{\sqrt{a + b \cdot x^2}} \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> regnormal(x,a,b) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> regnormal(x,a,b) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> regnormal(x,a,b) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ x \in ℝ \f$ , \f$ a,b \in ℝ_{>0}\f$
+    </table>
+ <br>
+</details>
+
+<details>
+  <summary> Printing Output </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> <tt> std::cout << "Object Type #" << number << ":" </tt> <br>
+                                                        <tt> << x << std::endl </tt>
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> mc_print(x,number) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> N/A
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> N/A
+    <tr><td> <b> Domain: </b>                           <td> \f$ ℝ \f$
+    <tr><td> <b> Remarks: </b>                          <td> This can be used for debugging. To reduce output turn <br>
+                                                        off pre-processing.
+    </table>
+ <br>
+</details>
+
+@subsection bounding_func Bounding Functions
+
+These functions can be used to exploit valid bounds that are known to the user. The functions
+cut off the relaxations at a given value.
+It is up to the user to make sure the bounds are actually valid! If they are not,
+the resulting relaxations may be wrong, and MAiNGO may or may not detect
+this and (possibly) throw an exception.
+
+<details>
+  <summary> Positive </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> [only cuts off the convex relaxation at \f$ \epsilon \f$ ]
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> pos(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> pos(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> pos(x) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ x \geq \epsilon > 0 \f$
+    <tr><td> <b> Remarks: </b>                          <td> Used to make sure that the convex relaxation stays positive; <br>
+                                                        \f$ \epsilon \f$ is the McCormick tolerance specified in the settings <br>
+                                                        file. If the function is evaluated at some \f$ \hat{x} < \epsilon \f$, an <br>
+                                                        exception is thrown. It is especially useful in cases when <br>
+                                                        interval extensions provide nonpositive values.
+    </table>
+  <br>
+</details>
+
+<details>
+  <summary> Negative </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> [only cuts off the convex relaxation at \f$ - \epsilon \f$ ]
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> neg(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> neg(x) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> neg(x) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ x \leq - \epsilon < 0 \f$
+    <tr><td> <b> Remarks: </b>                          <td> Used to make sure that the convex relaxation stays negative; <br>
+                                                        \f$ \epsilon \f$ is the McCormick tolerance specified in the settings <br>
+                                                        file. If the function is evaluated at some \f$ \hat{x} > - \epsilon \f$, an <br>
+                                                        exception is thrown. It is especially useful in cases when <br>
+                                                        interval extensions provide nonnegative values.
+    </table>
+  <br> 
+</details>
+
+<details>
+  <summary> Lower Bounding Function </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> [only cuts off the convex relaxation at \f$ lb \f$ ]
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> lb_func(x,lb) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> lb_func(x,lb) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> lb_func(x,lb) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ x \geq lb \in ℝ \f$
+    <tr><td> <b> Remarks: </b>                          <td> Used to make sure that the convex relaxation stays above \f$ lb \f$. <br>
+                                                        If the function is evaluated at some \f$ \hat{x} < lb \f$, an <br>
+                                                        exception is thrown. It is especially useful in cases when <br>
+                                                        interval extensions provide values strictly lower than \f$ lb \f$.
+    </table>
+  <br> 
+</details>
+
+<details>
+  <summary> Upper Bounding Function </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> [only cuts off the concave relaxation at \f$ ub \f$ ]
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> ub_func(x,ub) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> ub_func(x,ub) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> ub_func(x,lb) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ x \leq ub \in ℝ \f$
+    <tr><td> <b> Remarks: </b>                          <td> Used to make sure that the convex relaxation stays under \f$ ub \f$. <br>
+                                                        If the function is evaluated at some \f$ \hat{x} > ub \f$, an <br>
+                                                        exception is thrown. It is especially useful in cases when <br>
+                                                        interval extensions provide values strictly greater than \f$ ub \f$.
+    </table>
+  <br> 
+</details>
+
+<details>
+  <summary> Bounding Function </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> [only cuts off the convex relaxation at \f$ lb \f$ and the concave <br>
+                                                        relaxation at \f$ ub \f$ ]
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> bounding_func(x,lb,ub) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> bounding_func(x,lb,ub) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> bounding_func(x,lb,ub) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ lb \leq x \leq ub \f$ with \f$ lb, x, ub \in ℝ \f$
+    <tr><td> <b> Remarks: </b>                          <td> Used to make sure that the relaxations stays between <br>
+                                                        \f$ lb \f$ and \f$ ub \f$.If the function is evaluated at some \f$ \hat{x} \notin [lb,ub] \f$, <br>
+                                                        an exception is thrown. It is especially useful in cases when <br>
+                                                        interval extensions provide values not within \f$ [lb,ub] \f$.
+    </table>
+  <br> 
+</details>
+
+<details>
+  <summary> Squash Node </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> [only cuts off the convex relaxation at \f$ lb \f$ and the concave <br>
+                                                                  relaxation at \f$ ub \f$ ]
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt> squash_node(x,lb,ub) </tt>
+    <tr>                                                          <td> <tt> squash(x,lb,ub) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt> squash(x,lb,ub) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt> squash_node(x,lb,ub) </tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ lb \leq x \leq ub \f$ with \f$ lb, x, ub \in ℝ \f$
+    <tr><td> <b> Remarks: </b>                                    <td> Used to make sure that the relaxations stays between <br>
+                                                                  \f$ lb \f$ and \f$ ub \f$. In order to properly use this function, the <br>
+                                                                  user <b>has to</b> define squash inequalities \f$ lb \leq x \leq ub \f$. <br>
+                                                                  This function's main purpose is to reduce the number <br>
+                                                                  of variables and equality constraints. It works especially <br>
+                                                                  well when removing linear equality constraints. <br>
+                                                                  The only difference between <tt> squash_node(x,lb,ub) </tt> <br>
+                                                                  and <tt> bounding_func(x,lb,ub) </tt> is that the former will <br>
+                                                                  not raise an exception, since the user has to provide <br>
+                                                                  valid squash inequalities. <br>
+    </table>
+  <br>  
+</details>
+
+@subsection phys_func Physically Motivated Functions
+
+<details>
+  <summary> Arrhenius Function </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \exp\left(- \frac{k}{x} \right) \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt> arh(x,k) </tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt> arh(x,k) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt> arh(x,k) </tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ x > 0 \f$
+    </table>
+  <br>  
+</details>
+
+<details>
+  <summary> Logarithmic Mean Temperature Difference </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \frac{\Delta T_1 - \Delta T_2}{\log(\Delta T_1) - \log(\Delta T_2)} \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>lmtd(</tt>\f$ \Delta T_1 , \Delta T_2 \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt>lmtd(</tt>\f$ \Delta T_1 , \Delta T_2 \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt>lmtd(</tt>\f$ \Delta T_1 , \Delta T_2 \f$<tt>)</tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ \Delta T_1 , \Delta T_2 > 0 \f$
+    <tr><td> <b> Remarks: </b>                          <td> Used for heat exchangers. More details can be found in <br>
+                                                        <a href="https://www.sciencedirect.com/science/article/pii/S0098135416302216">Mistry & Misener 2016</a> and in <a href="https://www.sciencedirect.com/science/article/pii/B9780444634283502721">Najman & Mitsos 2016</a>.
+    </table>
+  <br>  
+</details>
+
+<details>
+  <summary> Reciprocal of Logarithmic Mean Temperature Difference </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \frac{\log(\Delta T_1) - \log(\Delta T_2)}{\Delta T_1 - \Delta T_2} \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>rlmtd(</tt>\f$ \Delta T_1 , \Delta T_2 \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt>rlmtd(</tt>\f$ \Delta T_1 , \Delta T_2 \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt>rlmtd(</tt>\f$ \Delta T_1 , \Delta T_2 \f$<tt>)</tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ \Delta T_1 , \Delta T_2 > 0 \f$
+    <tr><td> <b> Remarks: </b>                          <td> Used for heat exchangers. More details can be found in <br>
+                                                        <a href="https://www.sciencedirect.com/science/article/pii/S0098135416302216">Mistry & Misener 2016</a>.
+    </table>
+  <br>  
+</details>
+
+@subsubsection vapor_p Vapor Pressure
+
+ There are four functions for vapor pressure.
+ All functions are assumed to be convex and increasing.
+ While this is true for all physically reasonable parameter sets (<a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019b</a>), it should be checked
+ whether it holds in any given case (e.g., by plotting the function on a sufficiently fine grid).
+
+ <details>
+  <summary> Extended Antoine </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \exp(p_1 + \frac{p_2}{T + p_3} + p_4 \cdot T + p_5 \cdot \log(T) + p_6 \cdot T^{p_7}) \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>vapor_pressure(</tt>\f$ T , 1 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>ext_antoine_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>ext_antoine_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 7
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>ext_antoine_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>ext_antoine_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>ext_antoine_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 7
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_7 \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> Antoine </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ 10^{p_1 - \frac{p_2}{p_3 + T}} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>vapor_pressure(</tt>\f$ T , 2 , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>antoine_psat(</tt>\f$ T , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>antoine_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>antoine_psat(</tt>\f$ T , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>antoine_psat(</tt>\f$ T , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>antoine_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_3 \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> Wagner </summary>
+  <table>
+  <tr><td> <b> Form: </b>                                           <td> \f$ p_6 \cdot \exp\left( \frac{p_1 \cdot (1 - \frac{T}{T_c}) + p_2 \cdot (1 - \frac{T}{T_c})^{1.5} + p_3 \cdot (1 - \frac{T}{T_c})^3 + p_4 \cdot (1 - \frac{T}{T_c})^6}{\frac{T}{T_c}} \right) \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>vapor_pressure(</tt>\f$ T , 3 , p_1 , p_2 , p_3 , p_4 , T_c , p_6 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>wagner_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , T_c , p_6 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>wagner_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 6
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>wagner_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , T_c , p_6 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>wagner_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , T_c , p_6 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>wagner_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 6
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+  <tr><td> <b> Remarks: </b>                                        <td> \f$ p_1 - p_4 \f$ , \f$ p_6 \f$ and \f$ T_c \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> IK-CAPE </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \exp( p_1 + p_2 \cdot T + p_3 \cdot T^2 + p_4 \cdot T^3 + p_5 \cdot T^4 + p_6 \cdot T^5 + p_7\cdot T^6 \f$ <br>
+       \f$ + p_8 \cdot T^7 + p_9 \cdot T^8 + p_{10} \cdot T^9 ) \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>vapor_pressure(</tt>\f$ T , 4 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 , p_8 , p_9 , p_{10} \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>ik_cape_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 , p_8 , p_9 , p_{10} \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>ik_cape_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 10
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>ik_cape_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 , p_8 , p_9 , p_{10} \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>ik_cape_psat(</tt>\f$ T , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 , p_8 , p_9 , p_{10} \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>ik_cape_psat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 10
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_{10} \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+@subsubsection sat_t Saturation Temperature
+
+ There are four functions for saturation temperature, which are the inverse of the vapor 
+ pressure functions listed above. Currently only the Antoine saturation temperature is 
+ implemented.
+ All functions are assumed to be concave and increasing.
+ While this is true for all physically reasonable parameter sets (<a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019b</a>), it should be checked
+ whether it holds in any given case (e.g., by plotting the function on a sufficiently fine grid).
+
+ <details>
+  <summary> Extended Antoine </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \exp(p_1 + \frac{p_2}{T + p_3} + p_4 \cdot T + p_5 \cdot \log(T) + p_6 \cdot T^{p_7})^{-1} \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> Not implemented
+    <tr><td> <b> Domain: </b>                           <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                          <td> \f$ p_1 - p_7 \f$ are constant parameters. The computation <br>
+        of the inverse is performed numerically.
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> Antoine </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \frac{p_2}{p_1 - \frac{\log(T)}{\log(10)}} - p_3 \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>saturation_temperature(</tt>\f$ T , 2 , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>antoine_tsat(</tt>\f$ T , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>antoine_tsat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>antoine_tsat(</tt>\f$ T , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>antoine_tsat(</tt>\f$ T , p_1 , p_2 , p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>antoine_tsat(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_3 \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> Wagner </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \exp\left( \frac{p_1 \cdot (1 - \frac{T}{T_c}) + p_2 \cdot (1 - \frac{T}{T_c})^{1.5} + p_3 \cdot (1 - \frac{T}{T_c})^3 + p_4 \cdot (1 - \frac{T}{T_c})^6}{\frac{T}{T_c}} \right)^{-1} \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> Not implemented
+    <tr><td> <b> Domain: </b>                           <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                          <td> \f$ p_1 - p_4 \f$ and \f$ T_c \f$ are constant parameters. The computation <br>
+        of the inverse is performed numerically.
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> IK-CAPE </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \exp( p_1 + p_2 \cdot T + p_3 \cdot T^2 + p_4 \cdot T^3 + p_5 \cdot T^4 + p_6 \cdot T^5 + p_7\cdot T^6 \f$ <br>
+                                                        \f$ + p_8 \cdot T^7 + p_9 \cdot T^8 + p_{10} \cdot T^9 )^{-1} \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> Not implemented
+    <tr><td> <b> Domain: </b>                           <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                          <td> \f$ p_1 - p_{10} \f$ are constant parameters. The computation <br>
+                                                        of the inverse is performed numerically.
+    </table>
+  <br>  
+ </details>
+
+@subsubsection id_gas_enth Ideal Gas Enthalpy
+
+ There are four functions for ideal gas enthalpy, which correspond to an integration over four
+ different heat capacity models from \f$ T_0 \f$ to \f$ T \f$.
+ All functions are assumed to be convex and increasing.
+ While for all physically reasonable parameter sets it should be increasing and in most cases
+ it should also be convex (<a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019b</a>), it should be checked whether it holds in any given case (e.g.,
+ by plotting the function on a sufficiently fine grid).
+
+ <details>
+  <summary> Aspen Polynomial </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \int_{T_0}^{T} p_1 + p_2 \cdot \tilde{T} + p_3 \cdot \tilde{T}^2 +  p_4 \cdot \tilde{T}^3 + p_5 \cdot \tilde{T}^4 + p_6 \cdot \tilde{T}^5 \, d\tilde{T} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>ideal_gas_enthalpy(</tt>\f$ T , T_0 , 1 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>aspen_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>aspen_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 6
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>aspen_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>aspen_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>aspen_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 6
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_6 \f$ are constant parameters, \f$ T_0 \f$ is the reference temperature. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> NASA 9-Coefficient </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \int_{T_0}^{T} \frac{p_1}{\tilde{T}^2} + \frac{p_2}{\tilde{T}} + p_3 +  p_4 \cdot \tilde{T} + p_5 \cdot \tilde{T}^2 + p_6 \cdot \tilde{T}^3 + p_7 \cdot \tilde{T}^4 \, d\tilde{T} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>ideal_gas_enthalpy(</tt>\f$ T , T_0 , 2 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nasa9_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+  <tr>                                                              <td> <tt>nasa9_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 7
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>nasa9_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>nasa9_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nasa9_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 7
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_7 \f$ are constant parameters, \f$ T_0 \f$ is the reference temperature. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> DIPPR 107 </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \int_{T_0}^{T} p_1 + p_2 \cdot \left(\frac{\frac{p_3}{\tilde{T}}}{\sinh(\frac{p_3}{\tilde{T}})}\right)^2 + p_4 \cdot \left(\frac{\frac{p_5}{\tilde{T}}}{\cosh(\frac{p_5}{\tilde{T}})}\right)^2 \, d\tilde{T} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>ideal_gas_enthalpy(</tt>\f$ T , T_0 , 3 , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr107_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr107_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>dippr107_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>dippr107_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr107_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_5 \f$ are constant parameters, \f$ T_0 \f$ is the reference temperature. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> DIPPR 127 </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \int_{T_0}^{T} p_1 + p_2 \cdot \left( \left(\frac{p_3}{\tilde{T}} \right)^2 \cdot \frac{\exp(\frac{p_3}{\tilde{T}})}{\exp(\frac{p_3}{\tilde{T}} - 1)^2} \right) + p_4 \cdot \left( \left(\frac{p_5}{\tilde{T}} \right)^2 \cdot \frac{\exp(\frac{p_5}{\tilde{T}})}{\exp(\frac{p_5}{\tilde{T}} - 1)^2} \right) \f$ <br>
+       \f$ + p_6 \cdot \left( \left(\frac{p_7}{\tilde{T}} \right)^2 \cdot \frac{\exp(\frac{p_7}{\tilde{T}})}{\exp(\frac{p_7}{\tilde{T}} - 1)^2} \right) \, d\tilde{T} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>ideal_gas_enthalpy(</tt>\f$ T , T_0 , 4 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr127_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr127_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 7
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>dippr127_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>dippr127_hig(</tt>\f$ T , T_0 , p_1 , p_2 , p_3 , p_4 , p_5 , p_6 , p_7 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr127_hig(</tt>\f$ T , T_0 , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 7
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_7 \f$ are constant parameters, \f$ T_0 \f$ is the reference temperature. 
+    </table>
+  <br>  
+ </details>
+
+@subsubsection enth_vaporization Enthalpy of Vaporization
+
+ There are two functions for enthalpy of vaporization. The functional forms listed below are
+ only used for \f$ T \leq Tc \f$. For \f$ T > Tc \f$, the enthalpy of vaporization is set to zero. This makes
+ it possible to extrapolate correctly beyond the critical point.
+ All functions are assumed to be concave and decreasing below \f$ T_c \f$.
+ While for all physically reasonable parameter sets it should be decreasing and in most cases
+ it should also be concave (<a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019b</a>), it should be checked whether it holds in any given case (e.g.,
+ by plotting the function on a sufficiently fine grid). 
+
+ <details>
+  <summary> Watson </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ dHT_1 \cdot \left( \frac{1 - \frac{T}{T_c}}{1 - \frac{T_1}{T_c}} \right)^{a + b \cdot (1 - \frac{T}{T_c})} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>enthalpy_of_vaporization(</tt>\f$ T , 1 , T_c , a , b , T_1 , dHT_1 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>watson_dhvap(</tt>\f$ T , T_c , a , b , T_1 , dHT_1 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>watson_dhvap(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>watson_dhvap(</tt>\f$ T , T_c , a , b , T_1 , dHT_1 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>watson_dhvap(</tt>\f$ T , T_c , a , b , T_1 , dHT_1 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>watson_dhvap(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ T_c , a , b , T_1 , dHT_1 \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> DIPPR </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ p_1 \cdot \left(1 - \frac{T}{T_c}\right)^{p_2 + p_3 \cdot (\frac{T}{T_c})^2 + p_5 \cdot (\frac{T}{T_c})^3} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>enthalpy_of_vaporization(</tt>\f$ T , 2 , T_c , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr106_dhvap(</tt>\f$ T , T_c , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr106_dhvap(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 6
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>dippr106_dhvap(</tt>\f$ T , T_c , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>dippr106_dhvap(</tt>\f$ T , T_c , p_1 , p_2 , p_3 , p_4 , p_5 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>dippr106_dhvap(</tt>\f$ T , p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 6
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ p_1 - p_5 \f$ and \f$ T_c \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+@subsubsection nrtl Functions for NRTL
+ 
+ All analyzes can be found in <a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019b</a>.
+
+ <details>
+  <summary> <tt> nrtl_tau(T,p) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ a + \frac{b}{T} + e \cdot \log(T) + f \cdot T \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt> nrtl_tau(T,a,b,e,f) </tt>
+    <tr>                                                          <td> <tt>nrtl_tau(T,p)</tt>, with \f$ p \f$ a vector of length 4
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt> nrtl_tau(T,a,b,e,f) </tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>nrtl_tau(T,p)</tt>, with \f$ p \f$ a vector of length 4
+    <tr><td> <b> Domain: </b>                                     <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                    <td> \f$ a , b , e , f \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> <tt> nrtl_dtau(T,p) </tt> </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ - \frac{b}{T^2} + \frac{e}{T} + f \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>nrtl_dtau(T,b,e,f)</tt>
+    <tr>                                                          <td> <tt>nrtl_dtau(T,p)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>nrtl_dtau(T,b,e,f)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>nrtl_dtau(T,p)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> Domain: </b>                                     <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                    <td> \f$ b , e , f \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary> <tt>nrtl_g(T,p)</tt></summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \exp( -\alpha \cdot (a + \frac{b}{T} + e \cdot \log(T) + f \cdot T)) \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>nrtl_G(</tt>\f$ T,a,b,e,f, \alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_g(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_g(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>nrtl_g(</tt>\f$ T , a , b , e , f , \alpha \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>nrtl_g(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_g(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ a , b , e , f , \alpha \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary><tt>nrtl_gtau(T,p)</tt></summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \exp( -\alpha \cdot (a + \frac{b}{T} + e \cdot \log(T) + f \cdot T)) \cdot (a + \frac{b}{T} + e \cdot \log(T) + f \cdot T) \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>nrtl_Gtau(</tt>\f$ T,a,b,e,f, \alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_gtau(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_gtau(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>nrtl_gtau(</tt>\f$ T , a , b , e , f , \alpha \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>nrtl_gtau(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_gtau(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ a , b , e , f , \alpha \f$ are constant parameters. 
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary><tt>nrtl_gdtau(T,p)</tt></summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ \exp( -\alpha \cdot (a + \frac{b}{T} + e \cdot \log(T) + f \cdot T)) \cdot (- \frac{b}{T^2} + \frac{e}{T} + f) \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>nrtl_Gdtau(</tt>\f$ T,a,b,e,f, \alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_gdtau(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_gdtau(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>nrtl_gtau(</tt>\f$ T , a , b , e , f , \alpha \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>nrtl_gdtau(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_gdtau(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ a , b , e , f , \alpha \f$ are constant parameters. Monotonicity and <br>
+                                                                    convexity are determined heuristically for \f$ e,f \neq 0 \f$.
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary><tt>nrtl_dgtau(T,p)</tt></summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ - \alpha \cdot \exp( -\alpha \cdot (a + \frac{b}{T} + e \cdot \log(T) + f \cdot T)) \cdot (- \frac{b}{T^2} + \frac{e}{T} + f) \f$ <br>
+                                                                    \f$ \cdot (a + \frac{b}{T} + e \cdot \log(T) + f \cdot T) \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>nrtl_dGtau(</tt>\f$ T,a,b,e,f, \alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_dgtau(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_dgtau(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>nrtl_dgtau(</tt>\f$ T , a , b , e , f , \alpha \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>nrtl_dgtau(</tt>\f$ T,a,b,e,f,\alpha \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>nrtl_dgtau(T,p)</tt>, with \f$ p \f$ a vector of length 5
+    <tr><td> <b> Domain: </b>                                       <td> \f$ T > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> \f$ a , b , e , f , \alpha \f$ are constant parameters. Monotonicity and <br>
+                                                                    convexity are determined heuristically.
+    </table>
+  <br>  
+ </details>
+
+@subsubsection schroeder Schroeder Functions
+
+ The following functions implement special correlations for thermodynamic properties of
+ ethanol (<a href="https://pubs.aip.org/aip/jpr/article/43/4/043102/242109/A-Fundamental-Equation-of-State-for-Ethanol">Schroeder et al. 2014</a>). 
+ Functions <i>a</i> and <i>b</i> are convex and increasing for \f$ T \leq 514.71K \f$. Function
+ <i>c</i> is concave and decreasing for \f$ 290.3 \leq T \leq 514.71K \f$.
+
+ <details>
+  <summary><tt>schroeder_ethanol_p(T)</tt></summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ 62.68 \cdot \exp( \frac{514.71}{T} \cdot ( -8.94161 \cdot (1 - \frac{T}{514.71}) + 1.61761 \cdot (1 - \frac{T}{514.71})^{1.5} \f$ <br>
+                                                                  \f$  - 51.1428 \cdot (1 - \frac{T}{514.71})^{3.4} + 53.1360 \cdot (1 - \frac{T}{514.71})^{3.7})) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>p_sat_ethanol_schroeder(T)</tt>
+    <tr>                                                          <td> <tt>schroeder_ethanol_p(T)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>schroeder_ethanol_p(T)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>schroeder_ethanol_p(T)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ T > 514.71 \f$
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary><tt>schroeder_ethanol_rhovap(T)</tt></summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ 273.195 \cdot \exp( -1.75362 \cdot (1 - \frac{T}{514.71})^{0.21} - 10.5323 \cdot (1 - \frac{T}{514.71})^{1.1} \f$ <br>
+                                                                  \f$  - 37.6407 \cdot (1 - \frac{T}{514.71})^{3.4} - 129.762 \cdot (1 - \frac{T}{514.71})^{10}) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>rho_vap_sat_ethanol_schroeder(T)</tt>
+    <tr>                                                          <td> <tt>schroeder_ethanol_rhovap(T)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>schroeder_ethanol_rhovap(T)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>schroeder_ethanol_rhovap(T)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ T > 514.71 \f$
+    </table>
+  <br>  
+ </details>
+
+ <details>
+  <summary><tt>schroeder_ethanol_rholiq(T)</tt></summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ 273.195 \cdot \exp( 9.00921 \cdot (1 - \frac{T}{514.71})^{0.5} - 23.1668 \cdot (1 - \frac{T}{514.71})^{0.8} \f$ <br>
+                                                                  \f$  + 30.9092 \cdot (1 - \frac{T}{514.71})^{1.1} - 16.5459 \cdot (1 - \frac{T}{514.71})^{1.5} +3.64294 \cdot (1 - \frac{T}{514.71})^{3.3}) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>rho_liq_sat_ethanol_schroeder(T)</tt>
+    <tr>                                                          <td> <tt>schroeder_ethanol_rholiq(T)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>schroeder_ethanol_rholiq(T)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>schroeder_ethanol_rholiq(T)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ T > 514.71 \f$
+    </table>
+  <br>  
+ </details>
+
+@subsection cost_func Cost Functions
+
+Currently, only one cost function is implemented.
+
+<details>
+  <summary> Guthrie </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                         <td> \f$ 10^{p_1 + p_2 \cdot \log_{10}(x) + p_3 \cdot (\log_{10}(x))^2} \f$
+    <tr><td rowspan="3"> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>cost_function(</tt>\f$ x,1,p_1,p_2,p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>cost_turton(</tt>\f$ x,p_1,p_2,p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>cost_turton(</tt>\f$ x,p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:                <td> <tt>cost_turton(</tt>\f$ x,p_1,p_2,p_3 \f$<tt>)</tt>
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> Python </tt>: <td> <tt>cost_turton(</tt>\f$ x,p_1,p_2,p_3 \f$<tt>)</tt>
+    <tr>                                                            <td> <tt>cost_turton(</tt>\f$ x,p \f$<tt>)</tt>, with \f$ p \f$ a vector of length 3
+    <tr><td> <b> Domain: </b>                                       <td> \f$ x > 0 \f$
+    <tr><td> <b> Remarks: </b>                                      <td> Function for equipment costing based on a characteristic <br>
+                                                                    sizing variable \f$ x \f$. \f$ p1-p3 \f$ are constant parameters. <br>
+                                                                    The ananlysis of this function can be found in <a href="https://www.sciencedirect.com/science/article/abs/pii/S0098135419309494">Najman et al. 2019b</a>. <br>
+                                                                    More information on the Guthrie cost function can be found <br>
+                                                                    in <a href="https://richardturton.faculty.wvu.edu/publications/analysis-synthesis-and-design-of-chemical-processes-5th-edition">Turton et al. 2009</a>.
+    </table>
+  <br>  
+ </details>
+
+@subsection nn_func Neural Networks
+  
+<details>
+  <summary> Hyperbolic Tangent </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \tanh(x) \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>tanh(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt>tanh(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt>tanh(x)</tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ ℝ \f$
+    <tr><td> <b> Remarks: </b>                          <td> More information can be found in <a href="https://link.springer.com/article/10.1007/s10957-018-1396-0">Schweidtmann & Mitsos 2019</a>. 
+    </table>
+   <br> 
+ </details>
+  
+<details>
+  <summary> Hyperbolic Cotangent </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ \coth(x) \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>coth(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> <tt>coth(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> <tt>coth(x)</tt>
+    <tr><td> <b> Domain: </b>                           <td> \f$ x \neq 0 \f$
+    </table>
+ <br> 
+ </details>
+ 
+<details>
+  <summary> Inverse Hyperbolic Cotangent </summary>
+  <table>
+    <tr><td> <b> Form: </b>                             <td> \f$ acoth(x) \f$
+    <tr><td> <b> How to call in </b> <tt> C++ </tt>:    <td> <tt>acoth(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:    <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> Python </tt>: <td> Not implemented
+    <tr><td> <b> Domain: </b>                           <td> \f$ |x| > 1 \f$
+    </table>
+ <br> 
+ </details>
+ 
+@subsection gauss_proc_func Gaussian Processes
+
+@subsubsection covariance_func Covariance Functions
+ 
+ <details>
+  <summary> Matérn 1/2 </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ \exp(- \sqrt{x}) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>covariance_function(x,1)</tt>
+    <tr>                                                          <td> <tt>covar_matern_1(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>covar_matern_1(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>covar_matern_1(x)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ x \geq 0 \f$
+    </table>
+  <br> 
+  </details>
+
+ <details>
+  <summary> Matérn 3/2 </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ (1 + \sqrt{3} \sqrt{x}) \cdot \exp(- \sqrt{3} \sqrt{x}) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>covariance_function(x,2)</tt>
+    <tr>                                                          <td> <tt>covar_matern_3(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>covar_matern_3(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>covar_matern_3(x)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ x \geq 0 \f$
+    </table>
+  <br> 
+  </details>
+
+ <details>
+  <summary> Matérn 5/2 </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ (1 + \sqrt{5} \sqrt{x} + \frac{5}{3} x) \cdot \exp(- \sqrt{5} \sqrt{x}) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>covariance_function(x,3)</tt>
+    <tr>                                                          <td> <tt>covar_matern_5(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>covar_matern_5(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>covar_matern_5(x)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ x \geq 0 \f$
+    </table>
+  <br> 
+  </details>
+
+ <details>
+  <summary> Squared Exponential </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ \exp(- \frac{1}{2} x) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>covariance_function(x,4)</tt>
+    <tr>                                                          <td> <tt>covar_sqrexp(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>covar_sqrexp(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>covar_sqrexp(x)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ x \geq 0 \f$
+    </table>
+  <br> 
+  </details>
+
+@subsubsection acq_func Acquisition Functions
+
+ <details>
+  <summary> Lower Confidence Bound </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ \mu - \kappa \cdot \sigma \f$
+    <tr><td rowspan="2">  <b> How to call in </b> <tt> C++ </tt>: <td> <tt>acquisition_function(</tt>\f$ \mu , \sigma , 1 , \kappa \f$<tt>)</tt>
+    <tr>                                                          <td> <tt>af_lcb(</tt>\f$ \mu , \sigma , \kappa \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>af_lcb(</tt>\f$ \mu , \sigma , \kappa \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>af_lcb(</tt>\f$ \mu , \sigma , \kappa \f$<tt>)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ \mu \in ℝ , \sigma \geq 0 \f$
+    </table>
+  <br> 
+  </details>
+
+ <details>
+  <summary> Expected Improvement </summary>
+  <table>
+    <tr><td rowspan="2"> <b> Form: </b>                           <td> \f$ \sigma > 0 \f$: <td> \f$ (f_{min} - \mu) \cdot \left( \frac{erf\left( \frac{\frac{f_{min} - \mu}{\sigma}}{\sqrt{2}}\right)}{2} + \frac{1}{2} \right) + \sigma \cdot \frac{\exp\left( - \frac{ \left(\frac{f_{min} - \mu}{\sigma}\right)^2}{2}\right)}{\sqrt{2 \pi}} \f$
+    <tr>                                                          <td> \f$ \sigma = 0 \f$: <td> max\f$ \{ f_{min} - \mu , 0 \} \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td colspan="2"> <tt>acquisition_function(</tt>\f$ \mu , \sigma , 2 , f_{min} \f$<tt>)</tt>
+    <tr>                                                          <td colspan="2"> <tt>af_ei(</tt>\f$ \mu , \sigma , f_{min} \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td colspan="2"> <tt>af_ei(</tt>\f$ \mu , \sigma , f_{min} \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td colspan="2"> <tt>af_ei(</tt>\f$ \mu , \sigma , f_{min} \f$<tt>)</tt>
+    <tr><td> <b> Domain: </b>                                     <td colspan="2"> \f$ \mu \in ℝ , \sigma \geq 0 \f$
+    </table>
+  <br> 
+  </details>
+
+ <details>
+  <summary> Probability of Improvement </summary>
+  <table>
+    <tr><td rowspan="3"> <b> Form: </b>                           <td> \f$ \sigma > 0 \f$: <td> \f$ \frac{erf\left( \frac{\frac{f_{min} - \mu}{\sigma}}{\sqrt{2}}\right)}{2} + \frac{1}{2} \f$
+    <tr>                                                          <td> \f$ \sigma = 0 \f$ , \f$ f_{min} \leq \mu \f$: <td> \f$ 0 \f$
+    <tr>                                                          <td> \f$ \sigma = 0 \f$ , \f$ f_{min} > \mu \f$:    <td> \f$ 1 \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td colspan="2"> <tt>acquisition_function(</tt>\f$ \mu , \sigma , 3 , f_{min} \f$<tt>)</tt>
+    <tr>                                                          <td colspan="2"> <tt>af_pi(</tt>\f$ \mu , \sigma , f_{min} \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td colspan="2"> <tt>af_pi(</tt>\f$ \mu , \sigma , f_{min} \f$<tt>)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td colspan="2"> <tt>af_pi(</tt>\f$ \mu , \sigma , f_{min} \f$<tt>)</tt>
+    <tr><td> <b> Domain: </b>                                     <td colspan="2"> \f$ \mu \in ℝ , \sigma \geq 0 \f$
+    </table>
+  <br> 
+  </details>
+
+@subsubsection prob_func Probability Functions
+
+ <details>
+  <summary> Gaussian Cumulative Distribution </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ \frac{1}{2} \cdot \left( erf\left( \frac{x}{\sqrt{2}} \right) + 1 \right) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>gaussian_cumulative_distribution(x)</tt>
+    <tr>                                                          <td> <tt>gcd(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> Not implemented
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> Not implemented
+    <tr><td> <b> Domain: </b>                                     <td> \f$ x \in ℝ \f$
+    </table>
+  <br> 
+  </details>
+
+ <details>
+  <summary> Gaussian Probability Density Function </summary>
+  <table>
+    <tr><td> <b> Form: </b>                                       <td> \f$ \frac{1}{\sqrt{2\pi}} \cdot \exp(- \frac{x^2}{2}) \f$
+    <tr><td rowspan="2"> <b> How to call in </b> <tt> C++ </tt>:  <td> <tt>gaussian_probability_density_function(x)</tt>
+    <tr>                                                          <td> <tt>gpdf(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> ALE </tt>:              <td> <tt>gpdf(x)</tt>
+    <tr><td> <b> How to call in </b> <tt> Python </tt>:           <td> <tt>gpdf(x)</tt>
+    <tr><td> <b> Domain: </b>                                     <td> \f$ x \in ℝ \f$
+    </table>
+  <br> 
+  </details>
 
 \page maingo_output MAiNGO Output
 
@@ -729,6 +1676,21 @@ The <tt>csv</tt> output is divided into to files, called <tt>statisticsAndSoluti
 The latter contains the same information on the individual B&B iterations as the log file, but in csv format.
 The <tt>json</tt> output file is called <tt>statisticsAndSolution.json</tt> by default and also contains the solution point and various statistics.
 
+\page maingo_settings MAiNGO Settings
+
+The documentation of all available settings can be found on the page of the \ref maingo::Settings "Settings" struct.
+
+When using the C++ or Python APIs of MAiNGO, settings can be changed via \ref maingo.MAiNGO.set_option "set_option" function or read from a file via the \ref maingo.MAiNGO.read_settings "read_settings" function.
+If no file name is given to \ref maingo.MAiNGO.read_settings "read_settings", the default file name is <tt>MAiNGOSettings.txt</tt>.
+An example for such a settings file can be found at <tt>examples/MAiNGOSettings.txt</tt>.
+
+In the example main file for the C++-API, <tt>examples/mainCppApi.cpp</tt>, the name of the desired settings file is read as optional (first and only) command line argument.
+If a file name is specified this way, MAiNGO will attempt to open a file of this name in the current working directory (i.e., typically where your <tt>MAiNGOcpp</tt> executable is).
+If this file is not found, it will display a warning and continue with default settings.
+If not file name is specified, MAiNGO will instead use the file <tt>MAiNGOSettings.txt</tt> if it exists in the working directory.
+
+Similarly, in the example main file for using text input based on ALE, <tt>examples/mainAleParser.cpp</tt>, the settings file name is read as optional second command line argument after the name of the input file containing the problem definition (cf. \ref modeling_ALE).
+
 
 \page algorithm How does MAiNGO work?
 
@@ -905,8 +1867,9 @@ MAiNGO currently supports local solvers found in the <a href="https://nlopt.read
 solvers \ref maingo::ubp::UBP_SOLVER_LBFGS "LBFGS" and \ref maingo::ubp::UBP_SOLVER_SLSQP "SLSQP". \ref maingo::ubp::UBP_SOLVER_KNITRO "Knitro" is a commercial local (MI)NLP solver consisting of many
 different algorithms.
 
+\page special_uses Special Uses of MAiNGO
 
-\page parallel_version MAiNGO - Parallel Version
+@section parallel_version MAiNGO - Parallel Version
 
 There is also a parallelized version of MAiNGO, which allows the use of multiple processors via MPI. Its main use is for large problems where the B&B algorithm needs a long time to converge. The parallel version can be accessed and compiled the same way
 as the sequential version. In order to generate a project of the parallel MAiNGO version please set the CMake variable <tt>MAiNGO_use_mpi=true</tt> and make sure you have an MPI library installed.
@@ -929,11 +1892,12 @@ If you type in a wrong password or a wrong username resulting in MPI not allowin
 In this case you can reset it via <tt>\<mpiexec\> -remove</tt>.
 
 
-\page growing_datasets MAiNGO - Parameter estimation
+@section growing_datasets MAiNGO - Parameter estimation
 
 MAiNGO implements the extension for handling parameter estimation problems considering large datasets proposed in
 
-S. Sass, A. Mitsos, D. Bongartz, I. H. Bell, N. I. Nikolov, A. Tsoukalas: A branch-and-bound algorithm with growing datasets for large-scale parameter estimation (Submitted in 2023)
+S. Sass, A. Mitsos, D. Bongartz, I. H. Bell, N. I. Nikolov, A. Tsoukalas: A branch-and-bound algorithm with growing datasets for large-scale parameter estimation 
+(<a href="https://doi.org/10.1016/j.ejor.2024.02.020">Sass et al. 2024</a>, <a href="https://doi.org/10.1080/10556788.2023.2205645">Sass et al. 2023</a>) .
 
 This approach focuses on general nonconvex optimization problems of the form
 \htmlonly <style>div.image img[src="ParamEstProblem.PNG"]{width:6cm;align:left}</style> \endhtmlonly
@@ -966,7 +1930,6 @@ It may look like this:
 
 Additional settings allow to adapt this extension to the needs of the specific model solved, cf. settings with prefix <tt>growing</tt> in <tt>MAiNGOSettings.txt</tt>. These include, e.g., the choice when and how many data points to augment as well as the size of the initial dataset. For more details please refer to Sass et al. (Submitted in 2023) referenced above. 
 
-\page special_uses Special Uses of MAiNGO
 
 @section maingo_multistart Using MAiNGO as a multi-start local solver:
 
@@ -1000,10 +1963,7 @@ The more advanced way is to use the function \ref maingo::MAiNGO::write_model_to
 your model to a file with more options than when using the setting \ref maingo::Settings.modelWritingLanguage "modelWritingLanguage". An example for the use of this function can be found in the <tt>examples/mainCppApi.cpp</tt>.
 This function is extremely helpful if you want to do some cross-testing of solvers using the same model formulations.
 
-
-\page maingo_in_your_software Using MAiNGO in Other Software
-
-@section embedded Embedding MAiNGO in your Application
+\page embedded Embedding MAiNGO in your Application
 
 If you would like to embed MAiNGO in your own application, you need to link it to your software project first. Probably the easiest way it to embed MAiNGO as a submodule
 of your project. For this purpose, please refer to the <tt>CMakeLists.txt</tt> in the trunk of the MAiNGO repository.
@@ -1018,7 +1978,7 @@ For an example of how to use the MAiNGO object, please refer to the file <tt>exa
  - Solve the problem using \ref maingo.MAiNGO.solve "solve". This function will return a \ref babBase::enums::BAB_RETCODE "RETCODE".
  - Query solution information using the function provided by the \ref maingo.MAiNGO "MAiNGO" class.
 
-@section extensions Extending MAiNGO
+\page contrib Contribution
 
 MAiNGO is published under the Eclipse Public License - v2.0. Please refer to the <tt>LICENSE</tt> file in the root of the MAiNGO repository.
 Note that the third-party dependencies in the <tt>dep</tt> directory use different licenses.
@@ -1030,20 +1990,38 @@ Regarding the implementation of MAiNGO, just explore this documentation. If you
     - Enums are all capital letters
     - Private members (both functions and variables) additionally start with an underscore
 
-\page maingo_settings MAiNGO Settings
+To ensure uniform style guide we use ClangFormat. For these, format all header files with <tt> clang-format -style=file -i inc/*.h </tt>. Proceed in a similiar manner for all the other folders containing code. The command needs to be executed from the root folder of the repository. 
 
-The documentation of all available settings can be found on the page of the \ref maingo::Settings "Settings" struct.
+@section function_implementation Implementing your own Function 
 
-When using the C++ or Python APIs of MAiNGO, settings can be changed via \ref maingo.MAiNGO.set_option "set_option" function or read from a file via the \ref maingo.MAiNGO.read_settings "read_settings" function.
-If no file name is given to \ref maingo.MAiNGO.read_settings "read_settings", the default file name is <tt>MAiNGOSettings.txt</tt>.
-An example for such a settings file can be found at <tt>examples/MAiNGOSettings.txt</tt>.
+This section briefly describes how to implement your own non-elementary intrinsic function. First check the @function_library to see if it is already implemented in MAiNGO. 
+
+If not, you have to implement the function by hand in the submodule: MC++. Here you have to implement the function, relaxation, subgradients, interval bounds and more. 
+For this you have to modify some files in MC++ (<a href="https://git.rwth-aachen.de/avt-svt/public/thirdparty/mcpp/-/tree/master/src/mc?ref_type=heads"> MAiNGO/dep/MCpp/src/mc/</a>). Which specific files need to be extended can be found in the header of <tt>library_of_functions.hpp</tt>. 
+For a better understanding of what needs to be implemented and how, you should have a look at the <a href="https://github.com/omega-icl/mcpp"> MC++ documentation </a>. 
+ 
+Furthermore, the function needs to be included in MAiNGO. To do this, the newly implemented function must to be included in the following MAiNGO header files: <tt>MAiNGOevaluator.h</tt>, <tt>functionWrapper.h</tt> and <tt>ubpLazyQuadExpr.h</tt>.
+If you want to use the Python API, the function must also be defined in <tt>_maingopy.cpp</tt> in <a href="https://git.rwth-aachen.de/avt-svt/public/maingo/-/tree/master/maingopy?ref_type=heads">MAiNGO/maingopy/</a>. 
+
+@section lbp_implementation Integrating your own lower/upper bounding solver 
+
+In MAiNGO we have implemented the following Lower Bounding solvers: CLP, CPLEX, MAiNGO internal solver and a solver based on interval arithmetic only. 
+If you want to integrate your own solver for the Lower Bounding Problem into MAiNGO, we will explain this in the following section. 
+The process is similar for Upper Bounding Problem solvers. It consists of the following steps:
+
+-# Write a wrapper for to the new solver. Herefor, add a new header file (<tt> inc/lbp<yourSolver>.h </tt>) that defines a class for your solver and acts as a wrapper for handling LBPs with an interface to the new solver. The class inherits from the LowerBoundingSolver class.
+Implement the interfaces and functions necessary for the integration and functionality of the new solver in <tt> src/lbp<yourSolver>.cpp</tt>.
+-# Integrate it into MAiNGO. To handle the new solver, add a new case into: <tt> src/lbpFactory.cpp </tt> and </tt> src/MAiNGO.cpp </tt> (Preprocessing step).
+-# Update this file: <tt> src/MAiNGOprintingFunctions.cpp </tt>.
+-# Include the solver in the settings and modify the following files: <tt> src/MAiNGOsetOption.cpp </tt> and <tt> inc/settings.h </tt>.
+-# Bind the new solver in <tt> maingopy/_maingopy.cpp </tt> to enable its use in the Python API.
+-# Include the new solvers in CMake to ensure they are included during the build process:
+	<tt> CMakeList.txt </tt> and <tt> cmake/MAiNGOsourceFiles.cmake </tt>
+-# Update the test suite to include test cases for the new solver.
+
+In the case of an integration of an upper boundary solver, the same steps must be carried out. However, the keywords: lbp, must be replaced by ubp.
 
-In the example main file for the C++-API, <tt>examples/mainCppApi.cpp</tt>, the name of the desired settings file is read as optional (first and only) command line argument.
-If a file name is specified this way, MAiNGO will attempt to open a file of this name in the current working directory (i.e., typically where your <tt>MAiNGOcpp</tt> executable is).
-If this file is not found, it will display a warning and continue with default settings.
-If not file name is specified, MAiNGO will instead use the file <tt>MAiNGOSettings.txt</tt> if it exists in the working directory.
 
-Similarly, in the example main file for using text input based on ALE, <tt>examples/mainAleParser.cpp</tt>, the settings file name is read as optional second command line argument after the name of the input file containing the problem definition (cf. \ref modeling_ALE).
 
 <br>
 \page faq What can go wrong?
@@ -1093,10 +2071,10 @@ This can have several causes: there may be a mistake in the model equations, the
 mc_print(,) function.
 There are two different ways to remedy such situations (except for reformulating the problem or choosing tighter bounds) depending on why the domain violation occurs:\n
 If you know that the argument of interest is within the correct domain for all values of your optimization variables within their box constraints (i.e., without considering additional (linear or nonlinear) constraints),
-the domain violation is purely caused by weak relaxations. In this case, you can use the functions pos(), neg(), lb_func(), ub_func() and bounding_func() to artificially cut the relaxations (cf. <tt>doc/implementedFunctions/Implemented_functions.pdf</tt>).\n
+the domain violation is purely caused by weak relaxations. In this case, you can use the functions pos(), neg(), lb_func(), ub_func() and bounding_func() to artificially cut the relaxations (cf. @ref function_library or <tt>doc/implementedFunctions/Implemented_functions.pdf</tt>).\n
 If, however, there are values of you optimization variables within their bounds (that may potentially violate other constraints) that leads to the argument actually violating the domain, the above functions must not be used.
 Doing so would lead to wrong relaxations and unpredictable behavior. Instead, the points that lead to domain violations need to be excluded via a constraint and the argument can then be
-restricted using the functions min(,) or max(,) (cf. <tt>doc/implementedFunctions/Implemented_functions.pdf</tt> in the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo">MAiNGO git repository</a>).
+restricted using the functions min(,) or max(,) (cf. @ref function_library or <tt>doc/implementedFunctions/Implemented_functions.pdf</tt> in the <a href="https://git.rwth-aachen.de/avt-svt/public/maingo">MAiNGO git repository</a>).
 
 @section faq6 MAiNGO finds feasible solutions early on, but the LBD takes forever to converge
 
@@ -1110,8 +2088,6 @@ enable local searches at the root node. If the issue persists, your problem migh
 use the point reported by the external solver as an initial point for MAiNGO. Previous experience has shown that one possible cause can be redundant constraints (since these destroy
 constraint qualifications). If it seems like the lower bound converged, try using simple \ref maingo::ubp::UBP_SOLVER_EVAL "function evaluations". If your problem contains binary variables, improvements may be needed to the upper bounding strategy that is currently rather basic for integers.<br><br>
 
-\page maingo_settings MAiNGO Settings
-
 \page bib Where can I read more?
 
 Some more general information on MAiNGO can be found in the latest MAiNGO report:<br>
@@ -1194,4 +2170,8 @@ Examples of MAiNGO applications with machine-learning models using the "MeLOn" t
     - A.M. Schweidtmann, W.R. Huster, J.T. Lüthje and A. Mitsos, Deterministic global process optimization: Accurate (single-species) properties via artificial neural networks, Computers & Chemical Engineering 121 (2019) 67-74.
     - W.R. Huster, A.M. Schweidtmann, J.T. Lüthje and A. Mitsos, Deterministic global superstructure-based optimization of an organic Rankine cycle, Computers & Chemical Engineering 141 (2020) 106996.
     - A.M. Schweidtmann, D. Bongartz, G. Grothe, T. Kerkenhoff, X. Lin, J. Najman, and A. Mitsos, Global optimization of Gaussian processes, Submitted. Preprint available at https://arxiv.org/abs/2005.10902 (2020).
+
+MAiNGO with extension for handling parameter estimation problems considering large datasets:
+    - S. Sass, A. Tsoukalas, I.H. Bell, D. Bongartz, J. Najman and A. Mitsos, Towards global parameter estimation exploiting reduced data sets, Optimization Methods and Software 38 (2023) 1129-1141.
+    - S. Sass, A. Mitsos, D. Bongartz, I.H. Bell, N.I. Nikolov and A. Tsoukalas, A branch-and-bound algorithm with growing datasets for large-scale parameter estimation, European Journal of Operational Research 316 (2024) 36-45.
  */
diff --git a/gcovr_config.txt b/gcovr_config.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3cbd4c2987d6ca61e59dd8acb38f3edd0d48800c
--- /dev/null
+++ b/gcovr_config.txt
@@ -0,0 +1,9 @@
+root = . 
+root = build/
+filter = inc/
+filter = src/
+html-details = yes
+output = build/coverage/coverage.html
+exclude-unreachable-branches = yes
+exclude-throw-branches = yes
+sort-percentage = yes
\ No newline at end of file
diff --git a/inc/MAiNGO.h b/inc/MAiNGO.h
index e3229b222bdb3c1fbf284d7b8f5238dea1bda6f1..e10158d8731740796a1680e3d693d1d6de1fd24a 100644
--- a/inc/MAiNGO.h
+++ b/inc/MAiNGO.h
@@ -52,14 +52,20 @@ class MAiNGO {
 
   public:
     /**
-        *  @brief Constructor which initializes models and solvers
+        *  @brief Constructor that does not require a model
         */
-    MAiNGO(std::shared_ptr<MAiNGOmodel> myModel);
+    MAiNGO();
 
     /**
-        *  @brief Destructor
+        *  @brief Constructor that requires a model
         */
-    ~MAiNGO() {}
+    MAiNGO(std::shared_ptr<MAiNGOmodel> myModel);
+
+    MAiNGO(const MAiNGO &) = delete;
+    MAiNGO(MAiNGO &&) = delete;
+    MAiNGO &operator=(const MAiNGO &) = delete;
+    MAiNGO &operator=(MAiNGO &&) = delete;
+    ~MAiNGO() = default;
 
     /**
         *  @brief Initializes model
@@ -111,10 +117,17 @@ class MAiNGO {
         */
     void read_settings(const std::string &settingsFileName = "MAiNGOSettings.txt");
 
+    /**
+        *  @brief Sets input stream from which user input may be read during solution.
+        *
+        *  @param[in] input is the address of the new input stream to be used by MAiNGO.
+        */
+    void set_input_stream(std::istream *const inputStream) { _inputStream = inputStream; }
+
     /**
         *  @brief Sets output stream onto which logging information may be printed.
         *
-        *  @param[in,out] outputStream is the new output stream to be used by MAiNGO.
+        *  @param[in] outputStream is the address of the new output stream to be used by MAiNGO.
         */
     void set_output_stream(std::ostream *const outputStream) { _logger->set_output_stream(outputStream); }
 
@@ -284,20 +297,6 @@ class MAiNGO {
     void print_MAiNGO(std::ostream &outstream = std::cout);
 
   private:
-    /**
-        *  @brief Preventing use of default constructor
-        */
-    MAiNGO();
-
-    /**
-        *  @brief Preventing use of default copy constructor
-        */
-    MAiNGO(const MAiNGO &);
-
-    /**
-        *  @brief Preventing use of default copy assignment
-        */
-    MAiNGO &operator=(const MAiNGO &);
 
     /**
         *  @brief Internal function conducts structure recognition, sets constraint properties, and invokes the correct solution routine
@@ -503,7 +502,7 @@ class MAiNGO {
         *  @param[in] solverName is the solver name. If it is empty, the default solver SCIP will be called in the gams file.
         *  @param[in] writeRelaxationOnly if true then relaxation-only equalities and inequalities will be written into the GAMS file as well
         */
-    void _write_gams_file(const std::string gamsFileName = "MAiNGO_GAMS_file", const std::string solverName = "SCIP", const bool writeRelaxationOnly = false);
+    void _write_gams_file(const std::string gamsFileName, const std::string solverName = "SCIP", const bool writeRelaxationOnly = false);
 
     /**
         * @brief Function writing variables, variable bounds and a initial point in the gams file
@@ -542,7 +541,7 @@ class MAiNGO {
         *  @param[in] solverName is the solver name. If it is empty, the default solver SCIP will be called in the gams file.
         *  @param[in] writeRelaxationOnly if true then relaxation-only equalities and inequalities will be written into the ALE file as well
         */
-    void _write_ale_file(const std::string aleFileName = "MAiNGO_ALE_file", const std::string solverName = "SCIP", const bool writeRelaxationOnly = false);
+    void _write_ale_file(const std::string aleFileName, const std::string solverName = "SCIP", const bool writeRelaxationOnly = false);
 
     /**
         * @brief Function writing variables, variable bounds and a initial point in the ale file
@@ -658,7 +657,7 @@ class MAiNGO {
     std::vector<std::string> _outputNames;                               /*!< strings for output variables */
     std::shared_ptr<MAiNGOmodel> _myFFVARmodel;                          /*!< pointer to a MAiNGOmodel object which will be evaluated with mc::FFVar variables */
     EvaluationContainer _modelOutput;                                    /*!< object holding the actual modelOutput in mc::FFVar, it is needed to not lose information on pointers */
-    bool _readyToSolve;                                                  /*!< flag storing whether a model has been successfully specified and is ready to solve */
+    bool _modelSpecified;                                                /*!< flag storing whether a model has been successfully specified */
     bool _DAGconstructed;                                                /*!< flag storing whether the DAG has already been constructed */
     bool _variablesFeasible;                                             /*!< flag indicating whether the variable bounds define a non-empty set */
     bool _constantConstraintsFeasible;                                   /*!< flag indicating whether the constant constraints are feasible */
@@ -729,9 +728,10 @@ class MAiNGO {
     Settings _maingoOriginalSettings;                                         /*!< object storing original settings */
 
     /**
-        * @name Output
+        * @name Communication
         */
     /**@{*/
+    std::istream* _inputStream             = &std::cin;                                 /*!< stream from which user input may be read during solution */
     std::shared_ptr<Logger> _logger        = std::make_shared<Logger>(_maingoSettings); /*!< object taking care of printing and saving information to logs */
     std::string _jsonFileName              = "statisticsAndSolution.json";              /*!< name of the json file into which information about the problem and solution may be written */
     std::string _resultFileName            = "MAiNGOresult.txt";                        /*!< name of the text file into which the results (solution point, constraints residuals etc.) may be written */
diff --git a/inc/MAiNGOException.h b/inc/MAiNGOException.h
index 34d8e86bde8a57407b9bd13205fd49857eb6c3e4..5fabb6101d5ea2d3c9d0caf9cf49875ccf83ea84 100644
--- a/inc/MAiNGOException.h
+++ b/inc/MAiNGOException.h
@@ -16,7 +16,6 @@
 #include <exception>
 #include <sstream>
 #include <string>
-#include <typeinfo>
 
 
 namespace maingo {
@@ -40,76 +39,22 @@ class MAiNGOException: public std::exception {
     MAiNGOException(MAiNGOException&&)                 = default;
     MAiNGOException& operator=(const MAiNGOException&) = default;
     MAiNGOException& operator=(MAiNGOException&&)      = default;
-    virtual ~MAiNGOException()                         = default;
+    virtual ~MAiNGOException()                         = default; // GCOVR_EXCL_LINE
 
-    explicit MAiNGOException(const std::string& errorMessage)
-    {
-        _construct_complete_error_message(errorMessage, nullptr, nullptr);
-    }
-
-    MAiNGOException(const std::string& errorMessage, const babBase::BabNode& nodeThatErrorOccurredIn)
-    {
-        _construct_complete_error_message(errorMessage, nullptr, &nodeThatErrorOccurredIn);
-    }
-
-    MAiNGOException(const std::string& errorMessage, const std::exception& originalException)
-    {
-        _construct_complete_error_message(errorMessage, &originalException, nullptr);
-    }
-
-    MAiNGOException(const std::string& errorMessage, const std::exception& originalException, const babBase::BabNode& nodeThatErrorOccurredIn)
-    {
-        _construct_complete_error_message(errorMessage, &originalException, &nodeThatErrorOccurredIn);
-    }
-
-    const char* what() const noexcept override
-    {
-        return _errorMessage.c_str();
-    }
+    explicit MAiNGOException(const std::string& errorMessage);
+    MAiNGOException(const std::string& errorMessage, const babBase::BabNode& nodeThatErrorOccurredIn);
+    MAiNGOException(const std::string& errorMessage, const std::exception& originalException);
+    MAiNGOException(const std::string& errorMessage, const std::exception& originalException, const babBase::BabNode& nodeThatErrorOccurredIn);
 
+    const char* what() const noexcept override;
 
   private:
     std::string _errorMessage{""};
 
-    void _construct_complete_error_message(const std::string& errorMessage, const std::exception* originalException, const babBase::BabNode* nodeThatErrorOccurredIn)
-    {
-        std::ostringstream errorMessageStream;
-
-        _append_original_exception_info_to_message(originalException, errorMessageStream);
-        _append_current_error_message_to_message(errorMessage, errorMessageStream);
-        _append_node_info_to_message(nodeThatErrorOccurredIn, errorMessageStream);
-
-        _errorMessage = errorMessageStream.str();
-    }
-
-    void _append_current_error_message_to_message(const std::string& currentErrorMessage, std::ostringstream& completeErrorMessage)
-    {
-        completeErrorMessage << currentErrorMessage;
-    }
-
-    void _append_original_exception_info_to_message(const std::exception* originalException, std::ostringstream& completeErrorMessage)
-    {
-        if (originalException) {
-            if (typeid(*originalException).name() != typeid(*this).name()) {
-                completeErrorMessage << "  Original exception type: " << typeid(*originalException).name() << ": " << std::endl
-                                     << "   ";
-            }
-            completeErrorMessage << originalException->what() << std::endl;
-        }
-    }
-
-    void _append_node_info_to_message(const babBase::BabNode* nodeThatErrorOccurredIn, std::ostringstream& completeErrorMessage)
-    {
-        if (nodeThatErrorOccurredIn) {
-            std::vector<double> lowerVarBounds(nodeThatErrorOccurredIn->get_lower_bounds()), upperVarBounds(nodeThatErrorOccurredIn->get_upper_bounds());
-            completeErrorMessage << std::endl
-                                 << "  Exception was thrown while processing node no. " << nodeThatErrorOccurredIn->get_ID() << ":";
-            for (size_t i = 0; i < lowerVarBounds.size(); i++) {
-                completeErrorMessage << std::endl
-                                     << "    x(" << i << "): " << std::setprecision(16) << lowerVarBounds[i] << ":" << upperVarBounds[i];
-            }
-        }
-    }
+    void _construct_complete_error_message(const std::string& errorMessage, const std::exception* originalException, const babBase::BabNode* nodeThatErrorOccurredIn);
+    void _append_current_error_message_to_message(const std::string& currentErrorMessage, std::ostringstream& completeErrorMessage);
+    void _append_original_exception_info_to_message(const std::exception* originalException, std::ostringstream& completeErrorMessage);
+    void _append_node_info_to_message(const babBase::BabNode* nodeThatErrorOccurredIn, std::ostringstream& completeErrorMessage);
 };
 
 
diff --git a/inc/MAiNGOmodel.h b/inc/MAiNGOmodel.h
index ca6ad91ed2277b83bcbfacd4b63ac117b54aa5ac..9151498badb0c7fa5132d5bb7d7666b85d2fc9b6 100644
--- a/inc/MAiNGOmodel.h
+++ b/inc/MAiNGOmodel.h
@@ -67,9 +67,9 @@ class MAiNGOmodel {
     /**
 		* @brief Virtual function which has to be implemented by the user in order to enable getting data on the initial point
 		*/
-    virtual std::vector<double> get_initial_point() { return std::vector<double>(); }
+    virtual std::vector<double> get_initial_point() { return std::vector<double>(); }  // GCOVR_EXCL_START
 
-  private:
+  private: // GCOVR_EXCL_STOP
 };
 
 
diff --git a/inc/MAiNGOmodelEpsCon.h b/inc/MAiNGOmodelEpsCon.h
index 182a4e154c504bb396b4a898583e6c9b971b929d..73989967eed94ab80124558d937455a2d63259e7 100644
--- a/inc/MAiNGOmodelEpsCon.h
+++ b/inc/MAiNGOmodelEpsCon.h
@@ -33,7 +33,7 @@ class MAiNGOmodelEpsCon: public MAiNGOmodel {
     /**
       * @brief Destructor
       */
-    virtual ~MAiNGOmodelEpsCon() {}
+    virtual ~MAiNGOmodelEpsCon() {} 
 
     /**
       * @brief Virtual function which has to be implemented by the user in order to enable evaluation of the model
@@ -57,7 +57,7 @@ class MAiNGOmodelEpsCon: public MAiNGOmodel {
     /**
       * @brief Virtual function which has to be implemented by the user in order to enable getting data on the initial point
       */
-    virtual std::vector<double> get_initial_point() { return std::vector<double>(); }
+    virtual std::vector<double> get_initial_point() { return std::vector<double>(); } // GCOVR_EXCL_LINE
 
     /**
       * @brief Function for changing the epsilon-parameters
@@ -90,9 +90,9 @@ class MAiNGOmodelEpsCon: public MAiNGOmodel {
     }
 
   private:
-    std::vector<double> _epsilon; /*!< vector of epsilon parameters for use in the epsilon-constraint method */
-    size_t _objectiveIndex;       /*!< index of objective to be minimized during epsilon-constraint method. The other objective will be used in the epsilon-constraint */
-    bool _singleObjective = true; /*!< flag indicating whether the next problem should be considered as single-objective (for objective _objectiveIndex), or whether to use the epsilon constraint(s) */
+    std::vector<double> _epsilon = {}; /*!< vector of epsilon parameters for use in the epsilon-constraint method */
+    size_t _objectiveIndex = 0;        /*!< index of objective to be minimized during epsilon-constraint method. The other objective will be used in the epsilon-constraint */
+    bool _singleObjective = true;      /*!< flag indicating whether the next problem should be considered as single-objective (for objective _objectiveIndex), or whether to use the epsilon constraint(s) */
 };
 
 
diff --git a/inc/bab.h b/inc/bab.h
index 5d86779a6ad033becdbe0e899420581e12b62e6d..905158e454761023ab6e30ead2627e0ff41d9722 100644
--- a/inc/bab.h
+++ b/inc/bab.h
@@ -67,9 +67,10 @@ class BranchAndBound {
         * @param[in] settingsIn is a pointer to an object containing the settings for the Branch-and-Bound solvers
         * @param[in] loggerIn is a pointer to the MAiNGO logger object
         * @param[in] nvarWOaux is the number of optimization variables without the additional auxiliary variables added by the LBP_addAuxiliaryVars option
+        * @param[in] inputStream is the address of the input stream from which user input may be read during solution
         */
     BranchAndBound(const std::vector<babBase::OptimizationVariable> &variables, std::shared_ptr<lbp::LowerBoundingSolver> LBSIn, std::shared_ptr<ubp::UpperBoundingSolver> UBSIn,
-                   std::shared_ptr<Settings> settingsIn, std::shared_ptr<Logger> loggerIn, const unsigned nvarWOaux);
+                   std::shared_ptr<Settings> settingsIn, std::shared_ptr<Logger> loggerIn, const unsigned nvarWOaux, std::istream *const inputStream = &std::cin);
 
     /**
         * @brief Destructor
@@ -281,49 +282,13 @@ class BranchAndBound {
         */
     void _print_termination(std::string message);
 
-    /**
-        * @brief Function printing one node
-        *
-        * @param[in] theLBD is the lower bound of the node
-        * @param[in] ID is the id of the node
-        * @param[in] lowerVarBounds are the variables lower bounds
-        * @param[in] upperVarBounds are the variables upper bounds
-        */
-    void _print_one_node(const double theLBD, const int ID, const std::vector<double> lowerVarBounds, const std::vector<double> upperVarBounds);
-
-    /**
-        * @brief Function printing one node
-        *
-        * @param[in] theLBD is the lower bound of the node
-        * @param[in] ID is the id of the node
-        * @param[in] lowerVarBounds are the variables lower bounds
-        * @param[in] upperVarBounds are the variables upper bounds
-        * @param[in] outstream is the stream to be written to, e.g., an error message
-        */
-    void _print_one_node(const double theLBD, const int ID, const std::vector<double> lowerVarBounds, const std::vector<double> upperVarBounds, std::ostream &outstream);
-
     /**
         * @brief Function printing one node
         *
         * @param[in] theLBD is the lower bound of the node
         * @param[in] theNode is the node to be printed
         */
-    void _print_one_node(const double theLBD, const babBase::BabNode &theNode)
-    {
-        _print_one_node(theLBD, theNode.get_ID(), theNode.get_lower_bounds(), theNode.get_upper_bounds());
-    }
-
-    /**
-        * @brief Function printing one node
-        *
-        * @param[in] theLBD is the lower bound of the node
-        * @param[in] theNode is the node to be printed
-        * @param[in] outstream is the stream to be written to, e.g., an error message
-        */
-    void _print_one_node(const double theLBD, const babBase::BabNode &theNode, std::ostream &outstream)
-    {
-        _print_one_node(theLBD, theNode.get_ID(), theNode.get_lower_bounds(), theNode.get_upper_bounds(), outstream);
-    }
+    void _print_one_node(const double theLBD, const babBase::BabNode &theNode);
 
 #ifdef HAVE_MAiNGO_MPI
     /**
@@ -516,6 +481,7 @@ class BranchAndBound {
     bool _printNewIncumbent;         /*!< auxiliary variable to make sure a line is printed whenever a new incumbent, which is better than the old one for more than the tolerances, is found */
     unsigned _writeToLogEverySec;    /*!< auxiliary variable to make sure we print to log every writeToLogSec seconds */
     std::shared_ptr<Logger> _logger; /*!< pointer to MAiNGO logger */
+    std::istream* _inputStream = &std::cin; /*!< stream from which user input may be read during solution */
                                      /**@}*/
 
 #ifdef HAVE_MAiNGO_MPI
diff --git a/inc/constraint.h b/inc/constraint.h
index 6762e01063c06ad2303ff2e45e31c36a7f962e89..e6e5a57d2a4b3fde2bd35d9bf1fbccbd8c65f690 100644
--- a/inc/constraint.h
+++ b/inc/constraint.h
@@ -1,5 +1,5 @@
 /**********************************************************************************
- * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ * Copyright (c) 2019-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License 2.0 which is available at
@@ -87,7 +87,7 @@ enum CONSTRAINT_DEPENDENCY {
     * @struct Constraint
     * @brief Struct for storing information about constraints
     *
-    * This struct stores constraint properties such as constraint type, convexity ,monotonicity. It also stores several indices for easier access to the correct constraint such as
+    * This struct stores constraint properties such as constraint type, convexity, monotonicity. It also stores several indices for easier access to the correct constraint such as
     * the index in the originalFunctions which was read in from the model, index in the constantFunctions vector, index in the nonConstantFunctions vector,
     * index among linear functions, and index among nonlinear function. Moreover, it holds the type of a constraint, e.g., linear, quadratic, bilinear etc., the number of participating
     * variables in the constraint, and the number of (non)linearly participating variables in the given constraint
@@ -99,107 +99,27 @@ struct Constraint {
     /**
             * @brief Default conststructor
             */
-    Constraint():
-        name(""), constantValue(0), type(CONSTRAINT_TYPE::TYPE_UNKNOWN), convexity(CONSTRAINT_CONVEXITY::CONV_NONE),
-        monotonicity(CONSTRAINT_MONOTONICITY::MON_NONE), dependency(CONSTRAINT_DEPENDENCY::DEP_UNKNOWN), isConstant(false),
-        isFeasible(true), indexOriginal(0), indexNonconstant(0), indexNonconstantUBP(0), indexConstant(0), indexLinear(0), indexNonlinear(0),
-        indexType(0), indexTypeNonconstant(0), indexTypeConstant(0), nparticipatingVariables(0) {}
+    Constraint();
 
     /**
             * @brief Conststructor for non-constant constraints with a possible name
             */
     Constraint(const CONSTRAINT_TYPE typeIn, const unsigned indexOriginalIn, const unsigned indexTypeIn, const unsigned indexNonconstantIn,
-               const unsigned indexTypeNonconstantIn, const std::string& nameIn = ""):
-        name(nameIn),
-        constantValue(0), type(typeIn), convexity(CONSTRAINT_CONVEXITY::CONV_NONE),
-        monotonicity(CONSTRAINT_MONOTONICITY::MON_NONE), dependency(CONSTRAINT_DEPENDENCY::DEP_UNKNOWN), isConstant(false),
-        isFeasible(true), indexOriginal(indexOriginalIn), indexNonconstant(indexNonconstantIn), indexNonconstantUBP(0), indexConstant(0),
-        indexLinear(0), indexNonlinear(0), indexType(indexTypeIn), indexTypeNonconstant(indexTypeNonconstantIn), indexTypeConstant(0), nparticipatingVariables(0)
-    {
-        if (name == "") {
-            std::string str;
-            switch (typeIn) {
-                case OBJ:
-                    str = "obj" + std::to_string(indexTypeIn + 1);
-                    break;
-                case INEQ:
-                    str = "ineq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case EQ:
-                    str = "eq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case INEQ_REL_ONLY:
-                    str = "relOnlyIneq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case EQ_REL_ONLY:
-                    str = "relOnlyEq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case INEQ_SQUASH:
-                    str = "squashIneq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case AUX_EQ_REL_ONLY:
-                    str = "auxRelOnlyEq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case OUTPUT:
-                    str = "output" + std::to_string(indexTypeIn + 1);
-                    break;
-                default:
-                    str = "constraint" + std::to_string(indexTypeIn + 1);
-                    break;
-            }
-            name = str;
-        }
-    }
+               const unsigned indexTypeNonconstantIn, const std::string& nameIn = "");
 
     /**
             * @brief Conststructor for constant constraints with a possible name
             */
-    Constraint(const CONSTRAINT_TYPE typeIn, const unsigned indexOriginalIn, const unsigned indexTypeIn,
-               const unsigned indexConstantIn, const unsigned indexTypeConstantIn, const bool isConstantIn,
-               const bool isFeasibleIn, const double valueIn, const std::string& nameIn = ""):
-        name(nameIn),
-        constantValue(valueIn), type(typeIn), convexity(CONSTRAINT_CONVEXITY::CONV_NONE),
-        monotonicity(CONSTRAINT_MONOTONICITY::MON_NONE), dependency(CONSTRAINT_DEPENDENCY::DEP_UNKNOWN), isConstant(isConstantIn),
-        isFeasible(isFeasibleIn), indexOriginal(indexOriginalIn), indexNonconstant(0), indexNonconstantUBP(0), indexConstant(indexConstantIn),
-        indexLinear(0), indexNonlinear(0), indexType(indexTypeIn), indexTypeNonconstant(0), indexTypeConstant(indexTypeConstantIn), nparticipatingVariables(0)
-    {
-        if (name == "") {
-            std::string str;
-            switch (typeIn) {
-                case OBJ:
-                    str = "obj" + std::to_string(indexTypeIn + 1);
-                    break;
-                case INEQ:
-                    str = "ineq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case EQ:
-                    str = "eq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case INEQ_REL_ONLY:
-                    str = "relOnlyIneq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case EQ_REL_ONLY:
-                    str = "relOnlyEq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case INEQ_SQUASH:
-                    str = "squashIneq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case AUX_EQ_REL_ONLY:
-                    str = "auxRelOnlyEq" + std::to_string(indexTypeIn + 1);
-                    break;
-                case OUTPUT:
-                    str = "output" + std::to_string(indexTypeIn + 1);
-                    break;
-                default:
-                    str = "constraint" + std::to_string(indexTypeIn + 1);
-                    break;
-            }
-            name = str;
-        }
-    }
-
-    Constraint(const Constraint&)                         = default; /*!< Use default copy constructor */
-    Constraint& operator=(const Constraint& constraintIn) = default; /*!< Use default copy constructor */
+    Constraint(const CONSTRAINT_TYPE typeIn, const unsigned indexOriginalIn, const unsigned indexTypeIn, const unsigned indexConstantIn,
+               const unsigned indexTypeConstantIn, const bool isConstantIn,
+               const bool isFeasibleIn, const double valueIn, const std::string& nameIn = "");
+
+    Constraint(const Constraint&)                         = default;
+    Constraint(Constraint&&)                              = default;
+    Constraint& operator=(const Constraint& constraintIn) = default;
+    Constraint& operator=(Constraint&& constraintIn)      = default;
+    ~Constraint()                                         = default;
+
 
     std::string name;                             /*!< Name of the constraint */
     double constantValue;                         /*!< Value of the constraint (only used if the constraint is constant) */
diff --git a/inc/decayingProbability.h b/inc/decayingProbability.h
index 87a8fd611656fc6fda4d9c7869557f133bbaef8e..86b9bc1f46de6eb6cb5e165345e4375df6935db4 100644
--- a/inc/decayingProbability.h
+++ b/inc/decayingProbability.h
@@ -11,20 +11,11 @@
 
 #pragma once
 
-#include <cmath>
-#include <cstdlib>
-
 
 namespace maingo {
 
 
-bool
-do_based_on_decaying_probability(const double decayCoefficient, const double decisionVariable)
-{
-    const double probabilityThreshold = std::exp(-decayCoefficient * decisionVariable);
-    const double randomNumber         = std::rand() / ((double)RAND_MAX);
-    return randomNumber <= probabilityThreshold;
-}
+bool do_based_on_decaying_probability(const double decayCoefficient, const double decisionVariable);
 
 
 }    // end namespace maingo
\ No newline at end of file
diff --git a/inc/evaluationContainer.h b/inc/evaluationContainer.h
index 1f70342f828b117dc71e50f5deb4a0cfb0c30b40..3328b089830cc9da3dc5aad8fe51b35452a1d557 100644
--- a/inc/evaluationContainer.h
+++ b/inc/evaluationContainer.h
@@ -11,6 +11,7 @@
 
 #pragma once
 
+#include "modelFunction.h"
 #include "outputVariable.h"
 
 #include "ffunc.hpp"
@@ -21,182 +22,6 @@
 namespace maingo {
 
 
-/**
-    * @struct ModelFunction
-    * @brief Struct for making work with the EvaluationContainer easier for the user and also to ensure backward compatibility
-    */
-struct ModelFunction {
-
-    ModelFunction()                                 = default;
-    ~ModelFunction()                                = default;
-    ModelFunction(const ModelFunction &)            = default;
-    ModelFunction(ModelFunction &&)                 = default;
-    ModelFunction &operator=(const ModelFunction &) = default;
-    ModelFunction &operator=(ModelFunction &&)      = default;
-
-    /**
-        *  @brief Constructor with FFVar value only
-        */
-    ModelFunction(const mc::FFVar var)
-    {
-        value.clear();
-        value.push_back(var);
-        name.clear();
-        name.push_back("");
-    }
-
-    /**
-        *  @brief Constructor with FFVar value and a name
-        */
-    ModelFunction(const mc::FFVar var, const std::string &str)
-    {
-        value.clear();
-        value.push_back(var);
-        name.clear();
-        name.push_back(str);
-    }
-
-    /**
-        *  @brief Constructor with vector of FFVar
-        */
-    ModelFunction(const std::vector<mc::FFVar> &vars)
-    {
-        value = vars;
-        name  = std::vector<std::string>(value.size(), "");
-    }
-
-    /**
-        *  @brief Function deleting everything in the model function
-        */
-    void clear()
-    {
-        value.clear();
-        name.clear();
-    }
-
-    /**
-        *  @brief Function for inserting a FFVar value at the end of the value vector
-        */
-    void push_back(const mc::FFVar var)
-    {
-        value.push_back(var);
-        name.push_back("");
-    }
-
-    /**
-        *  @brief Function for inserting a FFVar and a name at the end of the vectors
-        */
-    void push_back(const mc::FFVar var, const std::string &str)
-    {
-        value.push_back(var);
-        name.push_back(str);
-    }
-
-    /**
-        *  @brief Function for inserting a vector of FFVar at the end of the value vector
-        */
-    void push_back(const std::vector<mc::FFVar> &vars)
-    {
-        for (size_t i = 0; i < vars.size(); i++) {
-            value.push_back(vars[i]);
-            name.push_back("");
-        }
-    }
-
-    /**
-        *  @brief Function for inserting a vector of FFVar at the end of the value vector with names
-        */
-    void push_back(const std::vector<mc::FFVar> &vars, const std::string &baseName)
-    {
-        if (vars.size() == 1) {
-            value.push_back(vars[0]);
-            name.push_back(baseName);
-        }
-        else if (baseName == "") {
-            push_back(vars);
-        }
-        else {
-            for (size_t i = 0; i < vars.size(); i++) {
-                value.push_back(vars[i]);
-                name.push_back(baseName + '_' + std::to_string(i + 1));
-            }
-        }
-    }
-
-    /**
-        *  @brief Function returning the size of the value vector. Note that value and name vectors have the same size at any time
-        */
-    size_t size() const
-    {
-        return value.size();
-    }
-
-    /**
-        *  @brief Function for resizing of the underlying vectors
-        */
-    void resize(const size_t size)
-    {
-        value.resize(size);
-        name.resize(size);
-    }
-
-    /**
-        *  @brief Function for seting FFVar value at a given index
-        */
-    void set_value(const mc::FFVar var, const unsigned i)
-    {
-        value[i] = var;
-    }
-
-    /**
-        *  @brief Function for seting name value at a given index
-        */
-    void set_name(const std::string str, const unsigned i)
-    {
-        name[i] = str;
-    }
-
-    /**
-        *  @brief = operator for backward compatibility
-        */
-    inline ModelFunction &operator=(const mc::FFVar var)
-    {
-        value.clear();
-        value.push_back(var);
-        name.clear();
-        name.push_back("");
-        return *this;
-    }
-
-    /**
-        *  @brief [] operator for easier access to value vector
-        */
-    inline mc::FFVar &operator[](const unsigned int i)
-    {
-        return value[i];
-    }
-
-    /**
-        *  @brief Function for accessing elements
-        */
-    inline mc::FFVar &at(const unsigned int i)
-    {
-        return value.at(i);
-    }
-
-    /**
-        *  @brief Equality comparison operator
-        */
-    inline bool operator==(const ModelFunction &other) const
-    {
-        return ((name == other.name) && (value == other.value));
-    }
-
-    std::vector<std::string> name; /*!< vector holding possible function names */
-    std::vector<mc::FFVar> value;  /*!< vector holding the actual propagated FFVar values */
-};
-
-
 /**
     * @struct EvaluationContainer
     * @brief Struct for storing the values returned by model evaluation at the given point "var"
diff --git a/inc/logger.h b/inc/logger.h
index 1764f3da1c5baafc911fe8b4a59810ab5b9dd77b..4cdc69e089db813a992c5de95288782cf533386d 100644
--- a/inc/logger.h
+++ b/inc/logger.h
@@ -40,8 +40,7 @@ class Logger {
         * @param[in] settings shared pointer to _maingoSettings
         */
 
-    Logger(const std::shared_ptr<Settings> settings):
-        _settings(settings) {}
+    Logger(const std::shared_ptr<Settings> settings);
 
     /**
         * @brief The main function used for printing a given message and storing it in log and/or csv
diff --git a/inc/modelFunction.h b/inc/modelFunction.h
new file mode 100644
index 0000000000000000000000000000000000000000..00fdd0e8c11101ff0ddc0990fc4ff7335227c5f0
--- /dev/null
+++ b/inc/modelFunction.h
@@ -0,0 +1,198 @@
+/**********************************************************************************
+ * Copyright (c) 2019-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "ffunc.hpp"
+
+#include <string>
+#include <vector>
+
+
+namespace maingo {
+
+
+/**
+    * @struct ModelFunction
+    * @brief Struct for making work with the EvaluationContainer easier for the user and also to ensure backward compatibility
+    */
+struct ModelFunction {
+
+    ModelFunction()                                 = default;
+    ~ModelFunction()                                = default;
+    ModelFunction(const ModelFunction &)            = default;
+    ModelFunction(ModelFunction &&)                 = default;
+    ModelFunction &operator=(const ModelFunction &) = default;
+    ModelFunction &operator=(ModelFunction &&)      = default;
+
+    /**
+        *  @brief Constructor with FFVar value only
+        */
+    ModelFunction(const mc::FFVar var)
+    {
+        value.clear();
+        value.push_back(var);
+        name.clear();
+        name.push_back("");
+    }
+
+    /**
+        *  @brief Constructor with FFVar value and a name
+        */
+    ModelFunction(const mc::FFVar var, const std::string &str)
+    {
+        value.clear();
+        value.push_back(var);
+        name.clear();
+        name.push_back(str);
+    }
+
+    /**
+        *  @brief Constructor with vector of FFVar
+        */
+    ModelFunction(const std::vector<mc::FFVar> &vars)
+    {
+        value = vars;
+        name  = std::vector<std::string>(value.size(), "");
+    }
+
+    /**
+        *  @brief Function deleting everything in the model function
+        */
+    void clear()
+    {
+        value.clear();
+        name.clear();
+    }
+
+    /**
+        *  @brief Function for inserting a FFVar value at the end of the value vector
+        */
+    void push_back(const mc::FFVar var)
+    {
+        value.push_back(var);
+        name.push_back("");
+    }
+
+    /**
+        *  @brief Function for inserting a FFVar and a name at the end of the vectors
+        */
+    void push_back(const mc::FFVar var, const std::string &str)
+    {
+        value.push_back(var);
+        name.push_back(str);
+    }
+
+    /**
+        *  @brief Function for inserting a vector of FFVar at the end of the value vector
+        */
+    void push_back(const std::vector<mc::FFVar> &vars)
+    {
+        for (size_t i = 0; i < vars.size(); i++) {
+            value.push_back(vars[i]);
+            name.push_back("");
+        }
+    }
+
+    /**
+        *  @brief Function for inserting a vector of FFVar at the end of the value vector with names
+        */
+    void push_back(const std::vector<mc::FFVar> &vars, const std::string &baseName)
+    {
+        if (vars.size() == 1) {
+            value.push_back(vars[0]);
+            name.push_back(baseName);
+        }
+        else if (baseName == "") {
+            push_back(vars);
+        }
+        else {
+            for (size_t i = 0; i < vars.size(); i++) {
+                value.push_back(vars[i]);
+                name.push_back(baseName + '_' + std::to_string(i + 1));
+            }
+        }
+    }
+
+    /**
+        *  @brief Function returning the size of the value vector. Note that value and name vectors have the same size at any time
+        */
+    size_t size() const
+    {
+        return value.size();
+    }
+
+    /**
+        *  @brief Function for resizing of the underlying vectors
+        */
+    void resize(const size_t size)
+    {
+        value.resize(size);
+        name.resize(size);
+    }
+
+    /**
+        *  @brief Function for seting FFVar value at a given index
+        */
+    void set_value(const mc::FFVar var, const unsigned i)
+    {
+        value[i] = var;
+    }
+
+    /**
+        *  @brief Function for seting name value at a given index
+        */
+    void set_name(const std::string str, const unsigned i)
+    {
+        name[i] = str;
+    }
+
+    /**
+        *  @brief = operator for backward compatibility
+        */
+    inline ModelFunction &operator=(const mc::FFVar var)
+    {
+        value.clear();
+        value.push_back(var);
+        name.clear();
+        name.push_back("");
+        return *this;
+    }
+
+    /**
+        *  @brief [] operator for easier access to value vector
+        */
+    inline mc::FFVar &operator[](const unsigned int i)
+    {
+        return value[i];
+    }
+
+    /**
+        *  @brief Function for accessing elements
+        */
+    inline mc::FFVar &at(const unsigned int i)
+    {
+        return value.at(i);
+    }
+
+    /**
+        *  @brief Equality comparison operator
+        */
+    inline bool operator==(const ModelFunction &other) const
+    {
+        return ((name == other.name) && (value == other.value));
+    }
+
+    std::vector<std::string> name = {}; /*!< vector holding possible function names */
+    std::vector<mc::FFVar> value = {};  /*!< vector holding the actual propagated FFVar values */
+};
+
+}    // end namespace maingo
\ No newline at end of file
diff --git a/inc/outputVariable.h b/inc/outputVariable.h
index eea1c00beb6fe67dc39a393251759ae5d6830f09..d69190358092da64aeb660bd383386c58b57c0bd 100644
--- a/inc/outputVariable.h
+++ b/inc/outputVariable.h
@@ -1,5 +1,5 @@
 /**********************************************************************************
- * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ * Copyright (c) 2019-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License 2.0 which is available at
@@ -21,90 +21,32 @@ namespace maingo {
 
 /**
 	* @struct OutputVariable
-	* @brief Struct for storing additional output variables
+	* @brief Struct for storing output variables
 	*
-	* Since the model evaluation can contain several intermediate variables that appear neither as optimization variables nor as constraints directly, but the value of which might be interesting at the optimal solution point,
-	* a vector of these structs can be used in the EvaluationContainer to give such additional output after the problem is solved.
+	* Can be used to tag intermediate calculation results (i.e., FFVars) along with a descriptive string.
 	*/
 struct OutputVariable {
 
   public:
-    /**
-			* @brief Constructor for use in the evaluate function
-			*
-			* @param[in] descIn is a string describing the variable
-			* @param[in] valueIn is the value of the variable at the current point
-			*/
-    OutputVariable(const std::string descIn, const mc::FFVar valueIn):
-        description(descIn), value(valueIn) {}
-
-    /**
-			* @brief Constructor for use in the evaluate function
-			*
-			* @param[in] valueIn is the value of the variable at the current point
-			* @param[in] descIn is a string describing the variable
-			*/
-    OutputVariable(const mc::FFVar valueIn, const std::string descIn):
-        value(valueIn), description(descIn) {}
-
-    /**
-			* @brief Constructor for use in the evaluate function
-			*
-			* @param[in] inTuple is a tuple containing the value of the variable at the current point and a descriptive string
-			*/
-    OutputVariable(const std::tuple<mc::FFVar, std::string> inTuple):
-        value(std::get<0>(inTuple)), description(std::get<1>(inTuple)) {}
-
-    /**
-			* @brief Constructor for use in the evaluate function
-			*
-			* @param[in] inTuple is a tuple containing the value of the variable at the current point and a descriptive string
-			*/
-    OutputVariable(const std::tuple<std::string, mc::FFVar> inTuple):
-        value(std::get<1>(inTuple)), description(std::get<0>(inTuple)) {}
-
-    /**
-			* @brief Destructor
-			*/
+    OutputVariable() = default;
+    OutputVariable(const std::string descriptionIn, const mc::FFVar valueIn);
+    OutputVariable(const mc::FFVar valueIn, const std::string descriptionIn);
+    OutputVariable(const std::tuple<mc::FFVar, std::string> tupleIn);
+    OutputVariable(const std::tuple<std::string, mc::FFVar> tupleIn);
+
+    OutputVariable(const OutputVariable& valueIn) = default;
+    OutputVariable(OutputVariable&& valueIn) = default;
     ~OutputVariable() = default;
 
-    /**
-			* @brief Copy constructor
-			*
-			* @param[in] variableIn is the output variable to be copied
-			*/
-    OutputVariable(const OutputVariable& variableIn) = default;
-
-    /**
-			* @brief Move constructor
-			*
-			* @param[in] variableIn is the output variable to be moved
-			*/
-    OutputVariable(OutputVariable&& variableIn) = default;
-
-    /**
-			* @brief Copy assignment operator
-			*
-			* @param[in] variableIn is the output variable to be copied
-			*/
-    OutputVariable& operator=(const OutputVariable& variableIn) = default;
-
-    /**
-			* @brief Move assignment operator
-			*
-			* @param[in] variableIn is the output variable to be moved
-			*/
-    OutputVariable& operator=(OutputVariable&& variableIn) = default;
+    OutputVariable& operator=(const OutputVariable& valueIn) = default;
+    OutputVariable& operator=(OutputVariable&& valueIn) = default;
 
-    /**
-        *  @brief Equality comparison operator
-        */
     inline bool operator==(const OutputVariable& other) const
     {
         return ((description == other.description) && (value == other.value));
     }
 
-    mc::FFVar value         = {}; /*!< Variable object */
+    mc::FFVar value         = {}; /*!< Variable object, allows access to value once evaluated*/
     std::string description = {}; /*!< Description, e.g. name of variable */
 };
 
diff --git a/inc/ubpLazyQuadExpr.h b/inc/ubpLazyQuadExpr.h
index 36fb29a780f6866d1a01a51281ac349086392ece..8b8ca8923ffb59c21ac3a0e32fb39694ad26be2a 100644
--- a/inc/ubpLazyQuadExpr.h
+++ b/inc/ubpLazyQuadExpr.h
@@ -423,10 +423,10 @@ class SparseMatrix {
         unsigned minNumber   = get_number_of_rows();    //we only allow appending, not replacing.
         unsigned nnz         = row.get_non_zero_ids().size();
         unsigned newRowIndex = rowNumber;
-        if (newRowIndex < minNumber) {
-            throw MAiNGOException("Tried to append a row to a sparse matrix, but given row index lead to an insertion. Requested row index to append: " + std::to_string(rowNumber) + " index of last row already in matrix: " + std::to_string(minNumber - 1));
+        if (newRowIndex < minNumber) { // GCOVR_EXCL_START
+            throw MAiNGOException("Tried to append a row to a sparse matrix, but given row index lead to an insertion. Requested row index to append: " + std::to_string(rowNumber) + " index of last row already in matrix: " + std::to_string(minNumber - 1)); // GCOVR_EXCL_LINE
         }
-        for (unsigned i = 0; i < nnz; i++) {
+        for (unsigned i = 0; i < nnz; i++) { // GCOVR_EXCL_STOP
             //efficently inserts at the end of the map!
             _matrix.insert(std::end(_matrix), std::make_pair(std::make_pair(newRowIndex, row.get_non_zero_ids()[i]), row.get_non_zero_values()[i]));
         }
@@ -789,10 +789,10 @@ class LazyQuadExprTreeNode {
 
             switch (_op) {
                 case (OperationType::IDENITY): {
-                    if (_order == Order::QUADRATIC) {
-                        throw MAiNGOException(std::string("It should be impossible to create a lazy quadratic expression without creating it from linear expressions") + std::string("but the lazy quadratic expression tree still has an element that claims to be quadratic and an original expression."));
+                    if (_order == Order::QUADRATIC) { // GCOVR_EXCL_START
+                        throw MAiNGOException(std::string("It should be impossible to create a lazy quadratic expression without creating it from linear expressions") + std::string("but the lazy quadratic expression tree still has an element that claims to be quadratic and an original expression.")); //GCOVR_EXCL_LINE
                     }
-                    result.linearPart = *_linearContent;
+                    result.linearPart = *_linearContent; // GCOVR_EXCL_STOP
                     return result;
                 }
                 case (OperationType::MINUS): {
@@ -933,10 +933,10 @@ operator*(std::shared_ptr<LazyQuadExprTreeNode> LHS, std::shared_ptr<LazyQuadExp
     bool resultQuadratic         = (LHS->is_linear() && RHS->is_linear()) || (LHS->is_quadratic() && RHS->is_scalar()) || (LHS->is_scalar() && RHS->is_quadratic());
     bool resultScalar            = LHS->is_scalar() && RHS->is_scalar();
     LazyQuadExprTreeNode::Order resultOrder;
-    if (resultMoreThanQuadratic) {
+    if (resultMoreThanQuadratic) { // GCOVR_EXCL_START
         throw MAiNGOException(("Cant multiply already quadratic expressions to generate a quadratic expression"));
     }
-    else if (resultQuadratic) {
+    else if (resultQuadratic) { // GCOVR_EXCL_STOP
         resultOrder = LazyQuadExprTreeNode::Order::QUADRATIC;
     }
     else if (resultScalar) {
@@ -957,10 +957,10 @@ inline std::shared_ptr<LazyQuadExprTreeNode>
 operator/(std::shared_ptr<LazyQuadExprTreeNode> LHS, std::shared_ptr<LazyQuadExprTreeNode> RHS)
 {
     LazyQuadExprTreeNode::Order resultOrder = LazyQuadExprTreeNode::Order::SCALAR;
-    if (!RHS->is_scalar()) {
+    if (!RHS->is_scalar()) { // GCOVR_EXCL_START
         throw MAiNGOException("Function 1/x not allowed in (MIQ)Ps.");
     }
-    if (LHS->is_linear()) {
+    if (LHS->is_linear()) { // GCOVR_EXCL_STOP
         resultOrder = LazyQuadExprTreeNode::Order::LINEAR;
     }
     else if (LHS->is_quadratic()) {
@@ -985,10 +985,10 @@ class LazyQuadExpr {
 	*/
     LazyQuadExpr(unsigned numberVars, unsigned active_index)
     {
-        if (active_index >= numberVars) {
-            throw MAiNGOException("Tried to create an lazy quadratic expresion for a variable with an index that is inconsistent with the specified number of variables");
+        if (active_index >= numberVars) { // GCOVR_EXCL_START
+            throw MAiNGOException("Tried to create an lazy quadratic expresion for a variable with an index that is inconsistent with the specified number of variables"); //GCOVR_EXCL_LINE
         }
-        LinExpr lin(0.0);
+        LinExpr lin(0.0); // GCOVR_EXCL_STOP
         lin.set_value(active_index, 1.0);
         _tree = std::make_shared<LazyQuadExprTreeNode>(lin);
     }
@@ -1118,14 +1118,14 @@ operator/(const LazyQuadExpr& LHS, double scalar)
 inline LazyQuadExpr
 operator/(const double in1, const LazyQuadExpr& in2)
 {
-    throw MAiNGOException("  Error: LazyQuadExpr -- function 1/x not allowed in (MIQ)Ps.");
+    throw MAiNGOException("  Error: LazyQuadExpr -- function 1/x not allowed in (MIQ)Ps."); // GCOVR_EXCL_LINE
 }
 
 /** @brief Operator/ for division of an int by an LazyQuadExpr */
 inline LazyQuadExpr
 operator/(const int in1, const LazyQuadExpr& in2)
 {
-    throw MAiNGOException("  Error: LazyQuadExpr -- function 1/x not allowed in (MIQ)Ps.");
+    throw MAiNGOException("  Error: LazyQuadExpr -- function 1/x not allowed in (MIQ)Ps."); // GCOVR_EXCL_LINE
 }
 
 
diff --git a/setup.py b/setup.py
index 12c027170d869949999864cadfaaf1447dccf208..3aa34f1b9f99cea2d6b2d6e289d45038ed1bef0f 100644
--- a/setup.py
+++ b/setup.py
@@ -52,13 +52,14 @@ setup(
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
         'Programming Language :: Python :: 3.11',
+        'Programming Language :: Python :: 3.12',
         'Operating System :: Microsoft :: Windows',
         'Operating System :: POSIX :: Linux',
         'Operating System :: MacOS :: MacOS X',
     ],
     keywords=['optimization','global','nonlinear programming','mixed integer','NLP','MINLP','MAiNGO'],
     cmake_languages=['CXX','C','Fortran'],
-    cmake_minimum_required_version='3.15',
+    cmake_minimum_required_version='3.19',
     cmake_install_dir='maingopy',
     cmake_process_manifest_hook=exclude_static_libraries,
 )
\ No newline at end of file
diff --git a/src/MAiNGO.cpp b/src/MAiNGO.cpp
index c5aab75ca95125fb7d461a2080081303ad82cdea..1fa710c71a455f4d80cf55bf15de8a55cde77ab2 100644
--- a/src/MAiNGO.cpp
+++ b/src/MAiNGO.cpp
@@ -19,15 +19,16 @@
 #include "mpiUtilities.h"
 #include "ubp.h"
 
+#include <cassert>
+
 
 using namespace maingo;
 
 
 /////////////////////////////////////////////////////////////////////////
-// constructor which initializes models and solvers and performs a sanity check on the model
-MAiNGO::MAiNGO(std::shared_ptr<MAiNGOmodel> myModel)
+// constructor that does not require a model (model can be set later)
+MAiNGO::MAiNGO()
 {
-
 #ifdef HAVE_MAiNGO_MPI
     // Set MPI variables
     MPI_Comm_rank(MPI_COMM_WORLD, &_rank);
@@ -36,8 +37,15 @@ MAiNGO::MAiNGO(std::shared_ptr<MAiNGOmodel> myModel)
         throw MAiNGOException("  Error initializing MAiNGO: The parallel version of MAiNGO requires at least 2 MPI processes.");
     }
 #endif
+    _modelSpecified     = false;
+    _DAGconstructed     = false;
+}
 
-    // Initialize  internal model representation
+
+/////////////////////////////////////////////////////////////////////////
+// constructor that requires a model
+MAiNGO::MAiNGO(std::shared_ptr<MAiNGOmodel> myModel) : MAiNGO()
+{
     set_model(myModel);
 }
 
@@ -48,7 +56,7 @@ RETCODE
 MAiNGO::solve()
 {
 
-    if (!_readyToSolve) {
+    if (!_modelSpecified) {
         throw MAiNGOException("  Error trying to solve problem: Model has not been set successfully.");
     }
 
@@ -121,7 +129,7 @@ MAiNGO::solve()
                 throw;
             MAiNGO_END_IF
     }
-    catch (...) {
+    catch (...) {   // GCOVR_EXCL_START
         MAiNGO_IF_BAB_MANAGER
             _write_files_error("  Encountered an unknown fatal error during DAG construction.");
             throw MAiNGOException("  Encountered an unknown fatal error during DAG construction.");
@@ -129,13 +137,8 @@ MAiNGO::solve()
                 throw;
             MAiNGO_END_IF
     }
-    if (_nobj > 1) {
-        MAiNGO_IF_BAB_MANAGER
-            throw MAiNGOException("  Error: Problem contains more than one objective. Did you want to call solve_epsilon_constraint instead of solve?");
-            MAiNGO_ELSE
-                throw;
-            MAiNGO_END_IF
-    }
+    // GCOVR_EXCL_STOP
+
     MAiNGO_IF_BAB_MANAGER
         _print_info_about_initial_point();
     MAiNGO_END_IF
@@ -177,7 +180,7 @@ RETCODE
 MAiNGO::solve_epsilon_constraint()
 {
 
-    if (!_readyToSolve) {
+    if (!_modelSpecified) {
         throw MAiNGOException("  Error trying to solve problem: Model has not been set successfully.");
     }
 
@@ -214,7 +217,6 @@ MAiNGO::solve_epsilon_constraint()
     MAiNGO_END_IF
     MAiNGO_MPI_BARRIER
 
-
         // ---------------------------------------------------------------------------------
         // 2: Get information on model
         // ---------------------------------------------------------------------------------
@@ -227,8 +229,31 @@ MAiNGO::solve_epsilon_constraint()
                 throw;
             MAiNGO_END_IF
     }
-    EvaluationContainer userResult = epsConModel->evaluate_user_model(std::vector<mc::FFVar>(_nvarOriginal));
-    size_t nObj                    = userResult.objective.size();
+    EvaluationContainer userResult;
+    try {
+        userResult = epsConModel->evaluate_user_model(std::vector<mc::FFVar>(_nvarOriginal));
+    }
+    catch (const std::exception& e) {
+        MAiNGO_IF_BAB_MANAGER
+            std::ostringstream errmsg;
+            errmsg << e.what() << "\n  Encountered a fatal error while evaluating model in epsilon constraint method.";
+            _write_files_error(errmsg.str());
+            throw MAiNGOException("  Encountered a fatal error while evaluating model in epsilon constraint method.", e);
+            MAiNGO_ELSE
+                throw;
+            MAiNGO_END_IF
+    }
+    catch (...) {   // GCOVR_EXCL_START
+        MAiNGO_IF_BAB_MANAGER
+            _write_files_error("  Encountered an unknown fatal error while evaluating model in epsilon constraint method.");
+            throw MAiNGOException("  Encountered an unknown fatal error while evaluating model in epsilon constraint method.");
+            MAiNGO_ELSE
+                throw;
+            MAiNGO_END_IF
+    }
+    //GCOVR_EXCL_STOP
+
+    size_t nObj = userResult.objective.size();
     if (nObj != 2) {
         MAiNGO_IF_BAB_MANAGER
             throw MAiNGOException("  Error in epsilon-constraint method: currently only supporting exactly two objectives.");
@@ -259,7 +284,7 @@ MAiNGO::solve_epsilon_constraint()
         try {
             _construct_DAG();
         }
-        catch (const std::exception& e) {
+        catch (const std::exception& e) {   //GCOVR_EXCL_START
             MAiNGO_IF_BAB_MANAGER
                 std::ostringstream errmsg;
                 errmsg << e.what() << "\n  Encountered a fatal error during DAG construction.";
@@ -277,6 +302,8 @@ MAiNGO::solve_epsilon_constraint()
                     throw;
                 MAiNGO_END_IF
         }
+        //GCOVR_EXCL_STOP
+
         status = _analyze_and_solve_problem();
         MAiNGO_IF_BAB_MANAGER
             // Print problem statistics, solution, additional output & CPU time.
@@ -287,7 +314,7 @@ MAiNGO::solve_epsilon_constraint()
             _print_time();
             if (status == INFEASIBLE) {
                 if (iObj != 0) {
-                    _print_message(std::string("*** Error in epsilon-constraint: false infeasibility claim ***"));
+                    _print_message(std::string("*** Error in epsilon-constraint: false infeasibility claim ***")); // GCOVR_EXCL_LINE
                 }
                 else {
                     _print_message(std::string("*** Problem is infeasible. Stopping epsilon-constraint method. ***"));
@@ -318,6 +345,7 @@ MAiNGO::solve_epsilon_constraint()
 #endif
             MAiNGO_END_IF
             *_maingoSettings = _maingoOriginalSettings;
+
             // Next, minimize the other objective s.t. iObj stays the same
             MAiNGO_IF_BAB_MANAGER
                 // Reset timing for this run and give intermediate output
@@ -341,7 +369,7 @@ MAiNGO::solve_epsilon_constraint()
             try {
                 _construct_DAG();
             }
-            catch (const std::exception& e) {
+            catch (const std::exception& e) {   // GCOVR_EXCL_START
                 MAiNGO_IF_BAB_MANAGER
                     std::ostringstream errmsg;
                     errmsg << e.what() << "\n  Encountered a fatal error during DAG construction.";
@@ -359,6 +387,8 @@ MAiNGO::solve_epsilon_constraint()
                         throw;
                     MAiNGO_END_IF
             }
+            // GCOVR_EXCL_STOP
+
             status = _analyze_and_solve_problem();
             MAiNGO_IF_BAB_MANAGER
                 // Print problem statistics, solution, additional output & CPU time.
@@ -368,17 +398,12 @@ MAiNGO::solve_epsilon_constraint()
                 _print_additional_output();
                 _print_time();
                 if (status == INFEASIBLE) {
-                    if (iObj != 0) {
-                        _print_message(std::string("*** Error in epsilon-constraint: false infeasibility claim ***"));
-                    }
-                    else {
-                        _print_message(std::string("*** Problem is infeasible. Stopping epsilon-constraint method. ***"));
-                    }
+                    _print_message(std::string("*** Error in epsilon-constraint: false infeasibility claim ***"));  // GCOVR_EXCL_LINE
 #ifdef HAVE_MAiNGO_MPI
                     BCAST_TAG bcastTag = BCAST_EXCEPTION;
                     MPI_Bcast(&bcastTag, 1, MPI_INT, 0, MPI_COMM_WORLD);
 #endif
-                    break;
+                    break;  // GCOVR_EXCL_LINE
                 }
                 std::vector<std::pair<std::string, double>> tmpOutput2 = evaluate_additional_outputs_at_solution_point();
                 for (size_t jObj = 0; jObj < nObj; jObj++) {
@@ -439,7 +464,7 @@ MAiNGO::solve_epsilon_constraint()
                 try {
                     _construct_DAG();
                 }
-                catch (const std::exception& e) {
+                catch (const std::exception& e) {   // GCOVR_EXCL_START
                     MAiNGO_IF_BAB_MANAGER
                         std::ostringstream errmsg;
                         errmsg << e.what() << "\n  Encountered a fatal error during DAG construction.";
@@ -457,6 +482,8 @@ MAiNGO::solve_epsilon_constraint()
                             throw;
                         MAiNGO_END_IF
                 }
+                // GCOVR_EXCL_STOP
+
                 status = _analyze_and_solve_problem();
                 MAiNGO_IF_BAB_MANAGER
                     // Print problem statistics, solution, additional output & CPU time.
@@ -466,12 +493,12 @@ MAiNGO::solve_epsilon_constraint()
                     _print_additional_output();
                     _print_time();
                     if (status == INFEASIBLE) {
-                        _print_message(std::string("*** Error in epsilon-constraint: false infeasibility claim ***"));
+                        _print_message(std::string("*** Error in epsilon-constraint: false infeasibility claim ***"));    //GCOVR_EXCL_LINE
 #ifdef HAVE_MAiNGO_MPI
                         BCAST_TAG bcastTag = BCAST_EXCEPTION;
                         MPI_Bcast(&bcastTag, 1, MPI_INT, 0, MPI_COMM_WORLD);
 #endif
-                        break;
+                        break;  //GCOVR_EXCL_LINE
                     }
                     std::vector<double> tmpObjectives(nObj);
                     std::vector<std::pair<std::string, double>> tmpOutput = evaluate_additional_outputs_at_solution_point();
@@ -524,6 +551,7 @@ MAiNGO::solve_epsilon_constraint()
 RETCODE
 MAiNGO::_analyze_and_solve_problem()
 {
+    assert(_nobj == 1);
 
     // Proceed only if the problem is not already found to be infeasible because of constant, infeasible constraints (e.g., 2<=1; this is checked in _construct_DAG()) or inconsistent variable bounds (e.g., x in [0,-1]; this is checked in set_model)
     if (_constantConstraintsFeasible && _infeasibleVariables.empty()) {
@@ -537,7 +565,7 @@ MAiNGO::_analyze_and_solve_problem()
             _set_constraint_and_variable_properties();
             MAiNGO_MPI_BARRIER
         }
-        catch (const std::exception& e) {
+        catch (const std::exception& e) {   // GCOVR_EXCL_START
             MAiNGO_IF_BAB_MANAGER
                 std::ostringstream errmsg;
                 errmsg << e.what() << "\n  Encountered a fatal error during structure recognition.";
@@ -555,6 +583,7 @@ MAiNGO::_analyze_and_solve_problem()
                     throw;
                 MAiNGO_END_IF
         }
+        // GCOVR_EXCL_STOP
 
         // ---------------------------------------------------------------------------------
         // 4: Solve the problem
@@ -647,6 +676,7 @@ MAiNGO::_analyze_and_solve_problem()
 RETCODE
 MAiNGO::_solve_MIQP()
 {
+    assert(_nobj == 1);
 
     MAiNGO_IF_BAB_MANAGER
         try {
@@ -685,11 +715,8 @@ MAiNGO::_solve_MIQP()
                     }
                     break;
                 }
-                default: {
-                    std::ostringstream errmsg;
-                    errmsg << "    Error in _solve_MIQP: Unknown lower bounding solver: " << _maingoSettings->LBP_solver;
-                    throw MAiNGOException(errmsg.str());
-                }
+                default:    // GCOVR_EXCL_LINE
+                    throw MAiNGOException("    Error in _solve_MIQP: Unknown lower bounding solver: " + std::to_string(_maingoSettings->LBP_solver));   // GCOVR_EXCL_LINE
             }
 #else
             // It is not possible to reach this point with a problem which is not an LP due to the code in lines 564-601
@@ -722,6 +749,7 @@ MAiNGO::_solve_MIQP()
             }
 #endif
             _print_third_party_software_miqp();
+
             _initialize_solve();
             _logger->print_message(aboutSolver, VERB_NORMAL, BAB_VERBOSITY);
             _preprocessTime = get_cpu_time() - _preprocessTime;
@@ -759,7 +787,7 @@ MAiNGO::_solve_MIQP()
             throw MAiNGOException("  Encountered a fatal error during MIQP solution.", e);
         }
 #endif
-        catch (const std::exception& e) {
+        catch (const std::exception& e) {   // GCOVR_EXCL_START
 #ifdef HAVE_MAiNGO_MPI
             BCAST_TAG bcastTag = BCAST_EXCEPTION;
             MPI_Bcast(&bcastTag, 1, MPI_INT, 0, MPI_COMM_WORLD);
@@ -787,6 +815,7 @@ MAiNGO::_solve_MIQP()
             }
         MAiNGO_END_IF
 #endif
+        // GCOVR_EXCL_STOP
         return _maingoStatus;
 }
 
@@ -796,6 +825,7 @@ MAiNGO::_solve_MIQP()
 RETCODE
 MAiNGO::_solve_MINLP()
 {
+    assert(_nobj == 1);
 
     try {
 
@@ -966,6 +996,7 @@ MAiNGO::_solve_MINLP()
 
         return _maingoStatus;
     }
+    // GCOVR_EXCL_START
 #ifdef HAVE_MAiNGO_MPI
     catch (MAiNGOMpiException& e) {
         MAiNGO_IF_BAB_MANAGER
@@ -996,6 +1027,7 @@ MAiNGO::_solve_MINLP()
                 throw;
             MAiNGO_END_IF
     }
+    // GCOVR_EXCL_STOP
 }
 
 
@@ -1015,7 +1047,7 @@ MAiNGO::set_model(std::shared_ptr<MAiNGOmodel> myModel)
         MAiNGO_END_IF
         _problemStructure   = MINLP;    // default
         _feasibilityProblem = false;
-        _readyToSolve       = false;
+        _modelSpecified     = false;
         _DAGconstructed     = false;
 
         // Store pointer to problem
@@ -1049,8 +1081,8 @@ MAiNGO::set_model(std::shared_ptr<MAiNGOmodel> myModel)
                 case babBase::enums::VT_INTEGER:
                     _nvarOriginalInteger++;
                     break;
-                default:
-                    break;
+                default:    // GCOVR_EXCL_LINE
+                    throw MAiNGOException("  MAiNGO: Error while setting model: unknown variable type " + std::to_string(_originalVariables[i].get_variable_type()));   //GCOVR_EXCL_LINE
             }
         }
 
@@ -1063,7 +1095,7 @@ MAiNGO::set_model(std::shared_ptr<MAiNGOmodel> myModel)
         }
 
         // Confirm model is ready to use
-        _readyToSolve = true;
+        _modelSpecified = true;
 }
 
 
@@ -1212,7 +1244,7 @@ MAiNGO::_construct_DAG()
         try {
             _add_auxiliary_variables_to_lbd_dag();
         }
-        catch (const filib::interval_io_exception& e) {
+        catch (const filib::interval_io_exception& e) { // GCOVR_EXCL_START
             MAiNGO_IF_BAB_MANAGER
                 const std::string errmsg = "  Encountered a fatal error in intervals while adding auxiliary variables to the DAG used for lower bounding.";
                 std::ostringstream completeMessage;
@@ -1269,6 +1301,7 @@ MAiNGO::_construct_DAG()
                     throw;
                 MAiNGO_END_IF
         }
+        // GCOVR_EXCL_STOP
     }
 
     _DAGconstructed = true;
@@ -1315,7 +1348,7 @@ MAiNGO::_initialize_solve()
             _myLBS->pass_data_position_to_solver(_datasets, 1 + _nineq + _neq + _nineqSquash + _nineqRelaxationOnly + _neqRelaxationOnly + _nauxiliaryRelOnlyEqs);
 #endif    // HAVE_GROWING_DATASETS
 
-            _myBaB = std::make_shared<bab::BranchAndBound>(_variablesLbd, _myLBS, _myUBSBab, _maingoSettings, _logger, /*number of variables w/o auxiliaries*/ _nvar);
+            _myBaB = std::make_shared<bab::BranchAndBound>(_variablesLbd, _myLBS, _myUBSBab, _maingoSettings, _logger, /*number of variables w/o auxiliaries*/ _nvar, _inputStream);
 
 #if defined(MAiNGO_DEBUG_MODE) && defined(HAVE_GROWING_DATASETS)
             _myLBSFull = nullptr;
@@ -1407,7 +1440,7 @@ MAiNGO::_root_obbt_feasibility()
             try {
                 _rootObbtStatus = _myLBS->solve_OBBT(_rootNode, _maingoSettings->infinity, lbp::OBBT_FEAS, true /*include linear variables*/);
             }
-            catch (std::exception& e) {
+            catch (std::exception& e) { // GCOVR_EXCL_START
 #ifdef HAVE_MAiNGO_MPI
                 // Inform workers about exceptions
                 BCAST_TAG bcastTag = BCAST_EXCEPTION;
@@ -1423,6 +1456,8 @@ MAiNGO::_root_obbt_feasibility()
 #endif
                 throw MAiNGOException("  Encountered an unknown fatal error during feasibility-based OBBT during pre-processing.");
             }
+            // GCOVR_EXCL_STOP
+
             // If we make no more progress or prove infeasibility, terminate
             if ((_rootObbtStatus == TIGHTENING_INFEASIBLE) || (_rootObbtStatus == TIGHTENING_UNCHANGED)) {
                 break;
@@ -1476,7 +1511,7 @@ MAiNGO::_root_obbt_feasibility_optimality()
         try {
             _rootObbtStatus = _myLBS->solve_OBBT(tmpNode, _solutionValue, lbp::OBBT_FEASOPT, true /*include linear variables*/);
         }
-        catch (std::exception& e) {
+        catch (std::exception& e) { // GCOVR_EXCL_START
 #ifdef HAVE_MAiNGO_MPI
             // Inform workers about exceptions
             BCAST_TAG bcastTag = BCAST_EXCEPTION;
@@ -1491,8 +1526,9 @@ MAiNGO::_root_obbt_feasibility_optimality()
 #endif
             throw MAiNGOException("  Encountered an unknown fatal error during feasibility- and optimality-based OBBT during pre-processing.");
         }
+        // GCOVR_EXCL_STOP
 
-        if (_rootObbtStatus == TIGHTENING_INFEASIBLE) {
+        if (_rootObbtStatus == TIGHTENING_INFEASIBLE) { // GCOVR_EXCL_START
             std::string str = "      Warning: OBBT declared the problem infeasible although a feasible point was found.\n";
             str += "               This may be caused by numerical difficulties or an isolated optimum in your model.\n";
             str += "               Turning off OBBT, restoring valid bounds and proceeding...\n";
@@ -1508,6 +1544,7 @@ MAiNGO::_root_obbt_feasibility_optimality()
             BCAST_TAG tag = BCAST_FEASIBLE;
             MPI_Bcast(&tag, 1, MPI_INT, 0, MPI_COMM_WORLD);
 #endif
+        // GCOVR_EXCL_STOP
         }
         else if (_rootObbtStatus == TIGHTENING_CHANGED) {
             _rootNode = tmpNode;
@@ -1555,7 +1592,7 @@ MAiNGO::_root_constraint_propagation()
         // If we prove infeasibility, don't overwrite root node
         if (_rootConPropStatus == TIGHTENING_INFEASIBLE) {
             // Don't overwrite root node
-            if (_rootMultistartStatus == SUBSOLVER_FEASIBLE) {    // Something went wrong
+            if (_rootMultistartStatus == SUBSOLVER_FEASIBLE) {    // GCOVR_EXCL_START
                 std::string str = "      Warning: Constraint propagation declared the problem infeasible although a feasible point was found.\n";
                 str += "               This may be caused by numerical difficulties.\n";
                 str += "               Turning off constraint propagation, restoring valid bounds and proceeding...\n";
@@ -1566,6 +1603,7 @@ MAiNGO::_root_constraint_propagation()
                 BCAST_TAG tag = BCAST_CONSTR_PROP_INFEASIBLE;
                 MPI_Bcast(&tag, 1, MPI_INT, 0, MPI_COMM_WORLD);
 #endif
+            // GCOVR_EXCL_STOP
             }
             else {
                 _logger->print_message("      Found problem to be infeasible.\n", VERB_NORMAL, BAB_VERBOSITY);
@@ -1737,9 +1775,8 @@ MAiNGO::_recognize_structure()
             case mc::FFDep::D:
                 temp = integer ? MINLP : DNLP;
                 break;
-            default:
-                temp = integer ? MINLP : NLP;
-                break;
+            default:    // GCOVR_EXCL_LINE
+                throw MAiNGOException("Error recognizing structure: unknown dependency type " + std::to_string(functionsStructure[i])); //GCOVR_EXCL_LINE
         }
         _problemStructure = std::max(_problemStructure, temp);
     }
@@ -1766,9 +1803,8 @@ MAiNGO::_recognize_structure()
         case MINLP:
             _logger->print_message("\n  The problem is an MINLP", VERB_ALL, BAB_VERBOSITY);
             break;
-        default:
-            _logger->print_message("\n  Could not recognize structure", VERB_ALL, BAB_VERBOSITY);
-            break;
+        default:    // GCOVR_EXCL_LINE
+            throw MAiNGOException("Error recognizing structure: unknown problem structure " + std::to_string(_problemStructure)); //GCOVR_EXCL_LINE
     }
 }
 
@@ -2153,10 +2189,10 @@ MAiNGO::_check_for_hidden_zero_constraints(const std::vector<mc::FFVar>& tmpDAGV
                     break;
                 case INEQ_SQUASH:
                     _nineqSquash--;
-                    _nineqSquash++;
-                    break;
-                default:
+                    _nconstantIneqSquash++;
                     break;
+                default:    // GCOVR_EXCL_LINE
+                    throw MAiNGOException("Error recognizing hidden zeros in problem: Unknown constraint type " + std::to_string((*_nonconstantConstraints)[i].type));    // GCOVR_EXCL_LINE
 
             }    // End of switch
             // Erase the constraint from nonconstant constraints and insert it into the constant constraints vector
@@ -2194,6 +2230,7 @@ MAiNGO::_check_for_hidden_zero_constraints(const std::vector<mc::FFVar>& tmpDAGV
         }
     }                                                                // End of for loop over _resultVars - _noutputVariables
     std::reverse(tmpDAGFunctions.begin(), tmpDAGFunctions.end());    // Reverse the ordering to be equal to initial user input
+
     // Update nonconstant and constant index of constraints
     if (updateIndices) {
         unsigned indexObj = 0, indexIneq = 0, indexEq = 0, indexIneqRelOnly = 0, indexEqRelOnly = 0, indexIneqSquash = 0;
@@ -2225,8 +2262,8 @@ MAiNGO::_check_for_hidden_zero_constraints(const std::vector<mc::FFVar>& tmpDAGV
                     (*_nonconstantConstraints)[i].indexTypeNonconstant                                        = indexIneqSquash;
                     (*_originalConstraints)[(*_nonconstantConstraints)[i].indexOriginal].indexTypeNonconstant = indexIneqSquash++;
                     break;
-                default:
-                    break;
+                default:    // GCOVR_EXCL_LINE
+                    throw MAiNGOException("Error recognizing hidden zeros in problem: Unknown constraint type " + std::to_string((*_nonconstantConstraints)[i].type));    // GCOVR_EXCL_LIN
             }
         }
         indexObj         = 0;
@@ -2263,11 +2300,12 @@ MAiNGO::_check_for_hidden_zero_constraints(const std::vector<mc::FFVar>& tmpDAGV
                     (*_constantConstraints)[i].indexTypeConstant                                        = indexIneqSquash;
                     (*_originalConstraints)[(*_constantConstraints)[i].indexOriginal].indexTypeConstant = indexIneqSquash++;
                     break;
-                default:
-                    break;
+                default:    // GCOVR_EXCL_LINE
+                    throw MAiNGOException("Error recognizing hidden zeros in problem: Unknown constraint type " + std::to_string((*_nonconstantConstraints)[i].type));    // GCOVR_EXCL_LINE
             }
         }
     }
+
     // Check if resulting output functions are constant
     updateIndices               = false;
     unsigned newConstantOutputs = 0;
@@ -2319,6 +2357,7 @@ MAiNGO::_check_for_hidden_zero_constraints(const std::vector<mc::FFVar>& tmpDAGV
             (*_constantOutputs)[i].indexConstant = i;
         }
     }
+
     return foundHiddenZero;
 }
 
diff --git a/src/MAiNGOException.cpp b/src/MAiNGOException.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3b15c563e83abb06ee26b02e9a3a56619b5c218d
--- /dev/null
+++ b/src/MAiNGOException.cpp
@@ -0,0 +1,102 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGOException.h"
+
+#include <typeinfo>
+
+
+using namespace maingo;
+
+
+
+//////////////////////////////////////////////////////////////////////////
+MAiNGOException::MAiNGOException(const std::string& errorMessage)
+{
+    _construct_complete_error_message(errorMessage, nullptr, nullptr);
+}
+
+//////////////////////////////////////////////////////////////////////////
+MAiNGOException::MAiNGOException(const std::string& errorMessage, const babBase::BabNode& nodeThatErrorOccurredIn)
+{
+    _construct_complete_error_message(errorMessage, nullptr, &nodeThatErrorOccurredIn);
+}
+
+//////////////////////////////////////////////////////////////////////////
+MAiNGOException::MAiNGOException(const std::string& errorMessage, const std::exception& originalException)
+{
+    _construct_complete_error_message(errorMessage, &originalException, nullptr);
+}
+
+//////////////////////////////////////////////////////////////////////////
+MAiNGOException::MAiNGOException(const std::string& errorMessage, const std::exception& originalException, const babBase::BabNode& nodeThatErrorOccurredIn)
+{
+    _construct_complete_error_message(errorMessage, &originalException, &nodeThatErrorOccurredIn);
+}
+
+//////////////////////////////////////////////////////////////////////////
+const char*
+MAiNGOException::what() const noexcept
+{
+    return _errorMessage.c_str();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void
+MAiNGOException::_construct_complete_error_message(const std::string& errorMessage, const std::exception* originalException, const babBase::BabNode* nodeThatErrorOccurredIn)
+{
+    std::ostringstream errorMessageStream;
+
+    _append_original_exception_info_to_message(originalException, errorMessageStream);
+    _append_current_error_message_to_message(errorMessage, errorMessageStream);
+    _append_node_info_to_message(nodeThatErrorOccurredIn, errorMessageStream);
+
+    _errorMessage = errorMessageStream.str();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void
+MAiNGOException::_append_current_error_message_to_message(const std::string& currentErrorMessage, std::ostringstream& completeErrorMessage)
+{
+    completeErrorMessage << currentErrorMessage;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void
+MAiNGOException::_append_original_exception_info_to_message(const std::exception* originalException, std::ostringstream& completeErrorMessage)
+{
+    if (originalException) {
+        if (typeid(*originalException).name() != typeid(*this).name()) {
+            completeErrorMessage << "  Original exception type: " << typeid(*originalException).name() << ": " << std::endl
+                                 << "   ";
+        }
+        completeErrorMessage << originalException->what() << std::endl;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void
+MAiNGOException::_append_node_info_to_message(const babBase::BabNode* nodeThatErrorOccurredIn, std::ostringstream& completeErrorMessage)
+{
+    if (nodeThatErrorOccurredIn) {
+        std::vector<double> lowerVarBounds(nodeThatErrorOccurredIn->get_lower_bounds()), upperVarBounds(nodeThatErrorOccurredIn->get_upper_bounds());
+        completeErrorMessage << std::endl
+                             << "  Exception was thrown while processing node no. " << nodeThatErrorOccurredIn->get_ID() << ":";
+        for (size_t i = 0; i < lowerVarBounds.size(); i++) {
+            completeErrorMessage << std::endl
+                                 << "    x(" << i << "): " << std::setprecision(16) << lowerVarBounds[i] << ":" << upperVarBounds[i];
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/MAiNGOevaluationFunctions.cpp b/src/MAiNGOevaluationFunctions.cpp
index 3b824677585c02e59541e1b72e0b25908ad30bbc..f5d1ecc7d3bf4c43fded3db0ff5c4135584ca78a 100644
--- a/src/MAiNGOevaluationFunctions.cpp
+++ b/src/MAiNGOevaluationFunctions.cpp
@@ -21,7 +21,6 @@ using namespace maingo;
 std::vector<double>
 MAiNGO::evaluate_model_at_solution_point()
 {
-
     // Problem has to be solved
     if (_solutionPoint.empty()) {
         std::ostringstream errmsg;
@@ -41,7 +40,6 @@ MAiNGO::evaluate_model_at_solution_point()
 std::vector<std::pair<std::string, double>>
 MAiNGO::evaluate_additional_outputs_at_solution_point()
 {
-
     // Return variable additional model outputs
     if (_solutionPoint.empty()) {
         std::ostringstream errmsg;
@@ -63,18 +61,17 @@ MAiNGO::evaluate_additional_outputs_at_solution_point()
 std::pair<std::vector<double>, bool>
 MAiNGO::evaluate_model_at_point(const std::vector<double> &point)
 {
+    if (!_modelSpecified) {
+        std::ostringstream errmsg;
+        errmsg << "  MAiNGO: Error in get_model_at_point. Model has not been set yet.";
+        throw MAiNGOException(errmsg.str());
+    }
 
     // DAG has to be constructed
     if (!_DAGconstructed) {
         _construct_DAG();
     }
 
-    if (!_readyToSolve) {
-        std::ostringstream errmsg;
-        errmsg << "  MAiNGO: Error in get_model_at_point. Model has not been set yet.";
-        throw MAiNGOException(errmsg.str());
-    }
-
     if (point.size() != _nvarOriginal) {
         std::ostringstream errmsg;
         errmsg << "  MAiNGO: The dimension of the point in function get_model_at_point does not match the dimensions of the set MAiNGO model.";
@@ -116,17 +113,16 @@ MAiNGO::evaluate_model_at_point(const std::vector<double> &point)
 std::vector<std::pair<std::string, double>>
 MAiNGO::evaluate_additional_outputs_at_point(const std::vector<double> &point)
 {
-    // DAG has to be constructed
-    if (!_DAGconstructed) {
-        _construct_DAG();
-    }
-
-    if (!_readyToSolve) {
+    if (!_modelSpecified) {
         std::ostringstream errmsg;
         errmsg << "  MAiNGO: Error in get_additional_output_at_point. Model has not been set yet.";
         throw MAiNGOException(errmsg.str());
     }
 
+    if (!_DAGconstructed) {
+        _construct_DAG();
+    }
+
     if (point.size() != _nvarOriginal) {
         std::ostringstream errmsg;
         errmsg << "  MAiNGO: The dimension of the point in function get_additional_output_at_point does not match the dimensions of the set MAiNGO model.";
@@ -151,19 +147,20 @@ MAiNGO::evaluate_additional_outputs_at_point(const std::vector<double> &point)
 std::vector<std::pair<std::string, double>>
 MAiNGO::_evaluate_additional_outputs_at_point(const std::vector<double> &pointUsed)
 {
-
     // Match each DAG variable to a double variable
     // Evaluate DAG to compute outputs
     std::vector<double> outputRes(_DAGoutputFunctions.size());
     try {
         _DAG.eval(_DAGoutputFunctions.size(), _DAGoutputFunctions.data(), outputRes.data(), _nvar, _DAGvars.data(), pointUsed.data());
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  MAiNGO: Error while evaluating additional user outputs.", e);
     }
     catch (...) {
         throw MAiNGOException("  MAiNGO: Unknown error while evaluating additional user outputs.");
     }
+    // GCOVR_EXCL_STOP
+    
     // Get additional output, don't forget the constant ones
     std::vector<std::pair<std::string, double>> additionalModelOutputs(_noutputVariables + _nconstantOutputVariables);
     // Non-constant outputs first
diff --git a/src/MAiNGOgetOption.cpp b/src/MAiNGOgetOption.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..660249e7dcd647500ff1d5d7720052b65231c03b
--- /dev/null
+++ b/src/MAiNGOgetOption.cpp
@@ -0,0 +1,202 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+
+using namespace maingo;
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+// function returning the value of a desired option
+double
+MAiNGO::get_option(const std::string& option) const
+{
+    if (option == "epsilonA") {
+        return _maingoSettings->epsilonA;
+    }
+    else if (option == "epsilonR") {
+        return _maingoSettings->epsilonR;
+    }
+    else if (option == "deltaIneq") {
+        return _maingoSettings->deltaIneq;
+    }
+    else if (option == "deltaEq") {
+        return _maingoSettings->deltaEq;
+    }
+    else if (option == "relNodeTol") {
+        return _maingoSettings->relNodeTol;
+    }
+    else if (option == "BAB_maxNodes") {
+        return _maingoSettings->BAB_maxNodes;
+    }
+    else if (option == "BAB_maxIterations") {
+        return _maingoSettings->BAB_maxIterations;
+    }
+    else if (option == "maxTime") {
+        return _maingoSettings->maxTime;
+    }
+    else if (option == "confirmTermination") {
+        return _maingoSettings->confirmTermination;
+    }
+    else if (option == "terminateOnFeasiblePoint") {
+        return _maingoSettings->terminateOnFeasiblePoint;
+    }
+    else if (option == "targetLowerBound") {
+        return _maingoSettings->targetLowerBound;
+    }
+    else if (option == "targetUpperBound") {
+        return _maingoSettings->targetUpperBound;
+    }
+    else if (option == "PRE_maxLocalSearches") {
+        return _maingoSettings->PRE_maxLocalSearches;
+    }
+    else if (option == "PRE_obbtMaxRounds") {
+        return _maingoSettings->PRE_obbtMaxRounds;
+    }
+    else if (option == "PRE_pureMultistart") {
+        return _maingoSettings->PRE_pureMultistart;
+    }
+    else if (option == "BAB_nodeSelection") {
+        return _maingoSettings->BAB_nodeSelection;
+    }
+    else if (option == "BAB_branchVariable") {
+        return _maingoSettings->BAB_branchVariable;
+    }
+    else if (option == "BAB_alwaysSolveObbt") {
+        return _maingoSettings->BAB_alwaysSolveObbt;
+    }
+    else if (option == "BAB_obbtDecayCoefficient") {
+        return _maingoSettings->BAB_obbtDecayCoefficient;
+    }
+    else if (option == "BAB_probing") {
+        return _maingoSettings->BAB_probing;
+    }
+    else if (option == "BAB_dbbt") {
+        return _maingoSettings->BAB_dbbt;
+    }
+    else if (option == "BAB_constraintPropagation") {
+        return _maingoSettings->BAB_constraintPropagation;
+    }
+    else if (option == "LBP_solver") {
+        return _maingoSettings->LBP_solver;
+    }
+    else if (option == "LBP_linPoints") {
+        return _maingoSettings->LBP_linPoints;
+    }
+    else if (option == "LBP_subgradientIntervals") {
+        return _maingoSettings->LBP_subgradientIntervals;
+    }
+    else if (option == "LBP_obbtMinImprovement") {
+        return _maingoSettings->LBP_obbtMinImprovement;
+    }
+    else if (option == "LBP_activateMoreScaling") {
+        return _maingoSettings->LBP_activateMoreScaling;
+    }
+    else if (option == "LBP_addAuxiliaryVars") {
+        return _maingoSettings->LBP_addAuxiliaryVars;
+    }
+    else if (option == "LBP_minFactorsForAux") {
+        return _maingoSettings->LBP_minFactorsForAux;
+    }
+    else if (option == "LBP_maxNumberOfAddedFactors") {
+        return _maingoSettings->LBP_maxNumberOfAddedFactors;
+    }
+    else if (option == "MC_mvcompUse") {
+        return _maingoSettings->MC_mvcompUse;
+    }
+    else if (option == "MC_mvcompTol") {
+        return _maingoSettings->MC_mvcompTol;
+    }
+    else if (option == "MC_envelTol") {
+        return _maingoSettings->MC_envelTol;
+    }
+    else if (option == "UBP_solverPreprocessing") {
+        return _maingoSettings->UBP_solverPreprocessing;
+    }
+    else if (option == "UBP_maxStepsPreprocessing") {
+        return _maingoSettings->UBP_maxStepsPreprocessing;
+    }
+    else if (option == "UBP_maxTimePreprocessing") {
+        return _maingoSettings->UBP_maxTimePreprocessing;
+    }
+    else if (option == "UBP_solverBab") {
+        return _maingoSettings->UBP_solverBab;
+    }
+    else if (option == "UBP_maxStepsBab") {
+        return _maingoSettings->UBP_maxStepsBab;
+    }
+    else if (option == "UBP_maxTimeBab") {
+        return _maingoSettings->UBP_maxTimeBab;
+    }
+    else if (option == "UBP_ignoreNodeBounds") {
+        return _maingoSettings->UBP_ignoreNodeBounds;
+    }
+    else if (option == "EC_nPoints") {
+        return _maingoSettings->EC_nPoints;
+    }
+    else if (option == "LBP_verbosity") {
+        return _maingoSettings->LBP_verbosity;
+    }
+    else if (option == "UBP_verbosity") {
+        return _maingoSettings->UBP_verbosity;
+    }
+    else if (option == "BAB_verbosity") {
+        return _maingoSettings->BAB_verbosity;
+    }
+    else if (option == "BAB_printFreq") {
+        return _maingoSettings->BAB_printFreq;
+    }
+    else if (option == "BAB_logFreq") {
+        return _maingoSettings->BAB_logFreq;
+    }
+    else if (option == "loggingDestination") {
+        return _maingoSettings->loggingDestination;
+    }
+    else if (option == "writeCsv") {
+        return _maingoSettings->writeCsv;
+    }
+    else if (option == "writeJson") {
+        return _maingoSettings->writeJson;
+    }
+    else if (option == "writeResultFile") {
+        return _maingoSettings->writeResultFile;
+    }
+    else if (option == "writeToLogSec") {
+        return _maingoSettings->writeToLogSec;
+    }
+    else if (option == "PRE_printEveryLocalSearch") {
+        return _maingoSettings->PRE_printEveryLocalSearch;
+    }
+    else if (option == "modelWritingLanguage") {
+        return _maingoSettings->modelWritingLanguage;
+    }
+    else if (option == "growing_dataSizeTol") {
+        return _maingoSettings->growing_dataSizeTol;
+    }
+    else if (option == "growing_dataSizeInit") {
+        return _maingoSettings->growing_dataSizeInit;
+    }
+    else if (option == "growing_augmentRule") {
+        return _maingoSettings->growing_augmentRule;
+    }
+    else if (option == "growing_augmentFreq") {
+        return _maingoSettings->growing_augmentFreq;
+    }
+    else if (option == "growing_augmentWeight") {
+        return _maingoSettings->growing_augmentWeight;
+    }
+    else if (option == "growing_augmentPercentage") {
+        return _maingoSettings->growing_augmentPercentage;
+    }
+    throw MAiNGOException("Error getting option: unknown option" + option + ".");
+}
\ No newline at end of file
diff --git a/src/MAiNGOgetterFunctions.cpp b/src/MAiNGOgetterFunctions.cpp
index 6ff2bd2823f8c8447c9c32bfdd40dd58820b0e87..5d3d3ebb907af4bafba9196b36a0598baea54548 100644
--- a/src/MAiNGOgetterFunctions.cpp
+++ b/src/MAiNGOgetterFunctions.cpp
@@ -46,7 +46,7 @@ MAiNGO::get_solution_point() const
     for (unsigned i = 0; i < _nvarOriginal; ++i) {
         if (_removedVariables[i]) {
             // If the variable has been removed from the optimization problem, simply return the middle point of the original interval
-            solutionPoint.push_back(_originalVariables[i].get_lower_bound());
+            solutionPoint.push_back(0.5*(_originalVariables[i].get_lower_bound() + _originalVariables[i].get_upper_bound()));
             removed++;
         }
         else {
@@ -219,172 +219,6 @@ MAiNGO::get_final_rel_gap() const
 }
 
 
-////////////////////////////////////////////////////////////////////////////////////////
-// function returning the value of a desired option
-double
-MAiNGO::get_option(const std::string& option) const
-{
-    if (option == "epsilonA") {
-        return _maingoSettings->epsilonA;
-    }
-    else if (option == "epsilonR") {
-        return _maingoSettings->epsilonR;
-    }
-    else if (option == "deltaIneq") {
-        return _maingoSettings->deltaIneq;
-    }
-    else if (option == "deltaEq") {
-        return _maingoSettings->deltaEq;
-    }
-    else if (option == "relNodeTol") {
-        return _maingoSettings->relNodeTol;
-    }
-    else if (option == "BAB_maxNodes") {
-        return _maingoSettings->BAB_maxNodes;
-    }
-    else if (option == "BAB_maxIterations") {
-        return _maingoSettings->BAB_maxIterations;
-    }
-    else if (option == "maxTime") {
-        return _maingoSettings->maxTime;
-    }
-    else if (option == "confirmTermination") {
-        return _maingoSettings->confirmTermination;
-    }
-    else if (option == "terminateOnFeasiblePoint") {
-        return _maingoSettings->terminateOnFeasiblePoint;
-    }
-    else if (option == "targetLowerBound") {
-        return _maingoSettings->targetLowerBound;
-    }
-    else if (option == "targetUpperBound") {
-        return _maingoSettings->targetUpperBound;
-    }
-    else if (option == "PRE_maxLocalSearches") {
-        return _maingoSettings->PRE_maxLocalSearches;
-    }
-    else if (option == "PRE_obbtMaxRounds") {
-        return _maingoSettings->PRE_obbtMaxRounds;
-    }
-    else if (option == "PRE_pureMultistart") {
-        return _maingoSettings->PRE_pureMultistart;
-    }
-    else if (option == "BAB_nodeSelection") {
-        return _maingoSettings->BAB_nodeSelection;
-    }
-    else if (option == "BAB_branchVariable") {
-        return _maingoSettings->BAB_branchVariable;
-    }
-    else if (option == "BAB_alwaysSolveObbt") {
-        return _maingoSettings->BAB_alwaysSolveObbt;
-    }
-    else if (option == "BAB_probing") {
-        return _maingoSettings->BAB_probing;
-    }
-    else if (option == "BAB_dbbt") {
-        return _maingoSettings->BAB_dbbt;
-    }
-    else if (option == "BAB_constraintPropagation") {
-        return _maingoSettings->BAB_constraintPropagation;
-    }
-    else if (option == "LBP_solver") {
-        return _maingoSettings->LBP_solver;
-    }
-    else if (option == "LBP_linPoints") {
-        return _maingoSettings->LBP_linPoints;
-    }
-    else if (option == "LBP_subgradientIntervals") {
-        return _maingoSettings->LBP_subgradientIntervals;
-    }
-    else if (option == "LBP_obbtMinImprovement") {
-        return _maingoSettings->LBP_obbtMinImprovement;
-    }
-    else if (option == "LBP_activateMoreScaling") {
-        return _maingoSettings->LBP_activateMoreScaling;
-    }
-    else if (option == "LBP_addAuxiliaryVars") {
-        return _maingoSettings->LBP_addAuxiliaryVars;
-    }
-    else if (option == "LBP_minFactorsForAux") {
-        return _maingoSettings->LBP_minFactorsForAux;
-    }
-    else if (option == "LBP_maxNumberOfAddedFactors") {
-        return _maingoSettings->LBP_maxNumberOfAddedFactors;
-    }
-    else if (option == "MC_mvcompUse") {
-        return _maingoSettings->MC_mvcompUse;
-    }
-    else if (option == "MC_mvcompTol") {
-        return _maingoSettings->MC_mvcompTol;
-    }
-    else if (option == "MC_envelTol") {
-        return _maingoSettings->MC_envelTol;
-    }
-    else if (option == "UBP_solverPreprocessing") {
-        return _maingoSettings->UBP_solverPreprocessing;
-    }
-    else if (option == "UBP_maxStepsPreprocessing") {
-        return _maingoSettings->UBP_maxStepsPreprocessing;
-    }
-    else if (option == "UBP_maxTimePreprocessing") {
-        return _maingoSettings->UBP_maxTimePreprocessing;
-    }
-    else if (option == "UBP_solverBab") {
-        return _maingoSettings->UBP_solverBab;
-    }
-    else if (option == "UBP_maxStepsBab") {
-        return _maingoSettings->UBP_maxStepsBab;
-    }
-    else if (option == "UBP_maxTimeBab") {
-        return _maingoSettings->UBP_maxTimeBab;
-    }
-    else if (option == "UBP_ignoreNodeBounds") {
-        return _maingoSettings->UBP_ignoreNodeBounds;
-    }
-    else if (option == "EC_nPoints") {
-        return _maingoSettings->EC_nPoints;
-    }
-    else if (option == "LBP_verbosity") {
-        return _maingoSettings->LBP_verbosity;
-    }
-    else if (option == "UBP_verbosity") {
-        return _maingoSettings->UBP_verbosity;
-    }
-    else if (option == "BAB_verbosity") {
-        return _maingoSettings->BAB_verbosity;
-    }
-    else if (option == "BAB_printFreq") {
-        return _maingoSettings->BAB_printFreq;
-    }
-    else if (option == "BAB_logFreq") {
-        return _maingoSettings->BAB_logFreq;
-    }
-    else if (option == "loggingDestination") {
-        return _maingoSettings->loggingDestination;
-    }
-    else if (option == "writeCsv") {
-        return _maingoSettings->writeCsv;
-    }
-    else if (option == "writeJson") {
-        return _maingoSettings->writeJson;
-    }
-    else if (option == "writeResultFile") {
-        return _maingoSettings->writeResultFile;
-    }
-    else if (option == "writeToLogSec") {
-        return _maingoSettings->writeToLogSec;
-    }
-    else if (option == "PRE_printEveryLocalSearch") {
-        return _maingoSettings->PRE_printEveryLocalSearch;
-    }
-    else if (option == "modelWritingLanguage") {
-        return _maingoSettings->modelWritingLanguage;
-    }
-    std::cout << "Warning: No setting \"" << option << "\" found. \n";
-    return -1;
-}
-
-
 ////////////////////////////////////////////////////////////////////////////////////////
 // function returning the current MAiNGO status
 RETCODE
diff --git a/src/MAiNGOprintingFunctions.cpp b/src/MAiNGOprintingFunctions.cpp
index 14116e9f6025b5cee70d3c227fe2837ccf5ddbb6..1c09da4043b7c07127aaaf447bf7781c4e6f7ce3 100644
--- a/src/MAiNGOprintingFunctions.cpp
+++ b/src/MAiNGOprintingFunctions.cpp
@@ -15,6 +15,8 @@
 #include "getTime.h"
 #include "version.h"
 
+#include <cassert>
+
 
 using namespace maingo;
 
@@ -24,6 +26,8 @@ using namespace maingo;
 void
 MAiNGO::_print_info_about_initial_point()
 {
+    assert(_initialPointOriginal.empty() || (_initialPointOriginal.size() == _originalVariables.size()));
+
     if (_initialPointOriginal.empty()) {
         std::ostringstream outstream;
         outstream << std::endl
@@ -32,19 +36,9 @@ MAiNGO::_print_info_about_initial_point()
         _logger->print_message(outstream.str(), VERB_ALL, BAB_VERBOSITY);
         return;
     }
-    if (_initialPointOriginal.size() != _originalVariables.size()) {
-        std::ostringstream outstream;
-        outstream << std::endl
-                  << "  WARNING: Initial point discarded because its dimension (" << _initialPointOriginal.size() << ")";
-        outstream << "does not match the number of variables (" << _originalVariables.size() << ")." << std::endl
-                  << std::endl;
-        _logger->print_message(outstream.str(), VERB_ALL, BAB_VERBOSITY);
-        return;
-    }
-
-    std::ostringstream outstream;
 
     // Variables:
+    std::ostringstream outstream;
     outstream << std::endl
               << "  Initial point:" << std::endl;
     for (size_t i = 0; i < _originalVariables.size(); ++i) {
@@ -248,10 +242,8 @@ MAiNGO::_print_solution()
                         outstream << "  Inequality (squash) " << (*_constantConstraints)[i].name << " has value "
                                   << (*_constantConstraints)[i].constantValue << " > 0" << std::endl;
                         break;
-                    default:
-                        outstream << "  Constraint " << (*_constantConstraints)[i].name << " of type  " << (*_constantConstraints)[i].type << " has value "
-                                  << (*_constantConstraints)[i].constantValue << std::endl;
-                        break;
+                    default:    // GCOVR_EXCL_LINE
+                        throw MAiNGOException("Error printing solution: unknown constraint type " + std::to_string((*_constantConstraints)[i].type));   // GCOVR_EXCL_LINE
                 }
             }
         }
@@ -269,7 +261,7 @@ MAiNGO::_print_solution()
                     else {
                         outstream << "  Final relative gap = " << _myBaB->get_final_rel_gap() << std::endl;
                     }
-                    if (_myBaB->get_final_abs_gap() < 0) {
+                    if (_myBaB->get_final_abs_gap() < 0) {    // GCOVR_EXCL_START
                         if (_myBaB->get_final_abs_gap() >= -_maingoSettings->MC_mvcompTol) {
                             outstream << "  Warning: Final gap is negative. This is probably due to numerical precision and probably okay.\n";
                             outstream << "           You can try to re-run the problem with decreased MC_mvcompTol." << std::endl;
@@ -278,6 +270,7 @@ MAiNGO::_print_solution()
                             outstream << "  Warning: Final gap is negative. Please report this issue to the developers." << std::endl;
                         }
                     }
+                    // GCOVR_EXCL_STOP
                 }
                 outstream << "  Objective value = " << _solutionValue << std::endl;
             }
@@ -315,11 +308,12 @@ MAiNGO::_print_solution()
             // Check whether the incumbent fullfils relaxation only constraints
             std::string str;
             std::string whitespaces = "    ";
-            if (!_check_feasibility_of_relaxation_only_constraints(_solutionPoint, str, whitespaces)) {
+            if (!_check_feasibility_of_relaxation_only_constraints(_solutionPoint, str, whitespaces)) { // GCOVR_EXCL_START
                 if (_myBaB->get_final_abs_gap() < 0) {
                     str += "             This may also explain the negative final optimality gap.\n";
                 }
             }
+            // GCOVR_EXCL_STOP
             outstream << str;
         }
         else {
@@ -383,8 +377,7 @@ MAiNGO::_print_solution()
                 outstream << str;
             }
             else {
-                outstream << std::endl
-                          << "  Solution point could not be obtained from CPLEX although optimal objective was reported." << std::endl;
+                outstream << "\n  Solution point could not be obtained from CPLEX although optimal objective was reported." << std::endl; // GCOVR_EXCL_LINE
             }
         }
     }
@@ -586,8 +579,8 @@ MAiNGO::_print_third_party_software_minlp()
             case ubp::UBP_SOLVER_KNITRO:
                 usingKnitro = true;
                 break;
-            default:
-                throw MAiNGOException("    ERROR printing third-party software: unknown upper bounding solver for pre-processing");
+            default:    // GCOVR_EXCL_LINE
+                throw MAiNGOException("    ERROR printing third-party software: unknown upper bounding solver for pre-processing");    // GCOVR_EXCL_LINE
         }
     }
     if (!_maingoSettings->PRE_pureMultistart) {
@@ -613,8 +606,8 @@ MAiNGO::_print_third_party_software_minlp()
             case ubp::UBP_SOLVER_KNITRO:
                 usingKnitro = true;
                 break;
-            default:
-                throw MAiNGOException("    ERROR printing third-party software: unknown upper bounding solver for B&B");
+            default:    // GCOVR_EXCL_LINE
+                throw MAiNGOException("    ERROR printing third-party software: unknown upper bounding solver for B&B");    // GCOVR_EXCL_LINE
         }
     }
     bool usingCplex = false, usingClp = false;
@@ -631,8 +624,8 @@ MAiNGO::_print_third_party_software_minlp()
         case lbp::LBP_SOLVER_CPLEX:
             usingCplex = true;
             break;
-        default:
-            throw MAiNGOException("    ERROR printing third-party software: unknown lower bounding solver");
+        default:    // GCOVR_EXCL_LINE
+            throw MAiNGOException("    ERROR printing third-party software: unknown lower bounding solver");    // GCOVR_EXCL_LINE
     }
 
     // Always using MC++ and Filib++
diff --git a/src/MAiNGOsetOption.cpp b/src/MAiNGOsetOption.cpp
index a495fef92a59e01754b8875f25922c598917996f..6179f4d5e4ad8561e70ff32414eab2be7e1a3abb 100644
--- a/src/MAiNGOsetOption.cpp
+++ b/src/MAiNGOsetOption.cpp
@@ -114,9 +114,9 @@ MAiNGO::set_option(const std::string& option, const double value)
         }
     }
     else if (option == "maxTime") {
-        if (value < 10 && value != -1) {
-            _logger->save_setting(MAXTIME, "maxTime has to be >= 10 or -1 (=inf), setting it to 10");
-            _maingoSettings->maxTime = 10;
+        if (value < 0 && value != -1) {
+            _logger->save_setting(MAXTIME, "maxTime has to be >= 0 or -1 (=inf), setting it to 0");
+            _maingoSettings->maxTime = 0;
         }
         else {
             if (value == -1) {
@@ -265,7 +265,7 @@ MAiNGO::set_option(const std::string& option, const double value)
         }
     }
     else if (option == "BAB_probing") {
-        if (value < 0) {
+        if (value != 0 && value != 1) {
             _logger->save_setting(BAB_PROBING, "BAB_probing has to be 0 or 1, setting to 0");
             _maingoSettings->BAB_probing = false;
         }
@@ -475,7 +475,7 @@ MAiNGO::set_option(const std::string& option, const double value)
         }
     }
     else if (option == "UBP_solverPreprocessing") {
-        if (!((int)value >= 0 && (int)value <= 6)) {
+        if (value != 0 && value != 1 && value != 2 && value != 3 && value != 4 && value != 5 && value != 6) {
             _logger->save_setting(UBP_SOLVERPRE, "UBP_solverPreprocessing has to be 0, 1, 2, 3, 4, 5, 6, setting to 5");
             _maingoSettings->UBP_solverPreprocessing = ubp::UBP_SOLVER_IPOPT;
         }
@@ -532,7 +532,7 @@ MAiNGO::set_option(const std::string& option, const double value)
         }
     }
     else if (option == "UBP_solverBab") {
-        if (!((int)value >= 0 && (int)value <= 6)) {
+        if (value != 0 && value != 1 && value != 2 && value != 3 && value != 4 && value != 5 && value != 6) {
             _logger->save_setting(UBP_SOLVERBAB, "UBP_solverBab has to be 0, 1, 2, 3, 4, 5, 6, setting to 4");
             _maingoSettings->UBP_solverBab = ubp::UBP_SOLVER_SLSQP;
         }
@@ -756,7 +756,7 @@ MAiNGO::set_option(const std::string& option, const double value)
         }
     }
     else if (option == "writeToLogSec") {
-        if (value != -1 && value < 10.) {
+        if (value < 10.) {
             _logger->save_setting(WRITETOLOGSEC, "writeToLogSec has to be at least 10, setting it to default (1800)");
             _maingoSettings->writeToLogSec = 1800;
         }
diff --git a/src/MAiNGOtoOtherLanguage.cpp b/src/MAiNGOtoOtherLanguage.cpp
index 1cb5c9622ad0b19257e65da9c4d8ec2ec697498f..e75b30e3d8ee01bead6b8403282ac053761640a8 100644
--- a/src/MAiNGOtoOtherLanguage.cpp
+++ b/src/MAiNGOtoOtherLanguage.cpp
@@ -29,11 +29,14 @@ void
 MAiNGO::write_model_to_file_in_other_language(const WRITING_LANGUAGE writingLanguage, std::string fileName, const std::string solverName,
                                               const bool useMinMax, const bool useTrig, const bool ignoreBoundingFuncs, const bool writeRelaxationOnly)
 {
+    if (!_modelSpecified) {
+        throw MAiNGOException("  Error trying to write model to file: Model has not been set successfully.");
+    }
 
     try {
         _construct_DAG();
     }
-    catch (const std::exception &e) {
+    catch (const std::exception &e) {   // GCOVR_EXCL_START
         std::ostringstream errmsg;
         errmsg << e.what() << "\n  Encountered a fatal error during DAG construction.";
         if (_inMAiNGOsolve) {
@@ -47,18 +50,7 @@ MAiNGO::write_model_to_file_in_other_language(const WRITING_LANGUAGE writingLang
         }
         throw MAiNGOException("  Encountered an unknown fatal error during DAG construction.");
     }
-
-    if (_DAGvars.empty() || _DAGfunctions.empty()) {
-        std::ostringstream ostr;
-        ostr << "\n  You need to set your model before writing it to file in a different modeling language. Writing of model to file aborted. Proceeding...\n";
-        if (_inMAiNGOsolve) {
-            _logger->print_message(ostr.str(), VERB_NORMAL, BAB_VERBOSITY);
-        }
-        else {
-            _logger->print_message_to_stream_only(ostr.str());
-        }
-        return;
-    }
+    // GCOVR_EXCL_STOP
 
     // Set options
     mc::FFToString::options.USE_MIN_MAX                   = useMinMax;
@@ -81,16 +73,11 @@ MAiNGO::write_model_to_file_in_other_language(const WRITING_LANGUAGE writingLang
             }
             _write_ale_file(fileName, solverName, writeRelaxationOnly);
             break;
-        default:
-            std::ostringstream ostr;
-            ostr << "\n  Unknown or not supported modeling language. Writing of model to file aborted. Proceeding...\n";
-            if (_inMAiNGOsolve) {
-                _logger->print_message(ostr.str(), VERB_NORMAL, BAB_VERBOSITY);
-            }
-            else {
-                _logger->print_message_to_stream_only(ostr.str());
-            }
-            break;
+        case LANG_NONE:
+            _logger->print_message_to_stream_only("\n  WARNING: asked MAiNGO to write model to file, but chosen writing language is NONE. Not writing anything.\n");
+            return;
+        default:    // GCOVR_EXCL_LINE
+            throw MAiNGOException("Error trying to write model to file: unknown modeling language."); // GCOVR_EXCL_LINE
     }
 
     // Check if we have to warn the user
@@ -123,17 +110,9 @@ MAiNGO::_write_gams_file(const std::string gamsFileName, const std::string solve
         _logger->print_message_to_stream_only(ostr.str());
     }
 
-    std::string str;
-    if (gamsFileName.empty()) {
-        str = "MAiNGO_written_model.gms";
-    }
-    else {
-        str = gamsFileName;
-    }
-    std::ofstream gamsFile(str);
+    std::ofstream gamsFile(gamsFileName);
 
     _print_MAiNGO_header_for_other_modeling_language(LANG_GAMS, gamsFile);
-
     _write_gams_variables(gamsFile);
     _write_gams_functions(gamsFile, writeRelaxationOnly);
     _write_gams_options(gamsFile, solverName);
@@ -599,17 +578,10 @@ MAiNGO::_write_gams_options(std::ofstream &gamsFile, std::string solverName)
         case MINLP:
             str = "MINLP";
             break;
-        default:
-            str = "MINLP";
-            break;
-    }
-    gamsFile << "option " << str << " = ";
-    if (solverName.empty()) {
-        gamsFile << "SCIP;\n\n";
-    }
-    else {
-        gamsFile << solverName << ";\n\n";
+        default:    // GCOVR_EXCL_LINE
+            throw MAiNGOException("Error writing GAMS options while writing problem to file: unknown problem structure.");  // GCOVR_EXCL_LINE
     }
+    gamsFile << "option " << str << " = " << solverName << ";\n\n";
 
     // Solve statement
     gamsFile << "*Solve statement\n";
@@ -654,14 +626,7 @@ MAiNGO::_write_ale_file(const std::string aleFileName, const std::string solverN
         _logger->print_message_to_stream_only(ostr.str());
     }
 
-    std::string str;
-    if (aleFileName.empty()) {
-        str = "MAiNGO_written_model.txt";
-    }
-    else {
-        str = aleFileName;
-    }
-    std::ofstream aleFile(str);
+    std::ofstream aleFile(aleFileName);
 
     _print_MAiNGO_header_for_other_modeling_language(LANG_ALE, aleFile);
 
@@ -1013,9 +978,8 @@ MAiNGO::_print_MAiNGO_header_for_other_modeling_language(const WRITING_LANGUAGE
         case LANG_ALE:
             commentSign = "#";
             break;
-        default:
-            commentSign = "//";
-            break;
+         default:    // GCOVR_EXCL_LINE
+            throw MAiNGOException("Error printing MAiNGO header while writing model to file: unknown modeling language."); // GCOVR_EXCL_LINE
     }
 
     // This is not the same header as in function print_header()
diff --git a/src/MAiNGOwritingFunctions.cpp b/src/MAiNGOwritingFunctions.cpp
index 0d3b5ec77ba4618d346d8c4753436d98ca961a6d..1babae95e9ee4323e8d27a1f206b7ea3ea099c07 100644
--- a/src/MAiNGOwritingFunctions.cpp
+++ b/src/MAiNGOwritingFunctions.cpp
@@ -9,8 +9,9 @@
  *
  **********************************************************************************/
 
-#include "MAiNGO.h"
 #include "bab.h"
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
 #include "version.h"
 
 
@@ -44,7 +45,7 @@ MAiNGO::_write_files()
 ////////////////////////////////////////////////////////////////////////
 // writes final logging information to disk
 void
-MAiNGO::_write_files_error(const std::string& errorMessage)
+MAiNGO::_write_files_error(const std::string& errorMessage) // GCOVR_EXCL_START
 {
     if ((_maingoSettings->loggingDestination == LOGGING_FILE) || (_maingoSettings->loggingDestination == LOGGING_FILE_AND_STREAM)) {
         _logger->write_all_lines_to_log(errorMessage);
@@ -54,6 +55,7 @@ MAiNGO::_write_files_error(const std::string& errorMessage)
         _logger->write_all_iterations_to_csv();
     }
 }
+// GCOVR_EXCL_STOP
 
 
 ////////////////////////////////////////////////////////////////////////
@@ -89,8 +91,8 @@ MAiNGO::_write_result_file()
         for (size_t i = 1; i < 1 + _nineq + _nconstantIneq; i++) {
             std::string ineq = (*_originalConstraints)[i].name;
             resultFile << std::setw(25) << ineq << std::setw(25) << std::setprecision(16) << modelValuesAtSolutionPoint[i];
-            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaIneq) {
-                resultFile << std::setw(25) << "VIOLATED" << std::endl;
+            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaIneq) {   // Should never occur, but just to be sure
+                resultFile << std::setw(25) << "VIOLATED" << std::endl; // GCOVR_EXCL_LINE
             }
             else if (modelValuesAtSolutionPoint[i] < _maingoSettings->deltaIneq && modelValuesAtSolutionPoint[i] >= 0.) {
                 resultFile << std::setw(25) << " * " << std::endl;
@@ -114,9 +116,8 @@ MAiNGO::_write_result_file()
         for (size_t i = 1 + _nineq + _nconstantIneq; i < 1 + _nineq + _nconstantIneq + _neq + _nconstantEq; i++) {
             std::string eq = (*_originalConstraints)[i].name;
             resultFile << std::setw(25) << eq << std::setw(25) << std::setprecision(16) << modelValuesAtSolutionPoint[i];
-            // These should never be violated but just to make sure we check it here
-            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaEq || modelValuesAtSolutionPoint[i] < -_maingoSettings->deltaEq) {
-                resultFile << std::setw(25) << "VIOLATED" << std::endl;
+            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaEq || modelValuesAtSolutionPoint[i] < -_maingoSettings->deltaEq) {   // Should never occur, but just to be sure
+                resultFile << std::setw(25) << "VIOLATED" << std::endl; // GCOVR_EXCL_LINE
             }
             else {
                 resultFile << std::endl;
@@ -135,8 +136,8 @@ MAiNGO::_write_result_file()
         for (size_t i = 1 + _nineq + _nconstantIneq + _neq + _nconstantEq; i < 1 + _nineq + _nconstantIneq + _neq + _nconstantEq + _nineqRelaxationOnly + _nconstantIneqRelOnly; i++) {
             std::string ineq = (*_originalConstraints)[i].name;
             resultFile << std::setw(25) << ineq << std::setw(25) << std::setprecision(16) << modelValuesAtSolutionPoint[i];
-            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaIneq) {
-                resultFile << std::setw(25) << "VIOLATED" << std::endl;
+            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaIneq) {   // Should never occur, but just to be sure
+                resultFile << std::setw(25) << "VIOLATED" << std::endl; // GCOVR_EXCL_LINE
             }
             else if (modelValuesAtSolutionPoint[i] < _maingoSettings->deltaIneq && modelValuesAtSolutionPoint[i] >= 0.) {
                 resultFile << std::setw(25) << " * " << std::endl;
@@ -161,8 +162,8 @@ MAiNGO::_write_result_file()
         for (size_t i = 1 + _nineq + _nconstantIneq + _neq + _nconstantEq + _nineqRelaxationOnly + _nconstantIneqRelOnly; i < 1 + _nineq + _nconstantIneq + _neq + _nconstantEq + _nineqRelaxationOnly + _nconstantIneqRelOnly + _neqRelaxationOnly + _nconstantEqRelOnly; i++) {
             std::string eq = (*_originalConstraints)[i].name;
             resultFile << std::setw(25) << eq << std::setw(25) << std::setprecision(16) << modelValuesAtSolutionPoint[i];
-            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaEq || modelValuesAtSolutionPoint[i] < -_maingoSettings->deltaEq) {
-                resultFile << std::setw(25) << "VIOLATED" << std::endl;
+            if (modelValuesAtSolutionPoint[i] > _maingoSettings->deltaEq || modelValuesAtSolutionPoint[i] < -_maingoSettings->deltaEq) {   // Should never occur, but just to be sure
+                resultFile << std::setw(25) << "VIOLATED" << std::endl; // GCOVR_EXCL_LINE
             }
             else {
                 resultFile << std::endl;
@@ -181,8 +182,8 @@ MAiNGO::_write_result_file()
         for (size_t i = 1 + _nineq + _nconstantIneq + _neq + _nconstantEq + _nineqRelaxationOnly + _nconstantIneqRelOnly + _neqRelaxationOnly + _nconstantEqRelOnly; i < _originalConstraints->size(); i++) {
             std::string ineq = (*_originalConstraints)[i].name;
             resultFile << std::setw(25) << ineq << std::setw(25) << std::setprecision(16) << modelValuesAtSolutionPoint[i];
-            if (modelValuesAtSolutionPoint[i] > 0) {
-                resultFile << std::setw(25) << "VIOLATED" << std::endl;
+            if (modelValuesAtSolutionPoint[i] > 0) {   // Should never occur, but just to be sure
+                resultFile << std::setw(25) << "VIOLATED" << std::endl; // GCOVR_EXCL_LINE
             }
             else if (modelValuesAtSolutionPoint[i] < 0 && modelValuesAtSolutionPoint[i] >= -_maingoSettings->deltaIneq) {
                 resultFile << std::setw(25) << "(*)" << std::endl;
@@ -246,9 +247,8 @@ MAiNGO::_write_solution_and_statistics_csv()
         case MINLP:
             solutionStatisticsFile << "6" << std::endl;
             break;
-        default:
-            solutionStatisticsFile << "6" << std::endl;
-            break;
+        default:    // GCOVR_EXCL_LINE
+            throw MAiNGOException("Error writing solution csv file: unknown problem structure " + std::to_string(_problemStructure)); // GCOVR_EXCL_LINE
     }
 
     if (!_maingoSettings->PRE_pureMultistart && _problemStructure > MIQP) {
@@ -325,9 +325,8 @@ MAiNGO::_write_json_file()
         case MINLP:
             jsonFile << "MINLP\"," << std::endl;
             break;
-        default:
-            jsonFile << "MINLP\"," << std::endl;
-            break;
+        default:    // GCOVR_EXCL_LINE
+            throw MAiNGOException("Error writing json file: unknown problem structure " + std::to_string(_problemStructure)); // GCOVR_EXCL_LINE
     }
     if (!_maingoSettings->PRE_pureMultistart && _problemStructure > MIQP) {
         jsonFile << "  \"SolutionStatistics\" : {" << std::endl;
@@ -364,15 +363,15 @@ MAiNGO::_write_json_file()
         case BOUND_TARGETS:
             jsonFile << "\"Reached target bound\"," << std::endl;
             break;
-        case NOT_SOLVED_YET:
+        case NOT_SOLVED_YET: // GCOVR_EXCL_START
             jsonFile << "\"Not solved yet\"," << std::endl;
             break;
         case JUST_A_WORKER_DONT_ASK_ME:
             jsonFile << "\"Just a worker\"," << std::endl;
             break;
         default:
-            jsonFile << "\"Not solved yet\"," << std::endl;
-            break;
+            throw MAiNGOException("Error writing json file: unknown status " + std::to_string(_maingoStatus));
+        // GCOVR_EXCL_STOP
     }
 
 
@@ -425,31 +424,37 @@ MAiNGO::_write_json_file()
 void
 MAiNGO::_write_epsilon_constraint_result(const std::vector<std::vector<double>>& objectiveValues, const std::vector<std::vector<double>>& solutionPoints)
 {
-
     std::ofstream objectiveValuesFile("MAiNGO_epsilon_constraint_objective_values.csv", std::ios::out);
-    objectiveValuesFile << "obj1, obj2" << std::endl;
-
-    for (size_t i = 0; i < objectiveValues.size(); i++) {
-        objectiveValuesFile << objectiveValues[i][0];
-        for (size_t j = 1; j < objectiveValues[i].size(); j++) {
-            objectiveValuesFile << ", " << objectiveValues[i][j];
+    if (_maingoStatus == INFEASIBLE) {
+        objectiveValuesFile << "Problem is infeasible." << std::endl;
+    } else {
+        objectiveValuesFile << "obj1, obj2" << std::endl;
+        for (size_t i = 0; i < objectiveValues.size(); i++) {
+            objectiveValuesFile << objectiveValues[i][0];
+            for (size_t j = 1; j < objectiveValues[i].size(); j++) {
+                objectiveValuesFile << ", " << objectiveValues[i][j];
+            }
+            objectiveValuesFile << std::endl;
         }
-        objectiveValuesFile << std::endl;
     }
     objectiveValuesFile.close();
 
     std::ofstream pointsFile("MAiNGO_epsilon_constraint_solution_points.csv", std::ios::out);
-    pointsFile << "x0";
-    for (size_t i = 1; i < solutionPoints[0].size(); i++) {
-        pointsFile << ", x" << i;
-    }
-    pointsFile << std::endl;
-    for (size_t i = 0; i < solutionPoints.size(); i++) {
-        pointsFile << solutionPoints[i][0];
-        for (size_t j = 1; j < solutionPoints[i].size(); j++) {
-            pointsFile << ", " << solutionPoints[i][j];
+    if (_maingoStatus == INFEASIBLE) {
+        pointsFile << "Problem is infeasible." << std::endl;
+    } else {
+        pointsFile << "x0";
+        for (size_t i = 1; i < solutionPoints[0].size(); i++) {
+            pointsFile << ", x" << i;
         }
         pointsFile << std::endl;
+        for (size_t i = 0; i < solutionPoints.size(); i++) {
+            pointsFile << solutionPoints[i][0];
+            for (size_t j = 1; j < solutionPoints[i].size(); j++) {
+                pointsFile << ", " << solutionPoints[i][j];
+            }
+            pointsFile << std::endl;
+        }
     }
     pointsFile.close();
 }
\ No newline at end of file
diff --git a/src/bab.cpp b/src/bab.cpp
index 914c3b7aba4cab8d0754bcf63b85d8339c7688a8..8f533d3cdd9e5d038cf667417ac30833d3875bdc 100644
--- a/src/bab.cpp
+++ b/src/bab.cpp
@@ -27,9 +27,9 @@ using namespace bab;
 ////////////////////////////////////////////////////////////////////////////////////////
 // constructor for the branch and bound object
 BranchAndBound::BranchAndBound(const std::vector<babBase::OptimizationVariable> &variables, std::shared_ptr<lbp::LowerBoundingSolver> LBSIn, std::shared_ptr<ubp::UpperBoundingSolver> UBSIn,
-                               std::shared_ptr<Settings> settingsIn, std::shared_ptr<Logger> loggerIn, const unsigned nvarWOauxIn):
+                               std::shared_ptr<Settings> settingsIn, std::shared_ptr<Logger> loggerIn, const unsigned nvarWOauxIn, std::istream *const inputStream):
     _originalVariables(variables),
-    _LBS(LBSIn), _UBS(UBSIn), _nvar(variables.size()), _maingoSettings(settingsIn), _logger(loggerIn), _nvarWOaux(nvarWOauxIn)
+    _LBS(LBSIn), _UBS(UBSIn), _nvar(variables.size()), _maingoSettings(settingsIn), _logger(loggerIn), _nvarWOaux(nvarWOauxIn), _inputStream(inputStream)
 {
 
 #ifdef HAVE_MAiNGO_MPI
@@ -469,7 +469,7 @@ BranchAndBound::solve(babBase::BabNode &rootNodeIn, double &solutionValue, std::
                 // -----------------------------------
                 // Get time
                 currentTime = get_cpu_time();
-                if ((currentTime - startTime) < lastTime) {
+                if ((currentTime - startTime) < lastTime) { // GCOVR_EXCL_START
                     _daysPassed += 1;
                     MAiNGO_IF_BAB_MANAGER
                         std::ostringstream outstr;
@@ -478,6 +478,7 @@ BranchAndBound::solve(babBase::BabNode &rootNodeIn, double &solutionValue, std::
                         _logger->print_message(outstr.str(), VERB_NORMAL, BAB_VERBOSITY);
                     MAiNGO_END_IF
                 }
+                // GCOVR_EXCL_STOP
                 _timePassed = _timePreprocess + _daysPassed * 86400 + (currentTime - startTime);
                 lastTime    = currentTime - startTime;
                 MAiNGO_IF_BAB_MANAGER
@@ -573,7 +574,7 @@ BranchAndBound::solve(babBase::BabNode &rootNodeIn, double &solutionValue, std::
             _communicate_exception_and_throw(e);
     }
 #else
-catch (std::exception &e)
+catch (std::exception &e) // GCOVR_EXCL_START
 {
     throw MAiNGOException("  Error during branch-and-bound.", e);
 }
@@ -581,6 +582,7 @@ catch (...)
 {
     throw MAiNGOException("  Unknown error during branch-and-bound.");
 }
+// GCOVR_EXCL_STOP
 #endif
     return _status;    // Return code is determined in _check_termination()
 }
@@ -738,14 +740,14 @@ BranchAndBound::_solve_LBP(const babBase::BabNode &currentNode)
 
     SUBSOLVER_RETCODE lbpStatus = _LBS->solve_LBP(currentNode, currentLBD, lbpSolutionPoint, dualInfo);
 
-    if (currentLBD < parentLBD) {
-
+    if (currentLBD < parentLBD) {   // GCOVR_EXCL_START
         std::ostringstream outstr;
         outstr << "  LBD obtained for node " << currentNode.get_ID() << " is lower than LBD of its parent node. Using parent LBD." << std::endl;
         _logger->print_message(outstr.str(), VERB_ALL, BAB_VERBOSITY);
 
         currentLBD = parentLBD;
     }
+    // GCOVR_EXCL_STOP
 
     // Check if LBP proved node to be infeasible
     if (lbpStatus == SUBSOLVER_INFEASIBLE) {    // Ok, exit DBBT loop and just forget node
@@ -790,13 +792,12 @@ BranchAndBound::_solve_UBP(const babBase::BabNode &currentNode, std::vector<doub
     // Check if we found a feasible point
     if (ubpStatus == SUBSOLVER_FEASIBLE) {
         foundNewFeasiblePoint = true;
-
-        if ((ubpObjectiveValue < currentLBD - _maingoSettings->epsilonA) && (ubpObjectiveValue < currentLBD - std::fabs(ubpObjectiveValue) * _maingoSettings->epsilonR)) {    // Sanity check to detect inconsistent bounding operations
+        // Sanity check to detect inconsistent bounding operations
+        if ((ubpObjectiveValue < currentLBD - _maingoSettings->epsilonA) && (ubpObjectiveValue < currentLBD - std::fabs(ubpObjectiveValue) * _maingoSettings->epsilonR)) {   // GCOVR_EXCL_START
             if (ubpObjectiveValue > -_maingoSettings->infinity) {
                 std::ostringstream errmsg;
                 errmsg << std::endl
-                       << "  Error while checking objective returned by upper bounding solver: Upper bound < lower bound for the following node: " << std::endl;
-                _print_one_node(currentNode.get_pruning_score(), currentNode, errmsg);
+                       << "  Error while checking objective returned by upper bounding solver: Upper bound < lower bound:" << std::endl;
                 errmsg << "  LBD = " << std::setprecision(16) << currentLBD << std::endl
                        << "UBD = " << ubpObjectiveValue << std::endl;
 #ifdef HAVE_MAiNGO_MPI
@@ -813,6 +814,7 @@ BranchAndBound::_solve_UBP(const babBase::BabNode &currentNode, std::vector<doub
                 _logger->print_message(outstr.str(), VERB_NORMAL, BAB_VERBOSITY);
             }
         }
+        // GCOVR_EXCL_STOP
 
 #ifdef HAVE_MAiNGO_MPI
         // Check if this feasible point is better than the incumbent & inform manager about it
@@ -1051,7 +1053,7 @@ BranchAndBound::_check_if_more_scaling_needed()
             _lbdNotChanged = 0;
         }
         // If the lbd did not change for at least LBP_activateMoreScaling iterations, scaling was not yet activated (checked before going into this function) and the difference between lowest lbd and current best ubd is small enough, we activate more scaling in the LBS
-        if (_lbdNotChanged > _maingoSettings->LBP_activateMoreScaling && (_lbd >= (_ubd - 1E-2) || _lbd >= (_ubd - std::fabs(_ubd) * 1E-1))) {
+        if (_lbdNotChanged > _maingoSettings->LBP_activateMoreScaling && (_lbd >= (_ubd - 1E-2) || _lbd >= (_ubd - std::fabs(_ubd) * 1E-1))) {  // GCOVR_EXCL_START
             _LBS->activate_more_scaling();
             _moreScalingActivated = true;
             _lbdNotChanged        = 0;
@@ -1062,6 +1064,7 @@ BranchAndBound::_check_if_more_scaling_needed()
                 _logger->print_message("  Warning: Additional scaling in the lower bounding solver activated.\n", VERB_NORMAL, BAB_VERBOSITY, LBP_VERBOSITY);
             }
         }
+        // GCOVR_EXCL_STOP
     }
 }
 
@@ -1351,33 +1354,18 @@ BranchAndBound::_log_nodes(const babBase::BabNode &currentNode, const double cur
 
 
 ////////////////////////////////////////////////////////////////////////////////////////
-// function for printing exactly one node
 void
-BranchAndBound::_print_one_node(const double theLBD, const int ID, const std::vector<double> lowerVarBounds, const std::vector<double> upperVarBounds)
+BranchAndBound::_print_one_node(const double theLBD, const babBase::BabNode &theNode)
 {
     std::ostringstream outstr;
-    outstr << "  NODE " << ID << "  has lbd (inherited from parent) =" << std::setprecision(16) << theLBD << std::endl;
+    outstr << "  NODE " << theNode.get_ID() << "  has lbd (inherited from parent) =" << std::setprecision(16) << theLBD << std::endl;
     for (unsigned int i = 0; i < _nvar; i++) {
-        outstr << "  " << std::setprecision(16) << "var " << i + 1 << " " << lowerVarBounds[i] << "..." << upperVarBounds[i] << std::endl;
+        outstr << "  " << std::setprecision(16) << "var " << i + 1 << " " << theNode.get_lower_bounds()[i] << "..." << theNode.get_upper_bounds()[i] << std::endl;
     }
     _logger->print_message(outstr.str(), VERB_ALL, BAB_VERBOSITY);
 }
 
 
-////////////////////////////////////////////////////////////////////////////////////////
-// function for printing exactly one node
-void
-BranchAndBound::_print_one_node(const double theLBD, const int ID, const std::vector<double> lowerVarBounds, const std::vector<double> upperVarBounds, std::ostream &outstream)
-{
-    std::ostringstream outstr;
-    outstr << "  NODE " << ID << "  has lbd (inherited from parent) =" << std::setprecision(16) << theLBD << std::endl;
-    for (unsigned int i = 0; i < _nvar; i++) {
-        outstr << std::setprecision(16) << "var " << i + 1 << " " << lowerVarBounds[i] << "..." << upperVarBounds[i] << std::endl;
-    }
-    outstream << outstr.str();
-}
-
-
 ////////////////////////////////////////////////////////////////////////////////////////
 // function for checking termination
 BranchAndBound::_TERMINATION_TYPE
@@ -1514,7 +1502,7 @@ BranchAndBound::_check_termination()
             // Query input
             outstr << "  Do you want to continue (y/n)? ";
             _logger->print_message(outstr.str(), VERB_NONE, BAB_VERBOSITY);
-            while (getline(std::cin, userInput) && userInput != "y" && userInput != "n") {
+            while (getline((*_inputStream), userInput) && userInput != "y" && userInput != "n") {
                 _logger->print_message("  Invalid input. Please type 'y' or 'n' and press enter: ", VERB_NONE, BAB_VERBOSITY);
             }
 
@@ -1524,7 +1512,7 @@ BranchAndBound::_check_termination()
                 outstr.clear();
                 outstr << "  User input: yes\n  Enter new limit for " << criterion << ": ";
                 _logger->print_message(outstr.str(), VERB_NONE, BAB_VERBOSITY);
-                while (getline(std::cin, userInput) && (*limit >= atof(userInput.c_str()))) {
+                while (getline((*_inputStream), userInput) && (*limit >= atof(userInput.c_str()))) {
                     outstr.str("");
                     outstr.clear();
                     outstr << "  Invalid input (has to be greater than  " << *limit << "), please revise: ";
@@ -1555,7 +1543,7 @@ BranchAndBound::_check_termination()
                 _status = potentialStatus;
             }
             else {
-                throw MAiNGOException("  Error while checking termination: invalid user input '" + userInput + "'");
+                throw MAiNGOException("  Error while checking termination: invalid user input '" + userInput + "'");    // GCOVR_EXCL_LINE
             }
         }
     }
diff --git a/src/constraint.cpp b/src/constraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..921af62050611211cff983580b11c3005f72db3d
--- /dev/null
+++ b/src/constraint.cpp
@@ -0,0 +1,114 @@
+/**********************************************************************************
+ * Copyright (c) 2019-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "constraint.h"
+
+
+using namespace maingo;
+
+
+/////////////////////////////////////////////////////////////////////////
+Constraint::Constraint():
+    name(""), constantValue(0), type(CONSTRAINT_TYPE::TYPE_UNKNOWN), convexity(CONSTRAINT_CONVEXITY::CONV_NONE),
+    monotonicity(CONSTRAINT_MONOTONICITY::MON_NONE), dependency(CONSTRAINT_DEPENDENCY::DEP_UNKNOWN), isConstant(false),
+    isFeasible(true), indexOriginal(0), indexNonconstant(0), indexNonconstantUBP(0), indexConstant(0), indexLinear(0), indexNonlinear(0),
+    indexType(0), indexTypeNonconstant(0), indexTypeConstant(0), nparticipatingVariables(0) 
+{}
+
+
+/////////////////////////////////////////////////////////////////////////
+Constraint::Constraint(const CONSTRAINT_TYPE typeIn, const unsigned indexOriginalIn, const unsigned indexTypeIn, const unsigned indexNonconstantIn,
+                       const unsigned indexTypeNonconstantIn, const std::string& nameIn):
+    name(nameIn),
+    constantValue(0), type(typeIn), convexity(CONSTRAINT_CONVEXITY::CONV_NONE),
+    monotonicity(CONSTRAINT_MONOTONICITY::MON_NONE), dependency(CONSTRAINT_DEPENDENCY::DEP_UNKNOWN), isConstant(false),
+    isFeasible(true), indexOriginal(indexOriginalIn), indexNonconstant(indexNonconstantIn), indexNonconstantUBP(0), indexConstant(0),
+    indexLinear(0), indexNonlinear(0), indexType(indexTypeIn), indexTypeNonconstant(indexTypeNonconstantIn), indexTypeConstant(0), nparticipatingVariables(0)
+{
+    if (name == "") {
+        std::string str;
+        switch (typeIn) {
+            case OBJ:
+                str = "obj" + std::to_string(indexTypeIn + 1);
+                break;
+            case INEQ:
+                str = "ineq" + std::to_string(indexTypeIn + 1);
+                break;
+            case EQ:
+                str = "eq" + std::to_string(indexTypeIn + 1);
+                break;
+            case INEQ_REL_ONLY:
+                str = "relOnlyIneq" + std::to_string(indexTypeIn + 1);
+                break;
+            case EQ_REL_ONLY:
+                str = "relOnlyEq" + std::to_string(indexTypeIn + 1);
+                break;
+            case INEQ_SQUASH:
+                str = "squashIneq" + std::to_string(indexTypeIn + 1);
+                break;
+            case AUX_EQ_REL_ONLY:
+                str = "auxRelOnlyEq" + std::to_string(indexTypeIn + 1);
+                break;
+            case OUTPUT:
+                str = "output" + std::to_string(indexTypeIn + 1);
+                break;
+            default:
+                str = "constraint" + std::to_string(indexTypeIn + 1);
+                break;
+        }
+        name = str;
+    }
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+Constraint::Constraint(const CONSTRAINT_TYPE typeIn, const unsigned indexOriginalIn, const unsigned indexTypeIn,
+                       const unsigned indexConstantIn, const unsigned indexTypeConstantIn, const bool isConstantIn,
+                       const bool isFeasibleIn, const double valueIn, const std::string& nameIn):
+    name(nameIn), constantValue(valueIn), type(typeIn), convexity(CONSTRAINT_CONVEXITY::CONV_NONE),
+    monotonicity(CONSTRAINT_MONOTONICITY::MON_NONE), dependency(CONSTRAINT_DEPENDENCY::DEP_UNKNOWN), isConstant(isConstantIn),
+    isFeasible(isFeasibleIn), indexOriginal(indexOriginalIn), indexNonconstant(0), indexNonconstantUBP(0), indexConstant(indexConstantIn),
+    indexLinear(0), indexNonlinear(0), indexType(indexTypeIn), indexTypeNonconstant(0), indexTypeConstant(indexTypeConstantIn), nparticipatingVariables(0)
+{
+    if (name == "") {
+        std::string str;
+        switch (typeIn) {
+            case OBJ:
+                str = "obj" + std::to_string(indexTypeIn + 1);
+                break;
+            case INEQ:
+                str = "ineq" + std::to_string(indexTypeIn + 1);
+                break;
+            case EQ:
+                str = "eq" + std::to_string(indexTypeIn + 1);
+                break;
+            case INEQ_REL_ONLY:
+                str = "relOnlyIneq" + std::to_string(indexTypeIn + 1);
+                break;
+            case EQ_REL_ONLY:
+                str = "relOnlyEq" + std::to_string(indexTypeIn + 1);
+                break;
+            case INEQ_SQUASH:
+                str = "squashIneq" + std::to_string(indexTypeIn + 1);
+                break;
+            case AUX_EQ_REL_ONLY:
+                str = "auxRelOnlyEq" + std::to_string(indexTypeIn + 1);
+                break;
+            case OUTPUT:
+                str = "output" + std::to_string(indexTypeIn + 1);
+                break;
+            default:
+                str = "constraint" + std::to_string(indexTypeIn + 1);
+                break;
+        }
+        name = str;
+    }
+}
\ No newline at end of file
diff --git a/src/decayingProbability.cpp b/src/decayingProbability.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc36e65b24c73c1578b521e5532faf577b4d6a25
--- /dev/null
+++ b/src/decayingProbability.cpp
@@ -0,0 +1,30 @@
+/**********************************************************************************
+ * Copyright (c) 2019-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "decayingProbability.h"
+
+#include <cmath>
+#include <cstdlib>
+
+
+namespace maingo {
+
+
+bool
+do_based_on_decaying_probability(const double decayCoefficient, const double decisionVariable)
+{
+    const double probabilityThreshold = std::exp(-decayCoefficient * decisionVariable);
+    const double randomNumber         = std::rand() / ((double)RAND_MAX);
+    return randomNumber <= probabilityThreshold;
+}
+
+
+}    // end namespace maingo
\ No newline at end of file
diff --git a/src/getTime.cpp b/src/getTime.cpp
index 391f89a54be2ef0293b0a33ac5a8aacf2e99e26f..ae4a28e9d9d6022a3ef8261f2c6aa29e1df3067e 100644
--- a/src/getTime.cpp
+++ b/src/getTime.cpp
@@ -27,6 +27,7 @@
 #endif
 
 #include "getTime.h"
+#include "MAiNGOException.h"
 
 
 using namespace maingo;
@@ -62,7 +63,8 @@ maingo::get_cpu_time()
 
 #endif
 
-    return -1;
+    throw MAiNGOException("Error querying CPU time."); // GCOVR_EXCL_LINE
+
 }
 
 
@@ -90,5 +92,6 @@ maingo::get_wall_time()
 
 #endif
 
-    return -1;
+    throw MAiNGOException("Error querying wall-clock time."); // GCOVR_EXCL_LINE
+
 }
\ No newline at end of file
diff --git a/src/lbp.cpp b/src/lbp.cpp
index c929e71492ad9b31bf570ded25c016d383cb9160..bf3f77221d208cb363241cedcefa9e1d2106f832 100644
--- a/src/lbp.cpp
+++ b/src/lbp.cpp
@@ -373,10 +373,10 @@ LowerBoundingSolver::_set_number_of_linpoints(const unsigned int LBP_linPoints)
                 //vMC::additionalLins.initialize(_DAGobj->chosenLinPoints.size(), _nvar, /*midIndex*/0, _DAGobj->subgraphNonlinear.l_op.size(), vMC::additionalLins.COMPOSITION_BEST_POINT);
                 break;
             }
-            default: {
+            default: { // GCOVR_EXCL_START
                 throw MAiNGOException("  Error initializing LowerBoundingSolver: Unknown linearization point for LBP.");
-            }
-        }    // End of switch(LBP_linPoints)
+            } 
+        }   // GCOVR_EXCL_STOP // End of switch(LBP_linPoints)
     }
 }
 
@@ -392,13 +392,13 @@ LowerBoundingSolver::solve_LBP(const babBase::BabNode &currentNode, double &lowe
     try {
         linStatus = _update_LP(currentNode);
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while modifying the lower bounding LP for LBP.", e, currentNode);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while modifying the lower bounding LP for LBP.", currentNode);
     }
-
+// GCOVR_EXCL_STOP
     // Solve problem and check return status
     if (linStatus == LINEARIZATION_UNKNOWN) {
         // Only need to solve the problem if it was not solved during linearization
@@ -546,13 +546,13 @@ LowerBoundingSolver::solve_OBBT(babBase::BabNode &currentNode, const double curr
     try {
         linStatus = _update_LP(currentNode);
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while modifying the lower bounding LP for OBBT.", e, currentNode);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while modifying the lower bounding LP for OBBT.", currentNode);
     }
-
+// GCOVR_EXCL_STOP
     bool foundInfeasible = false;
     if (linStatus == LINEARIZATION_INFEASIBLE) {
         _logger->print_message("  OBBT linearization status: Infeasible", VERB_ALL, LBP_VERBOSITY);
@@ -612,12 +612,12 @@ LowerBoundingSolver::solve_OBBT(babBase::BabNode &currentNode, const double curr
                 _modify_LP_for_feasopt_OBBT(currentUBD, toTreatMax, toTreatMin);
                 break;
             }
-            default: {
+            default: { // GCOVR_EXCL_START
                 std::ostringstream errmsg;
                 errmsg << "  Unknown OBBT range reduction type: " << reductionType;
                 throw MAiNGOException(errmsg.str(), currentNode);
             }
-        }
+        } // GCOVR_EXCL_STOP
 
         // Loop over variable bounds until all variable bounds have either been treated by OBBT or filtered
         unsigned OBBTcnt  = 0;
@@ -933,11 +933,11 @@ LowerBoundingSolver::solve_OBBT(babBase::BabNode &currentNode, const double curr
                                     }
                                 }
                                 break;
-                            default:
+                            default: // GCOVR_EXCL_START
                                 throw MAiNGOException("  Error while solving OBBT: Unknown variable type.");
                                 break;
                         }
-                    }
+                    } // GCOVR_EXCL_STOP
                 }
                 // Restore objective coefficient
                 _set_optimization_sense_of_variable(iVar, 0);
@@ -1095,13 +1095,13 @@ LowerBoundingSolver::do_constraint_propagation(babBase::BabNode &currentNode, co
                         return TIGHTENING_INFEASIBLE;
                     }
                     break;
-                default:
+                default: // GCOVR_EXCL_START
                     std::ostringstream errmsg;
                     errmsg << "  Error while solving constraint propagation: Unknown variable type " << _originalVariables[i].get_variable_type() << std::endl;
                     throw MAiNGOException(errmsg.str());
                     break;
             }
-        }
+        } // GCOVR_EXCL_STOP
     }
     else if (flag < 0) {    // Problem is found to be infeasible
         if (flag < -(int)maxpass) {
@@ -1170,12 +1170,12 @@ LowerBoundingSolver::do_dbbt_and_probing(babBase::BabNode &currentNode, const st
                     }
                     // Sanity check:
                     if (newLowerBounds[iVar] > newUpperBounds[iVar]) {
-                        std::ostringstream errmsg;
+                        std::ostringstream errmsg; // GCOVR_EXCL_START
                         errmsg << "  Error in LowerBoundingSolver - DBBT - 1: while setting new lower bound during DBBT for variable " << iVar << ": upper bound became larger than lower bound: " << std::endl;
                         errmsg << "  " << newLowerBounds[iVar] << " > " << newUpperBounds[iVar];
                         throw MAiNGOException(errmsg.str());
                     }
-                }
+                } // GCOVR_EXCL_STOP
             }
         }
         else if (lbpSolutionPoint[iVar] == newLowerBounds[iVar]) {
@@ -1197,12 +1197,12 @@ LowerBoundingSolver::do_dbbt_and_probing(babBase::BabNode &currentNode, const st
                     }
                     // Sanity check:
                     if (newLowerBounds[iVar] > newUpperBounds[iVar]) {
-                        std::ostringstream errmsg;
+                        std::ostringstream errmsg; // GCOVR_EXCL_START
                         errmsg << "  Error in LowerBoundingSolver - DBBT - 2: while setting new lower bound during DBBT for variable " << iVar << ": upper bound became larger than lower bound: " << std::endl;
                         errmsg << "  " << newLowerBounds[iVar] << " > " << newUpperBounds[iVar];
                         throw MAiNGOException(errmsg.str());
                     }
-                }
+                } // GCOVR_EXCL_STOP
             }
         }
         else {
@@ -1296,13 +1296,13 @@ LowerBoundingSolver::_solve_probing_LBP(babBase::BabNode &currentNode, LbpDualIn
     try {
         _update_LP(currentNode);
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while modifying the lower bounding LP for probing.", e, currentNode);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while modifying the lower bounding LP for probing.", currentNode);
     }
-
+// GCOVR_EXCL_STOP
     // Fix variable
     _fix_variable(iVar, fixToLowerBound);
     // Solve problem and check return status
@@ -1472,11 +1472,11 @@ LowerBoundingSolver::_update_LP(const babBase::BabNode &currentNode)
             return _linearization_points_Kelley_Simplex(currentNode);
             break;
         }
-        default: {
+        default: { // GCOVR_EXCL_START
             throw MAiNGOException("  Error while updating LP: Unknown linearization strategy.");
             break;
         }
-    }
+    } // GCOVR_EXCL_STOP
 }
 
 
@@ -2030,7 +2030,7 @@ LowerBoundingSolver::preprocessor_check_options(const babBase::BabNode &rootNode
         // Check whether the options can be applied with respect to the used solver
         _turn_off_specific_options();
     }
-    catch (const filib::interval_io_exception &e) {
+    catch (const filib::interval_io_exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException(std::string("  (Preprocessor) Error in interval extensions: ") + e.what());
     }
     catch (const MC::Exceptions &e) {
@@ -2042,7 +2042,7 @@ LowerBoundingSolver::preprocessor_check_options(const babBase::BabNode &rootNode
     catch (...) {
         throw MAiNGOException("  (Preprocessor) Unknown error in evaluation of relaxed model equations. ");
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 #ifdef HAVE_GROWING_DATASETS
diff --git a/src/lbpClp.cpp b/src/lbpClp.cpp
index d490342424f13f8c50027020ffcd2d65095b70ac..313f0e7afc1a3408ec79543476d901ce0a1f6eed 100644
--- a/src/lbpClp.cpp
+++ b/src/lbpClp.cpp
@@ -110,13 +110,13 @@ LbpClp::LbpClp(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, const st
         }
 #endif
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error initializing CLP during initialization of LowerBoundingSolver.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error initializing CLP during initialization of LowerBoundingSolver.");
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 ////////////////////////////////////////////////////////////////////////////////////////////
@@ -222,7 +222,7 @@ LbpClp::_update_LP_obj(const MC &resultRelaxation, const std::vector<double> &li
 
     // Linearize objective function:
     if (resultRelaxation.nsub() == 0) {
-        throw MAiNGOException("  Error in evaluation of the relaxed objective function for CLP: objective function does not depend on variables.");
+        throw MAiNGOException("  Error in evaluation of the relaxed objective function for CLP: objective function does not depend on variables."); // GCOVR_EXCL_LINE
     }
     double rhs = 0;
     // If the numbers are too large, we simply set the whole row to 0
@@ -260,11 +260,11 @@ LbpClp::_update_LP_ineq(const MC &resultRelaxation, const std::vector<double> &l
 
     // Linearize inequality constraints:
     if (resultRelaxation.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed inequality constraint " << iIneq + 1 << " (of " << _nineq << ") for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
-    double rhs = 0;
+    } 
+    double rhs = 0; // GCOVR_EXCL_STOP
     if (std::fabs(-resultRelaxation.cv()) > 1e19 || (resultRelaxation.cv() != resultRelaxation.cv())) {
         _rhsIneq[iIneq][iLin] = 0;
 
@@ -296,11 +296,11 @@ LbpClp::_update_LP_eq(const MC &resultRelaxationCv, const MC &resultRelaxationCc
 {
 
     if (resultRelaxationCv.nsub() == 0 || resultRelaxationCc.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed equality constraint " << iEq + 1 << " (of " << _neq << ") for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
-    double rhs = 0;
+    } 
+    double rhs = 0; // GCOVR_EXCL_STOP
     // Convex relaxation <=0:
     if (std::fabs(resultRelaxationCv.cv()) > 1e19 || (resultRelaxationCv.cv() != resultRelaxationCv.cv())) {
         _rhsEq1[iEq][iLin] = 0;
@@ -356,11 +356,11 @@ LbpClp::_update_LP_ineqRelaxationOnly(const MC &resultRelaxation, const std::vec
 {
 
     if (resultRelaxation.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only inequality constraint " << iIneqRelaxationOnly + 1 << " (of " << _nineqRelaxationOnly << ") for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
-    double rhs = 0;
+    } 
+    double rhs = 0; // GCOVR_EXCL_STOP
     if (std::fabs(resultRelaxation.cv()) > 1e19 || (resultRelaxation.cv() != resultRelaxation.cv())) {
         _rhsIneqRelaxationOnly[iIneqRelaxationOnly][iLin] = 0;
 
@@ -394,11 +394,11 @@ LbpClp::_update_LP_eqRelaxationOnly(const MC &resultRelaxationCv, const MC &resu
 
     // Linearize relaxation only equalities
     if (resultRelaxationCv.nsub() == 0 || resultRelaxationCc.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only equality constraint " << iEqRelaxationOnly + 1 << " (of " << _neqRelaxationOnly << ") for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
-    double rhs = 0;
+    } 
+    double rhs = 0; // GCOVR_EXCL_STOP
     // Convex relaxation <=0:
     if (std::fabs(resultRelaxationCv.cv()) > 1e19 || (resultRelaxationCv.cv() != resultRelaxationCv.cv())) {
         _rhsEqRelaxationOnly1[iEqRelaxationOnly][iLin] = 0;
@@ -458,11 +458,11 @@ LbpClp::_update_LP_ineq_squash(const MC &resultRelaxation, const std::vector<dou
 
     // Linearize inequality constraints:
     if (resultRelaxation.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed squash inequality constraint " << iIneqSquash + 1 << " (of " << _nineqSquash << ") for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
-    double rhs = 0;
+    } 
+    double rhs = 0; // GCOVR_EXCL_STOP
     if (std::fabs(-resultRelaxation.cv()) > 1e19 || (resultRelaxation.cv() != resultRelaxation.cv())) {
         _rhsIneqSquash[iIneqSquash][iLin] = 0;
 
@@ -495,10 +495,11 @@ LbpClp::_update_LP_obj(const vMC &resultRelaxationVMC, const std::vector<std::ve
 
     // Linearize objective function:
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of the relaxed objective function (vector) for CLP: objective function does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
+    } 
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinObj[0];
     for (unsigned iLin = 0; iLin < wantedLins; iLin++) {
@@ -540,10 +541,11 @@ LbpClp::_update_LP_ineq(const vMC &resultRelaxationVMC, const std::vector<std::v
 
     // Linearize inequality constraints:
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed inequality constraint " << iIneq + 1 << " (of " << _nineq << ") (vector) for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
+    } 
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinIneq[iIneq];
     for (unsigned iLin = 0; iLin < wantedLins; iLin++) {
@@ -581,10 +583,11 @@ LbpClp::_update_LP_eq(const vMC &resultRelaxationCvVMC, const vMC &resultRelaxat
 
     // Linearize equality Constraints:
     if (resultRelaxationCvVMC.nsub() == 0 || resultRelaxationCcVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed equality constraint " << iEq + 1 << " (of " << _neq << ") (vector) for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
+    } 
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinEq[iEq];
     for (unsigned iLin = 0; iLin < wantedLins; iLin++) {
@@ -646,10 +649,11 @@ LbpClp::_update_LP_ineqRelaxationOnly(const vMC &resultRelaxationVMC, const std:
 
     // Linearize relaxation only inequalities
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only inequality constraint " << iIneqRelaxationOnly + 1 << " (of " << _nineqRelaxationOnly << ") (vector) for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
+    } 
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinIneqRelaxationOnly[iIneqRelaxationOnly];
     for (unsigned iLin = 0; iLin < wantedLins; iLin++) {
@@ -687,10 +691,11 @@ LbpClp::_update_LP_eqRelaxationOnly(const vMC &resultRelaxationCvVMC, const vMC
 
     // Linearize relaxation only equalities
     if (resultRelaxationCvVMC.nsub() == 0 || resultRelaxationCcVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only equality constraint " << iEqRelaxationOnly + 1 << " (of " << _neqRelaxationOnly << ") (vector) for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
+    } 
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinEqRelaxationOnly[iEqRelaxationOnly];
     for (unsigned iLin = 0; iLin < wantedLins; iLin++) {
@@ -751,10 +756,11 @@ LbpClp::_update_LP_ineq_squash(const vMC &resultRelaxationVMC, const std::vector
 
     // Linearize inequality constraints:
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed squash inequality constraint " << iIneqSquash + 1 << " (of " << _nineqSquash << ") (vector) for CLP: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
+    } 
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinIneqSquash[iIneqSquash];
     for (unsigned iLin = 0; iLin < wantedLins; iLin++) {
@@ -895,13 +901,13 @@ LbpClp::_solve_LP(const babBase::BabNode &currentNode)
         // Use dual algorithm
         _clp.dual();
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while solving the LP with CLP.", e, currentNode);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while solving the LP with CLP.", currentNode);
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 /////////////////////////////////////////////////////////////////////////////////////////////
@@ -935,9 +941,10 @@ LbpClp::_get_solution_point(std::vector<double> &solution, double &etaVal)
         columnPrimal = _clp.primalColumnSolution();
         etaVal       = _clp.objectiveValue();
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error querying solution point from CLP.", e);
     }
+    // GCOVR_EXCL_STOP
     // Ok, successfully obtained solution point
     solution.clear();
     for (unsigned i = 0; i < _nvar; i++) {
@@ -969,9 +976,10 @@ LbpClp::_get_multipliers(std::vector<double> &multipliers)
             multipliers[i] = columnDual[i];
         }
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while extracting multipliers from CLP", e);
     }
+    // GCOVR_EXCL_STOP
 }
 
 
@@ -1133,13 +1141,13 @@ LbpClp::_check_infeasibility(const babBase::BabNode &currentNode)
             reallyInfeasible = true;
         }
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         std::ostringstream errmsg;
         errmsg << "  Error: Variables at dual point of Farkas' certificate of LBP could not be extracted from CLP. " << std::endl;
         errmsg << "  CLP status is: " << _clp.status();
         throw MAiNGOException(errmsg.str(), e, currentNode);
     }
-
+    // GCOVR_EXCL_STOP
     if (reallyInfeasible) {
         // Check Farkas' Lemma, for the application please read some literature.
         // In general, we want to find a point such that y^T *A>=0 and b^T *y <0 since then for x>=0 and A*x<=b, 0 > y^T *b >= y^T *A *x >=0 which is a contradiction, so y^T *b <= y^T *A *x has to hold for an x
@@ -1423,8 +1431,7 @@ LbpClp::_check_optimality(const babBase::BabNode &currentNode, const double newL
         double *rowDual = _clp.dualRowSolution();
 
         if (!rowDual) {
-            std::cout << std::endl
-                      << "Could not retreive Dual Row prices.." << std::endl;
+            _logger->print_message("Could not retreive Dual Row prices..", VERB_NORMAL, LBP_VERBOSITY);
             return SUBSOLVER_FEASIBLE;
         }
 
@@ -1470,10 +1477,10 @@ LbpClp::_check_optimality(const babBase::BabNode &currentNode, const double newL
                 dualVar++;
             }
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error in optimality check: Variables at dual solution of LBP could not be extracted from CLP", e, currentNode);
     }
-
+    // GCOVR_EXCL_STOP
     // Ok, successfully obtained dual solution point
     // If multiplier[i] of variable x_i is >0 then you add multiplier[i]*lower bound, else multiplier[i]*upper bound
     std::vector<double> primal;
diff --git a/src/lbpCplex.cpp b/src/lbpCplex.cpp
index 62458826463d9cbc91bdf86a5fab404cf6095efd..288d55181455bcac8fe1b8d74ba30e902c4469be 100644
--- a/src/lbpCplex.cpp
+++ b/src/lbpCplex.cpp
@@ -182,13 +182,13 @@ LbpCplex::LbpCplex(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, cons
         }
 #endif
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error initializing CPLEX during initialization of LowerBoundingSolver.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error initializing CPLEX during initialization of LowerBoundingSolver.");
     }
-}
+}// GCOVR_EXCL_STOP
 
 
 /////////////////////////////////////////////////////////////////////////////////////////////
@@ -236,11 +236,11 @@ LbpCplex::_update_LP_obj(const MC &resultRelaxation, const std::vector<double> &
 
     // Linearize objective function:
     if (resultRelaxation.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of the relaxed objective function for CPLEX: objective function does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
-    double rhs = 0;
+    double rhs = 0; // GCOVR_EXCL_STOP
     // If the numbers are too large, we simply set the whole row to 0
     // NOTE: second check is for NaN
     if (std::fabs(-resultRelaxation.cv()) > 1e19 || (resultRelaxation.cv() != resultRelaxation.cv())) {
@@ -287,12 +287,12 @@ LbpCplex::_update_LP_ineq(const MC &resultRelaxation, const std::vector<double>
 {
 
     // Linearize inequality constraints:
-    if (resultRelaxation.nsub() == 0) {
-        std::ostringstream errmsg;
+    if (resultRelaxation.nsub() == 0) { 
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed inequality constraint " << iIneq + 1 << " (of " << _nineq << ") for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
-    double rhs = 0;
+    double rhs = 0; // GCOVR_EXCL_STOP
     if (std::fabs(-resultRelaxation.cv()) > 1e19 || (resultRelaxation.cv() != resultRelaxation.cv())) {
         linIneq[iIneq][iLin].setUB(0);
 #ifdef LP__OPTIMALITY_CHECK
@@ -334,11 +334,11 @@ LbpCplex::_update_LP_eq(const MC &resultRelaxationCv, const MC &resultRelaxation
 
     // Linearize equality Constraints:
     if (resultRelaxationCv.nsub() == 0 || resultRelaxationCc.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed equality constraint " << iEq + 1 << " (of " << _neq << ") for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
-    double rhs = 0;
+    double rhs = 0; // GCOVR_EXCL_STOP
     // Convex relaxation <=0:
     if (std::fabs(resultRelaxationCv.cv()) > 1e19 || (resultRelaxationCv.cv() != resultRelaxationCv.cv())) {
         linEq1[iEq][iLin].setUB(0);
@@ -413,11 +413,11 @@ LbpCplex::_update_LP_ineqRelaxationOnly(const MC &resultRelaxation, const std::v
 
     // Linearize relaxation only inequalities
     if (resultRelaxation.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only inequality constraint " << iIneqRelaxationOnly + 1 << " (of " << _nineqRelaxationOnly << ") for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
-    double rhs = 0;
+    double rhs = 0; // GCOVR_EXCL_STOP
     if (std::fabs(resultRelaxation.cv()) > 1e19 || (resultRelaxation.cv() != resultRelaxation.cv())) {
         linIneqRelaxationOnly[iIneqRelaxationOnly][iLin].setUB(0);
 #ifdef LP__OPTIMALITY_CHECK
@@ -459,11 +459,11 @@ LbpCplex::_update_LP_eqRelaxationOnly(const MC &resultRelaxationCv, const MC &re
 
     // Linearize relaxation only equalities
     if (resultRelaxationCv.nsub() == 0 || resultRelaxationCc.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only equality constraint " << iEqRelaxationOnly + 1 << " (of " << _neqRelaxationOnly << ") for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
-    double rhs = 0;
+    double rhs = 0; // GCOVR_EXCL_STOP
     // Convex relaxation <=0:
     if (std::fabs(resultRelaxationCv.cv()) > 1e19 || (resultRelaxationCv.cv() != resultRelaxationCv.cv())) {
         linEqRelaxationOnly1[iEqRelaxationOnly][iLin].setUB(0);
@@ -537,11 +537,11 @@ LbpCplex::_update_LP_ineq_squash(const MC &resultRelaxation, const std::vector<d
 
     // Linearize inequality constraints:
     if (resultRelaxation.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed squash inequality constraint " << iIneqSquash + 1 << " (of " << _nineqSquash << ") for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
-    double rhs = 0;
+    double rhs = 0; // GCOVR_EXCL_STOP
     if (std::fabs(-resultRelaxation.cv()) > 1e19 || (resultRelaxation.cv() != resultRelaxation.cv())) {
         linIneqSquash[iIneqSquash][iLin].setUB(0);
 #ifdef LP__OPTIMALITY_CHECK
@@ -583,10 +583,11 @@ LbpCplex::_update_LP_obj(const vMC &resultRelaxationVMC, const std::vector<std::
 
     // Linearize objective function:
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of the relaxed objective function (vector) for CPLEX: objective function does not depend on variables.";
         throw MAiNGOException(errmsg.str());
-    }
+    } 
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinObj[0];
     for (unsigned int iLin = 0; iLin < wantedLins; iLin++) {
@@ -639,10 +640,11 @@ LbpCplex::_update_LP_ineq(const vMC &resultRelaxationVMC, const std::vector<std:
 
     // Linearize inequality constraints:
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed inequality constraint " << iIneq + 1 << " (of " << _nineq << ") (vector) for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinIneq[iIneq];
     for (unsigned int iLin = 0; iLin < wantedLins; iLin++) {
@@ -689,10 +691,11 @@ LbpCplex::_update_LP_eq(const vMC &resultRelaxationCvVMC, const vMC &resultRelax
 
     // Linearize equality Constraints:
     if (resultRelaxationCvVMC.nsub() == 0 || resultRelaxationCcVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed equality constraint " << iEq + 1 << " (of " << _neq << ") (vector) for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinEq[iEq];
     for (unsigned int iLin = 0; iLin < wantedLins; iLin++) {
@@ -772,10 +775,11 @@ LbpCplex::_update_LP_ineqRelaxationOnly(const vMC &resultRelaxationVMC, const st
 
     // Linearize relaxation only inequalities
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only inequality constraint " << iIneqRelaxationOnly + 1 << " (of " << _nineqRelaxationOnly << ") (vector) for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinIneqRelaxationOnly[iIneqRelaxationOnly];
     for (unsigned int iLin = 0; iLin < wantedLins; iLin++) {
@@ -822,10 +826,11 @@ LbpCplex::_update_LP_eqRelaxationOnly(const vMC &resultRelaxationCvVMC, const vM
 
     // Linearize relaxation only equalities
     if (resultRelaxationCvVMC.nsub() == 0 || resultRelaxationCcVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxation-only equality constraint " << iEqRelaxationOnly + 1 << " (of " << _neqRelaxationOnly << ") (vector) for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinEqRelaxationOnly[iEqRelaxationOnly];
     for (unsigned int iLin = 0; iLin < wantedLins; iLin++) {
@@ -904,10 +909,11 @@ LbpCplex::_update_LP_ineq_squash(const vMC &resultRelaxationVMC, const std::vect
 
     // Linearize inequality constraints:
     if (resultRelaxationVMC.nsub() == 0) {
-        std::ostringstream errmsg;
+        std::ostringstream errmsg; // GCOVR_EXCL_START
         errmsg << "  Error in evaluation of relaxed squash inequality constraint " << iIneqSquash + 1 << " (of " << _nineqSquash << ") (vector) for CPLEX: constraint does not depend on variables.";
         throw MAiNGOException(errmsg.str());
     }
+    // GCOVR_EXCL_STOP
     // Loop over all linearization points
     unsigned wantedLins = _differentNumberOfLins ? _DAGobj->chosenLinPoints.size() : _nLinIneqSquash[iIneqSquash];
     for (unsigned int iLin = 0; iLin < wantedLins; iLin++) {
@@ -954,13 +960,13 @@ LbpCplex::_solve_LP(const babBase::BabNode &currentNode)
     try {
         cplex.solve();
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while solving the LP with CPLEX.", e, currentNode);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while solving the LP with CPLEX.", currentNode);
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 /////////////////////////////////////////////////////////////////////////////////////////////
@@ -998,13 +1004,14 @@ LbpCplex::_get_solution_point(std::vector<double> &solution, double &etaVal)
         cplex.getValues(vals, cplxVars);
         etaVal = cplex.getValue(eta);
     }
-    catch (IloException &e) {
+    catch (IloException &e) { // GCOVR_EXCL_START
         // Return empty solution instead
         vals.end();
         std::ostringstream errmsg;
         errmsg << "  Could not extract solution point from CPLEX: " << e;
         throw MAiNGOException(errmsg.str());
     }
+    // GCOVR_EXCL_STOP
     // Ok, successfully obtained solution point
     solution.clear();
     for (unsigned int i = 0; i < _nvar; i++) {
@@ -1039,12 +1046,12 @@ LbpCplex::_get_multipliers(std::vector<double> &multipliers)
         }
         cplxMultipliers.end();
     }
-    catch (const std::exception &e) {
+    catch (const std::exception &e) { // GCOVR_EXCL_START
         // This is okay, not providing multipliers
         cplxMultipliers.end();
         throw MAiNGOException("  Could not extract multipliers from CPLEX.", e);
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 /////////////////////////////////////////////////////////////////////////////////////////////
@@ -1215,13 +1222,13 @@ LbpCplex::_check_infeasibility(const babBase::BabNode &currentNode)
         }
         cplex.setParam(IloCplex::PreInd, 1);    // Turn on pre-solve
     }
-    catch (IloException &e) {
+    catch (IloException &e) { // GCOVR_EXCL_START
         std::ostringstream errmsg;
         errmsg << "  Error: Variables at dual point of Farkas' certificate of LBP could not be extracted from CPLEX: " << e << std::endl;
         errmsg << "         CPLEX status is: " << cplex.getStatus() << std::endl;
         throw MAiNGOException(errmsg.str(), currentNode);
     }
-    if (reallyInfeasible) {
+    if (reallyInfeasible) { // GCOVR_EXCL_STOP
         // Check Farkas' Lemma, for the application please read some literature.
         // In general, we want to find a point such that y^T *A>=0 and b^T *y <0 since then for x>=0 and A*x<=b, 0 > y^T *b >= y^T *A *x >=0 which is a contradiction, so y^T *b <= y^T *A *x has to hold for an x
         // Order of constraints in farkasVals: 1. obj constraint 2. ineq 3. eq convex 4. eq concave 5. rel_only_ineq  6. rel_only_eq convex 7. rel_only_eq concave 8. squash ineq
@@ -1521,11 +1528,12 @@ LbpCplex::_check_optimality(const babBase::BabNode &currentNode, const double ne
             cplex.getDuals(dualValsIneqSquash[i], linIneqSquash[i]);
         }
     }
-    catch (IloException &e) {
+    catch (IloException &e) { // GCOVR_EXCL_START
         std::ostringstream errmsg;
         errmsg << "  Error in optimality check:: Variables at dual solution of LBP could not be extracted from CPLEX:" << e << std::endl;
         throw MAiNGOException(errmsg.str(), currentNode);
     }
+    // GCOVR_EXCL_STOP
     // Ok, successfully obtained dual solution point
     // If multiplier[i] of variable x_i is >0 then you add multiplier[i]*lower bound, else multiplier[i]*upper bound
     std::vector<double> primal;
@@ -1640,13 +1648,13 @@ LbpCplex::_write_LP_to_file(const std::string &fileName)
     try {
         cplex.exportModel(str.c_str());
     }
-    catch (IloException &e) {
+    catch (IloException &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while exporting model from CPLEX.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while exporting model from CPLEX.";
     }
-}
+} // GCOVR_EXCL_STOP
 #endif
 
 /////////////////////////////////////////////////////////////////////////
diff --git a/src/lbpFactory.cpp b/src/lbpFactory.cpp
index 6650f8106944efc49caae7cf3bf5f311aa13c2ec..179b5f20b66fc09218a62e72ed8e9f8e9fe9ee02 100644
--- a/src/lbpFactory.cpp
+++ b/src/lbpFactory.cpp
@@ -51,7 +51,7 @@ lbp::make_lbp_solver(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, co
             return std::make_shared<LbpCplex>(DAG, DAGvars, DAGfunctions, variables, variableIsLinear, nineqIn, neqIn,
                                               nineqRelaxationOnlyIn, neqRelaxationOnlyIn, nineqSquashIn, settingsIn, loggerIn, constraintPropertiesIn);
 #else
-            throw MAiNGOException("  Error in LbpFactory: Cannot use lower bounding strategy LBP_SOLVER_CPLEX: Your MAiNGO build does not contain CPLEX.");
+            throw MAiNGOException("  Error in LbpFactory: Cannot use lower bounding strategy LBP_SOLVER_CPLEX: Your MAiNGO build does not contain CPLEX."); // GCOVR_EXCL_LINE
 #endif
         }
         case LBP_SOLVER_CLP: {
@@ -59,10 +59,10 @@ lbp::make_lbp_solver(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, co
             return std::make_shared<LbpClp>(DAG, DAGvars, DAGfunctions, variables, variableIsLinear, nineqIn, neqIn,
                                             nineqRelaxationOnlyIn, neqRelaxationOnlyIn, nineqSquashIn, settingsIn, loggerIn, constraintPropertiesIn);
         }
-        default: {
+        default: {// GCOVR_EXCL_START
             std::ostringstream errmsg;
             errmsg << "  Error in LbpFactory: Unknown lower bounding solver: " << settingsIn->LBP_solver;
             throw MAiNGOException(errmsg.str());
         }
-    }
+    } // GCOVR_EXCL_STOP
 }
diff --git a/src/lbpLinearizationStrats.cpp b/src/lbpLinearizationStrats.cpp
index bd85f9f4cbb9dfe1207ee8c919e45e516d4a9558..58a58db6397eb2ceca25d97a72e1bba07c2bff5d 100644
--- a/src/lbpLinearizationStrats.cpp
+++ b/src/lbpLinearizationStrats.cpp
@@ -90,7 +90,7 @@ LowerBoundingSolver::_linearize_functions_at_linpoint(std::vector<MC> &resultRel
             _DAGobj->DAG.eval(subgraph, _DAGobj->MCarray, functions.size(), functions.data(), resultRelaxation.data(), _nvar, _DAGobj->vars.data(), _DAGobj->McPoint.data());
         }
     }
-    catch (const filib::interval_io_exception &e) {
+    catch (const filib::interval_io_exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException(std::string("  Error in interval extensions: ") + e.what());
     }
     catch (const MC::Exceptions &e) {
@@ -105,7 +105,7 @@ LowerBoundingSolver::_linearize_functions_at_linpoint(std::vector<MC> &resultRel
     catch (...) {
         throw MAiNGOException("  Unknown error in evaluation of relaxed model equations.");
     }
-
+    // GCOVR_EXCL_STOP
     if (_maingoSettings->LBP_subgradientIntervals) {
         // Reset interval iterator to enable the computation of the next linearization point with the use of precomputed intervals
         MC::subHeur.reset_iterator();
@@ -137,7 +137,7 @@ LowerBoundingSolver::_linearize_functions_at_preset_vector_linpoint(std::vector<
             _DAGobj->DAG.eval(subgraph, _DAGobj->vMCarray, functions.size(), functions.data(), resultRelaxationVMC.data(), _nvar, _DAGobj->vars.data(), _DAGobj->vMcPoint.data());
         }
     }
-    catch (const filib::interval_io_exception &e) {
+    catch (const filib::interval_io_exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException(std::string("  Error in interval extensions: ") + e.what());
     }
     catch (const MC::Exceptions &e) {
@@ -152,7 +152,7 @@ LowerBoundingSolver::_linearize_functions_at_preset_vector_linpoint(std::vector<
     catch (...) {
         throw MAiNGOException("  Unknown error in evaluation of relaxed model equations. ");
     }
-
+    // GCOVR_EXCL_STOP
     if (_maingoSettings->LBP_subgradientIntervals) {
         // Reset interval iterator to enable the computation of the next linearization point with the use of precomputed intervals
         vMC::subHeur.reset_iterator();
diff --git a/src/logger.cpp b/src/logger.cpp
index 3c6ffdab341a994806c9813aa838c37a2d4f947c..4baea91a98efb87d8ad1277495cf565c445f4149 100644
--- a/src/logger.cpp
+++ b/src/logger.cpp
@@ -20,6 +20,12 @@
 using namespace maingo;
 
 
+/////////////////////////////////////////////////////////////////////////
+Logger::Logger(const std::shared_ptr<Settings> settings):
+        _settings(settings)
+{}
+
+
 /////////////////////////////////////////////////////////////////////////
 // helper function for print_message which handels printing to the right logging destinations
 void
@@ -233,16 +239,20 @@ Logger::create_iterations_csv_file(const bool writeCsv) const
 void
 Logger::write_all_lines_to_log(const std::string& errorMessage)
 {
-    std::ofstream logFile;
-    logFile.open(logFileName, std::ios::app);
-    while (babLine.size() > 0) {
-        logFile << babLine.front();
-        babLine.pop();
-    }
-    if (!errorMessage.empty()) {
-        logFile << errorMessage << std::endl;
+    const LOGGING_DESTINATION givenOutstreamVerbosity = _settings->loggingDestination;
+
+    if ((givenOutstreamVerbosity == LOGGING_FILE_AND_STREAM) || (givenOutstreamVerbosity == LOGGING_FILE)) {
+        std::ofstream logFile;
+        logFile.open(logFileName, std::ios::app);
+        while (babLine.size() > 0) {
+            logFile << babLine.front();
+            babLine.pop();
+        }
+        if (!errorMessage.empty()) {
+            logFile << errorMessage << std::endl;
+        }
+        logFile.close();
     }
-    logFile.close();
 }
 
 
@@ -304,7 +314,8 @@ Logger::save_setting(const SETTING_NAMES settingName, const std::string& str)
                 wrongSettings++;
             }
             _userSetSettings[wrongSettings] = str;
-        } break;
+            break;
+        }
         default:
             // Replace/insert the new setting string
             _userSetSettings[static_cast<int>(settingName)] = str;
diff --git a/src/outputVariable.cpp b/src/outputVariable.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b4831cfdf2f601e9b0e8741b7a9ceec774ae557c
--- /dev/null
+++ b/src/outputVariable.cpp
@@ -0,0 +1,39 @@
+/**********************************************************************************
+ * Copyright (c) 2019-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "outputVariable.h"
+
+
+using namespace maingo;
+
+
+/////////////////////////////////////////////////////////////////////////
+OutputVariable::OutputVariable(const std::string descriptionIn, const mc::FFVar valueIn):
+    description(descriptionIn), value(valueIn)
+{}
+
+
+/////////////////////////////////////////////////////////////////////////
+OutputVariable:: OutputVariable(const mc::FFVar valueIn, const std::string descriptionIn):
+        value(valueIn), description(descriptionIn)
+{}
+
+
+/////////////////////////////////////////////////////////////////////////
+OutputVariable::OutputVariable(const std::tuple<mc::FFVar, std::string> tupleIn):
+        value(std::get<0>(tupleIn)), description(std::get<1>(tupleIn))
+{}
+
+
+/////////////////////////////////////////////////////////////////////////
+OutputVariable::OutputVariable(const std::tuple<std::string, mc::FFVar> tupleIn):
+        value(std::get<1>(tupleIn)), description(std::get<0>(tupleIn))
+{}
\ No newline at end of file
diff --git a/src/ubp.cpp b/src/ubp.cpp
index 4e6adf3b4849edadca602bf2d9959b71f5b65c3f..6120b6a125cc496ffe0c27e43d37ef4384a721e7 100644
--- a/src/ubp.cpp
+++ b/src/ubp.cpp
@@ -34,7 +34,6 @@ UpperBoundingSolver::UpperBoundingSolver(mc::FFGraph &DAG, const std::vector<mc:
     _originalVariables(variables),
     _maingoSettings(settingsIn), _logger(loggerIn), _constraintProperties(constraintPropertiesIn), _intendedUse(useIn)
 {
-
     _DAGobj = std::make_shared<DagObj>(DAG, DAGvars, DAGfunctions, variables, nineqIn, neqIn, nineqSquashIn, constraintPropertiesIn, settingsIn, loggerIn);
 
     _nvar        = variables.size();
@@ -945,13 +944,13 @@ UpperBoundingSolver::check_feasibility(const std::vector<double> &currentPoint,
         // If we get here the point is infeasible
         return SUBSOLVER_INFEASIBLE;
     }
-    catch (const std::exception &e) {
+    catch (const std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error in evaluation of double Model equations while checking feasibility. ", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error in evaluation of double Model equations while checking feasibility. ");
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 #ifdef HAVE_GROWING_DATASETS
diff --git a/src/ubpClp.cpp b/src/ubpClp.cpp
index 2b160b6013cdf23ef2035a5067614049b9f2f663..2723c9445eaaba08425b1be20322cba63f3fa221 100644
--- a/src/ubpClp.cpp
+++ b/src/ubpClp.cpp
@@ -36,13 +36,13 @@ UbpClp::UbpClp(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, const st
         _clp.setDualTolerance(_maingoSettings->epsilonA);
         _clp.setRandomSeed(42);    // Make the behavior of CLP deterministic
     }
-    catch (const std::exception &e) {
+    catch (const std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error initializing UbpClp", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error initializing UbpClp.");
     }
-}
+} // GCOVR_EXCL_STOP
 
 /////////////////////////////////////////////////////////////////////////
 // solve the underlying problem
@@ -113,7 +113,7 @@ UbpClp::_solve_nlp(const std::vector<double> &lowerVarBounds, const std::vector<
         // Add coefficients and right-hand sides to the model
         size_t irow = 0;
         for (size_t i = 0; i < _constraintProperties->size(); i++) {
-            const size_t index       = (*_constraintProperties)[i].indexNonconstant;
+            const size_t index       = (*_constraintProperties)[i].indexNonconstantUBP;
             QuadExpr evaluatedResult = resultCoefficients[index].assemble_quadratic_expression_matrix_wise(_nvar);
             switch ((*_constraintProperties)[i].type) {
                 case OBJ:
@@ -174,13 +174,13 @@ UbpClp::_solve_nlp(const std::vector<double> &lowerVarBounds, const std::vector<
         // Solve problem using dual simplex
         _clp.dual();
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while solving the UBP with CLP.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while solving UBP with CLP.");
     }
-
+    // GCOVR_EXCL_STOP
     // Get CLP status
     const int clpStatus = _clp.status();
     if ((clpStatus == 1) || (clpStatus == 2)) {
diff --git a/src/ubpCplex.cpp b/src/ubpCplex.cpp
index 5c5b9ab9bf57bc317f9e992abedde397829d430c..db4992674aa8bd36c68b4f8b22d5f8750427ec85 100644
--- a/src/ubpCplex.cpp
+++ b/src/ubpCplex.cpp
@@ -29,7 +29,6 @@ UbpCplex::UbpCplex(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, cons
     UpperBoundingSolver(DAG, DAGvars, DAGfunctions, variables, nineqIn, neqIn, nineqSquashIn, settingsIn, loggerIn, constraintPropertiesIn, useIn)
 {
     try {
-
         // Initialize CPLEX problem
         // Model and variables
         cplxModel = IloModel(cplxEnv);
@@ -56,7 +55,7 @@ UbpCplex::UbpCplex(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, cons
 
         // Add functions to the model
         for (size_t i = 0; i < _constraintProperties->size(); i++) {
-            unsigned index = (*_constraintProperties)[i].indexNonconstant;
+            unsigned index = (*_constraintProperties)[i].indexNonconstantUBP;
 #ifdef LAZYQUAD
             ///QuadExpr constructedResult=resultCoefficients[index].assemble_quadratic_expression_element_wise(_nvar);
             QuadExpr constructedResult = resultCoefficients[index].assemble_quadratic_expression_matrix_wise(_nvar);
@@ -131,13 +130,13 @@ UbpCplex::UbpCplex(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, cons
         // Obtain global solution of non-convex MIQCPs
         cplex.setParam(IloCplex::OptimalityTarget, CPX_OPTIMALITYTARGET_OPTIMALGLOBAL);
     }
-    catch (const std::exception &e) {
+    catch (const std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error initializing UbpCplex.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error initializing UbpCplex.");
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 /////////////////////////////////////////////////////////////////////////
@@ -150,13 +149,13 @@ UbpCplex::_solve_nlp(const std::vector<double> &lowerVarBounds, const std::vecto
     try {
         cplex.solve();
     }
-    catch (std::exception &e) {
+    catch (std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error while solving the UBP with CPLEX.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error while solving UBP with CPLEX.");
     }
-
+    // GCOVR_EXCL_STOP
     // Get CPLEX status
     IloAlgorithm::Status cplexStatus = cplex.getStatus();
     if ((cplexStatus == IloAlgorithm::Infeasible) || (cplexStatus == IloAlgorithm::InfeasibleOrUnbounded)) {
@@ -208,9 +207,10 @@ UbpCplex::_solve_nlp(const std::vector<double> &lowerVarBounds, const std::vecto
         }
         return SUBSOLVER_FEASIBLE;
     }
-    catch (...) {
+    catch (...) { // GCOVR_EXCL_START
         throw MAiNGOException("  Unknown error while querying solution point from CPLEX.");
     }
+    // GCOVR_EXCL_STOP
     // Ok, successfully obtained solution point
     solutionPoint.clear();
     for (unsigned int i = 0; i < _nvar; i++) {
diff --git a/src/ubpFactory.cpp b/src/ubpFactory.cpp
index ccc467b564d797a1dbc8eac43baf6a545f1a522b..d45d3213bd289e8a14c876839ca4385fe7a9ea66 100644
--- a/src/ubpFactory.cpp
+++ b/src/ubpFactory.cpp
@@ -37,7 +37,6 @@ ubp::make_ubp_solver(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, co
                      const unsigned neqIn, const unsigned nineqSquashIn, std::shared_ptr<Settings> settingsIn, std::shared_ptr<Logger> loggerIn,
                      std::shared_ptr<std::vector<Constraint>> constraintPropertiesIn, UpperBoundingSolver::UBS_USE useIn)
 {
-
     UBP_SOLVER desiredSolver;
     std::string useDescription;
     switch (useIn) {
@@ -49,11 +48,11 @@ ubp::make_ubp_solver(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, co
             useDescription = "Upper bounding";
             desiredSolver  = settingsIn->UBP_solverBab;
             break;
-        default:
+        default: // GCOVR_EXCL_START
             throw MAiNGOException("  Error in UbpFactory: unknown intended use for upper bounding solver.");
     }
 
-    switch (desiredSolver) {
+    switch (desiredSolver) { // GCOVR_EXCL_STOP
         case UBP_SOLVER_EVAL: {
             loggerIn->print_message("      " + useDescription + ": Function evaluation\n", VERB_NORMAL, BAB_VERBOSITY);
             return std::make_shared<UpperBoundingSolver>(DAG, DAGvars, DAGfunctions, variables, nineqIn, neqIn, nineqSquashIn, settingsIn, loggerIn, constraintPropertiesIn, useIn);
@@ -83,23 +82,23 @@ ubp::make_ubp_solver(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, co
             loggerIn->print_message("      " + useDescription + ": KNITRO\n", VERB_NORMAL, BAB_VERBOSITY);
             return std::make_shared<UbpKnitro>(DAG, DAGvars, DAGfunctions, variables, nineqIn, neqIn, nineqSquashIn, settingsIn, loggerIn, constraintPropertiesIn, useIn);
 #else
-            throw MAiNGOException("  Error in UbpFactory: Cannot use upper bounding strategy UBP_SOLVER_KNITRO: Your MAiNGO build does not contain KNITRO.");
+            throw MAiNGOException("  Error in UbpFactory: Cannot use upper bounding strategy UBP_SOLVER_KNITRO: Your MAiNGO build does not contain KNITRO."); // GCOVR_EXCL_LINE
 #endif
         }
         case UBP_SOLVER_CPLEX: {
 #ifdef HAVE_CPLEX
             return std::make_shared<UbpCplex>(DAG, DAGvars, DAGfunctions, variables, nineqIn, neqIn, nineqSquashIn, settingsIn, loggerIn, constraintPropertiesIn, useIn);
 #else
-            throw MAiNGOException("  Error in UbpFactory: Cannot use upper bounding strategy UBP_SOLVER_CPLEX: Your MAiNGO build does not contain CPLEX.");
+            throw MAiNGOException("  Error in UbpFactory: Cannot use upper bounding strategy UBP_SOLVER_CPLEX: Your MAiNGO build does not contain CPLEX."); // GCOVR_EXCL_LINE
 #endif
         }
         case UBP_SOLVER_CLP: {
             return std::make_shared<UbpClp>(DAG, DAGvars, DAGfunctions, variables, nineqIn, neqIn, nineqSquashIn, settingsIn, loggerIn, constraintPropertiesIn, useIn);
         }
-        default: {
+        default: { // GCOVR_EXCL_START
             std::ostringstream errmsg;
             errmsg << "  Error in UbpFactory: Unknown upper bounding strategy: " << desiredSolver << std::endl;
-            throw MAiNGOException("  Error in UbpFactory: Unknown upper bounding strategy: " + std::to_string(desiredSolver));
+            throw MAiNGOException("  Error in UbpFactory: Unknown upper bounding strategy: " + std::to_string(desiredSolver)); 
         }
-    }
+    } // GCOVR_EXCL_STOP
 }
\ No newline at end of file
diff --git a/src/ubpIpopt.cpp b/src/ubpIpopt.cpp
index 84e295281bbfb4f39360e974331baea9d665ab1d..d6e14627ef473b9626b91054de177f582d8b2b8d 100644
--- a/src/ubpIpopt.cpp
+++ b/src/ubpIpopt.cpp
@@ -85,16 +85,16 @@ UbpIpopt::UbpIpopt(mc::FFGraph &DAG, const std::vector<mc::FFVar> &DAGvars, cons
         // Initialize
         Ipopt::ApplicationReturnStatus status = _Ipopt->Initialize();
         if (status != Ipopt::Solve_Succeeded) {
-            throw MAiNGOException(" Status of Ipopt initialization: " + std::to_string(status));
+            throw MAiNGOException(" Status of Ipopt initialization: " + std::to_string(status)); // GCOVR_EXCL_LINE
         }
     }
-    catch (const std::exception &e) {
+    catch (const std::exception &e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error initializing UbpIpopt.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error initializing UbpIpopt.");
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 /////////////////////////////////////////////////////////////////////////
@@ -115,7 +115,7 @@ UbpIpopt::_solve_nlp(const std::vector<double> &lowerVarBounds, const std::vecto
         _logger->print_message(outstr.str(), VERB_ALL, UBP_VERBOSITY);
 
         if (status == Ipopt::ApplicationReturnStatus::Internal_Error) {
-            throw MAiNGOException("  An unknown internal error occurred within Ipopt. Please contact Ipopt mailing list.");
+            throw MAiNGOException("  An unknown internal error occurred within Ipopt. Please contact Ipopt mailing list."); // GCOVR_EXCL_LINE
         }
         else {
             _theIpoptProblem->get_solution(solutionPoint);
diff --git a/src/ubpNLopt.cpp b/src/ubpNLopt.cpp
index 6f0d29a016572791b8d4747f8518b1698e0983bb..4b8ae4b47abb54770e6a8830bae143ce3398e7cf 100644
--- a/src/ubpNLopt.cpp
+++ b/src/ubpNLopt.cpp
@@ -36,9 +36,9 @@ UbpNLopt::UbpNLopt(mc::FFGraph& DAG, const std::vector<mc::FFVar>& DAGvars, cons
             case USE_BAB:
                 desiredSolver = settingsIn->UBP_solverBab;
                 break;
-            default:
+            default: // GCOVR_EXCL_START
                 throw MAiNGOException("  Unknown USAGE setting " + std::to_string(_intendedUse));
-        }
+        } // GCOVR_EXCL_STOP
 
         // Initialize solver (where necessary)
         switch (desiredSolver) {
@@ -64,10 +64,10 @@ UbpNLopt::UbpNLopt(mc::FFGraph& DAG, const std::vector<mc::FFVar>& DAGvars, cons
                 _NLopt.set_local_optimizer(_NLoptSubopt);
                 break;
             }
-            default: {
+            default: { // GCOVR_EXCL_START
                 throw MAiNGOException("  Unknown upper bounding solver selected for usage " + std::to_string(_intendedUse) + ": " + std::to_string(desiredSolver));
             }
-        }
+        } // GCOVR_EXCL_STOP
 
         // Objective
         _NLopt.set_min_objective(_NLopt_get_objective, this);    // Giving pointer to current object as data since it is needed to get access to the DAG (otherwise, DAG would need to be static)
@@ -78,7 +78,7 @@ UbpNLopt::UbpNLopt(mc::FFGraph& DAG, const std::vector<mc::FFVar>& DAGvars, cons
 
         // Equalities
         if (_neq > _nvar) {
-            throw MAiNGOException("  Error iniailizing NLopt: NLopt does not support problems containing more equality constraints than variables.");
+            throw MAiNGOException("  Error iniailizing NLopt: NLopt does not support problems containing more equality constraints than variables."); // GCOVR_EXCL_LINE
         }
         std::vector<double> eqTols(_neq, _maingoSettings->deltaEq);
         _NLopt.add_equality_mconstraint(_NLopt_get_eq, this, eqTols);    // Giving pointer to current object as data since it is needed to get access to the DAG (otherwise, DAG would need to be static)
@@ -106,18 +106,18 @@ UbpNLopt::UbpNLopt(mc::FFGraph& DAG, const std::vector<mc::FFVar>& DAGvars, cons
                 _NLoptSubopt.set_maxeval(_maingoSettings->UBP_maxStepsPreprocessing);
                 _NLoptSubopt.set_maxtime(_maingoSettings->UBP_maxTimePreprocessing);
                 break;
-            default: {
+            default: { // GCOVR_EXCL_START
                 throw MAiNGOException("  Unknown USAGE setting " + std::to_string(_intendedUse));
             }
-        }
+        } // GCOVR_EXCL_STOP
     }
-    catch (const std::exception& e) {
+    catch (const std::exception& e) { // GCOVR_EXCL_START
         throw MAiNGOException("  Error initializing NLopt.", e);
     }
     catch (...) {
         throw MAiNGOException("  Unknown error initializing NLopt.");
     }
-}
+} // GCOVR_EXCL_STOP
 
 
 /////////////////////////////////////////////////////////////////////////
diff --git a/tests/testProblems/main.cpp b/tests/testProblems/main.cpp
index 92ba170d676822445e44955a151db49ee733b8ac..17d7621b0dc31f5687a4002ed7d4ad70d79ac9f9 100644
--- a/tests/testProblems/main.cpp
+++ b/tests/testProblems/main.cpp
@@ -15,6 +15,8 @@
 #include "problem_Henry_RS_IdealGasFlash.h"
 #include "problem_LP.h"
 #include "problem_LP_random.h"
+#include "problem_LP_mod.h"
+#include "problem_LP_IN_RO.h"
 #include "problem_MILP.h"
 #include "problem_NRTL_RS_Flash.h"
 #include "problem_OME_RS_IdealGasFlash.h"
@@ -30,6 +32,13 @@
 #include "problem_nonsmooth.h"
 #include "problem_sudoku.h"
 #include "problem_unusedVars.h"
+#include "problem_relaxOnly.h"
+#include "problem_chance.h"
+#include "problem_wallfix.h"
+#include "problem_Squash.h"
+#include "problem_st_e27.h"
+#include "problem_1d.h"
+#include "problem_nonlinearCons.h"
 
 #include "MAiNGO.h"
 #include "getTime.h"
@@ -105,9 +114,12 @@ run_test(std::shared_ptr<maingo::MAiNGO> theMAiNGO, const std::string &name, con
     MPI_Comm_rank(MPI_COMM_WORLD, &_rank);
 #endif
 
-    std::cout << std::left << std::setw(40) << name << ": ";
-    const maingo::RETCODE maingoStatus            = theMAiNGO->solve();
+    std::cout << std::left << std::setw(65) << name << ": ";
+    maingo::RETCODE solverStatus; 
+    solverStatus = theMAiNGO->solve();
+    const maingo::RETCODE maingoStatus = solverStatus;
     MAiNGO_MPI_BARRIER const bool default_success = print_testResults(theMAiNGO, maingoStatus, correctSolution, epsilonA, epsilonR, CPUofAllProcesses);
+    
 
 #ifdef HAVE_MAiNGO_PARSER
     MAiNGO_IF_BAB_MANAGER
@@ -130,21 +142,21 @@ run_test(std::shared_ptr<maingo::MAiNGO> theMAiNGO, const std::string &name, con
     }
     catch (std::exception &e) {
         MAiNGO_IF_BAB_MANAGER
-            std::cout << std::left << std::setw(40) << name + " (parsed)"
+            std::cout << std::left << std::setw(65) << name + " (parsed)"
                       << ": ERROR - " << e.what() << std::endl;
         MAiNGO_END_IF
         MAiNGO_MPI_FINALIZE return false;
     }
     catch (...) {
         MAiNGO_IF_BAB_MANAGER
-            std::cout << std::left << std::setw(40) << name + " (parsed)"
+            std::cout << std::left << std::setw(65) << name + " (parsed)"
                       << ": ERROR - Encountered an unknown fatal error." << std::endl;
         MAiNGO_END_IF
         MAiNGO_MPI_FINALIZE return false;
     }
 
     theMAiNGO->set_model(myModel);
-    std::cout << std::left << std::setw(40) << name + " (parsed)"
+    std::cout << std::left << std::setw(65) << name + " (parsed)"
               << ": ";
     const maingo::RETCODE parsed_maingoStatus = theMAiNGO->solve();
     const bool parsed_success                 = print_testResults(theMAiNGO, parsed_maingoStatus, correctSolution, epsilonA, epsilonR, CPUofAllProcesses);
@@ -186,12 +198,22 @@ main(int argc, char *argv[])
     std::shared_ptr<Model_OME_RS_IdealGasFlash> myModel_OME_RS_IdealGasFlash;
     std::shared_ptr<Model_unusedVars> myModel_unusedVars;
     std::shared_ptr<Model_LP> myModel_LP;
-    std::shared_ptr<Model_QP> myModel_QP;
+    std::shared_ptr<Model_LP_IN_RO> myModel_LP_IN_RO;
+    std::shared_ptr<Model_LP_mod> myModel_LP_mod;
     std::shared_ptr<Model_LP_random> myModel_LP_random;
+    std::shared_ptr<Model_QP> myModel_QP;
     std::shared_ptr<Model_MILP> myModel_MILP;
     std::shared_ptr<Model_MILP_sudoku> myModel_MILP_sudoku;
     std::shared_ptr<Model_growing_simple> myModel_growing_simple;
     std::shared_ptr<Model_growing_AVM> myModel_growing_AVM;
+    std::shared_ptr<Model_relaxOnly> myModel_relaxOnly;
+    std::shared_ptr<Model_chance> myModel_chance;
+    std::shared_ptr<Model_wallfix> myModel_wallfix;
+    std::shared_ptr<Model_Squash> myModel_Squash;
+    std::shared_ptr<Model_st_e27> myModel_st_e27;
+    std::shared_ptr<Model_1d> myModel_1d;
+    std::shared_ptr<Model_nonlinearCons> myModel_nonlinearCons;
+
 
     std::shared_ptr<maingo::MAiNGO> myMAiNGO;
     try {
@@ -207,10 +229,19 @@ main(int argc, char *argv[])
         myModel_OME_RS_IdealGasFlash   = std::make_shared<Model_OME_RS_IdealGasFlash>();
         myModel_unusedVars             = std::make_shared<Model_unusedVars>();
         myModel_LP                     = std::make_shared<Model_LP>();
+        myModel_LP_random              = std::make_shared<Model_LP_random>(50, 1);
+        myModel_LP_IN_RO               = std::make_shared<Model_LP_IN_RO>();
+        myModel_LP_mod                 = std::make_shared<Model_LP_mod>();
         myModel_MILP                   = std::make_shared<Model_MILP>();
         myModel_QP                     = std::make_shared<Model_QP>();
-        myModel_LP_random              = std::make_shared<Model_LP_random>(50, 1);
         myModel_MILP_sudoku            = std::make_shared<Model_MILP_sudoku>();
+        myModel_relaxOnly              = std::make_shared<Model_relaxOnly>();
+        myModel_chance                 = std::make_shared<Model_chance>();
+        myModel_wallfix                = std::make_shared<Model_wallfix>();
+        myModel_Squash                 = std::make_shared<Model_Squash>();
+        myModel_st_e27                 = std::make_shared<Model_st_e27>();
+        myModel_1d                     = std::make_shared<Model_1d>();
+        myModel_nonlinearCons          = std::make_shared<Model_nonlinearCons>();
         myModel_growing_simple         = std::make_shared<Model_growing_simple>();    // Define a model object implemented in problem_growingDatasets_simple.h
         myModel_growing_AVM            = std::make_shared<Model_growing_AVM>();       // Define a model object implemented in problem_growingDatasets_AVM.h
         // Start with problem_bin1 and initialize MAiNGO object
@@ -354,6 +385,224 @@ main(int argc, char *argv[])
                 exceptionCounter++;
             }
 
+            // Problem with only relaxation constraints
+            myMAiNGO->set_model(myModel_relaxOnly);
+            if (!(run_test(myMAiNGO, "Problem_relaxOnly", 4.35581, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            // Problem LP with additional constant contraints
+            myMAiNGO->set_model(myModel_LP_mod);
+            if (!(run_test(myMAiNGO, "Problem_LP_mod", 153.675, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+	         // Problem with Squashing inequalities
+            myMAiNGO->set_model(myModel_Squash);
+            if (!(run_test(myMAiNGO, "Problem_Squash", -2.30259, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            // Problem wallfix
+            myMAiNGO->set_model(myModel_wallfix);
+            if (!(run_test(myMAiNGO, "Problem_wallfix", 1, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+	    // Problem LP_IN_RO (LP with relaxation only inequalities)
+            myMAiNGO->set_model(myModel_LP_IN_RO);
+            if (!(run_test(myMAiNGO, "Problem_LP_IN_RO", 0, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            // Problem chance, LinStrat: KELLEY_SIMPLEX; LBP_SubgradientIntervals:FALSE, probing:TRUE
+            myMAiNGO->set_option("BAB_probing", 1); 
+            myMAiNGO->set_option("LBP_subgradientIntervals", 0);  
+	        myMAiNGO->set_option("LBP_linPoints", maingo::lbp::LINP_KELLEY_SIMPLEX);
+	        myMAiNGO->set_model(myModel_chance);
+	        if (!(run_test(myMAiNGO, "Problem_chance_LINP_KELLEY_SIMPLEX_probing", 29.894 , epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            myMAiNGO->set_option("BAB_probing", 0); 
+	    myMAiNGO->set_option("LBP_subgradientIntervals", 1); 
+
+	    // Problem nonlinear Constraints, LinStrat: KELLEY_SIMPLEX        
+            myMAiNGO->set_model(myModel_nonlinearCons);
+            if (!(run_test(myMAiNGO, "Problem_nonlinearCons_LINP_KELLEY_SIMPLEX", -2.30259, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            } 
+	
+            // Problem chance, LinStrats: RANDOM
+	        myMAiNGO->set_option("LBP_linPoints", maingo::lbp::LINP_RANDOM);
+	        myMAiNGO->set_model(myModel_chance);
+            if (!(run_test(myMAiNGO, "Problem_chance_LINP_RANDOM", 29.894, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            // Problem 1d, LinStrats: SIMPLEX
+	        myMAiNGO->set_model(myModel_1d);
+	        if (!(run_test(myMAiNGO, "Problem_1d_LINP_SIMPLEX", 0, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            // Problem RelaxOnly constraints, LinStrats: SIMPLEX
+                myMAiNGO->set_model(myModel_relaxOnly);
+            	if (!(run_test(myMAiNGO, "Problem_relaxOnly_LINP_SIMPLEX", 4.35581, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            // Problem squash, LinStrats: SIMPLEX, subgradientIntervals:False           
+		    myMAiNGO->set_model(myModel_Squash);
+            	if (!(run_test(myMAiNGO, "Problem_Squash_LINP_SIMPLEX", -2.30259, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            myMAiNGO->set_option("LBP_solver", maingo::lbp::LBP_SOLVER_CLP);
+            // Problem RelaxOnly constraints, LinStrats: SIMPLEX
+                myMAiNGO->set_model(myModel_relaxOnly);
+            	if (!(run_test(myMAiNGO, "Problem_relaxOnly_LBP_CLP_LINP_SIMPLEX", 4.35581, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            
+            myMAiNGO->set_option("UBP_solverPreprocessing", maingo::ubp::UBP_SOLVER_EVAL);
+            myMAiNGO->set_option("UBP_solverBab", maingo::ubp::UBP_SOLVER_EVAL);
+
+            // Problem wallfix, Pre_printeveryLocalsearch: True, UBP_verbosity: ALL, UBP: EVAL, LBP: CLP
+            myMAiNGO->set_option("UBP_verbosity", 2);
+            myMAiNGO->set_option("PRE_printEveryLocalSearch", 1);   
+            myMAiNGO->set_option("LBP_subgradientIntervals", 0);
+            myMAiNGO->set_model(myModel_wallfix);
+            if (!(run_test(myMAiNGO, "Problem_wallfix_UBP_EVAL_pinteverylocalSearch", 1, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            myMAiNGO->set_option("UBP_verbosity", 0);
+            myMAiNGO->set_option("PRE_printEveryLocalSearch", 0);
+
+            // Problem ex8_1_3, UBP Solver: Eval, LBP Solver: CLP, LinStrat: Incumbent
+            myMAiNGO->set_option("LBP_linPoints", maingo::lbp::LINP_INCUMBENT);
+	        myMAiNGO->set_model(myModel_ex8_1_3);
+	        if (!(run_test(myMAiNGO, "Problem_ex8_1_3_UBP_EVAL_LBP_CLP_LINP_INCUMENT", 3, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            //Problem relxation only constraints, UBP: COBYLA, LBP: CLP, LinStrat: Kelley
+            myMAiNGO->set_option("UBP_solverPreprocessing", maingo::ubp::UBP_SOLVER_COBYLA);
+            myMAiNGO->set_option("UBP_solverBab", maingo::ubp::UBP_SOLVER_COBYLA);
+	        myMAiNGO->set_option("LBP_linPoints", maingo::lbp::LINP_KELLEY);
+            myMAiNGO->set_model(myModel_relaxOnly);
+            if (!(run_test(myMAiNGO, "Problem_relaxOnly_UBP_COBYLA_LBP_CLP_LINP_KELLEY", 4.35581, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+	    myMAiNGO->set_model(myModel_chance);
+            if (!(run_test(myMAiNGO, "Problem_chance_LBP_CLP_LINP_KELLEY", 29.894, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+ 
+	        // Problem wallfix, ignoreNodeBounds: True, UBP: COBYLA, LBP: CLP, LinStrat: Kelley 
+            myMAiNGO->set_option("UBP_ignoreNodeBounds", 1);
+            myMAiNGO->set_model(myModel_wallfix);
+            if (!(run_test(myMAiNGO, "Problem_wallfix_ignoreNodeBounds", 1, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            myMAiNGO->set_option("UBP_ignoreNodeBounds", 0);
+
+            // Problem LP with constant constraints, Bab_probing:True, UBP: COBYLA, LBP: CLP, LinStrat: Kelley
+            myMAiNGO->set_option("BAB_probing", 1); 
+            myMAiNGO->set_model(myModel_LP_mod);
+            if (!(run_test(myMAiNGO, "Problem_LP_mod_UBP_COBLYA_LBP_CLP_probing", 153.675, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            myMAiNGO->set_option("BAB_probing", 0); 
+
+            //Problem Squash, UBP: LBFGS, LBP: CLP, LinStrat: Kelley
+            myMAiNGO->set_option("UBP_solverPreprocessing", maingo::ubp::UBP_SOLVER_LBFGS);
+            myMAiNGO->set_option("UBP_solverBab", maingo::ubp::UBP_SOLVER_LBFGS);
+            myMAiNGO->set_model(myModel_Squash);
+            if (!(run_test(myMAiNGO, "Problem_Squash_UBP_LBFGS_LBP_CLP_LINP_KELLEY", -2.30259, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+            //Problem ste27, UBP: SLSQP , LBP:CLP; LinSTrat: Kelley
+            myMAiNGO->set_option("UBP_solverPreprocessing", maingo::ubp::UBP_SOLVER_SLSQP);
+            myMAiNGO->set_option("UBP_solverBab", maingo::ubp::UBP_SOLVER_SLSQP);
+            myMAiNGO->set_model(myModel_st_e27);
+            if (!(run_test(myMAiNGO, "Problem_st_e27_UBP_SLSQP_LBP_CLP", 2, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            
+	        // Problem Squash, UBP: BOBYQA, LBP: MAiNGO, LinStrat: SIMPLEX, LBP_subgradientIntervals: FALSE
+            myMAiNGO->set_option("LBP_solver", maingo::lbp::LBP_SOLVER_MAiNGO);
+            myMAiNGO->set_option("UBP_solverPreprocessing", maingo::ubp::UBP_SOLVER_BOBYQA);
+            myMAiNGO->set_option("UBP_solverBab", maingo::ubp::UBP_SOLVER_BOBYQA);
+	        myMAiNGO->set_option("LBP_linPoints", maingo::lbp::LINP_SIMPLEX);
+            myMAiNGO->set_option("LBP_subgradientIntervals", 0);   
+            myMAiNGO->set_model(myModel_Squash);
+            if (!(run_test(myMAiNGO, "Problem_Squash_UBP_BOBYQA_LBP_MAiNGO", -2.30259, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            myMAiNGO->set_option("LBP_subgradientIntervals", 1);   
+
+	        // Problem with relaxation only constraints, UBP: IPOPT, LBP: MAiNGO, LinStrat: SIMPLEX
+            myMAiNGO->set_option("UBP_solverPreprocessing", maingo::ubp::UBP_SOLVER_IPOPT);
+            myMAiNGO->set_option("UBP_solverBab", maingo::ubp::UBP_SOLVER_IPOPT);
+            myMAiNGO->set_model(myModel_relaxOnly);
+            if (!(run_test(myMAiNGO, "Problem_relaxOnly_UBP_IPOPT_LBP_MAiNGO", 4.35581, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            
+            //Problem chance, UBP: IPOPT, LBP: MAiNGO, LinStrat: SIMPLEX, BAB_probing: TRUE
+            myMAiNGO->set_option("BAB_probing", 1);
+            myMAiNGO->set_model(myModel_chance);
+	         if (!(run_test(myMAiNGO, "Problem_chance_LINP_SIMPLEX_probing", 29.894 , epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+            myMAiNGO->set_option("BAB_probing", 0);
+       
+	        // Problem chance, UBP: IPOPT, LBP: INTERVAL, LinStrat: KELLEY, LBP_subgradientIntervals: FALSE, BAB_probing: TRUE
+            myMAiNGO->set_option("LBP_solver", maingo::lbp::LBP_SOLVER_INTERVAL);
+	        myMAiNGO->set_option("LBP_subgradientIntervals", 0);  
+            myMAiNGO->set_option("LBP_linPoints", 2);
+            myMAiNGO->set_option("BAB_probing", 1); 
+            myMAiNGO->set_model(myModel_chance);
+            if (!(run_test(myMAiNGO, "Problem_chance_LBP_INTERVAL_probing",  29.894, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+	        myMAiNGO->set_option("LBP_subgradientIntervals", 1);   
+            myMAiNGO->set_option("BAB_probing", 0); 
+
+	        // Problem with relaxation only constraints, UBP: IPOPT, LBP: INTERVAL, LinStrat: LINP_RANDOM
+            myMAiNGO->set_model(myModel_relaxOnly);
+            if (!(run_test(myMAiNGO, "Problem_relaxOnly_UBP_IPOPT_LBP_INTERVAL_LINP_RANDOM", 4.35581, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+	        // Problem LP with constant constraints, UBP: IPOPT, LBP: INTERVAL, LinStrat: LINP_RANDOM
+            myMAiNGO->set_model(myModel_LP_mod);
+            if (!(run_test(myMAiNGO, "Problem_LP_mod_UBP_IPOPT_LBP_INTEVAL_LINP_RANDOM", 153.675, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+	        // Problem Squash, UBP: IPOPT, LBP: INTERVAL, LinStrat: LINP_RANDOM
+            myMAiNGO->set_model(myModel_Squash);
+            if (!(run_test(myMAiNGO, "Problem_Squash_UBP_IPOPT_LBP_INTEVAL_LINP_RANDOM", -2.30259, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
+	        myMAiNGO->set_option("LBP_linPoints", maingo::lbp::LINP_MID);
+         
+            // Setting growing data size options without having growing data size
+            myMAiNGO->set_model(myModel_LP);
+            myMAiNGO->set_option("growing_dataSizeTol", -1);
+            myMAiNGO->set_option("growing_dataSizeInit", -1);
+            myMAiNGO->set_option("growing_augmentRule", -1);
+            myMAiNGO->set_option("growing_augmentFreq", -1);
+            myMAiNGO->set_option("growing_augmentWeight", -1);
+            myMAiNGO->set_option("growing_augmentPercentage", -1);
+            if (!(run_test(myMAiNGO, "Problem_LP", 153.675, epsilonA, epsilonR, CPUofAllProcesses))) {
+                exceptionCounter++;
+            }
+
 #ifdef HAVE_MILP_SOLVER
             // Problem MILP Sudoku - only run if dedicated MILP solver available, takes too long otherwise
             myMAiNGO->set_model(myModel_MILP_sudoku);
diff --git a/tests/testProblems/problem_1d.h b/tests/testProblems/problem_1d.h
new file mode 100644
index 0000000000000000000000000000000000000000..19a520a5c6d16c2b96ebb122398c49d5952046cd
--- /dev/null
+++ b/tests/testProblems/problem_1d.h
@@ -0,0 +1,127 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user
+*
+* This class is used by the user to implement the model
+*/
+class Model_1d: public maingo::MAiNGOmodel {
+
+  public:
+    /**
+    * @brief Default constructor
+    */
+    Model_1d();
+
+    /**
+    * @brief Main function used to evaluate the model and construct a directed acyclic graph
+    *
+    * @param[in] optVars is the optimization variables vector
+    * @param[in] writeAdditionalOutput defines whether to write additional output
+    */
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+    /**
+    * @brief Function for getting optimization variables data
+    */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+    * @brief Function for getting initial point data
+    */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_1d::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-10000000000, 10000000000), maingo::VT_CONTINUOUS, "x1"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_1d::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    // Binary variables
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_1d::Model_1d()
+{
+    // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_1d::evaluate(const std::vector<Var> &optVars)
+{
+
+    // Rename  inputs
+    // Continuous variables
+    Var x1 = optVars[0];
+    // Binary variables
+    // Integer variables
+
+    // Prepare output
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+    // Objective function
+#ifndef HAVE_GROWING_DATASETS
+    result.objective = pow(x1,4);
+#else
+    result.objective_per_data.push_back(pow(x1,4));
+#endif
+
+    // Inequalities (<=0)
+
+    // Equalities (=0)
+
+    // relaxation only inequalities (<=0):
+
+    // relaxation only equalities (=0):
+
+    return result;
+}
diff --git a/tests/testProblems/problem_EpsCon.h b/tests/testProblems/problem_EpsCon.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed26d597fbabe14b839f5a35bb0fef67d19528b2
--- /dev/null
+++ b/tests/testProblems/problem_EpsCon.h
@@ -0,0 +1,121 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodelEpsCon.h"
+
+#define MY_PI 3.14159265358979323846 /* pi */
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user
+*
+* This class is used by the user to implement the model
+*/
+class Model_EpsCon: public maingo::MAiNGOmodelEpsCon {
+
+  public:
+    /**
+      * @brief Default constructor
+      */
+    Model_EpsCon();
+
+    /**
+      * @brief Main function used to evaluate the model and construct a directed acyclic graph
+      *
+      * @param[in] optVars is the optimization variables vector
+      */
+    maingo::EvaluationContainer evaluate_user_model(const std::vector<Var> &optVars);
+
+    /**
+      * @brief Function for getting optimization variables data
+      */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+      * @brief Function for getting initial point data
+      */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_EpsCon::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables   
+    variables.push_back(maingo::OptimizationVariable(/*Variable bounds*/ maingo::Bounds(-MY_PI, MY_PI), /*Variable type*/ maingo::VT_CONTINUOUS, /*Variable name*/ "x"));
+    variables.push_back(maingo::OptimizationVariable(/*Variable bounds*/ maingo::Bounds(-MY_PI, MY_PI), /*Variable type*/ maingo::VT_CONTINUOUS, /*Variable name*/ "y"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_EpsCon::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_EpsCon::Model_EpsCon()
+{
+      // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// evaluate the model
+maingo::EvaluationContainer
+Model_EpsCon::evaluate_user_model(const std::vector<Var> &optVars)
+{
+
+    // The vector optVars is of the same size and sorted in the same order as the user-defined variables vector in function get_variables()
+    // Rename inputs
+    Var x = optVars.at(0);    // We use .at() here to get a vector exception if a wrong access occurs
+    Var y = optVars.at(1);
+
+    Var A1 = 0.5 * sin(1) - 2 * cos(1) + sin(2) - 1.5 * cos(2);
+    Var A2 = 1.5 * sin(1) - cos(1) + 2 * sin(2) - 0.5 * cos(2);
+    Var B1 = 0.5 * sin(x) - 2 * cos(x) + sin(y) - 1.5 * cos(y);
+    Var B2 = 1.5 * sin(x) - cos(x) + 2 * sin(y) - 0.5 * cos(y);
+
+
+    // Prepare output
+    maingo::EvaluationContainer result;
+    // Objective: Kursawe function
+    result.objective.push_back(1 + sqr(A1 - B1) + pow(A2 - B2, 2));
+    result.objective.push_back(sqr(x + 3) + sqr(y + 1));
+    // Inequalities (<=0):
+    // Equalities (=0):
+    // Relaxation only inequalities (<=0):
+    // Relaxation only equalities (=0):
+    // Additional output:
+
+    return result;
+}
\ No newline at end of file
diff --git a/tests/testProblems/problem_LP_IN_RO.h b/tests/testProblems/problem_LP_IN_RO.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc9d5ad4be8a628aa97dc751f3afd9a0a1ecba92
--- /dev/null
+++ b/tests/testProblems/problem_LP_IN_RO.h
@@ -0,0 +1,148 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user
+*
+* This class is used by the user to implement the model
+*/
+class Model_LP_IN_RO: public maingo::MAiNGOmodel {
+
+  public:
+    /**
+    * @brief Default constructor
+    */
+    Model_LP_IN_RO();
+
+    /**
+    * @brief Main function used to evaluate the model and construct a directed acyclic graph
+    *
+    * @param[in] optVars is the optimization variables vector
+    * @param[in] writeAdditionalOutput defines whether to write additional output
+    */
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+    /**
+    * @brief Function for getting optimization variables data
+    */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+    * @brief Function for getting initial point data
+    */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_LP_IN_RO::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x1"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x2"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x3"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x4"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x5"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x6"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_LP_IN_RO::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    // Binary variables
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_LP_IN_RO::Model_LP_IN_RO()
+{
+    // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_LP_IN_RO::evaluate(const std::vector<Var> &optVars)
+{
+
+    // Rename  inputs
+    // Continuous variables
+    Var x1 = optVars[0];
+    Var x2 = optVars[1];
+    Var x3 = optVars[2];
+    Var x4 = optVars[3];
+    Var x5 = optVars[4];
+    Var x6 = optVars[5];
+    // Binary variables
+    // Integer variables
+
+    // Prepare output
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+    // Objective function
+#ifndef HAVE_GROWING_DATASETS
+    result.objective = -(-0.225 * x1 - 0.153 * x2 - 0.162 * x3 - 0.225 * x4 - 0.162 * x5 - 0.126 * x6);
+#else
+    result.objective_per_data.push_back(-(-0.225 * x1 - 0.153 * x2 - 0.162 * x3 - 0.225 * x4 - 0.162 * x5 - 0.126 * x6));
+#endif
+
+    // Inequalities (<=0)
+
+    // Equalities (=0)
+
+    // relaxation only inequalities (<=0):
+    result.ineqRelaxationOnly.push_back(x1 + x2 + x3 - (350));
+    result.ineqRelaxationOnly.push_back(x4 + x5 + x6 - (600));
+    result.ineqRelaxationOnly.push_back(-(x1 + x4) + (325));
+    result.ineqRelaxationOnly.push_back(-(x2 + x5) + (300));
+    result.ineqRelaxationOnly.push_back(-(x3 + x6) + (275));
+
+    // relaxation only equalities (=0):
+
+    return result;
+}
diff --git a/tests/testProblems/problem_LP_mod.h b/tests/testProblems/problem_LP_mod.h
new file mode 100644
index 0000000000000000000000000000000000000000..5590bb8ef986fd222cc1a53fd5bda63dfddd3100
--- /dev/null
+++ b/tests/testProblems/problem_LP_mod.h
@@ -0,0 +1,154 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user
+*
+* This class is used by the user to implement the model
+*/
+class Model_LP_mod: public maingo::MAiNGOmodel {
+
+  public:
+    /**
+    * @brief Default constructor
+    */
+    Model_LP_mod();
+
+    /**
+    * @brief Main function used to evaluate the model and construct a directed acyclic graph
+    *
+    * @param[in] optVars is the optimization variables vector
+    * @param[in] writeAdditionalOutput defines whether to write additional output
+    */
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+    /**
+    * @brief Function for getting optimization variables data
+    */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+    * @brief Function for getting initial point data
+    */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_LP_mod::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x1"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x2"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x3"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x4"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x5"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x6"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_LP_mod::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    // Binary variables
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_LP_mod::Model_LP_mod()
+{
+    // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_LP_mod::evaluate(const std::vector<Var> &optVars)
+{
+
+    // Rename  inputs
+    // Continuous variables
+    Var x1 = optVars[0];
+    Var x2 = optVars[1];
+    Var x3 = optVars[2];
+    Var x4 = optVars[3];
+    Var x5 = optVars[4];
+    Var x6 = optVars[5];
+    // Binary variables
+    // Integer variables
+
+    // Prepare output
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+    // Objective function
+#ifndef HAVE_GROWING_DATASETS
+    result.objective = -(-0.225 * x1 - 0.153 * x2 - 0.162 * x3 - 0.225 * x4 - 0.162 * x5 - 0.126 * x6);
+#else
+    result.objective_per_data.push_back(-(-0.225 * x1 - 0.153 * x2 - 0.162 * x3 - 0.225 * x4 - 0.162 * x5 - 0.126 * x6));
+#endif
+
+    // Inequalities (<=0)
+    result.ineq.push_back(x1 + x2 + x3 - (350));
+    result.ineq.push_back(x4 + x5 + x6 - (600));
+    result.ineq.push_back(-(x1 + x4) + (325));
+    result.ineq.push_back(-(x2 + x5) + (300));
+    result.ineq.push_back(-(x3 + x6) + (275));
+    result.ineq.push_back(-3);
+
+    // Equalities (=0)
+    result.eq.push_back(0);
+
+    // relaxation only inequalities (<=0):
+    result.ineqRelaxationOnly.push_back(-3);
+
+    // relaxation only equalities (=0):
+    result.eqRelaxationOnly.push_back(0);
+
+    result.ineqSquash.push_back(-3);
+
+    return result;
+}
diff --git a/tests/testProblems/problem_Squash.h b/tests/testProblems/problem_Squash.h
new file mode 100644
index 0000000000000000000000000000000000000000..e2676b327ccadc7009c689d2fab5e7a5fbd60068
--- /dev/null
+++ b/tests/testProblems/problem_Squash.h
@@ -0,0 +1,133 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user
+*
+* This class is used by the user to implement the model
+*/
+class Model_Squash: public maingo::MAiNGOmodel {
+
+  public:
+    /**
+    * @brief Default constructor
+    */
+    Model_Squash();
+
+    /**
+    * @brief Main function used to evaluate the model and construct a directed acyclic graph
+    *
+    * @param[in] optVars is the optimization variables vector
+    * @param[in] writeAdditionalOutput defines whether to write additional output
+    */
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+    /**
+    * @brief Function for getting optimization variables data
+    */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+    * @brief Function for getting initial point data
+    */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_Squash::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-0.2,2), maingo::VT_CONTINUOUS, "x1"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-0.2,2), maingo::VT_CONTINUOUS, "x2"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_Squash::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    // Binary variables
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_Squash::Model_Squash()
+{
+    // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_Squash::evaluate(const std::vector<Var> &optVars)
+{
+
+    // Rename  inputs
+    // Continuous variables
+    Var x1 = optVars[0];
+    Var x2 = optVars[1];
+    // Binary variables
+    // Integer variables
+
+    // Prepare output
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+    // Objective function
+#ifndef HAVE_GROWING_DATASETS
+    result.objective = log(squash_node(x1+x2,0.1,2));
+#else
+    result.objective_per_data.push_back(log(squash_node(x1+x2,0.1,2)));
+#endif
+
+    // Inequalities (<=0)
+
+    // Equalities (=0)
+
+
+    // relaxation only inequalities (<=0):
+
+    // relaxation only equalities (=0):
+
+    result.ineqSquash.push_back(0.1-x1+x2);
+    result.ineqSquash.push_back(x1+x2-2);
+
+    return result;
+}
diff --git a/tests/testProblems/problem_chance.h b/tests/testProblems/problem_chance.h
new file mode 100644
index 0000000000000000000000000000000000000000..f22208f43cd6ed4943449f2f5510f14abbe9e000
--- /dev/null
+++ b/tests/testProblems/problem_chance.h
@@ -0,0 +1,140 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user
+*
+* This class is used by the user to implement the model
+*/
+class Model_chance: public maingo::MAiNGOmodel {
+
+  public:
+    /**
+    * @brief Default constructor
+    */
+    Model_chance();
+
+    /**
+    * @brief Main function used to evaluate the model and construct a directed acyclic graph
+    *
+    * @param[in] optVars is the optimization variables vector
+    * @param[in] writeAdditionalOutput defines whether to write additional output
+    */
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+    /**
+    * @brief Function for getting optimization variables data
+    */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+    * @brief Function for getting initial point data
+    */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_chance::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x1"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x2"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x3"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 10000000000), maingo::VT_CONTINUOUS, "x4"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_chance::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    initialPoint.push_back(0.685244910300343);
+    initialPoint.push_back(0.0126990526103601);
+    initialPoint.push_back(0.302056037089293);
+    initialPoint.push_back(500000000000);
+    // Binary variables
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_chance::Model_chance()
+{
+    // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_chance::evaluate(const std::vector<Var> &optVars)
+{
+
+    // Rename  inputs
+    // Continuous variables
+    Var x1 = optVars[0];
+    Var x2 = optVars[1];
+    Var x3 = optVars[2];
+    Var x4 = optVars[3];
+    // Binary variables
+    // Integer variables
+
+    // Prepare output
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+    // Objective function
+#ifndef HAVE_GROWING_DATASETS
+    result.objective = (24.55 * x1 + 26.75 * x2 + 39 * x3 + 40.5 * x4 );
+#else
+    result.objective_per_data.push_back( 24.55 * x1 + 26.75 * x2 + 39 * x3 + 40.5 * x4 );
+#endif
+
+    // Inequalities (<=0)
+    result.ineq.push_back( -( 12 * x1  -1.645 * sqrt(0.28 * sqr(x1) + 0.19 * sqr(x2) + 20.5 * sqr(x3) + 0.62 *sqr(x4)) + 11.9 * x2 + 41.8 * x3 + 52.1 * x4  ) + ( 21 ), "e3" );
+    result.ineq.push_back( -( 2.3 * x1 + 5.6 * x2 + 11.1 * x3 + 1.3 * x4  ) + ( 5 ), "e4" );
+
+    // Equalities (=0)
+    result.eq.push_back( x1 + x2 + x3 + x4 - 1 , "e2" );
+
+    // Relaxation only inequalities (<=0):
+
+    // Relaxation only equalities (=0):
+
+    return result;
+}
diff --git a/tests/testProblems/problem_nonlinearCons.h b/tests/testProblems/problem_nonlinearCons.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac41ee0dbab2be652baf02e7f7ea09b1496d7beb
--- /dev/null
+++ b/tests/testProblems/problem_nonlinearCons.h
@@ -0,0 +1,142 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user
+*
+* This class is used by the user to implement the model
+*/
+class Model_nonlinearCons: public maingo::MAiNGOmodel {
+
+  public:
+    /**
+    * @brief Default constructor
+    */
+    Model_nonlinearCons();
+
+    /**
+    * @brief Main function used to evaluate the model and construct a directed acyclic graph
+    *
+    * @param[in] optVars is the optimization variables vector
+    * @param[in] writeAdditionalOutput defines whether to write additional output
+    */
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+    /**
+    * @brief Function for getting optimization variables data
+    */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+    * @brief Function for getting initial point data
+    */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_nonlinearCons::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-0.2,2), maingo::VT_CONTINUOUS, "x1"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-0.2,2), maingo::VT_CONTINUOUS, "x2"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-0.2,2), maingo::VT_CONTINUOUS, "x3"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_nonlinearCons::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    // Binary variables
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_nonlinearCons::Model_nonlinearCons()
+{
+    // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_nonlinearCons::evaluate(const std::vector<Var> &optVars)
+{
+
+    // Rename  inputs
+    // Continuous variables
+    Var x1 = optVars[0];
+    Var x2 = optVars[1];
+    Var x3 = optVars[2];
+    // Binary variables
+    // Integer variables
+
+    // Prepare output
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+    // Objective function
+#ifndef HAVE_GROWING_DATASETS
+    result.objective = log(squash_node(x1*x2,0.1,2));
+#else
+    result.objective_per_data.push_back(log(squash_node(x1*x2,0.1,2)));
+#endif
+
+    // Inequalities (<=0)
+
+
+    // Equalities (=0)
+
+
+    // relaxation only inequalities (<=0):
+    result.ineqRelaxationOnly.push_back(0.1-x1*x2);
+    result.ineqRelaxationOnly.push_back(x1*x2-2);
+
+    // relaxation only equalities (=0):
+    result.eqRelaxationOnly.push_back(x3*x2);
+    result.eqRelaxationOnly.push_back(x3*x1);
+
+    // Squashing inequalities
+
+    result.ineqSquash.push_back(0.1-x1*x2);
+    result.ineqSquash.push_back(x1*x2-2);
+
+    return result;
+}
diff --git a/tests/testProblems/problem_relaxOnly.h b/tests/testProblems/problem_relaxOnly.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed649242c38752188c4e1648ffcb060d2f44c6e4
--- /dev/null
+++ b/tests/testProblems/problem_relaxOnly.h
@@ -0,0 +1,130 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model implemented by the user 
+*
+* This class is used by the user to implement the model 
+*/
+class Model_relaxOnly: public maingo::MAiNGOmodel {
+
+  public:
+    /**
+    * @brief Default constructor
+    */
+    Model_relaxOnly();
+
+    /**
+    * @brief Main function used to evaluate the model and construct a directed acyclic graph
+    *
+    * @param[in] optVars is the optimization variables vector
+    * @param[in] writeAdditionalOutput defines whether to write additional output
+    */
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+    /**
+    * @brief Function for getting optimization variables data
+    */
+    std::vector<maingo::OptimizationVariable> get_variables();
+
+    /**
+    * @brief Function for getting initial point data
+    */
+    std::vector<double> get_initial_point();
+
+  private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_relaxOnly::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Some variables are missing bounds completely.
+
+    variables.push_back(maingo::OptimizationVariable(/*Variable bounds*/ maingo::Bounds(0, 1), /*Variable type*/ maingo::VT_BINARY, /*Variable name*/ "x"));
+    variables.push_back(maingo::OptimizationVariable(/*Variable bounds*/ maingo::Bounds(-2, 2), /*Variable type*/ maingo::VT_CONTINUOUS, /*Branching priority*/ 1, /*Variable name*/ "y"));
+ 
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_relaxOnly::get_initial_point()
+{
+
+    //here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // GAMS file did not provide initial values for all variables
+    initialPoint.push_back(0);
+    initialPoint.push_back(1);
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_relaxOnly::Model_relaxOnly()
+{
+
+    // Initialize data if necessary:
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_relaxOnly::evaluate(const std::vector<Var> &optVars)
+{
+
+    // rename  inputs
+    Var x1 = optVars[0];
+    Var x2 = optVars[1];
+
+    // Prepare output
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+    // objective function:
+#ifndef HAVE_GROWING_DATASETS
+    result.objective = -20 * exp(-0.2 * sqrt( (pow(x1,2) + pow(x2,2)) / 2 )) - exp((cos(3.14159265358979323846*x1) + cos(3.14159265358979323846*x2)) / 2) + 20 + exp(1);
+#else
+    result.objective_per_data.push_back(-20 * exp(-0.2 * sqrt( (pow(x1,2) + pow(x2,2)) / 2 )) - exp((cos(3.14159265358979323846*x1) + cos(3.14159265358979323846*x2)) / 2) + 20 + exp(1));
+#endif
+    // inequalities (<=0):
+    result.ineq.push_back(x1 - 1, "x <= 1");
+
+    // equalities (=0):
+    result.eq.push_back(pow(x2, 2) + pow(x1, 2) - 1, "circle equality");
+
+    // relaxation only inequalities (<=0):
+    result.ineqRelaxationOnly.push_back(x2 - 1,"y <= 1");
+
+    // relaxation only equalities (=0):
+    result.eqRelaxationOnly.push_back(x2 + x1 - 1,"y + x = 1");
+
+
+    return result;
+}
diff --git a/tests/testProblems/problem_st_e27.h b/tests/testProblems/problem_st_e27.h
new file mode 100644
index 0000000000000000000000000000000000000000..71dcf271c6837264c42bfc695dc4c9f0a8491ea0
--- /dev/null
+++ b/tests/testProblems/problem_st_e27.h
@@ -0,0 +1,154 @@
+/**********************************************************************************
+ * Copyright (c) 2021 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * MAiNGO and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * @file problem_gams.h.h
+ *
+ * @brief This file has been automatically generated by the MAiNGO Reader Writer
+ *        utility.
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model to be solved by MAiNGO 
+*/
+class Model_st_e27: public maingo::MAiNGOmodel {
+
+    public:
+        /**
+        * @brief Default constructor 
+        */
+        Model_st_e27();
+
+        /**
+        * @brief Main function used to evaluate the model and construct a directed acyclic graph
+        *
+        * @param[in] optVars is the optimization variables vector
+        */  
+        maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+        /**
+        * @brief Function for getting optimization variables data
+        */
+        std::vector<maingo::OptimizationVariable> get_variables();
+
+        /**
+        * @brief Function for getting initial point data
+        */
+        std::vector<double> get_initial_point();
+
+    private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_st_e27::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0,6), maingo::VT_CONTINUOUS, "x3"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0,5), maingo::VT_CONTINUOUS, "x4"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-1000000000000,1000000000000), maingo::VT_CONTINUOUS, "objvar"));
+    // Binary variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0,1), maingo::VT_BINARY, "b1"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0,1), maingo::VT_BINARY, "b2"));
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_st_e27::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    initialPoint.push_back(-1000000000000);
+    // Binary variables
+    initialPoint.push_back(0);
+    initialPoint.push_back(0);
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_st_e27::Model_st_e27()
+{
+
+    // Initialize data if necessary:
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_st_e27::evaluate(const std::vector<Var> &optVars)
+{
+
+    maingo::EvaluationContainer result; /*!< Variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+
+    // Rename  inputs
+    // Continuous variables
+    unsigned int cVar = 0;
+    Var x3 = optVars[cVar]; cVar++;
+    Var x4 = optVars[cVar]; cVar++;
+    Var objvar = optVars[cVar]; cVar++;
+    // Binary variables
+    unsigned int bVar = cVar;
+    Var b1 = optVars[bVar]; bVar++;
+    Var b2 = optVars[bVar]; bVar++;
+    // Integer variables
+    unsigned int iVar = bVar;
+
+    // Objective function
+    #ifndef HAVE_GROWING_DATASETS
+        result.objective = 2 - sqr(x3) + 4 * x3 - sqr(x4) + 2 * x4 + 2 * b1 + 2 * b2;
+    #else
+        result.objective_per_data.push_back(2 - sqr(x3) + 4 * x3 - sqr(x4) + 2 * x4 + 2 * b1 + 2 * b2);
+    #endif
+
+
+    // Inequalities (<=0)
+    result.ineq.push_back( -x3 + 3 * x4  - ( 5 ), "e1" );
+    result.ineq.push_back( 2 * x3 - x4  - ( 5 ), "e2" );
+    result.ineq.push_back( -2 * x3 + x4 , "e3" );
+    result.ineq.push_back( x3 - 3 * x4 , "e4" );
+    result.ineq.push_back( -6 * b1 + x3 , "e5" );
+    result.ineq.push_back( -5 * b2 + x4 , "e6" );
+
+    // Equalities (=0)
+
+    // Relaxation only inequalities (<=0):
+
+    // Relaxation only equalities (=0):
+
+    return result;
+}
diff --git a/tests/testProblems/problem_wallfix.h b/tests/testProblems/problem_wallfix.h
new file mode 100644
index 0000000000000000000000000000000000000000..d777e9271301bdbfcee486a160fa30bc889ea957
--- /dev/null
+++ b/tests/testProblems/problem_wallfix.h
@@ -0,0 +1,152 @@
+/**********************************************************************************
+ * Copyright (c) 2021 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * MAiNGO and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * @file problem_gams.h.h
+ *
+ * @brief This file has been automatically generated by the MAiNGO Reader Writer
+ *        utility.
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+
+
+using Var = mc::FFVar;    // This allows us to write Var instead of mc::FFVar
+
+
+/**
+* @class Model
+* @brief Class defining the actual model to be solved by MAiNGO 
+*/
+class Model_wallfix: public maingo::MAiNGOmodel {
+
+    public:
+        /**
+        * @brief Default constructor 
+        */
+        Model_wallfix();
+
+        /**
+        * @brief Main function used to evaluate the model and construct a directed acyclic graph
+        *
+        * @param[in] optVars is the optimization variables vector
+        */  
+        maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars);
+
+        /**
+        * @brief Function for getting optimization variables data
+        */
+        std::vector<maingo::OptimizationVariable> get_variables();
+
+        /**
+        * @brief Function for getting initial point data
+        */
+        std::vector<double> get_initial_point();
+
+    private:
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing optimization variable data to the Branch-and-Bound solver
+std::vector<maingo::OptimizationVariable>
+Model_wallfix::get_variables()
+{
+
+    std::vector<maingo::OptimizationVariable> variables;
+    // Required: Define optimization variables by specifying lower bound, upper bound (, optionally variable type, branching priority and a name)
+    // Continuous variables
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-10000000000,10000000000), maingo::VT_CONTINUOUS, "objvar"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0.1,10000000000), maingo::VT_CONTINUOUS, "x2"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0.1,10000000000), maingo::VT_CONTINUOUS, "x3"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0.1,10000000000), maingo::VT_CONTINUOUS, "x4"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0.1,10000000000), maingo::VT_CONTINUOUS, "x5"));
+    variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0.1,10000000000), maingo::VT_CONTINUOUS, "x6"));
+    // Binary variables
+    // Integer variables
+
+    return variables;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// function for providing initial point data to the Branch-and-Bound solver
+std::vector<double>
+Model_wallfix::get_initial_point()
+{
+
+    // Here you can provide an initial point for the local search
+    std::vector<double> initialPoint;
+    // Continuous variables
+    initialPoint.push_back(1);
+    initialPoint.push_back(1);
+    initialPoint.push_back(1);
+    initialPoint.push_back(1);
+    initialPoint.push_back(1);
+    initialPoint.push_back(1);
+    // Binary variables
+    // Integer variables
+
+    return initialPoint;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// constructor for the model
+Model_wallfix::Model_wallfix()
+{
+
+    // Initialize data if necessary:
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Evaluate the model
+maingo::EvaluationContainer
+Model_wallfix::evaluate(const std::vector<Var> &optVars)
+{
+
+   // Rename  inputs
+    // Continuous variables
+    Var objvar = optVars[0];
+    Var x2 = optVars[1];
+    Var x3 = optVars[2];
+    Var x4 = optVars[3];
+    Var x5 = optVars[4];
+    Var x6 = optVars[5];
+    // Binary variables
+    // Integer variables
+    maingo::EvaluationContainer result; /*!< variable holding the actual result consisting of an objective, inequalities, equalities, relaxation only inequalities and relaxation only equalities */
+  
+    // Objective function 
+    #ifndef HAVE_GROWING_DATASETS
+        result.objective = objvar;
+    #else
+        result.objective_per_data.push_back(objvar);
+    #endif
+
+    // Inequalities (<=0)
+
+    // Equalities (=0)
+    result.eq.push_back( objvar * x2  - ( 1 ), "e1" );
+    result.eq.push_back( x3 / (pos(x4 * objvar))  - ( 4.8 ), "e2" );
+    result.eq.push_back( x5 / (pos(x6 * x2))  - ( 0.98 ), "e3" );
+    result.eq.push_back( x6 * x4  - ( 1 ), "e4" );
+    result.eq.push_back( objvar - x2 + 1e-07 * x3 - 1e-05 * x5 , "e5" );
+    result.eq.push_back( 2 * objvar - 2 * x2 + 1e-07 * x3 - 0.01 * x4 - 1e-05 * x5 + 0.01 * x6 , "e6" );
+
+    // Relaxation only inequalities (<=0):
+
+    // Relaxation only equalities (=0):
+
+    return result;
+}
diff --git a/tests/unitTests/testBab.cpp b/tests/unitTests/testBab.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..99f3ea49038a300fc92bdbceb24b3e0b993d42de
--- /dev/null
+++ b/tests/unitTests/testBab.cpp
@@ -0,0 +1,255 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+#include <filesystem>
+
+
+
+using maingo::MAiNGO;
+
+
+class BabTestProblemRegular: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        Var x = optVars[0];
+        Var y = optVars[1];
+        result.objective = pow(x,3)*pow(y-0.5,5)*log(sqrt(exp(x)*(x-pow(x,3)))+1.5)*pow(x*y,5);
+        result.ineq.push_back(pow(x,3) - y + 0.5);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "y"));
+        return variables;
+    }
+
+  private:
+};
+
+
+class BabTestProblemInfeasible: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        Var x = optVars[0];
+        Var y = optVars[1];
+        result.objective = log(sqrt(exp(x)*(x-pow(x,3)))+1.5)*pow(x*y,5);
+        result.ineq.push_back(pow(x,3) - y + 0.5);
+        result.ineq.push_back(pow(x,3) - y + 3.5);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "y"));
+        return variables;
+    }
+
+  private:
+};
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, RegularSolve) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("LBP_verbosity", maingo::VERB_ALL);
+    maingo.set_option("UBP_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("epsilonA", 1e-9);
+    maingo.set_option("epsilonR", 1e-9);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_objective_value(), 0.);
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, Infeasible) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemInfeasible>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("BAB_constraintPropagation", 0);
+    maingo.set_option("UBP_solverBab", 0);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::INFEASIBLE);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, TargetUpperBound) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 5);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("BAB_alwaysSolveObbt", 0);
+    maingo.set_option("BAB_dbbt", 0);
+    maingo.set_option("targetUpperBound", 1e5);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::BOUND_TARGETS);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, TargetLowerBound) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 5);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("BAB_alwaysSolveObbt", 0);
+    maingo.set_option("BAB_dbbt", 0);
+    maingo.set_option("targetLowerBound", -1e5);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::BOUND_TARGETS);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, FeasiblePointOnly) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 5);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("BAB_alwaysSolveObbt", 0);
+    maingo.set_option("BAB_dbbt", 0);
+    maingo.set_option("terminateOnFeasiblePoint", 1);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::FEASIBLE_POINT);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, IterationsLimit) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 3);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("BAB_alwaysSolveObbt", 0);
+    maingo.set_option("BAB_dbbt", 0);
+    maingo.set_option("BAB_maxIterations", 1);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::FEASIBLE_POINT);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, NodeLimit) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 3);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("BAB_alwaysSolveObbt", 0);
+    maingo.set_option("BAB_dbbt", 0);
+    maingo.set_option("BAB_maxNodes", 1);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::FEASIBLE_POINT);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, TimeLimit) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 3);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("BAB_alwaysSolveObbt", 0);
+    maingo.set_option("BAB_dbbt", 0);
+    maingo.set_option("maxTime", 0);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::FEASIBLE_POINT);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestBab, ConfirmTermination) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BabTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_verbosity", maingo::VERB_ALL);
+    maingo.set_option("PRE_maxLocalSearches", 3);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    maingo.set_option("LBP_addAuxiliaryVars", true);
+    maingo.set_option("BAB_alwaysSolveObbt", 0);
+    maingo.set_option("BAB_dbbt", 0);
+    maingo.set_option("BAB_maxIterations", 1);
+    maingo.set_option("confirmTermination", 1);
+
+    std::stringstream inputStream("bogusinput\nn");
+    maingo.set_input_stream(&inputStream);
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::FEASIBLE_POINT);
+
+    inputStream = std::stringstream("y\n150");
+    maingo.set_input_stream(&inputStream);
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    inputStream = std::stringstream("bogusinput\ny\n-10\n1e150000");
+    maingo.set_input_stream(&inputStream);
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    inputStream = std::stringstream("y\n\n");
+    maingo.set_input_stream(&inputStream);
+    EXPECT_THROW(maingo.solve(), maingo::MAiNGOException);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testConstraint.cpp b/tests/unitTests/testConstraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7354c01389c7faea26a299d5e939d8dcf1e5b900
--- /dev/null
+++ b/tests/unitTests/testConstraint.cpp
@@ -0,0 +1,140 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "constraint.h"
+
+#include <gtest/gtest.h>
+
+
+using maingo::Constraint;
+using maingo::CONSTRAINT_CONVEXITY;
+using maingo::CONSTRAINT_DEPENDENCY;
+using maingo::CONSTRAINT_MONOTONICITY;
+using maingo::CONSTRAINT_TYPE;
+
+
+///////////////////////////////////////////////////
+TEST(TestConstraint, DefaultConstruct)
+{
+    Constraint con;
+    EXPECT_EQ(con.name, "");
+    EXPECT_EQ(con.isFeasible, true);
+    EXPECT_EQ(con.type, CONSTRAINT_TYPE::TYPE_UNKNOWN);
+    EXPECT_EQ(con.convexity, CONSTRAINT_CONVEXITY::CONV_NONE);
+    EXPECT_EQ(con.monotonicity, CONSTRAINT_MONOTONICITY::MON_NONE);
+    EXPECT_EQ(con.dependency, CONSTRAINT_DEPENDENCY::DEP_UNKNOWN);
+    EXPECT_EQ(con.nparticipatingVariables, 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestConstraint, ConstructNonConstant)
+{
+    Constraint con(CONSTRAINT_TYPE::INEQ, 0, 1, 2, 3, "my constraint");
+    EXPECT_EQ(con.name, "my constraint");
+    EXPECT_EQ(con.type, maingo::CONSTRAINT_TYPE::INEQ);
+    EXPECT_EQ(con.convexity, maingo::CONSTRAINT_CONVEXITY::CONV_NONE);
+    EXPECT_EQ(con.monotonicity, maingo::CONSTRAINT_MONOTONICITY::MON_NONE);
+    EXPECT_EQ(con.dependency, maingo::CONSTRAINT_DEPENDENCY::DEP_UNKNOWN);
+    EXPECT_EQ(con.indexOriginal, 0);
+    EXPECT_EQ(con.indexType, 1);
+    EXPECT_EQ(con.indexNonconstant, 2);
+    EXPECT_EQ(con.indexTypeNonconstant, 3);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestConstraint, ConstructNonConstantWithoutName)
+{
+    Constraint con(CONSTRAINT_TYPE::OBJ, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "obj2");
+
+    con = Constraint(CONSTRAINT_TYPE::INEQ, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "ineq2");
+
+    con = Constraint(CONSTRAINT_TYPE::EQ, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "eq2");
+
+    con = Constraint(CONSTRAINT_TYPE::INEQ_REL_ONLY, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "relOnlyIneq2");
+
+    con = Constraint(CONSTRAINT_TYPE::EQ_REL_ONLY, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "relOnlyEq2");
+
+    con = Constraint(CONSTRAINT_TYPE::INEQ_SQUASH, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "squashIneq2");
+
+    con = Constraint(CONSTRAINT_TYPE::AUX_EQ_REL_ONLY, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "auxRelOnlyEq2");
+
+    con = Constraint(CONSTRAINT_TYPE::OUTPUT, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "output2");
+
+    con = Constraint(CONSTRAINT_TYPE::TYPE_UNKNOWN, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "constraint2");
+
+    con = Constraint((CONSTRAINT_TYPE)-42, 0, 1, 2, 3);
+    EXPECT_EQ(con.name, "constraint2");
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestConstraint, ConstructConstant)
+{
+    Constraint con(CONSTRAINT_TYPE::INEQ, 0, 1, 2, 3, true, false, 42.0, "my constraint");
+    EXPECT_EQ(con.name, "my constraint");
+    EXPECT_EQ(con.type, maingo::CONSTRAINT_TYPE::INEQ);
+    EXPECT_EQ(con.convexity, maingo::CONSTRAINT_CONVEXITY::CONV_NONE);
+    EXPECT_EQ(con.monotonicity, maingo::CONSTRAINT_MONOTONICITY::MON_NONE);
+    EXPECT_EQ(con.dependency, maingo::CONSTRAINT_DEPENDENCY::DEP_UNKNOWN);
+    EXPECT_EQ(con.indexOriginal, 0);
+    EXPECT_EQ(con.indexType, 1);
+    EXPECT_EQ(con.indexConstant, 2);
+    EXPECT_EQ(con.indexTypeConstant, 3);
+    EXPECT_EQ(con.isConstant, true);
+    EXPECT_EQ(con.isFeasible, false);
+    EXPECT_EQ(con.constantValue, 42.0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestConstraint, ConstructConstantWithoutName)
+{
+    Constraint con(CONSTRAINT_TYPE::OBJ, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "obj2");
+
+    con = Constraint(CONSTRAINT_TYPE::INEQ, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "ineq2");
+
+    con = Constraint(CONSTRAINT_TYPE::EQ, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "eq2");
+
+    con = Constraint(CONSTRAINT_TYPE::INEQ_REL_ONLY, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "relOnlyIneq2");
+
+    con = Constraint(CONSTRAINT_TYPE::EQ_REL_ONLY, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "relOnlyEq2");
+
+    con = Constraint(CONSTRAINT_TYPE::INEQ_SQUASH, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "squashIneq2");
+
+    con = Constraint(CONSTRAINT_TYPE::AUX_EQ_REL_ONLY, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "auxRelOnlyEq2");
+
+    con = Constraint(CONSTRAINT_TYPE::OUTPUT, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "output2");
+
+    con = Constraint(CONSTRAINT_TYPE::TYPE_UNKNOWN, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "constraint2");
+
+    con = Constraint((CONSTRAINT_TYPE)-42, 0, 1, 2, 3, true, false, 42.0);
+    EXPECT_EQ(con.name, "constraint2");
+}
\ No newline at end of file
diff --git a/tests/unitTests/testLogger.cpp b/tests/unitTests/testLogger.cpp
index 226f97535439b15d3df555bb72f1c80281c12f8e..550befa50c147606c299f57eb6a78b123edfaec9 100644
--- a/tests/unitTests/testLogger.cpp
+++ b/tests/unitTests/testLogger.cpp
@@ -14,6 +14,11 @@
 
 #include <gtest/gtest.h>
 
+#include <filesystem>
+#include <fstream>
+#include <string>
+#include <system_error>
+
 
 ///////////////////////////////////////////////////
 // struct on which the unit test will be preformed on
@@ -25,7 +30,7 @@ struct TestLogger: testing::Test {
 
 ///////////////////////////////////////////////////
 // testing all three versions of _get_(max_)verb on different verbosities
-TEST_F(TestLogger, TestVerb)
+TEST_F(TestLogger, Verbosity)
 {
     settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
 
@@ -64,30 +69,31 @@ TEST_F(TestLogger, TestVerb)
     logger->print_message("E", maingo::VERB_NORMAL, maingo::UBP_VERBOSITY, maingo::LBP_VERBOSITY);
     logger->print_message("F", maingo::VERB_ALL, maingo::UBP_VERBOSITY, maingo::LBP_VERBOSITY);
 
+    logger->print_message("G", maingo::VERB_NONE, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("H", maingo::VERB_NORMAL, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("I", maingo::VERB_ALL, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
+
     // test _get_max_verb() for three input verbosities
 
     settings->LBP_verbosity = maingo::VERB_ALL;
     settings->UBP_verbosity = maingo::VERB_NORMAL;
     settings->BAB_verbosity = maingo::VERB_NONE;
 
-    logger->print_message("G", maingo::VERB_NONE, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
-    logger->print_message("H", maingo::VERB_NORMAL, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
-    logger->print_message("I", maingo::VERB_ALL, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("J", maingo::VERB_NONE, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("K", maingo::VERB_NORMAL, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("L", maingo::VERB_ALL, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY, maingo::BAB_VERBOSITY);
 
-    logger->print_message("J", maingo::VERB_NONE, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY);
-    logger->print_message("K", maingo::VERB_NORMAL, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY);
-    logger->print_message("L", maingo::VERB_ALL, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("M", maingo::VERB_NONE, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("N", maingo::VERB_NORMAL, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY);
+    logger->print_message("O", maingo::VERB_ALL, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY, maingo::BAB_VERBOSITY);
 
 
-    std::string output = testing::internal::GetCapturedStdout();
-
-    EXPECT_EQ("145789ABDEGHIJ", output);
+    EXPECT_EQ("145789ABDEGHIJKLM", testing::internal::GetCapturedStdout());
 }
 
 
 ///////////////////////////////////////////////////
-// testing output of logger to screen and log at different verbosities
-TEST_F(TestLogger, TestOutputLogger)
+TEST_F(TestLogger, OutputStream)
 {
     settings->LBP_verbosity = maingo::VERB_NONE;
     settings->UBP_verbosity = maingo::VERB_NORMAL;
@@ -103,16 +109,22 @@ TEST_F(TestLogger, TestOutputLogger)
     logger->print_message("2", maingo::VERB_ALL, maingo::LBP_VERBOSITY);
     logger->print_message("3", maingo::VERB_NORMAL, maingo::UBP_VERBOSITY);
 
-    std::string output = testing::internal::GetCapturedStdout();
-
     // second message should not be printed
-    EXPECT_EQ("13", output);
+    EXPECT_EQ("13", testing::internal::GetCapturedStdout());
+}
 
-    logger->clear();
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, OutputFile)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
 
 
     // testing setting option LOGGING_FILE
     settings->loggingDestination = maingo::LOGGING_FILE;
+    testing::internal::CaptureStdout();
 
     logger->print_message("1", maingo::VERB_NONE, maingo::BAB_VERBOSITY);
     logger->print_message("2", maingo::VERB_ALL, maingo::LBP_VERBOSITY);
@@ -124,13 +136,40 @@ TEST_F(TestLogger, TestOutputLogger)
     EXPECT_EQ("3", logger->babLine.front());
     logger->babLine.pop();
 
+    // nothing should have been printed to stream
+    EXPECT_EQ("", testing::internal::GetCapturedStdout());
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, OutputClear)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+
+
+    // testing setting option LOGGING_FILE
+    settings->loggingDestination = maingo::LOGGING_FILE;
+
+    logger->print_message("1", maingo::VERB_NONE, maingo::BAB_VERBOSITY);
+    logger->print_message("2", maingo::VERB_ALL, maingo::LBP_VERBOSITY);
+    logger->print_message("3", maingo::VERB_NORMAL, maingo::UBP_VERBOSITY);
 
     logger->clear();
 
     // testing clear()
     EXPECT_EQ(true, logger->babLine.empty());
+}
 
 
+///////////////////////////////////////////////////
+TEST_F(TestLogger, OutputStreamAndFile)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+
     // testing setting option LOGGING_FILE_AND_STREAM
     settings->loggingDestination = maingo::LOGGING_FILE_AND_STREAM;
 
@@ -146,15 +185,87 @@ TEST_F(TestLogger, TestOutputLogger)
     EXPECT_EQ("3", logger->babLine.front());
     logger->babLine.pop();
 
-    output = testing::internal::GetCapturedStdout();
+    EXPECT_EQ("13", testing::internal::GetCapturedStdout());
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, OutputNone)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+
+
+    // testing setting option LOGGING_NONE to suppress all output
+    settings->loggingDestination = maingo::LOGGING_NONE;
+
+    testing::internal::CaptureStdout();
 
-    EXPECT_EQ("13", output);
+    logger->print_message("1", maingo::VERB_NONE, maingo::BAB_VERBOSITY);
+    logger->print_message("2", maingo::VERB_ALL, maingo::LBP_VERBOSITY);
+    logger->print_message("3", maingo::VERB_NORMAL, maingo::UBP_VERBOSITY);
+
+    // second message should not be printed
+    EXPECT_EQ("", testing::internal::GetCapturedStdout());
+    EXPECT_EQ(true, logger->babLine.empty());
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, OutputForceStreamOnly)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+
+
+    // for LOGGING_OUTSTREAM, everything should be printed (irrespective of verbosity), but not stored for later printing to file
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+
+    testing::internal::CaptureStdout();
+
+    logger->print_message_to_stream_only("1");
+    logger->print_message_to_stream_only("2");
+    logger->print_message_to_stream_only("3");
+
+    EXPECT_EQ("123", testing::internal::GetCapturedStdout());
+    EXPECT_EQ(true, logger->babLine.empty());
+    logger->clear();
+
+
+    // for LOGGING_FILE, nothing should be printed
+    settings->loggingDestination = maingo::LOGGING_FILE;
+
+    testing::internal::CaptureStdout();
+
+    logger->print_message_to_stream_only("1");
+    logger->print_message_to_stream_only("2");
+    logger->print_message_to_stream_only("3");
+
+    EXPECT_EQ("", testing::internal::GetCapturedStdout());
+    EXPECT_EQ(true, logger->babLine.empty());
+    logger->clear();
+
+
+    // for LOGGING_FILE_AND_STREAM, everything should be printed (considering verbosity), but not stored for later printing to file
+    settings->loggingDestination = maingo::LOGGING_FILE_AND_STREAM;
+
+    testing::internal::CaptureStdout();
+
+    logger->print_message_to_stream_only("1");
+    logger->print_message_to_stream_only("2");
+    logger->print_message_to_stream_only("3");
+
+    EXPECT_EQ("123", testing::internal::GetCapturedStdout());
+    EXPECT_EQ(true, logger->babLine.empty());
+    logger->clear();
 }
 
 
 ///////////////////////////////////////////////////
 //testing the output of print_vector() by capturing the output to the consol and comparing it to the expected output
-TEST_F(TestLogger, TestPrintVector)
+TEST_F(TestLogger, PrintVector)
 {
     std::vector<double> testVector = {0.0, 1.0};
 
@@ -185,4 +296,234 @@ TEST_F(TestLogger, TestPrintVector)
 
     // expecting error if the numbers of values to be printed exceed the number of elements in the testVector
     ASSERT_ANY_THROW(logger->print_vector(3, testVector, "TestString", maingo::VERB_NONE, maingo::LBP_VERBOSITY));
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, CreateLogFile)
+{
+    logger->logFileName = "tmpLogFileForTesting.log";
+
+    // For LOGGING_FILE, should create a log file
+    settings->loggingDestination = maingo::LOGGING_FILE;
+    std::error_code errorCode;
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+    logger->create_log_file();
+    EXPECT_EQ(true, std::filesystem::exists("tmpLogFileForTesting.log"));
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+
+
+    // For LOGGING_FILE_AND_STREAM, should create a log file
+    settings->loggingDestination = maingo::LOGGING_FILE_AND_STREAM;
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+    logger->create_log_file();
+    EXPECT_EQ(true, std::filesystem::exists("tmpLogFileForTesting.log"));
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+
+
+    // For LOGGING_OUTSTREAM, no log file should be created
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+    logger->create_log_file();
+    EXPECT_EQ(false, std::filesystem::exists("tmpLogFileForTesting.log"));
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, WriteToLogFile)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+    logger->logFileName = "tmpLogFileForTesting.log";
+
+
+    // If logging destination includes file, should write log
+    settings->loggingDestination = maingo::LOGGING_FILE;
+    std::error_code errorCode;
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+    logger->print_message("1\n", maingo::VERB_NONE, maingo::BAB_VERBOSITY);
+    logger->print_message("2\n", maingo::VERB_ALL, maingo::LBP_VERBOSITY);
+    logger->print_message("3\n", maingo::VERB_NORMAL, maingo::UBP_VERBOSITY);
+    logger->write_all_lines_to_log("test error message at end");
+
+    std::ifstream file;
+    file.open("tmpLogFileForTesting.log");
+    if (file.is_open()) {
+        std::string line;;
+        std::getline(file, line);
+        EXPECT_EQ("1", line);
+        std::getline(file, line);
+        EXPECT_EQ("3", line);
+        std::getline(file, line);
+        EXPECT_EQ("test error message at end", line);
+        std::getline(file, line);
+        EXPECT_EQ(true, file.eof());
+    } else {
+        FAIL() << "Failed to open tmpLogFileForTesting.log";
+    }
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+
+
+    // If logging destination is only outstream, should not write log
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+
+    testing::internal::CaptureStdout();
+    logger->print_message("1", maingo::VERB_NONE, maingo::BAB_VERBOSITY);
+    logger->print_message("2", maingo::VERB_ALL, maingo::LBP_VERBOSITY);
+    logger->print_message("3", maingo::VERB_NORMAL, maingo::UBP_VERBOSITY);
+    logger->write_all_lines_to_log("test error message at end");
+    testing::internal::GetCapturedStdout();
+
+    file.open("tmpLogFileForTesting.log");
+    if (file.is_open()) {
+        EXPECT_EQ(true, file.eof());
+    } else {
+        FAIL() << "Failed to open tmpLogFileForTesting.log";
+    }
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, CreateIterationsCsvFile)
+{
+    // Iterations csv file should be created irrespective of logging destination, but only if writeCsv is true
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+    logger->csvIterationsName = "tmpIterationsCsvForTesting.csv";
+    std::error_code errorCode;
+    std::filesystem::remove("tmpIterationsCsvForTesting.csv", errorCode);
+
+    logger->create_iterations_csv_file(true);
+    EXPECT_EQ(true, std::filesystem::exists("tmpIterationsCsvForTesting.csv"));
+    std::filesystem::remove("tmpIterationsCsvForTesting.csv", errorCode);
+
+
+    logger->create_iterations_csv_file(false);
+    EXPECT_EQ(false, std::filesystem::exists("tmpIterationsCsvForTesting.csv"));
+    std::filesystem::remove("tmpIterationsCsvForTesting.csv", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, WriteToIterationsCsvFile)
+{
+    std::error_code errorCode;
+    std::filesystem::remove("tmpIterationsCsvForTesting.csv", errorCode);
+    logger->csvIterationsName = "tmpIterationsCsvForTesting.csv";
+
+    logger->babLineCsv.push("Line 1\n");
+    logger->babLineCsv.push("Line 2\n");
+
+    logger->write_all_iterations_to_csv();
+
+
+    std::ifstream file;
+    file.open("tmpIterationsCsvForTesting.csv");
+    if (file.is_open()) {
+        std::string line;;
+        std::getline(file, line);
+        EXPECT_EQ("Line 1", line);
+        std::getline(file, line);
+        EXPECT_EQ("Line 2", line);
+        std::getline(file, line);
+        EXPECT_EQ(true, file.eof());
+    } else {
+        FAIL() << "Failed to open tmpIterationsCsvForTesting.csv";
+    }
+    std::filesystem::remove("tmpIterationsCsvForTesting.csv", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, PrintSettingsNothingChanged)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NONE, maingo::BAB_VERBOSITY);
+    EXPECT_EQ("", testing::internal::GetCapturedStdout());
+
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY, maingo::LBP_VERBOSITY);
+    EXPECT_EQ("", testing::internal::GetCapturedStdout());
+
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY);
+    EXPECT_EQ("", testing::internal::GetCapturedStdout());
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, PrintSettingsSettingsChanged)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+
+    logger->save_setting(maingo::SETTING_NAMES::EPSILONA, "epsilon A: 1e-42");
+    logger->save_setting(maingo::SETTING_NAMES::EPSILONR, "epsilon R: 1e-43");
+    logger->save_setting(maingo::SETTING_NAMES::UNKNOWN_SETTING, "unknown setting 1: not known!");
+    logger->save_setting(maingo::SETTING_NAMES::UNKNOWN_SETTING, "unknown setting 2: not known!");
+
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY);
+    EXPECT_EQ("  Settings set by the user:\n    epsilon A: 1e-42\n    epsilon R: 1e-43\n    unknown setting 1: not known!\n    unknown setting 2: not known!\n  Done.\n", testing::internal::GetCapturedStdout());
+
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY, maingo::LBP_VERBOSITY);
+    EXPECT_EQ("  Settings set by the user:\n    epsilon A: 1e-42\n    epsilon R: 1e-43\n    unknown setting 1: not known!\n    unknown setting 2: not known!\n  Done.\n", testing::internal::GetCapturedStdout());
+
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY, maingo::LBP_VERBOSITY, maingo::UBP_VERBOSITY);
+    EXPECT_EQ("  Settings set by the user:\n    epsilon A: 1e-42\n    epsilon R: 1e-43\n    unknown setting 1: not known!\n    unknown setting 2: not known!\n  Done.\n", testing::internal::GetCapturedStdout());
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, PrintSettingsFileNameChangedSuccessful)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+
+    // user specified settings file, which was successfully read 
+    logger->save_settings_file_name("myFileName", true);
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY);
+    EXPECT_EQ("  \n  Read settings from file myFileName.\n", testing::internal::GetCapturedStdout());
+
+    // user specified settings file, which was successfully read 
+    logger->save_setting(maingo::SETTING_NAMES::EPSILONA, "epsilon A: 1e-42");
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY);
+    EXPECT_EQ("  \n  Read settings from file myFileName.\n  Settings set by the user:\n    epsilon A: 1e-42\n  Done.\n", testing::internal::GetCapturedStdout());
+}
+
+
+///////////////////////////////////////////////////
+TEST_F(TestLogger, PrintSettingsFileNameChangedUnsuccessful)
+{
+    settings->LBP_verbosity = maingo::VERB_NONE;
+    settings->UBP_verbosity = maingo::VERB_NORMAL;
+    settings->BAB_verbosity = maingo::VERB_ALL;
+    settings->loggingDestination = maingo::LOGGING_OUTSTREAM;
+
+    // user specified settings file, which was *not* successfully read 
+    logger->save_settings_file_name("myFileName", false);
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY);
+    EXPECT_EQ("  \n  Warning: Could not open settings file myFileName.\n           Proceeding with default settings.\n", testing::internal::GetCapturedStdout());
+
+    // user specified settings file, which was *not* successfully read 
+    logger->save_settings_file_name("MAiNGOSettings.txt", false);
+    testing::internal::CaptureStdout();
+    logger->print_settings(maingo::VERB_NORMAL, maingo::BAB_VERBOSITY);
+    EXPECT_EQ("  \n  Warning: Could not open settings file with default name MAiNGOSettings.txt.\n           Proceeding with default settings.\n  \n  Warning: Could not open settings file myFileName.\n           Proceeding with default settings.\n", testing::internal::GetCapturedStdout());
 }
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGO.cpp b/tests/unitTests/testMAiNGO.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..037a947ccadbe97e1d6beade39f1253c99008a44
--- /dev/null
+++ b/tests/unitTests/testMAiNGO.cpp
@@ -0,0 +1,712 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+#include <filesystem>
+
+
+
+using maingo::MAiNGO;
+
+
+class MAiNGOTestProblemRegular: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        maingo::EvaluationContainer result;
+        Var x = optVars[0];
+        Var y = optVars[1];
+        result.objective = pow(x,3)*pow(y-0.5,5)*log(sqrt(exp(x)*(x-pow(x,3)))+1.5)*pow(x*y,5);
+        result.ineq.push_back(pow(x,3) - y + 0.5);
+        result.ineqRelaxationOnly.push_back(pow(x,3) - y + 0.4);
+        result.output.push_back(maingo::OutputVariable(x*y - (x-x), "x*y"));
+        result.output.push_back(maingo::OutputVariable(42, "the answer"));
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "y"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(-2, 2), maingo::VT_BINARY, "z"));
+        return variables;
+    }
+
+    std::vector<double> get_initial_point() override {
+        return {0.5, 0.5, 0};
+    }
+};
+
+
+class ProblemWithoutVariables: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        return maingo::EvaluationContainer();
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return std::vector<maingo::OptimizationVariable>();
+    }
+};
+
+
+class ProblemThrowingException: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        throw std::runtime_error("Something went wrong during evaluation!");
+        return maingo::EvaluationContainer();
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+class ProblemThrowingInteger: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        throw -1;
+        return maingo::EvaluationContainer();
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+class ProblemConflictingBounds: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        return maingo::EvaluationContainer();
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(1, 0)) };
+    }
+};
+
+
+class ProblemConstantConstraintInfeasible: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        maingo::EvaluationContainer result;
+        result.ineq.push_back(0.5);
+        result.ineq.push_back(-0.5);
+        result.ineqRelaxationOnly.push_back(0.5);
+        result.ineqRelaxationOnly.push_back(-0.5);
+        result.ineqSquash.push_back(0.5);
+        result.ineqSquash.push_back(-0.5);
+        result.ineqSquash.push_back(optVars[0]);
+        result.eq.push_back(0.5);
+        result.eq.push_back(0.0);
+        result.eqRelaxationOnly.push_back(0.5);
+        result.eqRelaxationOnly.push_back(0.0);
+        result.eq.push_back(optVars[0]);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+class ProblemNonconstantConstraintInfeasible: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[0], 3);
+        result.ineq.push_back(2. - optVars[0]);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+class ProblemConstantObjective: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        maingo::EvaluationContainer result;
+        result.objective = 42;
+        result.ineq.push_back(0.5 - optVars[0]);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+class ProblemWithHiddenZero: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        maingo::EvaluationContainer result;
+        Var x = optVars[0];
+        result.objective = pow(x,3) + pow(x,3) -2*pow(x,3);
+        result.eq.push_back(pow(x,3) + pow(x,3) -2*pow(x,3));
+        result.eqRelaxationOnly.push_back(pow(x,3) + pow(x,3) -2*pow(x,3));
+        result.ineq.push_back(pow(x,3) + pow(x,3) -2*pow(x,3));
+        result.ineqRelaxationOnly.push_back(pow(x,3) + pow(x,3) -2*pow(x,3));
+        result.ineqSquash.push_back(pow(x,3) + pow(x,3) -2*pow(x,3));
+        result.eq.push_back(x);
+        result.eqRelaxationOnly.push_back(x);
+        result.ineq.push_back(x);
+        result.ineqRelaxationOnly.push_back(x);
+        result.ineqSquash.push_back(x);
+        result.output.push_back(maingo::OutputVariable(pow(x,3) + pow(x,3) -2*pow(x,3), "hidden zero"));
+        result.output.push_back(maingo::OutputVariable(pow(x,4) + pow(x,4) -2*pow(x,4), "another hidden zero"));
+        result.output.push_back(maingo::OutputVariable(x, "no hidden zero"));
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+class ProblemAdjustableNumberOfRelaxationOnlyConstraintsInfeasible: public maingo::MAiNGOmodel {
+  public:
+    ProblemAdjustableNumberOfRelaxationOnlyConstraintsInfeasible(const size_t nineq, const size_t neq): _nineq(nineq), _neq(neq) {}
+
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) override {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[0], 3);
+        for (size_t iIneq = 0; iIneq < _nineq; iIneq++) {
+            result.ineqRelaxationOnly.push_back(0.5 - optVars[0]);
+        }
+        for (size_t iEq = 0; iEq < _neq; iEq++) {
+            result.eqRelaxationOnly.push_back(0.5 - optVars[0]);
+        }
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+  private:
+    size_t _nineq = 0;
+    size_t _neq = 0;
+};
+
+
+class ProblemWithAdjustableNumberOfObjectives: public maingo::MAiNGOmodelEpsCon {
+  public:
+    ProblemWithAdjustableNumberOfObjectives(const size_t nobj) { _nobj = nobj;}
+
+    maingo::EvaluationContainer evaluate_user_model(const std::vector<Var> &optVars) {
+        Var x = optVars.at(0);
+        maingo::EvaluationContainer result;
+        for (size_t i = 0; i<_nobj; ++i) {
+            result.objective.push_back(x);
+        }
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable( maingo::Bounds(0, 1)));  
+        return variables;
+    }
+  private:
+    size_t _nobj = 0;
+};
+
+
+class BiObjectiveProblemThrowingException: public maingo::MAiNGOmodelEpsCon {
+  public:
+    maingo::EvaluationContainer evaluate_user_model(const std::vector<Var> &optVars) override {
+        throw std::runtime_error("Something went wrong during evaluation!");
+        return maingo::EvaluationContainer();
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+class InfeasibleBiObjectiveProblem: public maingo::MAiNGOmodelEpsCon {
+  public:
+    maingo::EvaluationContainer evaluate_user_model(const std::vector<Var> &optVars) override {
+        Var x = optVars.at(0);
+        maingo::EvaluationContainer result;
+        result.objective.push_back(x);
+        result.objective.push_back(x);
+        result.ineq.push_back(2. - x);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() override {
+        return { maingo::OptimizationVariable(maingo::Bounds(0, 1)) };
+    }
+};
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, NoModelSet) {
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.solve(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, ModelWithoutVariables) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemWithoutVariables>();
+    EXPECT_THROW(MAiNGO maingo(model), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, ModelThrowsException) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemThrowingException>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.solve(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, ModelThrowsInteger) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemThrowingInteger>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.solve(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, InitialPointWrongSize) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>(10, 0.5));
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.set_model(model), maingo::MAiNGOException);
+
+    model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>(8, 0.5));
+    EXPECT_THROW(maingo.set_model(model), maingo::MAiNGOException);
+
+    model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>(9, 0.5));
+    EXPECT_NO_THROW(maingo.set_model(model));
+
+    model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>(0));
+    EXPECT_NO_THROW(maingo.set_model(model));
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, RegularSolve) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("LBP_addAuxiliaryVars", 1);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, RegularSolveInfeasible) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemNonconstantConstraintInfeasible>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+
+    maingo.set_option("BAB_constraintPropagation", 0);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("BAB_constraintPropagation", 0);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, TargetLowerBound) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    maingo.set_option("targetLowerBound", -10);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::BOUND_TARGETS);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, NoFeasiblePointFound) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    maingo.set_option("BAB_maxIterations", 0);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::NO_FEASIBLE_POINT_FOUND);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, TargetUpperBound) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("targetUpperBound", 10);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::BOUND_TARGETS);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, ConflictingBounds) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemConflictingBounds>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, ConstantConstraintsInfeasible) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemConstantConstraintInfeasible>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, ConflictingRelaxationOnlyConstraints) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemAdjustableNumberOfRelaxationOnlyConstraintsInfeasible>(2, 2);
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("BAB_constraintPropagation", 0);
+    maingo.set_option("PRE_obbtMaxRounds", 0);
+    maingo.set_option("BAB_alwaysDoObbt", 0);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    model = std::make_shared<ProblemAdjustableNumberOfRelaxationOnlyConstraintsInfeasible>(1, 1);
+    maingo.set_model(model);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, ConstantObjective) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemConstantObjective>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, HiddenZero) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemWithHiddenZero>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, RegularSolveWithMultiobjectiveProblem) {
+    std::shared_ptr<maingo::MAiNGOmodelEpsCon> model = std::make_shared<BasicBiobjectiveModel>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.solve(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, PureMultistart) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("PRE_pureMultistart", 1);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::FEASIBLE_POINT);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::NO_FEASIBLE_POINT_FOUND);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    maingo.set_option("LBP_solver", 0);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 1);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 2);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 3);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveMIP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicMIP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    maingo.set_option("LBP_solver", 0);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 1);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 2);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 3);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveMIQP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicMIQP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    maingo.set_option("LBP_solver", 0);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 1);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 2);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+
+    maingo.set_option("LBP_solver", 3);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveDNLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicDNLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveMINLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicMINLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, RegularSolveWithMultiobjectiveProblemConvertedToSingleObjective) {
+    std::shared_ptr<maingo::MAiNGOmodelEpsCon> model = std::make_shared<BasicBiobjectiveModel>();
+    model->set_epsilon(std::vector<double>{1., 0.});
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("epsilonA", 1e-9);
+    maingo.set_option("epsilonR", 1e-9);
+    EXPECT_NO_THROW(maingo.solve());
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+    EXPECT_DOUBLE_EQ(maingo.get_objective_value(), 1.);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveAndWriteModelToAleFile) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("modelWritingLanguage", maingo::LANG_ALE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_written_model.txt", errorCode);
+    maingo.solve();
+    EXPECT_EQ(std::filesystem::exists("MAiNGO_written_model.txt"), true);
+    std::filesystem::remove("MAiNGO_written_model.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveAndWriteModelToGamsFile) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("modelWritingLanguage", maingo::LANG_GAMS);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+    maingo.solve();
+    EXPECT_EQ(std::filesystem::exists("MAiNGO_written_model.gms"), true);
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, NoModelSetEpsilonConstraint) {
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.solve_epsilon_constraint(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveEpsilonConstraintWithSingleObjectiveProblem) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<MAiNGOTestProblemRegular>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.solve_epsilon_constraint(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveEpsilonConstraintWithWrongObjectiveNumber) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemWithAdjustableNumberOfObjectives>(0);
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.solve_epsilon_constraint(), maingo::MAiNGOException);
+
+    model = std::make_shared<ProblemWithAdjustableNumberOfObjectives>(1);
+    maingo.set_model(model);
+    EXPECT_THROW(maingo.solve_epsilon_constraint(), maingo::MAiNGOException);
+
+    model = std::make_shared<ProblemWithAdjustableNumberOfObjectives>(3);
+    maingo.set_model(model);
+    EXPECT_THROW(maingo.solve_epsilon_constraint(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, BiObjectiveProblemThrowsException) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BiObjectiveProblemThrowingException>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.solve_epsilon_constraint(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveEpsilonConstraint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicBiobjectiveModel>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("EC_nPoints", 3);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+    std::filesystem::remove("MAiNGO_epsilon_constraint_solution_points.csv", errorCode);
+    maingo.solve_epsilon_constraint();
+    EXPECT_EQ(true, std::filesystem::exists("MAiNGO_epsilon_constraint_objective_values.csv"));
+    EXPECT_EQ(true, std::filesystem::exists("MAiNGO_epsilon_constraint_solution_points.csv"));
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+    std::filesystem::remove("MAiNGO_epsilon_constraint_solution_points.csv", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveEpsilonConstraintInfeasible) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<InfeasibleBiObjectiveProblem>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("EC_nPoints", 2);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+    std::filesystem::remove("MAiNGO_epsilon_constraint_solution_points.csv", errorCode);
+    maingo.solve_epsilon_constraint();
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+    EXPECT_EQ(true, std::filesystem::exists("MAiNGO_epsilon_constraint_objective_values.csv"));
+    EXPECT_EQ(true, std::filesystem::exists("MAiNGO_epsilon_constraint_solution_points.csv"));
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+    std::filesystem::remove("MAiNGO_epsilon_constraint_solution_points.csv", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGO, SolveEpsilonConstraintAndAskingToWriteModelToFile) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicBiobjectiveModel>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("modelWritingLanguage", maingo::LANG_GAMS);
+    maingo.set_option("EC_nPoints", 2);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+    std::filesystem::remove("MAiNGO_epsilon_constraint_solution_points.csv", errorCode);
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+
+    maingo.solve_epsilon_constraint();
+    EXPECT_EQ(true, std::filesystem::exists("MAiNGO_epsilon_constraint_objective_values.csv"));
+    EXPECT_EQ(true, std::filesystem::exists("MAiNGO_epsilon_constraint_solution_points.csv"));
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+    std::filesystem::remove("MAiNGO_epsilon_constraint_solution_points.csv", errorCode);
+
+    EXPECT_EQ(false, std::filesystem::exists("MAiNGO_written_model.gms"));
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOException.cpp b/tests/unitTests/testMAiNGOException.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0a05f7e0f73b83f441f35a84cb16f4d8f7b2ce03
--- /dev/null
+++ b/tests/unitTests/testMAiNGOException.cpp
@@ -0,0 +1,79 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGOException.h"
+
+#include "babNode.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+
+using maingo::MAiNGOException;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOException, ErrorMessage)
+{
+    const MAiNGOException e("my error message");
+    const std::string msg = e.what();
+    EXPECT_EQ("my error message", msg);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOException, CatchAsStdException)
+{
+    std::string msg;
+    try {
+        throw MAiNGOException("my error message");
+    }
+    catch(std::exception& e) {
+        msg = e.what();
+    }
+    EXPECT_EQ("my error message", msg);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOException, ConstructFromOtherException)
+{
+    const std::runtime_error originalException("original error message");
+    const MAiNGOException e("my error message", originalException);
+    const std::string msg = e.what();
+    EXPECT_EQ("  Original exception type: ", msg.substr(0, 27));
+    EXPECT_EQ(": \n   original error message\nmy error message", msg.substr(msg.length()-45,47));
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOException, ConstructWithBabNode)
+{
+    babBase::BabNode node(42, std::vector<double>(1, 0.), std::vector<double>(1, 1.), 0, 1, 2, true);
+    const MAiNGOException e("my error message", node);
+    const std::string msg = e.what();
+    EXPECT_EQ("my error message\n  Exception was thrown while processing node no. 1:\n    x(0): 0:1", msg);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOException, ConstructWithBabNodeFromOtherException)
+{
+    babBase::BabNode node(42, std::vector<double>(1, 0.), std::vector<double>(1, 1.), 0, 1, 2, true);
+    const std::runtime_error originalException("original error message");
+    const MAiNGOException e("my error message", originalException, node);
+    const std::string msg = e.what();
+
+    EXPECT_EQ("  Original exception type: ", msg.substr(0, 27));
+    EXPECT_EQ(": \n   original error message\nmy error message\n  Exception was thrown while processing node no. 1:\n    x(0): 0:1", msg.substr(msg.length()-111,115));
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOevaluationFunctions.cpp b/tests/unitTests/testMAiNGOevaluationFunctions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..206ee8ad72805b8b2eeb80693f3946de66347155
--- /dev/null
+++ b/tests/unitTests/testMAiNGOevaluationFunctions.cpp
@@ -0,0 +1,132 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+
+
+using maingo::MAiNGO;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateModelAtPoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    const std::pair<std::vector<double>, bool> result = maingo.evaluate_model_at_point({0.5, 0.5, 0.5, 0.5});
+    EXPECT_EQ(result.first.size(), 11);
+    EXPECT_EQ(result.first[0], 0.25);
+    EXPECT_EQ(result.second, false);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateModelAtPointNoModel) {
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.evaluate_model_at_point({0.5, 0.5}), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateModelAtPointIncompatiblePoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    EXPECT_THROW(maingo.evaluate_model_at_point({0.5, 0.5}), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateAdditionalOutputAtPoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    const std::vector<std::pair<std::string, double>> output = maingo.evaluate_additional_outputs_at_point({0.5, 0.5, 0.5, 0.5});
+    EXPECT_EQ(output.size(), 2);
+    EXPECT_EQ(output[0].first, "the answer");
+    EXPECT_EQ(output[0].second, 42.0);
+    EXPECT_EQ(output[1].first, "still the answer");
+    EXPECT_EQ(output[1].second, 42.0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateAdditionalOutputAtPointNoModel) {
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.evaluate_additional_outputs_at_point({0.5, 0.5}), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateAdditionalOutputAtPointIncompatiblePoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    EXPECT_THROW(maingo.evaluate_additional_outputs_at_point({0.5, 0.5}), maingo::MAiNGOException);
+}
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateModelAtSolutionPoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", 0);
+    maingo.set_option("writeResultFile", 0);
+    maingo.solve();
+
+    const std::vector<double> result = maingo.evaluate_model_at_solution_point();
+    EXPECT_EQ(result.size(), 11);
+    EXPECT_EQ(result[0], 0.);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateModelAtSolutionPointNotSolvedYet) {
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.evaluate_model_at_solution_point(), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateAdditionalOutputAtSolutionPoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", 0);
+    maingo.set_option("writeResultFile", 0);
+    maingo.solve();
+
+    const std::vector<std::pair<std::string, double>> output = maingo.evaluate_additional_outputs_at_solution_point();
+    EXPECT_EQ(output.size(), 2);
+    EXPECT_EQ(output[0].first, "the answer");
+    EXPECT_EQ(output[0].second, 41.5);
+    EXPECT_EQ(output[1].first, "still the answer");
+    EXPECT_EQ(output[1].second, 42.0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateAdditionalOutputAtSolutionPointNoOutputs) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", 0);
+    maingo.set_option("writeResultFile", 0);
+    maingo.solve();
+
+    const std::vector<std::pair<std::string, double>> output = maingo.evaluate_additional_outputs_at_solution_point();
+    EXPECT_EQ(output.size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOevaluationFunctions, EvaluateAdditionalOutputAtSolutionPointNotSolvedYet) {
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.evaluate_additional_outputs_at_solution_point(), maingo::MAiNGOException);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOgetterFunctions.cpp b/tests/unitTests/testMAiNGOgetterFunctions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..095bb0c79ede81f653f518ed23afde5b517eeedf
--- /dev/null
+++ b/tests/unitTests/testMAiNGOgetterFunctions.cpp
@@ -0,0 +1,212 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+#include <filesystem>
+
+
+
+using maingo::MAiNGO;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetObjectiveValue) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_objective_value(), maingo::MAiNGOException);
+
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_objective_value(), 0.);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetSolutonPoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_solution_point(), maingo::MAiNGOException);
+
+    maingo.solve();
+    const std::vector<double> solutionPoint = maingo.get_solution_point();
+    EXPECT_DOUBLE_EQ(solutionPoint.size(), 2);
+    EXPECT_DOUBLE_EQ(solutionPoint[0], 0);
+    EXPECT_DOUBLE_EQ(solutionPoint[1], 0.5);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetCpuSolutionTime) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_cpu_solution_time(), maingo::MAiNGOException);
+
+    maingo.solve();
+    EXPECT_GE(maingo.get_cpu_solution_time(), 0.);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetWallSolutionTime) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_wallclock_solution_time(), maingo::MAiNGOException);
+
+    maingo.solve();
+    EXPECT_GE(maingo.get_wallclock_solution_time(), 0.);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetIterations) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_iterations(), maingo::MAiNGOException);
+
+    maingo.set_option("PRE_pureMultistart", 1);
+    maingo.solve();
+    EXPECT_EQ(maingo.get_iterations(), 0);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_pureMultistart", 0);
+    maingo.solve();
+    EXPECT_GE(maingo.get_iterations(), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetMaxNodes) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_max_nodes_in_memory(), maingo::MAiNGOException);
+
+    maingo.set_option("PRE_pureMultistart", 1);
+    maingo.solve();
+    EXPECT_EQ(maingo.get_max_nodes_in_memory(), 1);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_pureMultistart", 0);
+    maingo.solve();
+    EXPECT_GE(maingo.get_max_nodes_in_memory(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetUbpCount) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_UBP_count(), maingo::MAiNGOException);
+
+    maingo.set_option("PRE_pureMultistart", 1);
+    maingo.solve();
+    EXPECT_EQ(maingo.get_UBP_count(), 1);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_pureMultistart", 0);
+    maingo.solve();
+    EXPECT_GE(maingo.get_UBP_count(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetLbpCount) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_LBP_count(), maingo::MAiNGOException);
+
+    maingo.set_option("PRE_pureMultistart", 1);
+    maingo.solve();
+    EXPECT_EQ(maingo.get_LBP_count(), 0);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_pureMultistart", 0);
+    maingo.solve();
+    EXPECT_GE(maingo.get_LBP_count(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetFinalLbd) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_final_LBD(), maingo::MAiNGOException);
+
+    maingo.set_option("PRE_pureMultistart", 1);
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_final_LBD(), 0);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_pureMultistart", 0);
+    maingo.solve();
+    EXPECT_DOUBLE_EQ(maingo.get_final_LBD(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetFinalAbsGap) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_final_abs_gap(), maingo::MAiNGOException);
+
+    maingo.set_option("PRE_pureMultistart", 1);
+    maingo.solve();
+    EXPECT_LT(maingo.get_final_abs_gap(), 1e-1);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_pureMultistart", 0);
+    maingo.solve();
+    EXPECT_EQ(maingo.get_final_abs_gap(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetFinalRelGap) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_THROW(maingo.get_final_rel_gap(), maingo::MAiNGOException);
+
+    maingo.set_option("PRE_pureMultistart", 1);
+    maingo.solve();
+    EXPECT_LT(maingo.get_final_rel_gap(), 1e-1);
+
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("PRE_pureMultistart", 0);
+    maingo.solve();
+    EXPECT_EQ(maingo.get_final_rel_gap(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOgetterFunctions, GetStatus) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel2>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    EXPECT_EQ(maingo.get_status(), maingo::NOT_SOLVED_YET);
+
+    maingo.solve();
+    EXPECT_EQ(maingo.get_status(), maingo::GLOBALLY_OPTIMAL);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOmodelEpsCon.cpp b/tests/unitTests/testMAiNGOmodelEpsCon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..771d672838f6cde836e8bdf5bebc632a9832f673
--- /dev/null
+++ b/tests/unitTests/testMAiNGOmodelEpsCon.cpp
@@ -0,0 +1,65 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2023 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGOmodelEpsCon.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+
+using Var = mc::FFVar;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOmodelEpsCon, ThrowsIfOnlyOneObjective)
+{
+    MultiobjectiveModelOneObjective model;
+    std::vector<Var> x(1);
+    EXPECT_THROW(model.evaluate(x), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOmodelEpsCon, ThrowsIfInconsistenEpsilonDimension)
+{
+    BasicBiobjectiveModel model;
+    model.set_epsilon({1});
+    std::vector<Var> x = {0.5, 0.5};
+    EXPECT_THROW(model.evaluate(x), maingo::MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOmodelEpsCon, ConstructSingleObjectiveProblem)
+{
+    BasicBiobjectiveModel model;
+    model.set_epsilon({0.1, 0.1});
+    model.set_single_objective(true);
+    std::vector<Var> x = {0.5, 0.5};
+    maingo::EvaluationContainer results = model.evaluate(x);
+    EXPECT_EQ(results.objective.size(), 1);
+    EXPECT_EQ(results.ineq.size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOmodelEpsCon, ConstructEpsilonConstraintProblem)
+{
+    BasicBiobjectiveModel model;
+    model.set_epsilon({0.1, 0.1});
+    model.set_single_objective(false);
+    std::vector<Var> x = {0.5, 0.5};
+    maingo::EvaluationContainer results = model.evaluate(x);
+    EXPECT_EQ(results.objective.size(), 1);
+    EXPECT_EQ(results.ineq.size(), 1);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOprintingFunctions.cpp b/tests/unitTests/testMAiNGOprintingFunctions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..26b243410f24dbe548952dd0c744975d7abe48e5
--- /dev/null
+++ b/tests/unitTests/testMAiNGOprintingFunctions.cpp
@@ -0,0 +1,222 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+#include <filesystem>
+
+
+
+using maingo::MAiNGO;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, RegularProgress) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>({0.5, 1, 0, 1, 1, 1, 1, 1, 1}));
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, FeasiblePointOnly) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>({0.5, 1, 0, 1, 1, 1, 1, 1, 1}));
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+    maingo.set_option("terminateOnFeasiblePoint", 1);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, RegularProgressLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, InfeasibleLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<InfeasibleLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, InitialPoint) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>({2.5, 0.5, 1, 0.5, 1, 0.5, 1, 1, 1}));
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, InfeasibleBounds) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemInfeasibleBounds>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, ConstantConstraintsInfeasible) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<ProblemConstantConstraintsInfeasible>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, Subsolvers) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>({0.5, 1, 0, 1, 1, 1, 1, 1, 1}));
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    maingo.set_option("LBP_solver", 0);
+    maingo.set_option("UBP_solverPreprocessing", 0);
+    maingo.set_option("UBP_solverBab", 0);
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+
+    maingo.set_option("LBP_solver", 1);
+    maingo.set_option("UBP_solverPreprocessing", 1);
+    maingo.set_option("UBP_solverBab", 1);
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+
+#ifdef HAVE_CPLEX
+    maingo.set_option("LBP_solver", 2);
+#endif
+    maingo.set_option("UBP_solverPreprocessing", 2);
+    maingo.set_option("UBP_solverBab", 2);
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+
+    maingo.set_option("LBP_solver", 3);
+    maingo.set_option("UBP_solverPreprocessing", 3);
+    maingo.set_option("UBP_solverBab", 3);
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+
+    maingo.set_option("UBP_solverPreprocessing", 4);
+    maingo.set_option("UBP_solverBab", 4);
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+
+    maingo.set_option("UBP_solverPreprocessing", 5);
+    maingo.set_option("UBP_solverBab", 5);
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+
+#ifdef HAVE_KNITRO
+    maingo.set_option("UBP_solverPreprocessing", 6);
+    maingo.set_option("UBP_solverBab", 6);
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+#endif
+
+    model = std::make_shared<BasicLP>();
+    maingo.set_model(model);
+    maingo.set_option("UBP_solverPreprocessing", 43); // CLP
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, PrintMAiNGO) {
+    MAiNGO maingo;
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+    testing::internal::CaptureStdout();
+    maingo.print_MAiNGO();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, PureMultistart) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>({0.5, 1, 0, 1, 1, 1, 1, 1, 1}));
+    MAiNGO maingo(model);
+    maingo.set_option("PRE_pureMultistart", true);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, FeasibilityOnly) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<FeasibilityProblem>();
+    MAiNGO maingo(model);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOprintingFunctions, TargetUpperBound) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLPcustomInitialPoint>(std::vector<double>({0.5, 1, 0, 1, 1, 1, 1, 1, 1}));
+    MAiNGO maingo(model);
+    maingo.set_option("targetUpperBound", 1e9);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    testing::internal::CaptureStdout();
+    maingo.solve();
+    EXPECT_GT(testing::internal::GetCapturedStdout().size(), 0);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOreadSettings.cpp b/tests/unitTests/testMAiNGOreadSettings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bfb56084a4eed28de74aa08c767028055343bb32
--- /dev/null
+++ b/tests/unitTests/testMAiNGOreadSettings.cpp
@@ -0,0 +1,56 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+
+#include <gtest/gtest.h>
+
+#include <filesystem>
+#include <fstream>
+
+
+using maingo::MAiNGO;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOreadSettings, NonexistingFile) {
+    if (std::filesystem::exists("bogusFileName")) {
+        FAIL() << "Eror testing read from non-existing file: File bogusFileName exists.";
+    }
+
+    MAiNGO maingo;
+    EXPECT_NO_THROW(maingo.read_settings("bogusFileName"));
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOreadSettings, Existing) {
+    if (std::filesystem::exists("testSettingsFile.txt")) {
+        FAIL() << "Eror writing dummy file to test reading of settings: File testSettingsFile.txt already exists.";
+    }
+
+    std::ofstream file("testSettingsFile.txt");
+    // Add BOM character at beginning of file (happens on some systems; MAiNGO should ignore it)
+    unsigned char bom[] = {0xEF,0xBB,0xBF };
+    file.write((char*)bom, sizeof(bom));
+    file << "epsilonR 0.42e-2" << std::endl;
+    file << "# This line is a comment." << std::endl;
+    file << "# epsilonA 0.42e-2" << std::endl;
+    file << "   deltaIneq 0.42e-2" << std::endl;
+    file.close();
+
+    MAiNGO maingo;
+    maingo.read_settings("testSettingsFile.txt");
+    EXPECT_EQ(maingo.get_option("epsilonA"), 1.0e-2);
+    EXPECT_EQ(maingo.get_option("epsilonR"), 0.42e-2);
+    EXPECT_EQ(maingo.get_option("deltaIneq"), 0.42e-2);
+    std::filesystem::remove("testSettingsFile.txt");
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOsetAndGetOption.cpp b/tests/unitTests/testMAiNGOsetAndGetOption.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8f7dc0b043925b2ab2e3f17707387285743a3430
--- /dev/null
+++ b/tests/unitTests/testMAiNGOsetAndGetOption.cpp
@@ -0,0 +1,1194 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include <gtest/gtest.h>
+
+
+using maingo::MAiNGO;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, epsilonA)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("epsilonA", 1e-4), true);
+    EXPECT_EQ(maingo.get_option("epsilonA"), 1e-4);
+
+    EXPECT_EQ(maingo.set_option("epsilonA", 1e-10), true);
+    EXPECT_EQ(maingo.get_option("epsilonA"), 1e-9);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, epsilonR)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("epsilonR", 1e-4), true);
+    EXPECT_EQ(maingo.get_option("epsilonR"), 1e-4);
+
+    EXPECT_EQ(maingo.set_option("epsilonR", 1e-10), true);
+    EXPECT_EQ(maingo.get_option("epsilonR"), 1e-9);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, deltaIneq)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("deltaIneq", 1e-4), true);
+    EXPECT_EQ(maingo.get_option("deltaIneq"), 1e-4);
+
+    EXPECT_EQ(maingo.set_option("deltaIneq", 1e-10), true);
+    EXPECT_EQ(maingo.get_option("deltaIneq"), 1e-9);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, deltaEq)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("deltaEq", 1e-4), true);
+    EXPECT_EQ(maingo.get_option("deltaEq"), 1e-4);
+
+    EXPECT_EQ(maingo.set_option("deltaEq", 1e-10), true);
+    EXPECT_EQ(maingo.get_option("deltaEq"), 1e-9);
+
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, relNodeTol)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("relNodeTol", 1e-4), true);
+    EXPECT_EQ(maingo.get_option("relNodeTol"), 1e-7);
+
+    EXPECT_EQ(maingo.set_option("relNodeTol", 1e-8), true);
+    EXPECT_EQ(maingo.get_option("relNodeTol"), 1e-8);
+
+    EXPECT_EQ(maingo.set_option("relNodeTol", 1e-13), true);
+    EXPECT_EQ(maingo.get_option("relNodeTol"), 1e-12);
+
+    
+    EXPECT_EQ(maingo.set_option("relNodeTol", 1e-4), true);
+    EXPECT_EQ(maingo.set_option("deltaIneq", 1e-5), true);
+    EXPECT_EQ(maingo.set_option("deltaEq", 1e-6), true);
+    EXPECT_EQ(maingo.get_option("relNodeTol"), 1e-7);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_maxNodes)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_maxNodes", 1e3), true);
+    EXPECT_EQ(maingo.get_option("BAB_maxNodes"), 1e3);
+
+    EXPECT_EQ(maingo.set_option("BAB_maxNodes", -1), true);
+    EXPECT_EQ(maingo.get_option("BAB_maxNodes"), std::numeric_limits<unsigned>::max());
+
+    EXPECT_EQ(maingo.set_option("BAB_maxNodes", -42), true);
+    EXPECT_EQ(maingo.get_option("BAB_maxNodes"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_maxIterations)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_maxIterations", 1e3), true);
+    EXPECT_EQ(maingo.get_option("BAB_maxIterations"), 1e3);
+
+    EXPECT_EQ(maingo.set_option("BAB_maxIterations", -1), true);
+    EXPECT_EQ(maingo.get_option("BAB_maxIterations"), std::numeric_limits<unsigned>::max());
+
+    EXPECT_EQ(maingo.set_option("BAB_maxIterations", -42), true);
+    EXPECT_EQ(maingo.get_option("BAB_maxIterations"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, maxTime)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("maxTime", 1e3), true);
+    EXPECT_EQ(maingo.get_option("maxTime"), 1e3);
+
+    EXPECT_EQ(maingo.set_option("maxTime", -1), true);
+    EXPECT_EQ(maingo.get_option("maxTime"), std::numeric_limits<unsigned>::max());
+
+    EXPECT_EQ(maingo.set_option("maxTime", -10), true);
+    EXPECT_EQ(maingo.get_option("maxTime"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, confirmTermination)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("confirmTermination", 0), true);
+    EXPECT_EQ(maingo.get_option("confirmTermination"), 0);
+
+    EXPECT_EQ(maingo.set_option("confirmTermination", 1), true);
+    EXPECT_EQ(maingo.get_option("confirmTermination"), 1);
+
+    EXPECT_EQ(maingo.set_option("confirmTermination", 2), true);
+    EXPECT_EQ(maingo.get_option("confirmTermination"), 0);
+
+    EXPECT_EQ(maingo.set_option("confirmTermination", 0.99), true);
+    EXPECT_EQ(maingo.get_option("confirmTermination"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, terminateOnFeasiblePoint)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("terminateOnFeasiblePoint", 0), true);
+    EXPECT_EQ(maingo.get_option("terminateOnFeasiblePoint"), 0);
+
+    EXPECT_EQ(maingo.set_option("terminateOnFeasiblePoint", 1), true);
+    EXPECT_EQ(maingo.get_option("terminateOnFeasiblePoint"), 1);
+
+    EXPECT_EQ(maingo.set_option("terminateOnFeasiblePoint", 2), true);
+    EXPECT_EQ(maingo.get_option("terminateOnFeasiblePoint"), 0);
+
+    EXPECT_EQ(maingo.set_option("terminateOnFeasiblePoint", 0.99), true);
+    EXPECT_EQ(maingo.get_option("terminateOnFeasiblePoint"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, targetLowerBound)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("targetLowerBound", 42.), true);
+    EXPECT_EQ(maingo.get_option("targetLowerBound"), 42.);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, targetUpperBound)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("targetUpperBound", 42.), true);
+    EXPECT_EQ(maingo.get_option("targetUpperBound"), 42.);
+}
+ 
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, PRE_maxLocalSearches)
+{
+ MAiNGO maingo;
+ EXPECT_EQ(maingo.set_option("PRE_maxLocalSearches", 42), true);
+ EXPECT_EQ(maingo.get_option("PRE_maxLocalSearches"), 42);
+
+ EXPECT_EQ(maingo.set_option("PRE_maxLocalSearches", 42.5), true);
+ EXPECT_EQ(maingo.get_option("PRE_maxLocalSearches"), (int)42.5);
+
+ EXPECT_EQ(maingo.set_option("PRE_maxLocalSearches", -1), true);
+ EXPECT_EQ(maingo.get_option("PRE_maxLocalSearches"), 0);
+}
+ 
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, PRE_obbtMaxRounds)
+{
+ MAiNGO maingo;
+ EXPECT_EQ(maingo.set_option("PRE_obbtMaxRounds", 42), true);
+ EXPECT_EQ(maingo.get_option("PRE_obbtMaxRounds"), 42);
+
+ EXPECT_EQ(maingo.set_option("PRE_obbtMaxRounds", 42.5), true);
+ EXPECT_EQ(maingo.get_option("PRE_obbtMaxRounds"), (int)42.5);
+
+ EXPECT_EQ(maingo.set_option("PRE_obbtMaxRounds", -1), true);
+ EXPECT_EQ(maingo.get_option("PRE_obbtMaxRounds"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, PRE_pureMultistart)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("PRE_pureMultistart", 0), true);
+    EXPECT_EQ(maingo.get_option("PRE_pureMultistart"), 0);
+
+    EXPECT_EQ(maingo.set_option("PRE_pureMultistart", 1), true);
+    EXPECT_EQ(maingo.get_option("PRE_pureMultistart"), 1);
+
+    EXPECT_EQ(maingo.set_option("PRE_pureMultistart", 2), true);
+    EXPECT_EQ(maingo.get_option("PRE_pureMultistart"), 0);
+
+    EXPECT_EQ(maingo.set_option("PRE_pureMultistart", 0.99), true);
+    EXPECT_EQ(maingo.get_option("PRE_pureMultistart"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_nodeSelection)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_nodeSelection", 0), true);
+    EXPECT_EQ(maingo.get_option("BAB_nodeSelection"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_nodeSelection", 1), true);
+    EXPECT_EQ(maingo.get_option("BAB_nodeSelection"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_nodeSelection", 2), true);
+    EXPECT_EQ(maingo.get_option("BAB_nodeSelection"), 2);
+
+    EXPECT_EQ(maingo.set_option("BAB_nodeSelection", 0.5), true);
+    EXPECT_EQ(maingo.get_option("BAB_nodeSelection"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_nodeSelection", 1.5), true);
+    EXPECT_EQ(maingo.get_option("BAB_nodeSelection"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_nodeSelection", 3), true);
+    EXPECT_EQ(maingo.get_option("BAB_nodeSelection"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_branchVariable)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_branchVariable", 0), true);
+    EXPECT_EQ(maingo.get_option("BAB_branchVariable"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_branchVariable", 1), true);
+    EXPECT_EQ(maingo.get_option("BAB_branchVariable"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_branchVariable", 2), true);
+    EXPECT_EQ(maingo.get_option("BAB_branchVariable"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_branchVariable", 0.99), true);
+    EXPECT_EQ(maingo.get_option("BAB_branchVariable"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_alwaysSolveObbt)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_alwaysSolveObbt", 0), true);
+    EXPECT_EQ(maingo.get_option("BAB_alwaysSolveObbt"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_alwaysSolveObbt", 1), true);
+    EXPECT_EQ(maingo.get_option("BAB_alwaysSolveObbt"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_alwaysSolveObbt", 2), true);
+    EXPECT_EQ(maingo.get_option("BAB_alwaysSolveObbt"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_alwaysSolveObbt", 0.99), true);
+    EXPECT_EQ(maingo.get_option("BAB_alwaysSolveObbt"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_obbtDecayCoefficient)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_obbtDecayCoefficient", 42.), true);
+    EXPECT_EQ(maingo.get_option("BAB_obbtDecayCoefficient"), 42.);
+
+    EXPECT_EQ(maingo.set_option("BAB_obbtDecayCoefficient", -1.), true);
+    EXPECT_EQ(maingo.get_option("BAB_obbtDecayCoefficient"), 0.);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_probing)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_probing", 0), true);
+    EXPECT_EQ(maingo.get_option("BAB_probing"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_probing", 1), true);
+    EXPECT_EQ(maingo.get_option("BAB_probing"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_probing", 2), true);
+    EXPECT_EQ(maingo.get_option("BAB_probing"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_probing", 0.99), true);
+    EXPECT_EQ(maingo.get_option("BAB_probing"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_dbbt)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_dbbt", 0), true);
+    EXPECT_EQ(maingo.get_option("BAB_dbbt"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_dbbt", 1), true);
+    EXPECT_EQ(maingo.get_option("BAB_dbbt"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_dbbt", 2), true);
+    EXPECT_EQ(maingo.get_option("BAB_dbbt"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_dbbt", 0.99), true);
+    EXPECT_EQ(maingo.get_option("BAB_dbbt"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_constraintPropagation)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_constraintPropagation", 0), true);
+    EXPECT_EQ(maingo.get_option("BAB_constraintPropagation"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_constraintPropagation", 1), true);
+    EXPECT_EQ(maingo.get_option("BAB_constraintPropagation"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_constraintPropagation", 2), true);
+    EXPECT_EQ(maingo.get_option("BAB_constraintPropagation"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_constraintPropagation", 0.99), true);
+    EXPECT_EQ(maingo.get_option("BAB_constraintPropagation"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_solver)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_solver", 0), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_solver", 1), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 1);
+
+#ifdef HAVE_CPLEX
+    EXPECT_EQ(maingo.set_option("LBP_solver", 2), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 2);
+#else
+    EXPECT_EQ(maingo.set_option("LBP_solver", 2), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 3);
+#endif
+
+    EXPECT_EQ(maingo.set_option("LBP_solver", 3), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 3);
+
+    EXPECT_EQ(maingo.set_option("LBP_solver", 0.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_solver", 1.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_solver", 4), true);
+    EXPECT_EQ(maingo.get_option("LBP_solver"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_linPoints)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 0), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 1), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 2), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 2);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 3), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 3);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 4), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 4);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 5), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 5);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 0.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 1.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_linPoints", 6), true);
+    EXPECT_EQ(maingo.get_option("LBP_linPoints"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_subgradientIntervals)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_subgradientIntervals", 0), true);
+    EXPECT_EQ(maingo.get_option("LBP_subgradientIntervals"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_subgradientIntervals", 1), true);
+    EXPECT_EQ(maingo.get_option("LBP_subgradientIntervals"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_subgradientIntervals", 2), true);
+    EXPECT_EQ(maingo.get_option("LBP_subgradientIntervals"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_subgradientIntervals", 0.99), true);
+    EXPECT_EQ(maingo.get_option("LBP_subgradientIntervals"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_obbtMinImprovement)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_obbtMinImprovement", 0.25), true);
+    EXPECT_EQ(maingo.get_option("LBP_obbtMinImprovement"), 0.25);
+
+    EXPECT_EQ(maingo.set_option("LBP_obbtMinImprovement", 0), true);
+    EXPECT_EQ(maingo.get_option("LBP_obbtMinImprovement"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_obbtMinImprovement", 1), true);
+    EXPECT_EQ(maingo.get_option("LBP_obbtMinImprovement"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_obbtMinImprovement", -0.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_obbtMinImprovement"), 0.5);
+
+    EXPECT_EQ(maingo.set_option("LBP_obbtMinImprovement", 1.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_obbtMinImprovement"), 0.5);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_activateMoreScaling)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_activateMoreScaling", 1e3), true);
+    EXPECT_EQ(maingo.get_option("LBP_activateMoreScaling"), 1e3);
+
+    EXPECT_EQ(maingo.set_option("LBP_activateMoreScaling", 99), true);
+    EXPECT_EQ(maingo.get_option("LBP_activateMoreScaling"), 10000);
+
+    EXPECT_EQ(maingo.set_option("LBP_activateMoreScaling", 100001), true);
+    EXPECT_EQ(maingo.get_option("LBP_activateMoreScaling"), 10000);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_addAuxiliaryVars)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_addAuxiliaryVars", 0), true);
+    EXPECT_EQ(maingo.get_option("LBP_addAuxiliaryVars"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_addAuxiliaryVars", 1), true);
+    EXPECT_EQ(maingo.get_option("LBP_addAuxiliaryVars"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_addAuxiliaryVars", 2), true);
+    EXPECT_EQ(maingo.get_option("LBP_addAuxiliaryVars"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_addAuxiliaryVars", 0.99), true);
+    EXPECT_EQ(maingo.get_option("LBP_addAuxiliaryVars"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_minFactorsForAux)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_minFactorsForAux", 4), true);
+    EXPECT_EQ(maingo.get_option("LBP_minFactorsForAux"), 4);
+
+    EXPECT_EQ(maingo.set_option("LBP_minFactorsForAux", 4.35), true);
+    EXPECT_EQ(maingo.get_option("LBP_minFactorsForAux"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("LBP_minFactorsForAux", 1), true);
+    EXPECT_EQ(maingo.get_option("LBP_minFactorsForAux"), 2);
+
+    EXPECT_EQ(maingo.set_option("LBP_minFactorsForAux", -10), true);
+    EXPECT_EQ(maingo.get_option("LBP_minFactorsForAux"), 2);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_maxNumberOfAddedFactors)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_maxNumberOfAddedFactors", 4), true);
+    EXPECT_EQ(maingo.get_option("LBP_maxNumberOfAddedFactors"), 4);
+
+    EXPECT_EQ(maingo.set_option("LBP_maxNumberOfAddedFactors", 4.35), true);
+    EXPECT_EQ(maingo.get_option("LBP_maxNumberOfAddedFactors"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("LBP_maxNumberOfAddedFactors", 0.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_maxNumberOfAddedFactors"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_maxNumberOfAddedFactors", -10), true);
+    EXPECT_EQ(maingo.get_option("LBP_maxNumberOfAddedFactors"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, MC_mvcompUse)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("MC_mvcompUse", 0), true);
+    EXPECT_EQ(maingo.get_option("MC_mvcompUse"), 0);
+
+    EXPECT_EQ(maingo.set_option("MC_mvcompUse", 1), true);
+    EXPECT_EQ(maingo.get_option("MC_mvcompUse"), 1);
+
+    EXPECT_EQ(maingo.set_option("MC_mvcompUse", 2), true);
+    EXPECT_EQ(maingo.get_option("MC_mvcompUse"), 1);
+
+    EXPECT_EQ(maingo.set_option("MC_mvcompUse", 0.99), true);
+    EXPECT_EQ(maingo.get_option("MC_mvcompUse"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, MC_mvcompTol)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("MC_mvcompTol", 1e-10), true);
+    EXPECT_EQ(maingo.get_option("MC_mvcompTol"), 1e-10);
+
+    EXPECT_EQ(maingo.set_option("MC_mvcompTol", 1e-13), true);
+    EXPECT_EQ(maingo.get_option("MC_mvcompTol"), 1e-12);
+
+    EXPECT_EQ(maingo.set_option("MC_mvcompTol", 1e-8), true);
+    EXPECT_EQ(maingo.get_option("MC_mvcompTol"), 1e-12);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, MC_envelTol)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("MC_envelTol", 1e-10), true);
+    EXPECT_EQ(maingo.get_option("MC_envelTol"), 1e-10);
+
+    EXPECT_EQ(maingo.set_option("MC_envelTol", 1e-13), true);
+    EXPECT_EQ(maingo.get_option("MC_envelTol"), 1e-12);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_solverPreprocessing)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 0), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 0);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 1), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 2), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 2);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 3), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 3);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 4), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 5), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 5);
+
+#ifdef HAVE_KNITRO
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 6), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 6);
+#else
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 6), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 5);
+#endif
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 0.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 5);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 1.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 5);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverPreprocessing", 7), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverPreprocessing"), 5);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_maxStepsPreprocessing)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsPreprocessing", 4), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsPreprocessing"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsPreprocessing", 4.35), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsPreprocessing"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsPreprocessing", 0.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsPreprocessing"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsPreprocessing", -10), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsPreprocessing"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_maxTimePreprocessing)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_maxTimePreprocessing", 4), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxTimePreprocessing"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxTimePreprocessing", 0.05), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxTimePreprocessing"), 0.1);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxTimePreprocessing", -10), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxTimePreprocessing"), 0.1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_solverBab)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 0), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 0);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 1), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 2), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 2);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 3), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 3);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 4), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 5), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 5);
+
+#ifdef HAVE_KNITRO
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 6), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 6);
+#else
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 6), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 4);
+#endif
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 0.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 1.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_solverBab", 7), true);
+    EXPECT_EQ(maingo.get_option("UBP_solverBab"), 4);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_maxStepsBab)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsBab", 4), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsBab"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsBab", 4.35), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsBab"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsBab", 0.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsBab"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxStepsBab", -10), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxStepsBab"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_maxTimeBab)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_maxTimeBab", 4), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxTimeBab"), 4);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxTimeBab", 0.05), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxTimeBab"), 0.1);
+
+    EXPECT_EQ(maingo.set_option("UBP_maxTimeBab", -10), true);
+    EXPECT_EQ(maingo.get_option("UBP_maxTimeBab"), 0.1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_ignoreNodeBounds)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_ignoreNodeBounds", 0), true);
+    EXPECT_EQ(maingo.get_option("UBP_ignoreNodeBounds"), 0);
+
+    EXPECT_EQ(maingo.set_option("UBP_ignoreNodeBounds", 1), true);
+    EXPECT_EQ(maingo.get_option("UBP_ignoreNodeBounds"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_ignoreNodeBounds", 2), true);
+    EXPECT_EQ(maingo.get_option("UBP_ignoreNodeBounds"), 0);
+
+    EXPECT_EQ(maingo.set_option("UBP_ignoreNodeBounds", 0.99), true);
+    EXPECT_EQ(maingo.get_option("UBP_ignoreNodeBounds"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, EC_nPoints)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("EC_nPoints", 4), true);
+    EXPECT_EQ(maingo.get_option("EC_nPoints"), 4);
+
+    EXPECT_EQ(maingo.set_option("EC_nPoints", 4.35), true);
+    EXPECT_EQ(maingo.get_option("EC_nPoints"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("EC_nPoints", 1), true);
+    EXPECT_EQ(maingo.get_option("EC_nPoints"), 2);
+
+    EXPECT_EQ(maingo.set_option("EC_nPoints", -10), true);
+    EXPECT_EQ(maingo.get_option("EC_nPoints"), 2);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, LBP_verbosity)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("LBP_verbosity", 0), true);
+    EXPECT_EQ(maingo.get_option("LBP_verbosity"), 0);
+
+    EXPECT_EQ(maingo.set_option("LBP_verbosity", 1), true);
+    EXPECT_EQ(maingo.get_option("LBP_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_verbosity", 2), true);
+    EXPECT_EQ(maingo.get_option("LBP_verbosity"), 2);
+
+    EXPECT_EQ(maingo.set_option("LBP_verbosity", 0.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_verbosity", 1.5), true);
+    EXPECT_EQ(maingo.get_option("LBP_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("LBP_verbosity", 3), true);
+    EXPECT_EQ(maingo.get_option("LBP_verbosity"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UBP_verbosity)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("UBP_verbosity", 0), true);
+    EXPECT_EQ(maingo.get_option("UBP_verbosity"), 0);
+
+    EXPECT_EQ(maingo.set_option("UBP_verbosity", 1), true);
+    EXPECT_EQ(maingo.get_option("UBP_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_verbosity", 2), true);
+    EXPECT_EQ(maingo.get_option("UBP_verbosity"), 2);
+
+    EXPECT_EQ(maingo.set_option("UBP_verbosity", 0.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_verbosity", 1.5), true);
+    EXPECT_EQ(maingo.get_option("UBP_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("UBP_verbosity", 3), true);
+    EXPECT_EQ(maingo.get_option("UBP_verbosity"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_verbosity)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_verbosity", 0), true);
+    EXPECT_EQ(maingo.get_option("BAB_verbosity"), 0);
+
+    EXPECT_EQ(maingo.set_option("BAB_verbosity", 1), true);
+    EXPECT_EQ(maingo.get_option("BAB_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_verbosity", 2), true);
+    EXPECT_EQ(maingo.get_option("BAB_verbosity"), 2);
+
+    EXPECT_EQ(maingo.set_option("BAB_verbosity", 0.5), true);
+    EXPECT_EQ(maingo.get_option("BAB_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_verbosity", 1.5), true);
+    EXPECT_EQ(maingo.get_option("BAB_verbosity"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_verbosity", 3), true);
+    EXPECT_EQ(maingo.get_option("BAB_verbosity"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_printFreq)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_printFreq", 4), true);
+    EXPECT_EQ(maingo.get_option("BAB_printFreq"), 4);
+
+    EXPECT_EQ(maingo.set_option("BAB_printFreq", 4.35), true);
+    EXPECT_EQ(maingo.get_option("BAB_printFreq"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("BAB_printFreq", 0.5), true);
+    EXPECT_EQ(maingo.get_option("BAB_printFreq"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_printFreq", -10), true);
+    EXPECT_EQ(maingo.get_option("BAB_printFreq"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, BAB_logFreq)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("BAB_logFreq", 4), true);
+    EXPECT_EQ(maingo.get_option("BAB_logFreq"), 4);
+
+    EXPECT_EQ(maingo.set_option("BAB_logFreq", 4.35), true);
+    EXPECT_EQ(maingo.get_option("BAB_logFreq"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("BAB_logFreq", 0.5), true);
+    EXPECT_EQ(maingo.get_option("BAB_logFreq"), 1);
+
+    EXPECT_EQ(maingo.set_option("BAB_logFreq", -10), true);
+    EXPECT_EQ(maingo.get_option("BAB_logFreq"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, loggingDestination)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("loggingDestination", 0), true);
+    EXPECT_EQ(maingo.get_option("loggingDestination"), 0);
+
+    EXPECT_EQ(maingo.set_option("loggingDestination", 1), true);
+    EXPECT_EQ(maingo.get_option("loggingDestination"), 1);
+
+    EXPECT_EQ(maingo.set_option("loggingDestination", 2), true);
+    EXPECT_EQ(maingo.get_option("loggingDestination"), 2);
+
+    EXPECT_EQ(maingo.set_option("loggingDestination", 3), true);
+    EXPECT_EQ(maingo.get_option("loggingDestination"), 3);
+
+
+    EXPECT_EQ(maingo.set_option("loggingDestination", 0.5), true);
+    EXPECT_EQ(maingo.get_option("loggingDestination"), 3);
+
+    EXPECT_EQ(maingo.set_option("loggingDestination", 1.5), true);
+    EXPECT_EQ(maingo.get_option("loggingDestination"), 3);
+
+    EXPECT_EQ(maingo.set_option("loggingDestination", 4), true);
+    EXPECT_EQ(maingo.get_option("loggingDestination"), 3);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, writeCsv)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("writeCsv", 0), true);
+    EXPECT_EQ(maingo.get_option("writeCsv"), 0);
+
+    EXPECT_EQ(maingo.set_option("writeCsv", 1), true);
+    EXPECT_EQ(maingo.get_option("writeCsv"), 1);
+
+    EXPECT_EQ(maingo.set_option("writeCsv", 2), true);
+    EXPECT_EQ(maingo.get_option("writeCsv"), 0);
+
+    EXPECT_EQ(maingo.set_option("writeCsv", 0.99), true);
+    EXPECT_EQ(maingo.get_option("writeCsv"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, writeJson)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("writeJson", 0), true);
+    EXPECT_EQ(maingo.get_option("writeJson"), 0);
+
+    EXPECT_EQ(maingo.set_option("writeJson", 1), true);
+    EXPECT_EQ(maingo.get_option("writeJson"), 1);
+
+    EXPECT_EQ(maingo.set_option("writeJson", 2), true);
+    EXPECT_EQ(maingo.get_option("writeJson"), 0);
+
+    EXPECT_EQ(maingo.set_option("writeJson", 0.99), true);
+    EXPECT_EQ(maingo.get_option("writeJson"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, writeResultFile)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("writeResultFile", 0), true);
+    EXPECT_EQ(maingo.get_option("writeResultFile"), 0);
+
+    EXPECT_EQ(maingo.set_option("writeResultFile", 1), true);
+    EXPECT_EQ(maingo.get_option("writeResultFile"), 1);
+
+    EXPECT_EQ(maingo.set_option("writeResultFile", 2), true);
+    EXPECT_EQ(maingo.get_option("writeResultFile"), 0);
+
+    EXPECT_EQ(maingo.set_option("writeResultFile", 0.99), true);
+    EXPECT_EQ(maingo.get_option("writeResultFile"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, writeToLogSec)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("writeToLogSec", 42.5), true);
+    EXPECT_EQ(maingo.get_option("writeToLogSec"), 42);
+
+    EXPECT_EQ(maingo.set_option("writeToLogSec", 4.2), true);
+    EXPECT_EQ(maingo.get_option("writeToLogSec"), 1800);
+
+    EXPECT_EQ(maingo.set_option("writeToLogSec", -10), true);
+    EXPECT_EQ(maingo.get_option("writeToLogSec"), 1800);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, PRE_printEveryLocalSearch)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("PRE_printEveryLocalSearch", 0), true);
+    EXPECT_EQ(maingo.get_option("PRE_printEveryLocalSearch"), 0);
+
+    EXPECT_EQ(maingo.set_option("PRE_printEveryLocalSearch", 1), true);
+    EXPECT_EQ(maingo.get_option("PRE_printEveryLocalSearch"), 1);
+
+    EXPECT_EQ(maingo.set_option("PRE_printEveryLocalSearch", 2), true);
+    EXPECT_EQ(maingo.get_option("PRE_printEveryLocalSearch"), 0);
+
+    EXPECT_EQ(maingo.set_option("PRE_printEveryLocalSearch", 0.99), true);
+    EXPECT_EQ(maingo.get_option("PRE_printEveryLocalSearch"), 0);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, modelWritingLanguage)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("modelWritingLanguage", 0), true);
+    EXPECT_EQ(maingo.get_option("modelWritingLanguage"), 0);
+
+    EXPECT_EQ(maingo.set_option("modelWritingLanguage", 1), true);
+    EXPECT_EQ(maingo.get_option("modelWritingLanguage"), 1);
+
+    EXPECT_EQ(maingo.set_option("modelWritingLanguage", 2), true);
+    EXPECT_EQ(maingo.get_option("modelWritingLanguage"), 2);
+
+
+    EXPECT_EQ(maingo.set_option("modelWritingLanguage", 0.5), true);
+    EXPECT_EQ(maingo.get_option("modelWritingLanguage"), 1);
+
+    EXPECT_EQ(maingo.set_option("modelWritingLanguage", 1.5), true);
+    EXPECT_EQ(maingo.get_option("modelWritingLanguage"), 1);
+
+    EXPECT_EQ(maingo.set_option("modelWritingLanguage", 3), true);
+    EXPECT_EQ(maingo.get_option("modelWritingLanguage"), 1);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, growing_dataSizeTol)
+{
+    MAiNGO maingo;
+#ifdef HAVE_GROWING_DATASETS
+    EXPECT_EQ(maingo.set_option("growing_dataSizeTol", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeTol"), 0.5);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeTol", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeTol"), 0.9);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeTol", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeTol"), 0.9);
+#else
+    EXPECT_EQ(maingo.set_option("growing_dataSizeTol", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeTol"), 0.9);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeTol", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeTol"), 0.9);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeTol", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeTol"), 0.9);
+#endif
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, growing_dataSizeInit)
+{
+    MAiNGO maingo;
+#ifdef HAVE_GROWING_DATASETS
+    EXPECT_EQ(maingo.set_option("growing_dataSizeInit", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeInit"), 0.5);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeInit", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeInit"), 0.1);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeInit", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeInit"), 0.1);
+#else
+    EXPECT_EQ(maingo.set_option("growing_dataSizeInit", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeInit"), 0.1);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeInit", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeInit"), 0.1);
+
+    EXPECT_EQ(maingo.set_option("growing_dataSizeInit", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_dataSizeInit"), 0.1);
+#endif
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, growing_augmentRule)
+{
+    MAiNGO maingo;
+#ifdef HAVE_GROWING_DATASETS
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 0), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 0);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 1), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 1);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 2), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 3), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+#else
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 0), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 1), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 2), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 3), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentRule", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentRule"), 2);
+#endif
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, growing_augmentFreq)
+{
+    MAiNGO maingo;
+#ifdef HAVE_GROWING_DATASETS
+    EXPECT_EQ(maingo.set_option("growing_augmentFreq", 4.35), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentFreq"), (int)4.35);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentFreq", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentFreq"), 10);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentFreq", -1), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentFreq"), 10);
+#else
+    EXPECT_EQ(maingo.set_option("growing_augmentFreq", 4.35), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentFreq"), 10);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentFreq", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentFreq"), 10);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentFreq", -1), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentFreq"), 10);
+#endif
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, growing_augmentWeight)
+{
+    MAiNGO maingo;
+#ifdef HAVE_GROWING_DATASETS
+    EXPECT_EQ(maingo.set_option("growing_augmentWeight", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentWeight"), 0.5);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentWeight", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentWeight"), 1.0);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentWeight", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentWeight"), 1.0);
+#else
+    EXPECT_EQ(maingo.set_option("growing_augmentWeight", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentWeight"), 1.0);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentWeight", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentWeight"), 1.0);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentWeight", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentWeight"), 1.0);
+#endif
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, growing_augmentPercentage)
+{
+    MAiNGO maingo;
+#ifdef HAVE_GROWING_DATASETS
+    EXPECT_EQ(maingo.set_option("growing_augmentPercentage", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentPercentage"), 0.5);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentPercentage", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentPercentage"), 0.25);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentPercentage", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentPercentage"), 0.25);
+#else
+    EXPECT_EQ(maingo.set_option("growing_augmentPercentage", 0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentPercentage"), 0.25);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentPercentage", -0.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentPercentage"), 0.25);
+
+    EXPECT_EQ(maingo.set_option("growing_augmentPercentage", 1.5), true);
+    EXPECT_EQ(maingo.get_option("growing_augmentPercentage"), 0.25);
+#endif
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOsetAndGetOption, UnkownOption)
+{
+    MAiNGO maingo;
+    EXPECT_EQ(maingo.set_option("bogusOption", 0.5), false);
+    EXPECT_THROW(maingo.get_option("bogusOption"), maingo::MAiNGOException);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOtoOtherLanguage.cpp b/tests/unitTests/testMAiNGOtoOtherLanguage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..658ed874424c48f329261eebf5dbc8fa6fea0c51
--- /dev/null
+++ b/tests/unitTests/testMAiNGOtoOtherLanguage.cpp
@@ -0,0 +1,288 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+#include <filesystem>
+
+
+
+using maingo::MAiNGO;
+using maingo::MAiNGOException;
+
+
+class TestProblemForWriting: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        Var x = optVars[0];
+        Var y = optVars[1];
+        result.objective = pow(x*y,5) + watson_dhvap(x, 100., 0.5, 0.5, 100., 2500.);
+        result.ineq.push_back(pow(x,3) - y + 0.5, "constraintName");
+        result.ineq.push_back(0.5, "constraintName");
+        result.ineqRelaxationOnly.push_back(pow(x,3) - y + 0.5, "constraintName");
+        result.ineqRelaxationOnly.push_back(0.5, "constraintName");
+        result.ineqSquash.push_back(pow(x,3) - y + 0.5, "constraintName");
+        result.ineqSquash.push_back(0.5, "constraintName");
+        result.eq.push_back(pow(x,3) - y + 0.5, "constraintName");
+        result.eq.push_back(0.5, "constraintName");
+        result.eqRelaxationOnly.push_back(pow(x,3) - y + 0.5, "constraintName");
+        result.eqRelaxationOnly.push_back(0.5, "constraintName");
+        result.output.push_back(maingo::OutputVariable(0.5, "outputName"));
+        result.output.push_back(maingo::OutputVariable(x - 0.5, "outputName"));
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "123!?_"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "LOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUM"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "LOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUM"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY, "LOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUM"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "LOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUMLOREMIPSUM"));
+        return variables;
+    }
+
+    std::vector<double> get_initial_point() {
+        return std::vector<double>(10, 0.);
+    }
+};
+
+
+class TestProblemForWritingLongExpressions: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        Var x = optVars[0];
+        Var y = optVars[1];
+        Var obj = 1;
+        for (size_t i = 0; i < 20; ++i) {
+            obj = obj*(obj + y);
+        }
+        result.objective = obj;
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "y"));
+        return variables;
+    }
+};
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, ModelNotSet) {
+    MAiNGO maingo;
+    EXPECT_THROW(maingo.write_model_to_file_in_other_language(maingo::LANG_ALE), MAiNGOException);
+    EXPECT_THROW(maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS), MAiNGOException);
+    EXPECT_THROW(maingo.write_model_to_file_in_other_language(maingo::LANG_NONE), MAiNGOException);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageNone) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWriting>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_OUTSTREAM);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    testing::internal::CaptureStdout();
+    maingo.write_model_to_file_in_other_language(maingo::LANG_NONE, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(testing::internal::GetCapturedStdout(), "\n  WARNING: asked MAiNGO to write model to file, but chosen writing language is NONE. Not writing anything.\n");
+
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), false);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGams) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWriting>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), true);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGamsLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), true);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGamsNLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicNLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), true);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGamsDNLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicDNLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), true);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGamsMINLP) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicMINLP>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), true);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGamsNoFileName) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWriting>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS);
+    EXPECT_EQ(std::filesystem::exists("MAiNGO_written_model.gms"), true);
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGamsLongExpressions) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWritingLongExpressions>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_GAMS, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), true);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageGamsInSolve) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWriting>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("modelWritingLanguage", maingo::LANG_GAMS);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+
+    maingo.solve();
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+
+    EXPECT_EQ(std::filesystem::exists("MAiNGO_written_model.gms"), true);
+    std::filesystem::remove("MAiNGO_written_model.gms", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageAle) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWriting>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_ALE, "tmpTestFileForWritingToOtherLanguage.txt");
+    EXPECT_EQ(std::filesystem::exists("tmpTestFileForWritingToOtherLanguage.txt"), true);
+    std::filesystem::remove("tmpTestFileForWritingToOtherLanguage.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageAleNoFileName) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWriting>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_written_model.txt", errorCode);
+
+    maingo.write_model_to_file_in_other_language(maingo::LANG_ALE);
+    EXPECT_EQ(std::filesystem::exists("MAiNGO_written_model.txt"), true);
+    std::filesystem::remove("MAiNGO_written_model.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOtoOtherLanguage, LanguageAleInSolve) {
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<TestProblemForWriting>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("modelWritingLanguage", maingo::LANG_ALE);
+
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_written_model.txt", errorCode);
+
+    maingo.solve();
+    EXPECT_EQ(maingo.get_status(), maingo::INFEASIBLE);
+
+    EXPECT_EQ(std::filesystem::exists("MAiNGO_written_model.txt"), true);
+    std::filesystem::remove("MAiNGO_written_model.txt", errorCode);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testMAiNGOwritingFunctions.cpp b/tests/unitTests/testMAiNGOwritingFunctions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f123d31a86dc6540e3ea3e0e0dabe64d3b098cce
--- /dev/null
+++ b/tests/unitTests/testMAiNGOwritingFunctions.cpp
@@ -0,0 +1,218 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "MAiNGO.h"
+#include "MAiNGOException.h"
+
+#include "utilities/testProblems.h"
+
+#include <gtest/gtest.h>
+
+#include <filesystem>
+
+
+
+using maingo::MAiNGO;
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOwritingFunctions, WriteLogFile) {
+    std::error_code errorCode;
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_FILE);
+    maingo.set_option("writeResultFile", false);
+    maingo.set_option("writeCsv", false);
+    maingo.set_option("writeJson", false);
+    maingo.set_log_file_name("tmpLogFileForTesting.log");
+    maingo.solve();
+
+    EXPECT_EQ(true, std::filesystem::exists("tmpLogFileForTesting.log"));
+    std::filesystem::remove("tmpLogFileForTesting.log", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOwritingFunctions, WriteResultFile) {
+    std::error_code errorCode;
+    std::filesystem::remove("tmpResultFileForTesting.txt", errorCode);
+
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("writeResultFile", true);
+    maingo.set_option("writeCsv", false);
+    maingo.set_option("writeJson", false);
+    maingo.set_result_file_name("tmpResultFileForTesting.txt");
+    maingo.solve();
+
+    EXPECT_EQ(true, std::filesystem::exists("tmpResultFileForTesting.txt"));
+    std::filesystem::remove("tmpResultFileForTesting.txt", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOwritingFunctions, WriteCsvFiles) {
+    std::error_code errorCode;
+    std::filesystem::remove("tmpCsvIterationsFileForTesting.csv", errorCode);
+    std::filesystem::remove("tmpCsvSolutionFileForTesting.csv", errorCode);
+
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("writeResultFile", false);
+    maingo.set_option("writeCsv", true);
+    maingo.set_option("writeJson", false);
+    maingo.set_option("PRE_printEveryLocalSearch", true);
+    maingo.set_iterations_csv_file_name("tmpCsvIterationsFileForTesting.csv");
+    maingo.set_solution_and_statistics_csv_file_name("tmpCsvSolutionFileForTesting.csv");
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvIterationsFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvIterationsFileForTesting.csv", errorCode);
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvSolutionFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvSolutionFileForTesting.csv", errorCode);
+
+    maingo.set_option("PRE_pureMultistart", true);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvIterationsFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvIterationsFileForTesting.csv", errorCode);
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvSolutionFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvSolutionFileForTesting.csv", errorCode);
+
+    maingo.set_option("PRE_pureMultistart", false);
+    model = std::make_shared<BasicLP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvIterationsFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvIterationsFileForTesting.csv", errorCode);
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvSolutionFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvSolutionFileForTesting.csv", errorCode);
+
+    model = std::make_shared<BasicNLP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvIterationsFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvIterationsFileForTesting.csv", errorCode);
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvSolutionFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvSolutionFileForTesting.csv", errorCode);
+
+    model = std::make_shared<BasicDNLP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvIterationsFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvIterationsFileForTesting.csv", errorCode);
+    EXPECT_EQ(true, std::filesystem::exists("tmpCsvSolutionFileForTesting.csv"));
+    std::filesystem::remove("tmpCsvSolutionFileForTesting.csv", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOwritingFunctions, WriteJsonFile) {
+    std::error_code errorCode;
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicModel1>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("writeResultFile", false);
+    maingo.set_option("writeCsv", false);
+    maingo.set_option("writeJson", true);
+    maingo.set_json_file_name("tmpJsonFileForTesting.json");
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<BasicLP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+#ifdef HAVE_CPLEX
+    model = std::make_shared<BasicQP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<BasicMIP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<BasicMIQP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+#endif
+
+    model = std::make_shared<BasicNLP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<BasicDNLP>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<BasicDNLP>();
+    maingo.set_model(model);
+    maingo.set_option("BAB_maxIterations", 0);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<BasicDNLP>();
+    maingo.set_model(model);
+    maingo.set_option("targetUpperBound", 10);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<BasicDNLP>();
+    maingo.set_model(model);
+    maingo.set_option("PRE_maxLocalSearches", 0);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+
+    model = std::make_shared<ProblemInfeasibleBounds>();
+    maingo.set_model(model);
+    maingo.solve();
+    EXPECT_EQ(true, std::filesystem::exists("tmpJsonFileForTesting.json"));
+    std::filesystem::remove("tmpJsonFileForTesting.json", errorCode);
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestMAiNGOwritingFunctions, WriteEpsilonConstraintResult) {
+    std::error_code errorCode;
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+
+    std::shared_ptr<maingo::MAiNGOmodel> model = std::make_shared<BasicBiobjectiveModel>();
+    MAiNGO maingo(model);
+    maingo.set_option("loggingDestination", maingo::LOGGING_NONE);
+    maingo.set_option("writeResultFile", false);
+    maingo.set_option("writeCsv", false);
+    maingo.set_option("writeJson", false);
+    maingo.set_option("EC_nPoints", 2);
+    maingo.solve_epsilon_constraint();
+
+    EXPECT_EQ(true, std::filesystem::exists("MAiNGO_epsilon_constraint_objective_values.csv"));
+    std::filesystem::remove("MAiNGO_epsilon_constraint_objective_values.csv", errorCode);
+}
\ No newline at end of file
diff --git a/tests/unitTests/testOutputVariable.cpp b/tests/unitTests/testOutputVariable.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9cf2b2be516f596af497e4824e58b46487009e5
--- /dev/null
+++ b/tests/unitTests/testOutputVariable.cpp
@@ -0,0 +1,69 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "outputVariable.h"
+
+#include <gtest/gtest.h>
+
+
+using maingo::OutputVariable;
+
+
+///////////////////////////////////////////////////
+TEST(TestOutputVariable, Construct)
+{
+    OutputVariable empytVar;
+    EXPECT_EQ(empytVar.value, mc::FFVar());
+    EXPECT_EQ(empytVar.description, "");
+
+    mc::FFVar ffVar = 42;
+    OutputVariable var1(ffVar, "the answer");
+    EXPECT_EQ(var1.value, ffVar);
+    EXPECT_EQ(var1.description, "the answer");
+
+    OutputVariable var2("the answer", ffVar);
+    EXPECT_EQ(var2.value, ffVar);
+    EXPECT_EQ(var2.description, "the answer");
+
+    std::tuple<mc::FFVar, std::string> myTuple1(ffVar, "the answer");
+    OutputVariable var3(myTuple1);
+    EXPECT_EQ(var3.value, ffVar);
+    EXPECT_EQ(var3.description, "the answer");
+
+    std::tuple<std::string, mc::FFVar> myTuple2("the answer", ffVar);
+    OutputVariable var4(myTuple2);
+    EXPECT_EQ(var4.value, ffVar);
+    EXPECT_EQ(var4.description, "the answer");
+}
+
+
+///////////////////////////////////////////////////
+TEST(TestOutputVariable, Copy)
+{
+    mc::FFVar ffVar = 42;
+    OutputVariable var1(ffVar, "the answer");
+    EXPECT_EQ(var1.value, ffVar);
+    EXPECT_EQ(var1.description, "the answer");
+
+    OutputVariable var2(var1);
+    EXPECT_EQ(var2.value, ffVar);
+    EXPECT_EQ(var2.description, "the answer");
+
+    var1.value = ffVar + 1.5;
+    OutputVariable var3(var1);
+    EXPECT_EQ(var3.value, ffVar + 1.5);
+    EXPECT_EQ(var3.description, "the answer");
+
+    OutputVariable var4;
+    var4 = var2;
+    EXPECT_EQ(var4.value, ffVar);
+    EXPECT_EQ(var4.description, "the answer");
+}
\ No newline at end of file
diff --git a/tests/unitTests/utilities/testProblems.h b/tests/unitTests/utilities/testProblems.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ffc985d8325bc32e39ee3b79cca09e84302fe8e
--- /dev/null
+++ b/tests/unitTests/utilities/testProblems.h
@@ -0,0 +1,347 @@
+/**********************************************************************************
+ * Copyright (c) 2021-2024 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#pragma once
+
+#include "MAiNGOmodel.h"
+#include "MAiNGOmodelEpsCon.h"
+
+
+using Var = mc::FFVar;
+
+
+class BasicModel1: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = optVars[0]*optVars[1];
+
+        result.ineq.push_back(exp(optVars[0])-1.);
+        result.ineqRelaxationOnly.push_back(optVars[0]);
+        result.eq.push_back(optVars[0]);
+        result.eqRelaxationOnly.push_back(optVars[0]);
+        result.ineqSquash.push_back(optVars[0]);
+
+        result.ineq.push_back(-0.5);
+        result.ineqRelaxationOnly.push_back(-0.5);
+        result.eq.push_back(0.0);
+        result.eqRelaxationOnly.push_back(0.0);
+        result.ineqSquash.push_back(-0.5);
+
+        result.output.push_back(maingo::OutputVariable(optVars[0] + 41.5, "the answer"));
+        result.output.push_back(maingo::OutputVariable(mc::FFVar(42.0), "still the answer"));
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "y"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY, "z1"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "z2"));
+        return variables;
+    }
+
+  private:
+};
+
+class BasicModel2: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[0],3);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "y"));
+        return variables;
+    }
+
+  private:
+};
+
+
+class BasicBiobjectiveModel: public maingo::MAiNGOmodelEpsCon {
+  public:
+    BasicBiobjectiveModel(){}
+
+    maingo::EvaluationContainer evaluate_user_model(const std::vector<Var> &optVars) {
+        Var x = optVars.at(0);
+        Var y = optVars.at(1);
+        Var A1 = 0.5 * sin(1) - 2 * cos(1) + sin(2) - 1.5 * cos(2);
+        Var A2 = 1.5 * sin(1) - cos(1) + 2 * sin(2) - 0.5 * cos(2);
+        Var B1 = 0.5 * sin(x) - 2 * cos(x) + sin(y) - 1.5 * cos(y);
+        Var B2 = 1.5 * sin(x) - cos(x) + 2 * sin(y) - 0.5 * cos(y);
+        maingo::EvaluationContainer result;
+        result.objective.push_back(1 + sqr(A1 - B1) + pow(A2 - B2, 2));
+        result.objective.push_back(sqr(x + 3) + sqr(y + 1));
+        return result;
+    }
+
+    std::vector<double> get_initial_point() {
+        return {0., 0.};
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable( maingo::Bounds(-3.14, 3.14)));
+        variables.push_back(maingo::OptimizationVariable( maingo::Bounds(-3.14, 3.14)));    
+        return variables;
+    }
+};
+
+
+class MultiobjectiveModelOneObjective: public maingo::MAiNGOmodelEpsCon {
+  public:
+    maingo::EvaluationContainer evaluate_user_model(const std::vector<Var> &optVars) {
+        Var x = optVars.at(0);
+        maingo::EvaluationContainer result;
+        result.objective.push_back(x);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable( maingo::Bounds(-3.14, 3.14))); 
+        return variables;
+    }
+};
+
+
+class BasicLP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = optVars[0];
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "y"));
+        return variables;
+    }
+};
+
+
+class InfeasibleLP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = optVars[0];
+        result.ineq.push_back(2 - optVars[0]);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        return variables;
+    }
+};
+
+
+class BasicQP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = sqr(optVars[0]);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        return variables;
+    }
+};
+
+
+class BasicMIP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = optVars[0];
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "x"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "y"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY, "z"));
+        return variables;
+    }
+};
+
+
+class BasicMIQP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = sqr(optVars[0]);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "x"));
+        return variables;
+    }
+};
+
+
+class BasicNLP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[0],3);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        return variables;
+    }
+};
+
+
+class BasicMINLP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[0],3);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "x"));
+        return variables;
+    }
+};
+
+
+class BasicDNLP: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = fabs(pow(optVars[0],3));
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "x"));
+        return variables;
+    }
+};
+
+
+class BasicNLPcustomInitialPoint: public maingo::MAiNGOmodel {
+  public:
+    BasicNLPcustomInitialPoint(const std::vector<double> initialPoint): _initialPoint(initialPoint) {}
+
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[3],3);
+        result.ineq.push_back(optVars[0] - 0.5, "ineq 1");
+        result.ineq.push_back(optVars[2] - 1.5);
+        result.ineq.push_back(-0.5);
+        result.ineqRelaxationOnly.push_back(-0.5);
+        result.ineqSquash.push_back(-0.5);
+        result.eq.push_back(optVars[0] - 0.5, "eq 1");
+        result.eq.push_back(optVars[1] - 1);
+        result.eq.push_back(1e-10);
+        result.eqRelaxationOnly.push_back(1e-10);
+        result.output.push_back(maingo::OutputVariable(optVars[0] - 1.5, "out1"));
+        result.output.push_back(maingo::OutputVariable(optVars[0] - 3.5, "out2"));
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS, "c1"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY, "b1"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER, "i1"));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_CONTINUOUS));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_INTEGER));
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(0, 1), maingo::VT_BINARY));
+        return variables;
+    }
+
+    std::vector<double> get_initial_point() {
+        return _initialPoint;
+    }
+  private:
+    std::vector<double> _initialPoint = {};
+};
+
+
+class ProblemInfeasibleBounds: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[0],3);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(2, 1), maingo::VT_CONTINUOUS, "c1"));
+        return variables;
+    }
+};
+
+
+class ProblemConstantConstraintsInfeasible: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.objective = pow(optVars[0],3);
+        result.ineq.push_back(0.5);
+        result.ineqRelaxationOnly.push_back(1.5);
+        result.ineqSquash.push_back(2.5);
+        result.eq.push_back(0.5);
+        result.eqRelaxationOnly.push_back(1.5);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(1, 2), maingo::VT_CONTINUOUS, "c1"));
+        return variables;
+    }
+};
+
+
+class FeasibilityProblem: public maingo::MAiNGOmodel {
+  public:
+    maingo::EvaluationContainer evaluate(const std::vector<Var> &optVars) {
+        maingo::EvaluationContainer result;
+        result.ineq.push_back(pow(optVars[0],3) - 1.5);
+        return result;
+    }
+
+    std::vector<maingo::OptimizationVariable> get_variables() {
+        std::vector<maingo::OptimizationVariable> variables;
+        variables.push_back(maingo::OptimizationVariable(maingo::Bounds(1, 2), maingo::VT_CONTINUOUS, "c1"));
+        return variables;
+    }
+};
\ No newline at end of file