GithubHelp home page GithubHelp logo

reaktoro / reaktoro Goto Github PK

View Code? Open in Web Editor NEW
148.0 12.0 53.0 65.06 MB

a unified framework for modeling chemically reactive systems

Home Page: https://reaktoro.org

License: GNU Lesser General Public License v2.1

CMake 0.87% C++ 89.44% Python 9.62% Shell 0.05% Rich Text Format 0.02%
chemical-equilibrium chemical-kinetics reactive-transport chemical-reactions geochemical geochemical-modeling

reaktoro's Introduction

Introduction

Reaktoro is a unified framework for modeling chemically reactive systems.

Below are some features and modeling capabilities of Reaktoro:

  • support to several thermochemical databases;
    • PHREEQC
    • SUPCRT
    • SUPCRTBL
    • NASA
    • ThermoFun
  • support to chemical equilibrium and kinetics calculations with general constraints;
  • efficient numerical algorithms implemented using modern programming techniques;
  • the chemical systems can contain any number of phases;
  • no limitations on the number of chemical species in each phase;
  • use of automatic differentiation for computation of derivatives with respect to virtually any variable or parameter.

For more information on how to install and use Reaktoro, you should go to Reaktoro's website.

This README file is intentionally kept succinct in preference to the website's content.

License

LGPL v2.1

Copyright © 2014-2024 Allan Leal

Reaktoro is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

Reaktoro is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

reaktoro's People

Contributors

alexandrebbruno avatar allanleal avatar armandoeng avatar cdeil avatar cskv avatar dimitrikulik avatar gdmiron avatar hendriko373 avatar hfcpeixoto avatar mtsveta avatar nicoddemus avatar pwhuang avatar rafaeljalves avatar roliveira avatar tadeu avatar tehrengruber avatar volpatto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reaktoro's Issues

Reaktoro usage can be even simpler with reaktoro.easy Python module

Motivation

Currently, the user needs to be know a few to many Reaktoro components to perform any calculation. For example, the user needs to understand how to create and operate objects of classes ChemicalEditor, ChemicalSystem, ChemicalState, EquilibriumProblem, and others to perform even the simplest calculations.

This proposal aims to simplify Reaktoro's usage as suggested in the self-explanatory examples below.

Examples

Equilibrium calculation

Current and more advanced approach

from reaktoro import *

editor = ChemicalEditor()
editor.addAqueousPhase('H2O NaCl CO2')
editor.addGaseousPhase(['H2O(g)', 'CO2(g)'])

system = ChemicalSystem(editor)

problem = EquilibriumProblem(system)
problem.setTemperature(100, 'celsius')
problem.setPressure(300, 'bar')

problem.add('H2O', 1, 'kg')
problem.add('NaCl', 1, 'mol')
problem.add('CO2', 1, 'mol')

state = equilibrate(problem)
state.output('state.csv')

Simplified approach

from reaktoro.easy import *

equilibrium.temperature(100, 'celsius')
equilibrium.pressure(300, 'bar')

equilibrium.add('H2O', 1, 'kg')
equilibrium.add('NaCl', 1, 'mol')
equilibrium.add('CO2', 1, 'mol')

equilibrium.solve()
equilibrium.output('state.csv')

Equilibrium path calculation

Simplified approach

from reaktoro.easy import *

equilibrium.temperature(100, 'celsius')
equilibrium.pressure(300, 'bar')

equilibrium.add('H2O', 1, 'kg')
equilibrium.add('NaCl', 1, 'mol')

state1 = equilibrium.solve()

equilibrium.add('CO2', 1, 'mol')

state2 = equilibrium.solve()

state1.output('state1.csv')
state2.output('state2.csv')

equilibriumpath.initialstate(state1)
equilibriumpath.finalstate(state2)
equilibriumpath.collect.temperature()
equilibriumpath.collect.elementAmount('C')
equilibriumpath.collect.pH()
equilibriumpath.solve()
equilibriumpath.output('states.csv')

Improve external dependency management of Reaktoro

This is a proposal to use a C++ dependency manager to simplify the installation of Reaktoro's external dependencies.

Currently, the external dependencies are embedded into the project (some libraries are zipped under thirdparty directory, others are available directly, such as Eigen, header only, copied directly to the source directory). CMake command ExternalProject_Add is then used to install each dependency.

By using a C++ dependency manager, these external projects need to be build and installed only once per machine, instead of every time Reaktoro is built from scratch.

Checking the available options (conan, hunter, vcpkg, etc), I found conan to be quite interesting, easy to use, and perhaps the most mature C++ dependency manager.

Any thoughts? Any other option to consider?

Convergence problem on GaseousPhase

Investigate the reason why Reaktoro's convergence is related with the order that we add the species on gaseous phase.

a system which the gaseous phase is added as:

ChemicalEditor editor(db);
editor.addAqueousPhaseWithElements("H O C S");
editor.addGaseousPhase({ "H2O(g)" , "CO2(g)",   "H2S(g)"  });

ChemicalSystem system(editor);

do not converge

a system which the gaseous phase is added as:

ChemicalEditor editor(db);
editor.addAqueousPhaseWithElements("H O C S");
editor.addGaseousPhase({"CO2(g)",  "H2O(g)" ,  "H2S(g)"  });

ChemicalSystem system(editor);

converge

Check the "demo-investigate-gaseous-initialization.cpp" on https://github.com/ESSS/reaktoro/tree/fb-RES-127-investigate-gaseous-phase-initialization to see this behavior.

Remove those methods in ChemicalEditor with name addSomePhaseWithElementsOf, but keep addSomePhaseWithElements

This is a proposal to deprecate the following methods in class ChemicalEditor:

addAqueousPhaseWithElementsOf
addGaseousPhaseWithElementsOf
addMineralPhaseWithElementsOf

