LCOV - code coverage report
Current view: top level - src/utils - GeochemicalDatabaseValidator.C (source / functions) Hit Total Coverage
Test: idaholab/moose geochemistry: 419b9d Lines: 172 172 100.0 %
Date: 2025-08-08 20:01:54 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "GeochemicalDatabaseValidator.h"
      11             : 
      12             : #include "Conversion.h"
      13             : #include "MooseUtils.h"
      14             : #include "string"
      15             : 
      16        1014 : GeochemicalDatabaseValidator::GeochemicalDatabaseValidator(const FileName filename,
      17        1014 :                                                            const nlohmann::json & db)
      18        1014 :   : _filename(filename), _root(db)
      19             : {
      20        1014 : }
      21             : 
      22             : void
      23        1014 : GeochemicalDatabaseValidator::validate()
      24             : {
      25             :   // Check that the database has a Header key (required)
      26        1014 :   if (!_root.contains("Header"))
      27           2 :     mooseError("The MOOSE database ", _filename, " does not have a required \"Header\" field");
      28             : 
      29             :   // Check that temperatures are present
      30        1012 :   checkHeaderField("temperatures");
      31             : 
      32             :   // The size of the temperature array is used to check all other arrays, which must
      33             :   // have the same number of elements
      34        1011 :   _temperature_size = _root["Header"]["temperatures"].size();
      35             : 
      36             :   // Now check that the values are all Real
      37        1011 :   checkHeaderArray("temperatures");
      38             : 
      39             :   // Check the pressure values are present and are Reals
      40        1011 :   checkHeaderField("pressures");
      41        1011 :   checkHeaderArray("pressures");
      42             : 
      43             :   // Check activity model coefficients
      44        1011 :   checkHeaderField("activity model");
      45             : 
      46             :   // If the activity model is Debye-Huckel, test the coefficients are also present
      47             :   // and are Reals
      48        1010 :   if (_root["Header"]["activity model"] == "debye-huckel")
      49             :   {
      50        1009 :     checkHeaderField("adh");
      51        1009 :     checkHeaderArray("adh");
      52             : 
      53        1009 :     checkHeaderField("bdh");
      54        1009 :     checkHeaderArray("bdh");
      55             : 
      56        1009 :     checkHeaderField("bdot");
      57        2018 :     checkHeaderArray("bdot");
      58             :   }
      59             : 
      60             :   // Check fugacity model is specified
      61        1010 :   checkHeaderField("fugacity model");
      62             : 
      63             :   // If there are neutral species, check their arrays of coefficients
      64        1010 :   if (_root["Header"].contains("neutral species"))
      65        4032 :     for (auto & ns : _root["Header"]["neutral species"].items())
      66       12619 :       for (auto & coeffs : ns.value().items())
      67             :       {
      68       17178 :         if (coeffs.key() == "note")
      69         805 :           continue;
      70             : 
      71             :         // Check that there are a correct number of values and that they are real numbers
      72        7784 :         auto values = coeffs.value();
      73       15568 :         checkArraySize(values, "Header:neutral species:" + ns.key() + ":" + coeffs.key());
      74       23350 :         checkArrayValues(values, "Header:neutral species:" + ns.key() + ":" + coeffs.key());
      75             :       }
      76             : 
      77             :   // Check the element data
      78       29878 :   for (auto & el : _root["elements"].items())
      79       55724 :     checkElements(el.key());
      80             : 
      81             :   // Check the basis species data
      82       35106 :   for (auto & species : _root["basis species"].items())
      83       66180 :     checkBasisSpecies(species.key());
      84             : 
      85             :   // Check the secondary species data
      86        1008 :   if (_root.contains("secondary species"))
      87      317974 :     for (auto & species : _root["secondary species"].items())
      88      631942 :       checkSecondarySpecies(species.key());
      89             : 
      90             :   // Check the mineral species data
      91        1003 :   if (_root.contains("mineral species"))
      92      357746 :     for (auto & species : _root["mineral species"].items())
      93      711534 :       checkMineralSpecies(species.key());
      94             : 
      95             :   // Check the sorbing mineral species data
      96        1002 :   if (_root.contains("sorbing minerals"))
      97        1735 :     for (auto & species : _root["sorbing minerals"].items())
      98        1778 :       checkSorbingMineralSpecies(species.key());
      99             : 
     100             :   // Check the gas species data
     101        1002 :   if (_root.contains("gas species"))
     102        8434 :     for (auto & species : _root["gas species"].items())
     103       13660 :       checkGasSpecies(species.key());
     104             : 
     105             :   // Check the redox couple data
     106        1002 :   if (_root.contains("redox couples"))
     107       31671 :     for (auto & species : _root["redox couples"].items())
     108       59346 :       checkRedoxSpecies(species.key());
     109             : 
     110             :   // Check the oxide species data
     111        1002 :   if (_root.contains("oxides"))
     112       25047 :     for (auto & species : _root["oxides"].items())
     113       46882 :       checkOxideSpecies(species.key());
     114             : 
     115             :   // Check the surface species data
     116        1002 :   if (_root.contains("surface species"))
     117       12104 :     for (auto & species : _root["surface species"].items())
     118       22516 :       checkSurfaceSpecies(species.key());
     119        1002 : }
     120             : 
     121             : bool
     122    10047776 : GeochemicalDatabaseValidator::isValueReal(const nlohmann::json & value) const
     123             : {
     124             :   if (value.is_number())
     125             :     return true;
     126             :   try
     127             :   {
     128      145949 :     MooseUtils::convert<Real>(value, true);
     129             :   }
     130           4 :   catch (const std::invalid_argument & err)
     131             :   {
     132             :     return false;
     133           4 :   }
     134             : 
     135      145945 :   return true;
     136             : }
     137             : 
     138             : void
     139       12832 : GeochemicalDatabaseValidator::checkArrayValues(const nlohmann::json & array,
     140             :                                                const std::string field) const
     141             : {
     142             :   // Check each value in the array can be successfully converted to a Real
     143      128319 :   for (auto & item : array.items())
     144      102656 :     if (!isValueReal(item.value()))
     145           1 :       mooseError("Array value ",
     146           2 :                  nlohmann::to_string(item.value()),
     147             :                  " in the ",
     148             :                  field,
     149             :                  " field of ",
     150           1 :                  _filename,
     151             :                  " cannot be converted to Real");
     152       12831 : }
     153             : 
     154             : void
     155      710968 : GeochemicalDatabaseValidator::checkArrayValues(const std::string type,
     156             :                                                const std::string species,
     157             :                                                const std::string field) const
     158             : {
     159             :   // Check each value in the array can be successfully converted to a Real
     160     7104212 :   for (auto & item : _root[type][species][field].items())
     161     5682277 :     if (!isValueReal(item.value()))
     162           1 :       mooseError("Array value ",
     163           2 :                  nlohmann::to_string(item.value()),
     164             :                  " in the ",
     165             :                  field,
     166             :                  " field of ",
     167             :                  type,
     168             :                  " ",
     169             :                  species,
     170             :                  " in ",
     171           1 :                  _filename,
     172             :                  " cannot be converted to Real");
     173      710967 : }
     174             : 
     175             : void
     176       12833 : GeochemicalDatabaseValidator::checkArraySize(const nlohmann::json & array,
     177             :                                              const std::string field) const
     178             : {
     179       12833 :   if (array.size() != _temperature_size)
     180           1 :     mooseError("The number of values in the ",
     181             :                field,
     182             :                " field of ",
     183           1 :                _filename,
     184             :                " is not equal to the number of temperature values");
     185       12832 : }
     186             : 
     187             : void
     188      708237 : GeochemicalDatabaseValidator::checkArraySize(const std::string type,
     189             :                                              const std::string species,
     190             :                                              const std::string field) const
     191             : {
     192      708237 :   if (_root[type][species][field].size() != _temperature_size)
     193           1 :     mooseError("The number of values in the ",
     194             :                field,
     195             :                " field of ",
     196             :                type,
     197             :                " ",
     198             :                species,
     199             :                " in ",
     200           1 :                _filename,
     201             :                " is not equal to the number of temperature values");
     202      708236 : }
     203             : 
     204             : void
     205        7071 : GeochemicalDatabaseValidator::checkHeaderField(const std::string field) const
     206             : {
     207        7071 :   if (!_root["Header"].contains(field))
     208           2 :     mooseError(
     209           2 :         "The MOOSE database ", _filename, " does not have a required \"Header:", field, "\" field");
     210        7069 : }
     211             : 
     212             : void
     213        5049 : GeochemicalDatabaseValidator::checkHeaderArray(const std::string field) const
     214             : {
     215             :   // Check that all values are real numbers and of size equal to the temperature
     216        5049 :   checkArraySize(_root["Header"][field], "Header:" + field);
     217        5049 :   checkArrayValues(_root["Header"][field], "Header:" + field);
     218        5049 : }
     219             : 
     220             : void
     221     1967185 : GeochemicalDatabaseValidator::checkSpeciesValue(const std::string type,
     222             :                                                 const std::string species,
     223             :                                                 const std::string field) const
     224             : {
     225     1967185 :   if (!_root[type].contains(species) || !_root[type][species].contains(field))
     226           1 :     mooseError("The ", type, " ", species, " in ", _filename, " does not have a ", field);
     227             : 
     228             :   // The field value should be a real number
     229     1967184 :   if (!isValueReal(_root[type][species][field]))
     230           1 :     mooseError(field,
     231             :                " value ",
     232           1 :                nlohmann::to_string(_root[type][species][field]),
     233             :                " of the ",
     234             :                type,
     235             :                " ",
     236             :                species,
     237             :                " in ",
     238           1 :                _filename,
     239             :                " cannot be converted to Real");
     240     1967183 : }
     241             : 
     242             : void
     243      776917 : GeochemicalDatabaseValidator::checkSpeciesWeightValue(const std::string type,
     244             :                                                       const std::string species,
     245             :                                                       const std::string field) const
     246             : {
     247      776917 :   if (!_root[type].contains(species) || !_root[type][species].contains(field))
     248           1 :     mooseError("The ", type, " ", species, " in ", _filename, " does not have a ", field);
     249             : 
     250             :   // Each weight value for each constituent should be a real number
     251     3849490 :   for (auto & item : _root[type][species][field].items())
     252     2295659 :     if (!isValueReal(item.value()))
     253           1 :       mooseError("Weight value ",
     254           2 :                  nlohmann::to_string(item.value()),
     255             :                  " of constituent ",
     256           1 :                  item.key(),
     257             :                  " of the ",
     258             :                  type,
     259             :                  " ",
     260             :                  species,
     261             :                  " in ",
     262           1 :                  _filename,
     263             :                  " cannot be converted to Real");
     264      776915 : }
     265             : 
     266             : void
     267       27862 : GeochemicalDatabaseValidator::checkElements(const std::string element) const
     268             : {
     269             :   // Check molecular weight can be converted to a Real
     270       55724 :   checkSpeciesValue("elements", element, "molecular weight");
     271       27862 : }
     272             : 
     273             : void
     274       33090 : GeochemicalDatabaseValidator::checkBasisSpecies(const std::string species) const
     275             : {
     276             :   // Check molecular weight can be converted to a Real
     277       66180 :   checkSpeciesValue("basis species", species, "molecular weight");
     278             : 
     279             :   // Check charge can be converted to a Real
     280       66180 :   checkSpeciesValue("basis species", species, "charge");
     281             : 
     282             :   // Check ionic radius can be converted to a Real
     283       66180 :   checkSpeciesValue("basis species", species, "radius");
     284             : 
     285             :   // Check element weights can be converted to a Real
     286       66180 :   checkSpeciesWeightValue("basis species", species, "elements");
     287       33090 : }
     288             : 
     289             : void
     290      315971 : GeochemicalDatabaseValidator::checkSecondarySpecies(const std::string species) const
     291             : {
     292             :   // Check molecular weight can be converted to a Real
     293      631942 :   checkSpeciesValue("secondary species", species, "molecular weight");
     294             : 
     295             :   // Check charge can be converted to a Real
     296      631943 :   checkSpeciesValue("secondary species", species, "charge");
     297             : 
     298             :   // Check ionic radius can be converted to a Real
     299      631941 :   checkSpeciesValue("secondary species", species, "radius");
     300             : 
     301             :   // Check basis species weights can be converted to a Real
     302      631940 :   checkSpeciesWeightValue("secondary species", species, "species");
     303             : 
     304             :   // Check the number of logk values and whether they can be converted to a Real
     305      631935 :   checkArraySize("secondary species", species, "logk");
     306      631932 :   checkArrayValues("secondary species", species, "logk");
     307      315966 : }
     308             : 
     309             : void
     310      355767 : GeochemicalDatabaseValidator::checkMineralSpecies(const std::string species) const
     311             : {
     312             :   // Check molecular weight can be converted to a Real
     313      711534 :   checkSpeciesValue("mineral species", species, "molecular weight");
     314             : 
     315             :   // Check molar volume can be converted to a Real
     316      711534 :   checkSpeciesValue("mineral species", species, "molar volume");
     317             : 
     318             :   // Check basis species weights can be converted to a Real
     319      711534 :   checkSpeciesWeightValue("mineral species", species, "species");
     320             : 
     321             :   // Check the number of logk values and whether they can be converted to a Real
     322      711534 :   checkArraySize("mineral species", species, "logk");
     323      711535 :   checkArrayValues("mineral species", species, "logk");
     324      355766 : }
     325             : 
     326             : void
     327         889 : GeochemicalDatabaseValidator::checkSorbingMineralSpecies(const std::string species) const
     328             : {
     329             :   // Check surface area can be converted to a Real
     330        1778 :   checkSpeciesValue("sorbing minerals", species, "surface area");
     331             : 
     332             :   // Check sorbing site weights can be converted to a Real
     333        1778 :   checkSpeciesWeightValue("sorbing minerals", species, "sorbing sites");
     334         889 : }
     335             : 
     336             : void
     337        6830 : GeochemicalDatabaseValidator::checkGasSpecies(const std::string species) const
     338             : {
     339             :   // Check molecular weight can be converted to a Real
     340       13660 :   checkSpeciesValue("gas species", species, "molecular weight");
     341             : 
     342             :   // Check basis species weights can be converted to a Real
     343       13660 :   checkSpeciesWeightValue("gas species", species, "species");
     344             : 
     345             :   // Check the number of logk values and whether they can be converted to a Real
     346       13660 :   checkArraySize("gas species", species, "logk");
     347       13660 :   checkArrayValues("gas species", species, "logk");
     348             : 
     349             :   // Check optional fugacity coefficients
     350        6830 :   if (_root["gas species"][species].contains("chi"))
     351        5464 :     checkArrayValues("gas species", species, "chi");
     352             : 
     353        6830 :   if (_root["gas species"][species].contains("Pcrit"))
     354       10264 :     checkSpeciesValue("gas species", species, "Pcrit");
     355             : 
     356        6830 :   if (_root["gas species"][species].contains("Tcrit"))
     357       10264 :     checkSpeciesValue("gas species", species, "Tcrit");
     358             : 
     359        6830 :   if (_root["gas species"][species].contains("omega"))
     360       10264 :     checkSpeciesValue("gas species", species, "omega");
     361        6830 : }
     362             : 
     363             : void
     364       29673 : GeochemicalDatabaseValidator::checkRedoxSpecies(const std::string species) const
     365             : {
     366             :   // Check molecular weight can be converted to a Real
     367       59346 :   checkSpeciesValue("redox couples", species, "molecular weight");
     368             : 
     369             :   // Check charge can be converted to a Real
     370       59346 :   checkSpeciesValue("redox couples", species, "charge");
     371             : 
     372             :   // Check ionic radius can be converted to a Real
     373       59346 :   checkSpeciesValue("redox couples", species, "radius");
     374             : 
     375             :   // Check basis species weights can be converted to a Real
     376       59346 :   checkSpeciesWeightValue("redox couples", species, "species");
     377             : 
     378             :   // Check the number of logk values and whether they can be converted to a Real
     379       59346 :   checkArraySize("redox couples", species, "logk");
     380       59346 :   checkArrayValues("redox couples", species, "logk");
     381       29673 : }
     382             : 
     383             : void
     384       23441 : GeochemicalDatabaseValidator::checkOxideSpecies(const std::string species) const
     385             : {
     386             :   // Check molecular weight can be converted to a Real
     387       46882 :   checkSpeciesValue("oxides", species, "molecular weight");
     388             : 
     389             :   // Check basis species weights can be converted to a Real
     390       46882 :   checkSpeciesWeightValue("oxides", species, "species");
     391       23441 : }
     392             : 
     393             : void
     394       11258 : GeochemicalDatabaseValidator::checkSurfaceSpecies(const std::string species) const
     395             : {
     396             :   // Check molecular weight can be converted to a Real
     397       22516 :   checkSpeciesValue("surface species", species, "molecular weight");
     398             : 
     399             :   // Check charge can be converted to a Real
     400       22516 :   checkSpeciesValue("surface species", species, "charge");
     401             : 
     402             :   // Check basis species weights can be converted to a Real
     403       22516 :   checkSpeciesWeightValue("surface species", species, "species");
     404             : 
     405             :   // Check equilibrium constants can be converted to a Real
     406       22516 :   checkSpeciesValue("surface species", species, "log K");
     407       22516 :   checkSpeciesValue("surface species", species, "dlogK/dT");
     408       11258 : }

Generated by: LCOV version 1.14