Reason: They are unnecessarily more complicated than the alternatives:

addAqueousPhaseWithElements
addGaseousPhaseWithElements
addMineralPhaseWithElements

Compare the following two equivalent examples:

editor = ChemicalEditor()
editor.addAqueousPhaseWithElementsOf('H2O NaCl CaCl2 MgCl2 CO2')

and

editor = ChemicalEditor()
editor.addAqueousPhaseWithElements('H O Na Cl Ca Mg C')

The latter is shorter and more intuitive (we use element names, instead of chemical formulas of substances, which can also be confused with creating a phase with only those substances).

Default constructor of ChemicalEditor should be deleted

In many Reaktoro demos, an object of ChemicalEditor is instantiated using a default constructor:

editor = ChemicalEditor()

This is equivalent to:

db = Database('supcrt98.xml')
editor = ChemicalEditor(db)

The former form saves a line of code, and skip the process of creating a Database object, but results in a more obscure usage. I think now a Database object should always be provided when creating a ChemicalEditor object for a more explicit dependency.

For now, we should deprecate it instead of deleting (which could happen later on).

Let me know @tadeu if this makes sense from your side.

Using different database than supcrt98.xml supcrt07.xml supcrt98-organics.xml supcrt07-organics.xml

Hi,

I want to run an equilibrium problem using the database phreeqc.dat. But when I wrote:

db = Database('phreeqc.dat')
the following error appeared:
RuntimeError:


*** Error: Could not initialize the Database instance with given database name phreeqc.dat.
*** Reason: This name either points to a non-existent database file, or it is not one of the built-in database files in Reaktoro. The built-in databases are: supcrt98.xml supcrt07.xml supcrt98-organics.xml supcrt07-organics.xml .
*** Location: This error was encountered in :445.


How can I fix this?
Regards

Reaktoro's workflow

Hi @allanleal,

Since Reaktoro is growing, I think it is a great opportunity to start thinking about the workflow that could be used inside the project. After we came into an agreement about that topic, I could create an official file and add to the project.

What do you think about the idea of using a Fork & Pull Request workflow? After we decided to work in a new Feature or fix a bug, we could create a new branch from our master fork, add all the code in that branch and, once we finish, make a PR to the reaktoro's main branch.

Doing that, we will only have one branch inside the repo and the releases could me done by the flag system offer by github.

It is a simpler version of gitflow, because won't have any developer, but I think that could work fine.

[]'s

EquilibriumSolver::solve fails with an EquilibriumProblem that has inert elements

When do you have an inert element on partition, the solver complains:

E       RuntimeError: 
E       ***************************************************************************************************************************************************************
E       *** Error: Cannot proceed with method EquilibriumSolver::solve.
E       *** Reason: The dimension of the given vector of molar amounts of the elements does not match the number of elements in the equilibrium partition.
E       *** Location:  This error was encountered in Reaktoro/Equilibrium/EquilibriumSolver.cpp:450.
E       ***************************************************************************************************************************************************************

Test to get that error on python, using the tests on EquilibriumSolver-test:

    editor = ChemicalEditor()
    editor.addAqueousPhase("H2O(l) H+ OH- HCO3- CO2(aq) CO3--".split())
    editor.addGaseousPhase("H2O(g) CO2(g) Ar(g)".split())
    editor.addMineralPhase("Graphite")
    chemical_system_adding_argon = ChemicalSystem(editor)
    partition = Partition(chemical_system_adding_argon)
    partition.setInertPhases(['Gaseous'])
    problem = _create_equilibrium_problem(partition)
    state = _create_chemical_state(chemical_system_adding_argon)

    # Compute equilibrium state; the amounts of CO2(g) and H2O(g) should remain the same
    solver = EquilibriumSolver(chemical_system_adding_argon)
    solver.setPartition(problem.partition())
    solver.solve(state, problem)

I don't know if EquilibriumProblem should return a elementAmounts with the corrected size, or if that is something the EquilibriumSolver should handle.

Considering reagent flow during calculations

Does Reaktoro support reagent flow during calculations to allow geochemical modelling in a Pore Network Model?

It should be possible to simulate reaction at each individual pore for a given period of time as a 'static' process and after this time interval change concentrations at pores based on flow. However, it seems likely that the flow itself interferes considerably with reactions velocity, in which case it's necessary to consider flow during calculations.

Missing Tutorial: How to use Reaktoro with Visual Studio Code

Visual Studio Code (vscode) is a popular editor with very nice integration with Python and environments. This issue is document work to be done in terms of writing tutorials on how to use Reaktoro with vscode.

Topics that should be considered:

  1. How to select a conda environment using Python: Select Interpreter (after clicking Ctrl+Shift+P)
  2. How to run the python script (Python: Run Python File in Terminal).
  3. How to open the output files.

reaktoro in MacOSX

I've tries everything but reaktoro does not work at all in Macos. help please?

reaktoro activated, but still show "ModuleNotFoundError: No module named 'reaktoro' "

Hi,
after running "Conda env list", Ican clearly see Reaktoro is installed.

C:\Users\Yue Liu>conda env list

conda environments:

base * C:\Miniconda
reaktoro C:\Miniconda\envs\reaktoro

I can activate it as well bu typing "conda activate reaktoro",

However, I cannot print the path, it shows error exactly like what we see on reaktoro.org.

Traceback (most recent call last):
File "", line 1, in
ModuleNotFoundError: No module named 'reaktoro'

I tried to open the reaktoro environment using pycharm, and running the example of solubility of CO2, it tells that no module named reaktoro as well. and the second error "database is not defined"

Does anyone can tell me what should do? I really appreciate your help.

Problem: installation using Cmake.

I am facing a dead end in this part during the installation (section 2.2.4).
A reaktoro environment has been activated and I want to install the package with Cmake. Is it because I'm using conda (therefore, the path should be manually specified, as in section 2.2.5?)
Refer to this prompt..

(reaktoro) C:\reaktoro>cmake -P install
-- Using 2 parallel jobs for the compilation. This system permits a total of 4 parallel jobs.
-- To change the default number of parallel jobs, use 'cmake -DJOBS=<number> -P <script-name>'.
-- The CXX compiler identification is unknown
CMake Error at CMakeLists.txt:11 (project):
  The CMAKE_CXX_COMPILER:

    cl

  is not a full path and was not found in the PATH.

  To use the NMake generator with Visual C++, cmake must be run from a shell
  that can use the compiler cl from the command line.  This environment is
  unable to invoke the cl compiler.  To fix this problem, run cmake from the
  Visual Studio Command Prompt (vcvarsall.bat).

  Tell CMake where to find the compiler by setting either the environment
  variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
  to the compiler, or to the compiler name if it is in the PATH.


-- Configuring incomplete, errors occurred!
See also "C:/reaktoro/build/CMakeFiles/CMakeOutput.log".
See also "C:/reaktoro/build/CMakeFiles/CMakeError.log".
The system cannot find the file specified
CMake Error: Generator: execution of make failed. Make command was: nmake /nologo install

====================================================================================================
Summary
====================================================================================================
The number of parallel jobs used were: 2
The external dependencies were built and installed in:

The library was built in:
    C:/reaktoro/build
The library was installed in:
    C:/reaktoro/build/install
----------------------------------------------------------------------------------------------------
How do I change the default build and install paths?
----------------------------------------------------------------------------------------------------
Change the default build path to an absolute path <build-dir> by executing:
    cmake -DBUILD_PATH=<build-dir> -P install
Change the default install path to an absolute path <install-dir> by executing:
    cmake -DPREFIX=<install-dir> -P install
Linux and Mac users might want to install in a system directory, for example:
    cmake -DPREFIX=/usr/local -P install
----------------------------------------------------------------------------------------------------
*** The above summary assumes a successfull build/installation for all components ***
====================================================================================================

Uninstall script for Reaktoro

For people wanting to use a scientific software uninstall is the first solution to a failed installation on their system.
However as Reaktoro is not packaged and install/uninstall is not as straightforward as simply typing:

  • apt install ... and apt remove ... ,
  • brew install ... and brew uninstall ...,
  • etc.

Should an uninstall script come with the whole directory, that would be helpful.
The current workaround proposed is by using the install_manifest.txt file coupled to a bash script called uninstall.sh:

#! /usr/bin/env/

for f in $(cat install_manifest.txt):
do
    rm -r $f
done

and then, in reaktoro/build/ folder :

chmod 754 uninstall.sh
./uninstall.sh

and finally by running, in the folder where reaktoro has been cloned :

sudo rm -r reaktoro/

I do not know however, if this is a viable solution.
UPDATE -> This doesn't seem to uninstall any python binaries or libraries.
Thans for your attention !

Better method to search index in vectors using names

If you have to find and index by name on reaktoro, it make a loop and compares each name to find it. Maybe it could implement a hash table that stores the names and the index, so this search is faster, enabling the practical use of functions that receive a name as argument.

Integrate ci with website/docs update

Right now, there is a need to manually run:

cd reaktoro/build
make website
make website-upload

to update reaktoro.org

This should be automated (performed once CI check passes and a merge is done?!).

Alternatively, readthedocs could be used for this, but then we would need to "teach" readthedocs to build the doxygen documentation as well.

Allow a special function to copy between different ChemicalStates

If I have two different ChemicalStates, with different ChemicalSystems (which have different phases and species). But they have some species in common, and I want to copy them.
It could have a special function to allow that copy, which verify all the species that both have, and copy the amounts.

Installing Reaktoro using Conda in python 3.6

I would like to install reaktoro using conda. Currently, a binary distribution is provided in anaconda cloud at https://anaconda.org/conda-forge/reaktoro. This is built for python 3.7.
Installing this on a python 3.6 base automatically upgrades the python base to 3.7.
An unfortunate side effect is that some applications are tied to python 3.6 and can no longer be used. For instance, the current distribution of FEniCS that could be installed via conda requires python 3.6.
It would be great if you could release a reaktoro distribution that works on python 3.6.

Residual values when reusing EquilibriumSolver Class

When you reuse the Equilibrium Solver Class to solve EquilibriumProblem, It looks like it keeps some residual values from last solution, which gives different values.

Below is a script that shows this problem. It has to do a diff on the output results.
If is set the warmstart = False on the EquilibriumSolver options, then that problem doesn't happen.

Removing yaml-cpp dependency

Reaktoro is not using yaml-cpp - this was something experimental in the past, to support thermodynamic databases in YAML format, but the whole thing did not work very well. Even tough a nice format, the parsing was considerably slow compared to xml (parsed using pugixml).

So, yaml-cpp should be removed. Maybe consider it again (or another lib) in the future should YAML be considered again. Maybe just rely on yaml package from python side.

Python support install issue on xUbuntu 18.04

Installation of Reaktoro (on /opt/, user privileges OK) on xUbuntu 18.04 works fine : C++ demos are compiled normally and can be executed with no error.
Issue comes when compiling Reaktoro with python support. Following error is output :

reaktoro_error.log

All required packages found in the installation instructions at reaktoro are installed. pybind11-dev package is additionally installed.
Build procedure is as follows, in /opt/ :

$ git clone https://github.com/reaktoro/reaktoro
$ cd reaktoro && mkdir build && cd build
$ cmake .. -DBUILD_PYTHON=ON
$ sudo make -j3 install

Thanks !

Change repository name from Reaktoro to reaktoro

Guys, about two years ago, this Reaktoro repository was created for some experimental work on CI and for some reason it remained named in title case Reaktoro.

However, in BitBucket it was always named reaktoro, which results in a nicer URL in my opinion:

github.com/reaktoro/reaktoro

This is a proposal to name this and other repositories in this organization with lower case letters.

problem with addAqueousPhaseWithElements('H O Na Cl C')

Hi, I'm new into python and I'm having an issue in using the attribute "addAqueousPhaseWithElements('H O Na Cl C')". I'm receiving the following error message:
AttributeError: 'reaktoro.PyReaktoro.ChemicalEditor' object has no attribute 'addAqueousPhaseWithElements'

So, I wrote the code: dir(editor) and the attribute 'addAqueousPhaseWithElements' is not in editor:

['class',
'delattr',
'dir',
'doc',
'eq',
'format',
'ge',
'getattribute',
'gt',
'hash',
'init',
'init_subclass',
'le',
'lt',
'module',
'ne',
'new',
'reduce',
'reduce_ex',
'repr',
'setattr',
'sizeof',
'str',
'subclasshook',
'addAqueousPhase',
'addGaseousPhase',
'addMineralPhase',
'addMineralReaction',
'addPhase',
'addReaction',
'aqueousPhase',
'createChemicalSystem',
'createReactionSystem',
'gaseousPhase',
'mineralPhases',
'setPressures',
'setTemperatures']

How can I fix this?

Properties shown with ChemicalState output

I think it would be nice to group the species in the standard ChemicalState output by element, and then sort them by abundance (similar to PHREEQC output) - this would make it a lot easier to quickly scan the output.

Also, for me the molalities (mol / kg water) would be a more interesting property to display instead of the mole fractions.

Maybe the properties that are shown by default could be added as some sort of configuration option?

Improvement on boundary conditions of TransportSolver.cpp

At this moment, the class TranspostSolver solves the advection-diffusion with Kurganov-Tadmor a 2nd order method, but approximates derivative at the boundary by half control volume which is a 1st order method. I'm creating this task just to open a discussion on the possibility to improve this and try to consider those boundary with a more precise technique.

Try to use undetermined coefficients

pls, check issue #38

pybind11 installation error

I cloned the repository and tries to install it with cmake .. -DCMAKE_BUILD_TYPE=Release, but I get the following error:

-- Boost version: 1.65.1
-- pybind11 v2.3.dev0
CMake Error at python/CMakeLists.txt:8 (find_package):
  By not providing "Findpybind11.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "pybind11",
  but CMake did not find one.

  Could not find a package configuration file provided by "pybind11" with any
  of the following names:

    pybind11Config.cmake
    pybind11-config.cmake

  Add the installation prefix of "pybind11" to CMAKE_PREFIX_PATH or set
  "pybind11_DIR" to a directory containing one of the above files.  If
  "pybind11" provides a separate development package or SDK, be sure it has
  been installed.


-- Configuring incomplete, errors occurred!
See also "/home/ali/packages/reaktoro/build/CMakeFiles/CMakeOutput.log".

Any help is appreciated.

Simplifying the current need to have different species and phase types

This is a proposal on how to simplify the current (and soon growing) number of classes to represent substances, mixtures, and phases existing in different physical states:

Species classes:

They all inherit from class Species.

Phase classes:

They all inherit from class Phase.

The intent of having different phase classes is to be able to have specific member methods in them for their configuration.
For example, to set Peng-Robinson model as the chemical model of a gaseous phase or Pitzer model for an aqueous phase as shown in the Python examples below:

aqueous_phase = AqueousPhase(aqueous_species)
aqueous_phase.setChemicalModelPitzerHMW()

gaseous_phase = GaseousPhase(gaseous_species)
phase.setChemicalModelPengRobinson();

Note: A chemical model is a model for the computation of properties of a phase and its species that depend on temperature T, pressure P, and species mole fractions x. For example, properties such as the phase molar volume and species activities. A thermodynamic model is also a model for the computation of properties of a phase and its species, but properties that depend on temperature T and pressure P only, such as standard Gibbs energies of species.

With an upcoming introduction of liquid phases (by @alexandrebbruno @ ESSS), so that chemical systems involving oil, gas, saline water, and minerals can be modelled, it becomes necessary to discuss how new classes LiquidSpecies and LiquidPhase are implemented, since they are very similar to GaseousSpecies and GaseousPhase. For example, all the set/get methods related to critical properties of GaseousSpecies are needed by LiquidSpecies, and since cubic equations of state (e.g., Peng-Robinson, Redlich-Kwong, etc.) can be used for both liquid and gaseous (also referred as vapor in the literature) phases, both LiquidPhase and GaseousPhase would be very similar (i.e., they would share the same setChemicalModelXYZ methods).

One possibility would be to have classes FluidSpecies and FluidPhase. Classes LiquidSpecies and GaseousSpecies would then inherit from FluidSpecies, and classes LiquidPhase and GaseousPhase would inherit from FluidPhase. Perhaps a parallel to consider (in the future, if we go down this way) would be to have classes SolidSpecies and SolidPhase and then MineralSpecies and MineralPhase inheriting from them respecitively.

Another drastic simplification approach would be to think about one species type and one phase type working for all possible scenarios. In this way, classes Species and Phase would be the only existing ones. Instead of having specific setChemicalModelXYZ methods in AqueousPhase, GaseousPhase, LiquidPhase, MineralPhase, (and who knows how many more in the future), we could use Phase::setChemicalModel(a_function_object_argument), which expects a function object that implements the specific chemical model (i.e., std::function):

See PhaseChemicalModel.hpp:

/// The signature of the chemical model function that calculates the chemical properties of the species in a phase.
using PhaseChemicalModel = std::function<void(PhaseChemicalModelResult&, double, double, VectorConstRef)>;

Thus, we could have something like this:

aqueous_phase = Phase(aqueous_species)
aqueous_phase.setChemicalModel(aqueousChemicalModelPitzerHMW(aqueous_species))

gaseous_phase = Phase(gaseous_species)
gaseous_phase.setChemicalModel(gaseousChemicalModelPengRobinson(gaseous_species))

system = ChemicalSystem([aqueous_phase, gaseous_phase])

to be continued...

Delete Default Class Constructors which uses ChemicalSystem

Classes which uses ChemicalSystem should be instantiated at least with a ChemicalSystem. So, there is no use for Class constructors with no parameters, deleting them.

At same side, an empty Chemical System can cause problems in the program (for now, it was show that cause crash on operator<< at ChemicalState. It is a good idea to delete his default constructor.

Using Conda to manage the external dependencies of Reaktoro

Let's use conda-forge to manage all dependencies of Reaktoro.

Below is a list of all external libraries we need to compile Reaktoro that are already available in conda-forge.

The other dependencies not yet in conda-forge are:

The later two might make more sense to handle using git submodule as I sometimes change them.

Tests passing CI, but some failing in Linux

The master branch after built and tested (pytest .), produces the log below, which shows some tests are failing (in Linux). All tests pass CI (Travis and AppVeyor)

========================================================= test session starts =========================================================
platform linux -- Python 3.6.7, pytest-4.0.1, py-1.7.0, pluggy-0.8.0
rootdir: /home/allan/codes/reaktoro-main, inifile:
plugins: xdist-1.24.1, timeout-1.3.3, regressions-1.0.5, lazy-fixture-0.4.2, forked-0.2, datadir-1.2.1
collected 124 items                                                                                                                   

tests/test_reaktoro_misc.py x..                                                                                                 [  2%]
tests/regression/test_equilibrium_path.py .                                                                                     [  3%]
tests/regression/test_equilibrium_solver.py ..............................                                                      [ 27%]
tests/regression/test_equilibrium_utils.py ........................................................................             [ 85%]
tests/regression/test_kinetic_solver.py ............                                                                            [ 95%]
tests/regression/test_transport_solver.py FFF...                                                                                [100%]

============================================================== FAILURES ===============================================================
_____________________________________ test_transport_solver_diffusion[diffusion-source rate q=0] ______________________________________

source_parameters = source_parameters(a=0, b=0)
num_regression = <pytest_regressions.num_regression.NumericRegressionFixture object at 0x7fdf2a6d9438>

    @pytest.mark.parametrize(
        "source_parameters",
        [
            pytest.param(source_parameters(0, 0), id="diffusion-source rate q=0"),
            pytest.param(source_parameters(0, 1), id="diffusion-source rate q=1"),
            pytest.param(source_parameters(1, 1), id="diffusion-source rate q=x+1"),
        ],
    )
    def test_transport_solver_diffusion(source_parameters, num_regression):
        """
        A test to check the solution of a advection-diffusion equation with v = 0
        and du/dt = 0
        Eq:
            du/dt + v du/dx = D d²u/dx² + q
    
        The result were compared with the following analytic solution and got
        near results when we increase the number of cells. We decided to compare with
        numerical solve to save some computational time and analytic result, but with
        relative error of 1e-1.
    
        analytic_u = -((a*x**3)/(6*D)) - ((b*x**2)/(2*D)) + ((a*x*xr**2)/(2*D)) + ((b*x*xr)/(D)) + ul
    
        @param source_parameters
            a tuple that has values of a and b coefficient of a source term
            that behaves as q a*x+b
        """
        a = source_parameters.a
        b = source_parameters.b
        D = 0.0002
        v = 0
        ul = 1
        dt = 100
        num_steps = 1000
        num_cells = 10
        xl = 0
        xr = 1.0
    
        mesh = rkt.Mesh(num_cells, xl, xr)
    
        x = mesh.xcells()
        q = a * x + b
    
        transp_solver = rkt.TransportSolver()
    
        transp_solver.setMesh(mesh)
        transp_solver.setVelocity(v)
        transp_solver.setDiffusionCoeff(D)
        transp_solver.setBoundaryValue(ul)
        transp_solver.setTimeStep(dt)
    
        transp_solver.initialize()
    
        numerical_u = np.zeros(num_cells)
        transp_solver.step(numerical_u, q)
    
        for i in range(num_steps):
            transp_solver.step(numerical_u, q)
    
>       num_regression.check({"u": numerical_u})
E       AssertionError: Values are not sufficiently close.
E       To update values, use --force-regen option.
E       
E       u:
E          obtained_u           expected_u                 diff
E       0           0  0.99999999999999956  0.99999999999999956
E       1           0  0.99999999999999944  0.99999999999999944
E       2           0  0.99999999999999878  0.99999999999999878
E       3           0  0.99999999999999845  0.99999999999999845
E       4           0  0.99999999999999822  0.99999999999999822
E       5           0  0.99999999999999789  0.99999999999999789
E       6           0  0.99999999999999789  0.99999999999999789
E       7           0  0.99999999999999789  0.99999999999999789
E       8           0  0.99999999999999778  0.99999999999999778
E       9           0  0.99999999999999778  0.99999999999999778

tests/regression/test_transport_solver.py:69: AssertionError
_____________________________________ test_transport_solver_diffusion[diffusion-source rate q=1] ______________________________________

source_parameters = source_parameters(a=0, b=1)
num_regression = <pytest_regressions.num_regression.NumericRegressionFixture object at 0x7fdf2a641cc0>

    @pytest.mark.parametrize(
        "source_parameters",
        [
            pytest.param(source_parameters(0, 0), id="diffusion-source rate q=0"),
            pytest.param(source_parameters(0, 1), id="diffusion-source rate q=1"),
            pytest.param(source_parameters(1, 1), id="diffusion-source rate q=x+1"),
        ],
    )
    def test_transport_solver_diffusion(source_parameters, num_regression):
        """
        A test to check the solution of a advection-diffusion equation with v = 0
        and du/dt = 0
        Eq:
            du/dt + v du/dx = D d²u/dx² + q
    
        The result were compared with the following analytic solution and got
        near results when we increase the number of cells. We decided to compare with
        numerical solve to save some computational time and analytic result, but with
        relative error of 1e-1.
    
        analytic_u = -((a*x**3)/(6*D)) - ((b*x**2)/(2*D)) + ((a*x*xr**2)/(2*D)) + ((b*x*xr)/(D)) + ul
    
        @param source_parameters
            a tuple that has values of a and b coefficient of a source term
            that behaves as q a*x+b
        """
        a = source_parameters.a
        b = source_parameters.b
        D = 0.0002
        v = 0
        ul = 1
        dt = 100
        num_steps = 1000
        num_cells = 10
        xl = 0
        xr = 1.0
    
        mesh = rkt.Mesh(num_cells, xl, xr)
    
        x = mesh.xcells()
        q = a * x + b
    
        transp_solver = rkt.TransportSolver()
    
        transp_solver.setMesh(mesh)
        transp_solver.setVelocity(v)
        transp_solver.setDiffusionCoeff(D)
        transp_solver.setBoundaryValue(ul)
        transp_solver.setTimeStep(dt)
    
        transp_solver.initialize()
    
        numerical_u = np.zeros(num_cells)
        transp_solver.step(numerical_u, q)
    
        for i in range(num_steps):
            transp_solver.step(numerical_u, q)
    
>       num_regression.check({"u": numerical_u})
E       AssertionError: Values are not sufficiently close.
E       To update values, use --force-regen option.
E       
E       u:
E                        obtained_u              expected_u                     diff
E       0  100100.00000000672298484   242.66666666666645824  99857.33333334005146753
E       1  100100.00000000673753675   692.66666666666594665  99407.33333334006601945
E       2  100100.00000000675208867  1092.66666666666560559  99007.33333334008057136
E       3  100100.00000000675208867  1442.66666666666469609  98657.33333334008057136
E       4  100100.00000000675208867  1742.66666666666401397  98357.33333334009512328
E       5  100100.00000000675208867  1992.66666666666401397  98107.33333334009512328
E       6  100100.00000000675208867  2192.66666666666333185  97907.33333334009512328
E       7  100100.00000000675208867  2342.66666666666287711  97757.33333334009512328
E       8  100100.00000000675208867  2442.66666666666333185  97657.33333334009512328
E       9  100100.00000000675208867  2492.66666666666242236  97607.33333334009512328

tests/regression/test_transport_solver.py:69: AssertionError
____________________________________ test_transport_solver_diffusion[diffusion-source rate q=x+1] _____________________________________

source_parameters = source_parameters(a=1, b=1)
num_regression = <pytest_regressions.num_regression.NumericRegressionFixture object at 0x7fdf2a668470>

    @pytest.mark.parametrize(
        "source_parameters",
        [
            pytest.param(source_parameters(0, 0), id="diffusion-source rate q=0"),
            pytest.param(source_parameters(0, 1), id="diffusion-source rate q=1"),
            pytest.param(source_parameters(1, 1), id="diffusion-source rate q=x+1"),
        ],
    )
    def test_transport_solver_diffusion(source_parameters, num_regression):
        """
        A test to check the solution of a advection-diffusion equation with v = 0
        and du/dt = 0
        Eq:
            du/dt + v du/dx = D d²u/dx² + q
    
        The result were compared with the following analytic solution and got
        near results when we increase the number of cells. We decided to compare with
        numerical solve to save some computational time and analytic result, but with
        relative error of 1e-1.
    
        analytic_u = -((a*x**3)/(6*D)) - ((b*x**2)/(2*D)) + ((a*x*xr**2)/(2*D)) + ((b*x*xr)/(D)) + ul
    
        @param source_parameters
            a tuple that has values of a and b coefficient of a source term
            that behaves as q a*x+b
        """
        a = source_parameters.a
        b = source_parameters.b
        D = 0.0002
        v = 0
        ul = 1
        dt = 100
        num_steps = 1000
        num_cells = 10
        xl = 0
        xr = 1.0
    
        mesh = rkt.Mesh(num_cells, xl, xr)
    
        x = mesh.xcells()
        q = a * x + b
    
        transp_solver = rkt.TransportSolver()
    
        transp_solver.setMesh(mesh)
        transp_solver.setVelocity(v)
        transp_solver.setDiffusionCoeff(D)
        transp_solver.setBoundaryValue(ul)
        transp_solver.setTimeStep(dt)
    
        transp_solver.initialize()
    
        numerical_u = np.zeros(num_cells)
        transp_solver.step(numerical_u, q)
    
        for i in range(num_steps):
            transp_solver.step(numerical_u, q)
    
>       num_regression.check({"u": numerical_u})
E       AssertionError: Values are not sufficiently close.
E       To update values, use --force-regen option.
E       
E       u:
E                        obtained_u              expected_u                      diff
E       0  149943.75000000742147677   367.25000000000017053  149576.50000000742147677
E       1  149966.25000000745058060  1064.75000000000068212  148901.50000000745058060
E       2  150006.25000000745058060  1704.75000000000159162  148301.50000000745058060
E       3  150058.75000000745058060  2282.25000000000136424  147776.50000000745058060
E       4  150118.75000000745058060  2792.25000000000227374  147326.50000000745058060
E       5  150181.25000000747968443  3229.75000000000318323  146951.50000000747968443
E       6  150241.25000000747968443  3589.75000000000409273  146651.50000000747968443
E       7  150293.75000000745058060  3867.25000000000500222  146426.50000000745058060
E       8  150333.75000000745058060  4057.25000000000545697  146276.50000000745058060
E       9  150356.25000000742147677  4154.75000000000545697  146201.50000000742147677

tests/regression/test_transport_solver.py:69: AssertionError
========================================== 3 failed, 120 passed, 1 xfailed in 36.89 seconds ===========================================

The following cmake output shows details of compilers and python version:

-- Using ccache to potentially speed up the build operation.
-- The CXX compiler identification is GNU 7.3.0
-- Check for working CXX compiler: /home/allan/miniconda3/envs/reaktoro/bin/x86_64-conda_cos6-linux-gnu-c++
-- Check for working CXX compiler: /home/allan/miniconda3/envs/reaktoro/bin/x86_64-conda_cos6-linux-gnu-c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conda environment recognized in /home/allan/miniconda3/envs/reaktoro
-- Boost version: 1.67.0
-- Found PythonInterp: /home/allan/miniconda3/envs/reaktoro/bin/python (found version "3.6.7") 
-- Found PythonLibs: /home/allan/miniconda3/envs/reaktoro/lib/libpython3.6m.so
-- Found pybind11 v2.2.4: /home/allan/miniconda3/envs/reaktoro/include/python3.6m;/home/allan/miniconda3/envs/reaktoro/include/python3.6m
-- Configuring done
-- Generating done
-- Build files have been written to: /home/allan/codes/reaktoro-main/build

Flaky behavior while using to solve kinetic problems

Hi guys,

I've just found some interesting behavior while I was using reaktoro to solve some kinetic problems that I think it worth to be mention here to open a discussion about it.

Some of the kinetic tests are given different results depending the number of processors used by the PC.

Here are some of the results that I've obtained:

Primary investigation pointed out that it could be something related to the VCode library, which is used during the integration process at line 214 in ODE.cpp, but I'm not quite sure about it 🤔

What do you guys think about it? Are there anyone who have face anything like that? What you think about the idea of replace VCode by another one? 🤔

more information about the test can be found at https://github.com/alexandrebbruno/Reaktoro/tree/study-kinetic-flaky.

Avoid god tests using pytest and add more test files for other library components

This issue is to remind us of having the pytest files as recommend by @tadeu here.

Something that you might consider now is to break from a single test_chemical_system "god test" into multiple smaller tests, such as test_numSpeciesInPhase, test_formulaMatrix, test_element, test_species, etc. Smaller tests are usually easier to maintain, the problem with big test functions is that a failure in the beginning of the test function would "disable" testing all further assertions, and also that they make it harder to isolate one "check" from another.

Creating a fixture for system here would probably help a lot.

ReaktoroShared install target not exactly implemeted as ReaktoroStatic install target

This is what we have for install target of ReaktoroShared

    install(TARGETS ReaktoroShared
        ARCHIVE
            DESTINATION lib
            COMPONENT libraries
        LIBRARY
            DESTINATION lib
            COMPONENT libraries
        RUNTIME
            DESTINATION bin
            COMPONENT libraries
    )

and this for ReaktoroStatic:

install(TARGETS ReaktoroStatic DESTINATION "lib" COMPONENT libraries)

Shouldn't the first be similar to the second?

Error when trying to calculate equilibrium with just a gaseous phase

I wasn't able to calculate the equilibrium state of systems where just a gaseous phase would be present:

db = Database('supcrt98')
editor = ChemicalEditor(db)
editor.addGaseousPhase('H O')

system = ChemicalSystem(editor)

problem = EquilibriumProblem(system)
problem.setTemperature(150, 'celsius')
problem.setPressure(1,'bar')
problem.add('H2O', 1.0, 'kg')

state = equilibrate(problem)

print(state)

This is the error I got:

RuntimeError: 
****************************************************************************************
*** Error: Could not get a reference to a Phase instance with given index.
*** Reason: The given index 1 is out of bounds.
*** Location:  This error was encountered in :236.
****************************************************************************************

Seems there is no phase present at all... Playing around, sometimes I already got an error at equilibrate(problem), telling me no equilibrium was found - but I couldn't reproduce this one again unfortunately.

I tried finding out more by trying to see what state.properties().phaseAmounts() returns, but wasn't able to get much out of it, as I didn't find much documentation on the ChemicalVector type yet.

It works if an aqueous phase is added using editor.addAqueousPhase('H O') to the problem though, so not sure if this is just a problem with displaying the output or with equilibrium calculations themselves.

Apart from this issue: Would it be possible to add an option to set the pressure to the vapor pressure at the specific temperature/composition when defining a problem? I guess this could be done by a user by running some iterations to find that phase boundary, but having it built in would be convenient I think...
Maybe that's already there, but I didn't find it in the docs yet.
I didn't think this through all the way, but this might require setting the volume to a fixed value (instead of the pressure) in such a problem. Is that possible, or will it ever be?

Generalizing this: How about adding some inverse-solving capabilities? An obvious interesting thing would be finding phase boundaries (such as water-vapor, as described above, but also between minerals etc.).

Another related "gimmick" would be to be able to define a certain pH for an equilibrium problem, which is realized by adding the right amount of an acid or base (such as HCl or NaOH). In PHREEQC, this can be done by defining a custom phase H+ with an equilibrium constant of 0, and then forcing the saturation index of this phase to -pH using HCl, NaOH, or other chemicals. Being able to set saturation indices to a specific value (not only 0) is a useful capabilities in general as well...

Failed conda installation of reaktoro in macOS

conda install -c conda-forge/label/gcc7 reaktoro
Solving environment: failed

PackagesNotFoundError: The following packages are not available from current channels:

  • reaktoro

Current channels:

To search for alternate channels that may provide the conda package you're
looking for, navigate to

https://anaconda.org

and use the search bar at the top of the page.

Formatting of ChemicalState output

The standard printed output of a ChemicalState object is quite useful to quickly check the state of a system, but it would be great if this output would be automatically formatted if printed in a Jupyter Notebook environment.

For example, the output is too wide for the standard Jupyter cells so that the columns are line wrapped, which is hard to read:
image

A nice way would be to have it shown similar to a Panda data frame object, which automatically add a horizontal scroll bar if too wide:
image

Implement class GeochemicalState

Currently, we have class ChemicalState, which stores temperature, pressure, and amounts of species distributed among one or more phases. This class should be general (i.e., applicable to any chemical system). However, it currently has some hard coded geochemical concepts in it (e.g., when printing a ChemicalState object, there is a section for aqueous phase, showing pH, pe, ionic strength, etc). This should be stripped from ChemicalState, otherwise those interested in chemical systems without water/aqueous phase will experience runtime errors when printing a ChemicalState object.

If the application of interest is related to geochemical modeling, then one has to convert a ChemicalState object into a GeochemicalState one:

state = equilibrate(problem)  # type(state) is ChemicalState
state = GeochemicalState(state)  # type(state) is now GeochemicalState

state.output()  # this will now output in a format that (most) geochemists are happy with

To address issue #57, we should also have a member method that converts the state into a dictionary so that it can be nicely printed in a Jupyter notebook using pandas.

Foreseen steps to accomplish this task:

  • implement GeochemicalState class
  • implement a conversion method from a GeochemicalState object to a dictionary
  • implement methods pH, pe, Eh, ionicStrength, alkalinity, saturationIndex, etc.
  • species should be printed in sections of chemical elements
  • species with higher amounts should be higher in the column
  • species with relatively low amounts should be filtered out from the output
  • phases that are not close to saturation with respect to the aqueous phase should be left out (possibly displayed in another section for completeness)

Printing could follow the following suggestion of @martinvoigt (#58):

pH, sometimes also alkalinity
Concentrations of elements and species of interest in the aqueous solution
Saturation states of solids/gases of interest (with respect to the aqueous solution)
How much of a phase reacted, in case this was part of the model
Temperature, pressure, ionic strength, charge balance, masses of phases, etc. - mainly to verify the model ran correctly, if something seems off

BatchEquilibriumSolver: A class for solving multiple equilibrium problems in parallel

This is a proposal for the implementation of a class BatchEquilibriumSolver for solving multiple equilibrium problems in parallel using OpenMP.

Example:

Vector T = { /* vector of temperature values */ };
Vector P = { /* vector of pressure values */ };
Matrix b = { /* "vector" of vectors of element amounts */ };

ChemicalStates states(system, size);
BatchEquilibriumSolver equilibrium(system);
equilibrium.solve(states, T, P, b);

The method BatchEquilibriumSolver::solve computes as many equilibrium problems as there are ChemicalState objects in states and values in T, P, and b. Here, for b, each column corresponds to a vector of element amounts for, say, a node/cell/dof in a mesh/domain.

Why OpenMP? In general, reactive transport and fluid flow simulators already have MPI parallelization support, say, in a domain decomposition context, and this causes Reaktoro to be used in parallel by different processes.

With OpenMP, we'll use CPU threads and in the end have a combination of MPI processes and OpenMP threads.

conda-devenv error when installing reaktoro

Hi @allanleal

Follow your request, This is a new issue following previous installing issues.

I uninstalled conda, reaktoro, cmke, etc, and restarted my desktop (win).

Starting from

  1. conda config --append channels conda-forge
  2. conda install reaktoro
  3. conda install -n base conda-devenv
  4. download reaktoro from github
  5. conda devenv (In the root of the reaktoro directory, execute:)

But, I have encountered a new problem. Please help me check what is the matter. thanks very much.

error.txt

Add automated tests run in CI

@allan, we have have some Python tests that we'll be adding next, but we'd also like to add a step to run the current Reaktoro tests. What is your current "workflow" to run the tests locally? Do you use ctest?

Cleaning up - many old stuff that need to be removed

The root directory of Reaktoro exposes many subdirs that are no longer maintained. Here is a small list of such dirs:

  • unsupported
  • tests/cute
  • tests/doctest
  • tests/Reaktoro-old

I propose this to be cleaned (and other hanging around codes no longer used).

Implement operator== to ChemicalSystem

As one of the most important classes (which holds sensitive information), I think it should have a operator== to not just compare vector sizes, but the content of it, to judge if they are equal.

auto ChemicalSystem::operator==(const ChemicalSystem& other)
{
const auto& impl = this->pimpl;
const auto& other_impl = other.pimpl;
return impl == other_impl || (impl->phases == other_impl ->phases && impl->species== other_impl ->species);
}

Probably it would have to implement an operator== to Phase and Species class as well.

Add a function that accepts a string vector to chemical compounds on ChemicalEditor

At function addAqueousPhase compounds are passed as string and species are passed as string vector.
But, the implementation of these functions receive both string vectors (Imp struct). I think that, instead of using overload functions for different things, we could change names to do different things, and the overload option to the function to add compounds as string or string vector.

For example:
addAqueousPhaseWithCompounds(string)
addAqueousPhaseWithCompounds(vector)
addAqueousPhaseWithSpecies(vector)

In that way, we avoid unnecessary steps in some cases.

Update repository and make it official

Hey @allanleal,

Since I'm a member of the project.
Can I help you with the process of migrate from bitbucket to here?

I suggest that we divide this activity as follow:

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.