{"id":190040,"date":"2024-10-24T12:51:32","date_gmt":"2024-10-24T12:51:32","guid":{"rendered":"https:\/\/predict.kikirpa.be\/?page_id=190040"},"modified":"2024-12-02T09:35:35","modified_gmt":"2024-12-02T09:35:35","slug":"moisture-and-salt-sample-data-analysis-tool","status":"publish","type":"page","link":"https:\/\/predict.kikirpa.be\/index.php\/tools\/moisture-and-salt-sample-data-analysis-tool\/","title":{"rendered":"Salt Content Calculator"},"content":{"rendered":"\n<p class=\"has-text-align-left\"><strong>The calculations used in this application are detailed in <a href=\"https:\/\/www.nature.com\/articles\/s41597-022-01445-9\" target=\"_blank\" rel=\"noreferrer noopener\">Charge balance calculations for mixed salt systems applied to a large dataset from the built environment | Scientific Data (nature.com)<\/a><\/strong>. Use of this tool is at your own risk, and the accuracy of the results depends on the correctness of the data you enter. Users are solely responsible for verifying all calculations independently and for any decisions or outcomes resulting from the use of this tool. We disclaim any liability for errors or consequences arising from its use.<\/p>\n\n\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Ion Data Entry and Analysis<\/title>\n    <!-- Include MathJax Library for rendering formulas -->\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/mathjax@3\/es5\/tex-mml-chtml.js\"><\/script>\n    <!-- Include Calibri Font and Fallbacks -->\n    <style>\n        body {\n            font-family: 'Calibri', 'Arial', sans-serif;\n            background-color: #f4f4f4;\n            margin: 0;\n            padding: 0;\n        }\n        .container {\n            width: 90%;\n            max-width: 900px;\n            margin: 20px auto;\n            padding: 40px;\n            background-color: white;\n            border-radius: 10px;\n        }\n        .title {\n            font-weight: bold;\n            font-size: 28px;\n            margin: 20px;\n            text-align: center;\n        }\n        .subtitle {\n            font-weight: bold;\n            font-size: 22px;\n            margin: 20px 0 10px;\n            text-align: left;\n        }\n        .input-group {\n            margin: 15px 0;\n        }\n        .input-group label {\n            font-weight: bold;\n            display: block;\n            margin-bottom: 5px;\n        }\n        .input-group input {\n            border-radius: 5px;\n            border: 1px solid #ccc;\n            width: 100%;\n            box-sizing: border-box;\n            padding: 10px;\n            font-size: 16px;\n        }\n        .input-group small {\n            display: block;\n            margin-top: 5px;\n            font-size: 14px;\n            color: #555;\n        }\n        button {\n            padding: 12px;\n            border-radius: 5px;\n            border: none;\n            color: white;\n            font-size: 16px;\n            cursor: pointer;\n            margin: 20px auto;\n            width: 240px;\n            display: block;\n        }\n        .calculate {\n            background-color: #4CAF50;\n        }\n        .override {\n            background-color: #FF5733;\n            display: none; \/* Initially hidden *\/\n        }\n        #results, #eq-results, #imbalance-results, #correction-results, #gypsum-results, #final-results, #ecos-results {\n            font-weight: bold;\n            margin: 30px 0;\n            font-size: 18px;\n        }\n        #results table, #eq-results table, #imbalance-results table, #correction-results table, #gypsum-results table, #final-results table, #ecos-results table {\n            width: 100%;\n            border-collapse: collapse;\n            margin-top: 20px;\n        }\n        #results table, #results th, #results td,\n        #eq-results table, #eq-results th, #eq-results td,\n        #imbalance-results table, #imbalance-results th, #imbalance-results td,\n        #correction-results table, #correction-results th, #correction-results td,\n        #gypsum-results table, #gypsum-results th, #gypsum-results td,\n        #final-results table, #final-results th, #final-results td,\n        #ecos-results table, #ecos-results th, #ecos-results td {\n            border: 1px solid black;\n        }\n        #results th, #results td,\n        #eq-results th, #eq-results td,\n        #imbalance-results th, #imbalance-results td,\n        #correction-results th, #correction-results td,\n        #gypsum-results th, #gypsum-results td,\n        #final-results th, #final-results td,\n        #ecos-results th, #ecos-results td {\n            padding: 10px;\n            text-align: center;\n        }\n        #results th, #eq-results th, #imbalance-results th, #correction-results th, #gypsum-results th, #final-results th, #ecos-results th {\n            background-color: #f2f2f2;\n        }\n        .notes {\n            background-color: #e7f3fe;\n            border-left: 6px solid #2196F3;\n            padding: 10px 20px;\n            margin: 20px 0;\n            font-size: 16px;\n        }\n        \/* Ion input fields layout *\/\n        .ion-inputs {\n            display: flex;\n            flex-wrap: wrap;\n            justify-content: space-between;\n        }\n        .ion-column {\n            flex: 0 1 calc(48% - 10px); \/* Adjust width and spacing *\/\n            box-sizing: border-box;\n        }\n        \/* Additional styling for responsiveness *\/\n        @media (max-width: 600px) {\n            .container {\n                padding: 20px 10px;\n            }\n            .title {\n                font-size: 24px;\n            }\n            .subtitle {\n                font-size: 20px;\n            }\n            button {\n                width: 100%;\n            }\n            #results table, #results th, #results td,\n            #eq-results table, #eq-results th, #eq-results td,\n            #imbalance-results table, #imbalance-results th, #imbalance-results td,\n            #correction-results table, #correction-results th, #correction-results td,\n            #gypsum-results table, #gypsum-results th, #gypsum-results td,\n            #final-results table, #final-results th, #final-results td,\n            #ecos-results table, #ecos-results th, #ecos-results td {\n                font-size: 14px;\n            }\n            .ion-column {\n                flex: 1 0 100%;\n            }\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"container\">\n        <div class=\"title\">Ion Data Entry and Analysis<\/div>\n        <div class=\"input-group\">\n        <small>Please double-check that the calculations have not inadvertently removed significant amounts of sodium or potassium. Keep in mind that these adjustments can influence crystallization behavior.<\/small>\n\t<small>If you use these results, please cite the following reference: Godts, S., Steiger, M., Orr, S.A., De Kock, T., Desarnaud, J., De Clercq, C. &#038; Cnudde, V. Charge balance calculations for mixed salt systems applied to a large dataset from the built environment. Scientific Data, 9, 324 (2022). <a href=\"https:\/\/www.nature.com\/articles\/s41597-022-01445-9\" target=\"_blank\">https:\/\/www.nature.com\/articles\/s41597-022-01445-9<\/a>.<\/small>\n\t<p style=\"color:blue;\"><strong>Enter your data using a decimal point as the separator, double check if the input values are accurate. Four decimal places are sufficient.<\/p>\n  \n        <!-- Input fields -->\n        <div class=\"input-group\">\n            <label for=\"drySampleMass\">Dry Sample Mass (\\( m_s \\)) [g]:<\/label>\n            <input type=\"text\" id=\"drySampleMass\" name=\"drySampleMass\" placeholder=\"e.g., 1.0\">\n        <\/div>\n        <div class=\"input-group\">\n            <label for=\"waterVolume\">Amount of Water Added (\\( V_w \\)) [mL]:<\/label>\n            <input type=\"text\" id=\"waterVolume\" name=\"waterVolume\" placeholder=\"e.g., 100\">\n        <\/div>\n        <div class=\"input-group\">\n            <label for=\"imbalanceLimit\">Imbalance Percentage Limit [%]:<\/label>\n            <input type=\"text\" id=\"imbalanceLimit\" name=\"imbalanceLimit\" placeholder=\"e.g., 2\" value=\"2\">\n            <small>This limit is set to 2% and is in most cases a reasonable setting, however it is dependent on the analytical method\/equipment, calibration, and is ideally adjusted accordingly. The calculation pathway is determined based on this limit value as indicated throughout the results.<\/small>\n        <\/div>\n\n        <!-- Ion Input Fields -->\n        <div class=\"ion-inputs\">\n            <div class=\"ion-column\">\n                <div class=\"subtitle\">Cation Concentrations [mg\/L]<\/div>\n                <!-- Cation input fields -->\n                <div class=\"input-group\">\n                    <label for=\"sodium\">Sodium (\\( \\text{Na}^+ \\)):<\/label>\n                    <input type=\"text\" id=\"sodium\" name=\"sodium\" placeholder=\"e.g., 40.0\">\n                <\/div>\n                <div class=\"input-group\">\n                    <label for=\"potassium\">Potassium (\\( \\text{K}^+ \\)):<\/label>\n                    <input type=\"text\" id=\"potassium\" name=\"potassium\" placeholder=\"e.g., 10.0\">\n                <\/div>\n                <div class=\"input-group\">\n                    <label for=\"calcium\">Calcium (\\( \\text{Ca}^{2+} \\)):<\/label>\n                    <input type=\"text\" id=\"calcium\" name=\"calcium\" placeholder=\"e.g., 15.0\">\n                <\/div>\n                <div class=\"input-group\">\n                    <label for=\"magnesium\">Magnesium (\\( \\text{Mg}^{2+} \\)):<\/label>\n                    <input type=\"text\" id=\"magnesium\" name=\"magnesium\" placeholder=\"e.g., 5.0\">\n                <\/div>\n            <\/div>\n            <div class=\"ion-column\">\n                <div class=\"subtitle\">Anion Concentrations [mg\/L]<\/div>\n                <!-- Anion input fields -->\n                <div class=\"input-group\">\n                    <label for=\"chloride\">Chloride (\\( \\text{Cl}^- \\)):<\/label>\n                    <input type=\"text\" id=\"chloride\" name=\"chloride\" placeholder=\"e.g., 50.0\">\n                <\/div>\n                <div class=\"input-group\">\n                    <label for=\"nitrate\">Nitrate (\\( \\text{NO}_3^- \\)):<\/label>\n                    <input type=\"text\" id=\"nitrate\" name=\"nitrate\" placeholder=\"e.g., 30.0\">\n                <\/div>\n                <div class=\"input-group\">\n                    <label for=\"sulfate\">Sulfate (\\( \\text{SO}_4^{2-} \\)):<\/label>\n                    <input type=\"text\" id=\"sulfate\" name=\"sulfate\" placeholder=\"e.g., 20.0\">\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- Calculation button -->\n        <button class=\"calculate\" onclick=\"calculateAll()\">Calculate<\/button>\n\n        <!-- Results sections -->\n        <div id=\"results\"><\/div>\n        <div id=\"eq-results\"><\/div>\n        <div id=\"imbalance-results\"><\/div>\n        <!-- Override button will be inserted dynamically in imbalance-results section -->\n\n        <div id=\"correction-results\"><\/div>\n        <div id=\"gypsum-results\" style=\"display:none;\"><\/div> <!-- Hide initially -->\n        <div id=\"final-results\" style=\"display:none;\"><\/div>  <!-- Hide initially -->\n        <div id=\"ecos-results\" style=\"display:none;\"><\/div>   <!-- Hide initially -->\n\n    <\/div>\n\n    <script>\n        \/\/ Ion data with molar masses (g\/mol) and charges\n        const ions = [\n            { name: 'Chloride', id: 'chloride', symbol: '\\\\text{Cl}^-', molarMass: 35.4527, charge: -1, type: 'anion' },\n            { name: 'Nitrate', id: 'nitrate', symbol: '\\\\text{NO}_3^-', molarMass: 62.0049, charge: -1, type: 'anion' },\n            { name: 'Sulfate', id: 'sulfate', symbol: '\\\\text{SO}_4^{2-}', molarMass: 96.064, charge: -2, type: 'anion' },\n            { name: 'Sodium', id: 'sodium', symbol: '\\\\text{Na}^+', molarMass: 22.9989768, charge: +1, type: 'cation' },\n            { name: 'Potassium', id: 'potassium', symbol: '\\\\text{K}^+', molarMass: 39.0983, charge: +1, type: 'cation' },\n            { name: 'Calcium', id: 'calcium', symbol: '\\\\text{Ca}^{2+}', molarMass: 40.078, charge: +2, type: 'cation' },\n            { name: 'Magnesium', id: 'magnesium', symbol: '\\\\text{Mg}^{2+}', molarMass: 24.305, charge: +2, type: 'cation' }\n        ];\n\n        let blockFurtherCalculations = false; \/\/ Flag to block steps 5 and 6\n\n        \/\/ Main calculation function called when \"Calculate\" button is clicked\n        function calculateAll() {\n            \/\/ Reset block flag and hide override button\n            blockFurtherCalculations = false;\n\n            \/\/ Remove override button if it exists\n            const overrideBtn = document.getElementById('overrideButton');\n            if (overrideBtn) {\n                overrideBtn.remove();\n            }\n\n            \/\/ Clear previous results\n            document.getElementById('gypsum-results').style.display = 'none';\n            document.getElementById('final-results').style.display = 'none';\n            document.getElementById('ecos-results').style.display = 'none';\n            document.getElementById('correction-results').innerHTML = '';\n\n            \/\/ Get input values and replace commas with periods (handle European decimal separators)\n            let ms_input = document.getElementById('drySampleMass').value.replace(',', '.');\n            let Vw_input = document.getElementById('waterVolume').value.replace(',', '.');\n            let imbalanceLimit_input = document.getElementById('imbalanceLimit').value.replace(',', '.');\n\n            \/\/ Parse inputs\n            let ms = parseFloat(ms_input);\n            let Vw = parseFloat(Vw_input);\n            let imbalanceLimit = parseFloat(imbalanceLimit_input);\n\n            \/\/ Validate sample mass and water volume\n            if (isNaN(ms) || ms <= 0) {\n                alert('Please enter a valid positive number for Dry Sample Mass.');\n                return;\n            }\n            if (isNaN(Vw) || Vw <= 0) {\n                alert('Please enter a valid positive number for Amount of Water Added.');\n                return;\n            }\n\n            \/\/ Validate imbalance limit\n            if (isNaN(imbalanceLimit) || imbalanceLimit <= 0) {\n                alert('Please enter a valid positive number for Imbalance Percentage Limit.');\n                return;\n            }\n\n            \/\/ Convert ms from grams to milligrams (1 g = 1000 mg)\n            ms = ms * 1000; \/\/ Now ms is in mg\n            \/\/ Convert Vw from mL to L (1 mL = 0.001 L)\n            Vw = Vw \/ 1000; \/\/ Now Vw is in L\n\n            \/\/ Process each ion\n            for (let ion of ions) {\n                \/\/ Get input value and replace commas with periods\n                const ci_input = document.getElementById(ion.id).value.replace(',', '.');\n                const ci = parseFloat(ci_input);\n\n                if (isNaN(ci) || ci < 0) {\n                    alert(`Please enter a valid non-negative numerical value for ${ion.name}.`);\n                    return;\n                }\n                const wi = (ci * Vw) \/ ms; \/\/ Weight fraction (dimensionless)\n                const wi_percent = wi * 100; \/\/ Convert to weight percent (w.%)\n                ion.concentration = ci.toFixed(2); \/\/ Store formatted concentration\n                ion.weightFraction = wi; \/\/ Store weight fraction\n                ion.weightPercent = wi_percent.toFixed(4); \/\/ Store formatted weight percent\n            }\n\n            \/\/ Build weight fraction results table\n            let wfTableRows = '';\n            ions.forEach(ion => {\n                wfTableRows += `\n                    <tr>\n                        <td>\\\\(${ion.symbol}\\\\)<\/td>\n                        <td>${ion.concentration}<\/td>\n                        <td>${ion.weightPercent}<\/td>\n                    <\/tr>\n                `;\n            });\n\n            \/\/ Display Weight Fraction Results\n            const resultsDiv = document.getElementById('results');\n            resultsDiv.innerHTML = `\n                <h2>1. Results of the Weight Fraction Calculation (displayed as w.%)<\/h2>\n                <div class=\"notes\">\n                    <p>The raw data derived from the ion analysis is given as a concentration of each ion in milligrams per liter (mg\/L). To facilitate the interpretation of the ion content in the material, it is common practice to present the raw ion data as a weight fraction relative to the dry sample mass:<\/p>\n                    <p style=\"text-align: center;\">\n                        $$ w_i = \\\\frac{c_i V_w}{m_s} $$\n                    <\/p>\n                    <p>This approximation assumes a liter of solution is equal to a kilogram of pure water (1.000 g\/cm\u00b3). Although a correction could be applied if the solution density of each individual sample solution was known, the calculated deviation is considered negligible, as the solutions are highly diluted, thus resulting in an acceptable deviation of several tenths to hundredths of mg\/L.<\/p>\n                <\/div>\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Ion<\/th>\n                            <th>Concentration \\\\( c_i \\\\) [mg\/L]<\/th>\n                            <th>Weight Percent \\\\( w_i \\\\) [w.%]<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody>\n                        ${wfTableRows}\n                    <\/tbody>\n                <\/table>\n            `;\n\n            \/\/ Proceed to calculate equivalents per kilogram\n            calculateEquivalents(ms, Vw, imbalanceLimit);\n        }\n\n        \/\/ Function to calculate equivalents per kilogram for each ion\n        function calculateEquivalents(ms, Vw, imbalanceLimit) {\n            \/\/ Process each ion to calculate equivalents per kilogram\n            let eqTableRows = '';\n\n            ions.forEach(ion => {\n                const wi = ion.weightFraction; \/\/ Weight fraction (dimensionless)\n                const zi = Math.abs(ion.charge); \/\/ Absolute charge\n                const M = ion.molarMass \/ 1000; \/\/ Convert molar mass to kg\/mol\n\n                \/\/ Calculate equivalents per kilogram (Eq\/kg)\n                const ei = (wi \/ M) * zi; \/\/ Eq\/kg\n                const ei_meqkg = ei * 1000; \/\/ Convert Eq\/kg to mEq\/kg\n\n                ion.equivalents = ei_meqkg; \/\/ Store mEq\/kg value\n                ion.equivalentsFormatted = ei_meqkg.toFixed(4); \/\/ Store formatted mEq\/kg\n            });\n\n            \/\/ Build equivalents per kilogram results table\n            ions.forEach(ion => {\n                eqTableRows += `\n                    <tr>\n                        <td>\\\\(${ion.symbol}\\\\)<\/td>\n                        <td>${ion.weightPercent}<\/td>\n                        <td>${ion.equivalentsFormatted}<\/td>\n                    <\/tr>\n                `;\n            });\n\n            \/\/ Display Equivalents per Kilogram Results\n            const eqResultsDiv = document.getElementById('eq-results');\n            eqResultsDiv.innerHTML = `\n                <h2>2. Results of the Equivalents per Kilogram Calculation (displayed as mEq\/kg)<\/h2>\n                <div class=\"notes\">\n                    <p>The concentration of each ion is converted to equivalents per kilogram (Eq\/kg) to eliminate the charge difference between ions and allow direct comparison between cation and anion balance:<\/p>\n                    <p style=\"text-align: center;\">\n                        $$ e_i = \\\\frac{w_i}{M} \\\\times |z_i| $$\n                    <\/p>\n                <\/div>\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Ion<\/th>\n                            <th>Weight Percent \\\\( w_i \\\\) [w.%]<\/th>\n                            <th>Equivalents \\\\( e_i \\\\) [mEq\/kg]<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody>\n                        ${eqTableRows}\n                    <\/tbody>\n                <\/table>\n            `;\n\n            \/\/ Now, proceed to calculate charge imbalance\n            calculateChargeImbalance(imbalanceLimit);\n        }\n\n        \/\/ Function to calculate charge imbalance between cations and anions\n        function calculateChargeImbalance(imbalanceLimit) {\n            \/\/ Calculate total cations and anions equivalents\n            let eCatTotal = 0;\n            let eAniTotal = 0;\n\n            ions.forEach(ion => {\n                if (ion.type === 'cation') {\n                    eCatTotal += ion.equivalents;\n                } else {\n                    eAniTotal += ion.equivalents;\n                }\n            });\n\n            \/\/ Prevent division by zero\n            if (eCatTotal === 0 || eAniTotal === 0) {\n                alert('Total cation or anion equivalents cannot be zero.');\n                return;\n            }\n\n            const deltaE = eCatTotal - eAniTotal;\n            const totalE = (eCatTotal + eAniTotal) \/ 2;\n            const imbalancePercentage = (Math.abs(deltaE) \/ totalE) * 100;\n\n            let imbalanceDirection = '';\n            if (deltaE > 0) {\n                imbalanceDirection = 'excess cations over anions';\n            } else if (deltaE < 0) {\n                imbalanceDirection = 'excess anions over cations';\n            } else {\n                imbalanceDirection = 'perfect balance between cations and anions';\n            }\n\n            let imbalanceMessage = `<p style=\"color:red;\"><strong>Warning:<\/strong>The charge imbalance is ${imbalancePercentage.toFixed(2)}%, indicating ${imbalanceDirection}. This may indicate missing ions or measurement errors. Corrections in the next step applied to cations are likely related to undetected carbonates. Further evaluation should be carried out with caution. See <a href=\"https:\/\/www.nature.com\/articles\/s41597-022-01445-9\" target=\"_blank\">https:\/\/www.nature.com\/articles\/s41597-022-01445-9<\/a> for more information.<\/p>`;\n            \n\n            const imbalanceDiv = document.getElementById('imbalance-results');\n            imbalanceDiv.innerHTML = `\n                <h2>3. Results of the Charge Imbalance<\/h2>\n                <div class=\"notes\">\n                    <p>With the values in equivalents per kilogram, an initial analysis is carried out to determine the charge imbalance (\\\\( \\\\Delta e \\\\)), which is the difference between the total sum of all cations (\\\\( e_{\\\\text{cat}} \\\\)) and all anions (\\\\( e_{\\\\text{ani}} \\\\)):<\/p>\n                    <p style=\"text-align: center;\">\n                        $$ \\\\Delta e = e_{\\\\text{cat}} - e_{\\\\text{ani}} $$\n                    <\/p>\n                    <p>${imbalanceMessage}<\/p>\n                <\/div>\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Total Cations \\\\( e_{\\\\text{cat}} \\\\) [mEq\/kg]<\/th>\n                            <th>Total Anions \\\\( e_{\\\\text{ani}} \\\\) [mEq\/kg]<\/th>\n                            <th>Charge Imbalance \\\\( \\\\Delta e \\\\) [mEq\/kg]<\/th>\n                            <th>Imbalance Percentage [%]<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody>\n                        <tr>\n                            <td>${eCatTotal.toFixed(4)}<\/td>\n                            <td>${eAniTotal.toFixed(4)}<\/td>\n                            <td>${deltaE.toFixed(4)}<\/td>\n                            <td>${imbalancePercentage.toFixed(2)}<\/td>\n                        <\/tr>\n                    <\/tbody>\n                <\/table>\n            `;\n\n            if (imbalancePercentage > imbalanceLimit && deltaE < 0) {\n                \/\/ Anions exceed cations, block further calculations\n                blockFurtherCalculations = true;\n\n                \/\/ Display warning and show override button\n                let overrideButtonHTML = `\n                    <div class=\"notes\" style=\"background-color: #ffcccc; border-left-color: red;\">\n                        <p><strong>Warning:<\/strong> The charge imbalance exceeds ${imbalanceLimit}% due to excess anions. Further calculations will not be carried out.<\/p>\n                        <p>The charge imbalance is likely related to undetected anions or a measurement error, please evaluate the results of the ion analysis.<\/p>\n                    <\/div>\n                    <button class=\"override\" id=\"overrideButton\" onclick=\"overrideCalculations()\">Override and Calculate Anyway (Pathway I)<\/button>\n                `;\n                imbalanceDiv.innerHTML += overrideButtonHTML;\n\n                \/\/ Hide further sections\n                document.getElementById('correction-results').innerHTML = '';\n                document.getElementById('gypsum-results').style.display = 'none';\n                document.getElementById('final-results').style.display = 'none';\n                document.getElementById('ecos-results').style.display = 'none';\n                renderMath();\n                return;\n            }\n\n            \/\/ Decide on calculation pathway\n            if (imbalancePercentage > imbalanceLimit) {\n                if (deltaE > 0) {\n                    \/\/ Cations exceed anions, proceed with Pathway II\n                    calculateWithPathwayII(eCatTotal, eAniTotal, deltaE);\n                }\n            } else {\n                \/\/ Imbalance within acceptable limits, proceed with Pathway I\n                calculateWithPathwayI(eCatTotal, eAniTotal);\n            }\n        }\n\n        \/\/ Function to perform corrections using Pathway I\n        function calculateWithPathwayI(eCatTotal, eAniTotal) {\n            \/\/ Implement Pathway I corrections\n            let correctedIons = [];\n            const totalEq = (eCatTotal + eAniTotal) \/ 2;\n\n            let correctionNotes = `\n                <p>Pathway I is followed when the charge imbalance is less than or equal to the specified limit:<\/p>\n                <p>An equal adjustment is applied to all ions to reach charge balance:<\/p>\n                <p style=\"text-align: center;\">\n                    $$ e_{i,\\\\text{adj}} = e_i \\\\times \\\\frac{(e_{\\\\text{cat}} + e_{\\\\text{ani}})\/2}{e_{\\\\text{cat}}} \\\\quad \\\\text{for cations} $$ <br>\n                    $$ e_{i,\\\\text{adj}} = e_i \\\\times \\\\frac{(e_{\\\\text{cat}} + e_{\\\\text{ani}})\/2}{e_{\\\\text{ani}}} \\\\quad \\\\text{for anions} $$\n                <\/p>\n            `;\n\n            ions.forEach(ion => {\n                let eAdjusted = ion.type === 'cation'\n                    ? ion.equivalents * (totalEq \/ eCatTotal)\n                    : ion.equivalents * (totalEq \/ eAniTotal);\n\n                const correction = eAdjusted - ion.equivalents;\n\n                ion.equivalentsAdjusted = eAdjusted;\n                ion.correction = correction;\n\n                correctedIons.push(ion);\n            });\n\n            \/\/ Proceed to gypsum calculation and final adjusted results\n            displayCorrectionResults(correctedIons, correctionNotes);\n            if (!blockFurtherCalculations) {\n                calculateGypsum(correctedIons);\n            }\n        }\n\n        \/\/ Function to perform corrections using Pathway II\n        function calculateWithPathwayII(eCatTotal, eAniTotal, deltaE) {\n            \/\/ Implement Pathway II corrections\n            let correctedIons = [];\n            let deltaERemaining = deltaE;\n\n            let correctionNotes = `\n                <p>Pathway II is followed when the charge imbalance exceeds the specified limit and cations exceed anions:<\/p>\n                <p>The adjustment is made sequentially on calcium, magnesium, sodium, and potassium until charge balance is achieved:<\/p>\n                <p style=\"text-align: center;\">\n                    $$ e_i^* = \\\\begin{cases} e_i - \\\\Delta e & \\\\text{if } e_i - \\\\Delta e \\\\geq 0 \\\\\\\\ 0 & \\\\text{if } e_i - \\\\Delta e < 0 \\\\end{cases} $$\n                <\/p>\n            `;\n\n            \/\/ Adjust cations in order: Calcium, Magnesium, Sodium, Potassium\n            let cationOrder = ['calcium', 'magnesium', 'sodium', 'potassium'];\n            cationOrder.forEach(ionId => {\n                if (deltaERemaining > 0) {\n                    let ion = ions.find(i => i.id === ionId);\n                    if (ion && ion.equivalents > 0) {\n                        let adjustment = Math.min(ion.equivalents, deltaERemaining);\n                        ion.equivalentsAdjusted = ion.equivalents - adjustment;\n                        ion.correction = ion.equivalentsAdjusted - ion.equivalents; \/\/ Negative value\n                        deltaERemaining -= adjustment;\n                        correctedIons.push(ion);\n                    }\n                }\n            });\n\n            \/\/ Add remaining ions without adjustment\n            ions.forEach(ion => {\n                if (!correctedIons.includes(ion)) {\n                    ion.equivalentsAdjusted = ion.equivalents;\n                    ion.correction = 0;\n                    correctedIons.push(ion);\n                }\n            });\n\n            \/\/ Proceed to gypsum calculation and final adjusted results\n            displayCorrectionResults(correctedIons, correctionNotes);\n            if (!blockFurtherCalculations) {\n                calculateGypsum(correctedIons);\n            }\n        }\n\n        \/\/ Function to display correction results\n        function displayCorrectionResults(correctedIons, correctionNotes) {\n            \/\/ Recalculate totals after adjustment\n            let eCatTotalAdj = 0;\n            let eAniTotalAdj = 0;\n\n            correctedIons.forEach(ion => {\n                if (ion.type === 'cation') {\n                    eCatTotalAdj += ion.equivalentsAdjusted;\n                } else {\n                    eAniTotalAdj += ion.equivalentsAdjusted;\n                }\n            });\n\n            const deltaEAdj = eCatTotalAdj - eAniTotalAdj;\n            const imbalanceAdjPercentage = (Math.abs(deltaEAdj) \/ ((eCatTotalAdj + eAniTotalAdj) \/ 2)) * 100;\n\n            \/\/ Display Correction Results\n            let correctionTableRows = '';\n            correctedIons.forEach(ion => {\n                const rowStyle = ion.correction !== 0 ? ' style=\"color:red;\"' : '';\n                correctionTableRows += `\n                    <tr${rowStyle}>\n                        <td>\\\\(${ion.symbol}\\\\)<\/td>\n                        <td>${ion.equivalentsFormatted}<\/td>\n                        <td>${ion.equivalentsAdjusted.toFixed(4)}<\/td>\n                        <td>${ion.correction.toFixed(4)}<\/td>\n                    <\/tr>\n                `;\n            });\n\n            const correctionDiv = document.getElementById('correction-results');\n            correctionDiv.innerHTML = `\n                <h2>4. Charge Balance Corrections<\/h2>\n                <div class=\"notes\">${correctionNotes}<\/div>\n                <p>After correction, the charge imbalance is ${imbalanceAdjPercentage.toFixed(2)}%.<\/p>\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Ion<\/th>\n                            <th>Initial Equivalents [mEq\/kg]<\/th>\n                            <th>Adjusted Equivalents [mEq\/kg]<\/th>\n                            <th>Correction [mEq\/kg]<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody>\n                        ${correctionTableRows}\n                    <\/tbody>\n                <\/table>\n            `;\n\n            renderMath();\n        }\n\n        \/\/ Function to calculate gypsum content and adjust calcium and sulfate\n        function calculateGypsum(correctedIons) {\n            if (blockFurtherCalculations) return;\n\n            \/\/ Show gypsum and final results sections\n            document.getElementById('gypsum-results').style.display = 'block';\n            document.getElementById('final-results').style.display = 'block';\n            document.getElementById('ecos-results').style.display = 'block';\n\n            \/\/ Step 5: Determination of Gypsum Content\n            let calciumIon = correctedIons.find(ion => ion.id === 'calcium');\n            let sulfateIon = correctedIons.find(ion => ion.id === 'sulfate');\n\n            let eCa_adj = calciumIon.equivalentsAdjusted;\n            let eSO4_adj = sulfateIon.equivalentsAdjusted;\n\n            \/\/ Calculate elim_CaSO4\n            let elim_CaSO4 = 0.5 * (eCa_adj + eSO4_adj - Math.abs(eCa_adj - eSO4_adj));\n\n            \/\/ Adjust calcium and sulfate\n            let eCa_adj_f = eCa_adj - elim_CaSO4;\n            let eSO4_adj_f = eSO4_adj - elim_CaSO4;\n\n            \/\/ Update 'equivalentsAdjusted' for calcium and sulfate\n            calciumIon.equivalentsAdjusted = eCa_adj_f;\n            sulfateIon.equivalentsAdjusted = eSO4_adj_f;\n\n            \/\/ Update 'correction' for calcium and sulfate to include gypsum correction\n            calciumIon.correction = calciumIon.equivalentsAdjusted - calciumIon.equivalents;\n            sulfateIon.correction = sulfateIon.equivalentsAdjusted - sulfateIon.equivalents;\n\n            \/\/ Gypsum content in mEq\/kg\n            let gypsumContent_mEqkg = elim_CaSO4;\n\n            \/\/ Build gypsum results\n            const gypsumDiv = document.getElementById('gypsum-results');\n            gypsumDiv.innerHTML = `\n                <h2>5. Determination of Gypsum* Content<\/h2>\n                <div class=\"notes\">\n\t    <p>The theoretical gypsum* content is determined using the following equation:<\/p>\n                    <p style=\"text-align: center;\">\n                        $$ e_{\\\\text{lim, CaSO_4}} = 0.5 \\\\left( e_{\\\\text{Ca, adj}} + e_{\\\\text{SO}_4, \\\\text{adj}} - | e_{\\\\text{Ca, adj}} - e_{\\\\text{SO}_4, \\\\text{adj}} | \\\\right) $$\n                    <\/p>\n                    <p>After removing the theoretical gypsum* content, the adjusted calcium and sulfate contents are:<\/p>\n                    <p style=\"text-align: center;\">\n                        $$ e_{\\\\text{Ca, adj, f}} = e_{\\\\text{Ca, adj}} - e_{\\\\text{lim, CaSO_4}} $$\n                        <br>\n                        $$ e_{\\\\text{SO}_4, adj, f} = e_{\\\\text{SO}_4, adj} - e_{\\\\text{lim, CaSO_4}} $$\n                    <\/p>\n                <\/div>\n                <p>Theoretical gypsum* content: ${gypsumContent_mEqkg.toFixed(4)} mEq\/kg<\/p>\n\t<div class=\"notes\" style=\"background-color: #ffcccc; border-left-color: red;\">\n                    <p>* the calculated gypsum content is based on the anhydrous form due to the nature of the ion analysis.<\/p>\n\t<\/div> \n            `;\n\n            \/\/ Step 6: Adjusted Results Displayed as w.%\n            \/\/ Convert adjusted equivalents back to weight fractions (w_i) and weight percents (w.%)\n            correctedIons.forEach(ion => {\n                const zi = Math.abs(ion.charge);\n                const M = ion.molarMass \/ 1000; \/\/ kg\/mol\n                \/\/ Use the final adjusted equivalents\n                let e_i_adj_f;\n                if (ion.id === 'calcium' || ion.id === 'sulfate') {\n                    e_i_adj_f = ion.equivalentsAdjusted \/ 1000; \/\/ Convert mEq\/kg to Eq\/kg\n                } else {\n                    e_i_adj_f = ion.equivalentsAdjusted \/ 1000; \/\/ Eq\/kg\n                }\n                \/\/ Calculate adjusted weight fraction\n                const wi_adj = (e_i_adj_f * M) \/ zi; \/\/ kg\/kg (dimensionless)\n                const wi_percent_adj = wi_adj * 100; \/\/ Convert to w.%\n                ion.weightFractionAdjusted = wi_adj;\n                ion.weightPercentAdjusted = wi_percent_adj.toFixed(4);\n            });\n\n            \/\/ Build final results table\n            let finalTableRows = '';\n            correctedIons.forEach(ion => {\n                finalTableRows += `\n                    <tr>\n                        <td>\\\\(${ion.symbol}\\\\)<\/td>\n                        <td>${ion.weightPercentAdjusted}<\/td>\n                        <td>${ion.correction.toFixed(4)}<\/td>\n                    <\/tr>\n                `;\n            });\n\n            \/\/ Calculate gypsum content in w.%\n            const M_gypsum = 136.142 \/ 1000; \/\/ kg\/mol\n            const gypsum_wi = (gypsumContent_mEqkg \/ 1000 * M_gypsum) \/ 2; \/\/ Divide by charge 2 for CaSO4\n            const gypsum_wi_percent = gypsum_wi * 100;\n\n            \/\/ Calculate total ion content excluding gypsum\n            let totalIonContentExGypsum = 0;\n            correctedIons.forEach(ion => {\n                totalIonContentExGypsum += parseFloat(ion.weightPercentAdjusted);\n            });\n\n            const finalDiv = document.getElementById('final-results');\n            finalDiv.innerHTML = `\n                <h2>6. Adjusted Results Displayed as w.%<\/h2>\n                <div class=\"notes\">\n                    <p>The adjusted equivalents are converted back to weight percent (w.%) using the formula:<\/p>\n                    <p style=\"text-align: center;\">\n                        $$ w_i = \\\\frac{e_{i, \\\\text{adj}} \\\\times M}{|z_i|} $$\n                    <\/p>\n                    <p>Here, \\\\( e_{i, \\\\text{adj}} \\\\) is the adjusted equivalents per kilogram (Eq\/kg), \\\\( M \\\\) is the molar mass (kg\/mol), and \\\\( |z_i| \\\\) is the absolute charge of the ion.<\/p>\n                <\/div>\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Ion<\/th>\n                            <th>Adjusted Weight Percent \\\\( w_i \\\\) [w.%]<\/th>\n                            <th>Total Correction [mEq\/kg]<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody>\n                        ${finalTableRows}\n                        <tr>\n                            <td>gypsum*<\/td>\n                            <td>${gypsum_wi_percent.toFixed(4)}<\/td>\n                            <td>-<\/td>\n                        <\/tr>\n                    <\/tbody>\n                <\/table>\n                <p>Total ion content excluding gypsum*: ${totalIonContentExGypsum.toFixed(4)} w.%<\/p>\n\t<div class=\"notes\" style=\"background-color: #ffcccc; border-left-color: red;\">\n                    <p>* the calculated gypsum content is based on the anhydrous form due to the nature of the ion analysis.<\/p>\n\t<\/div>\n            `;\n\n            \/\/ Step 7: ECOS\/RUNSALT Input Data\n            \/\/ Calculate moles per kg for each ion excluding gypsum\n            correctedIons.forEach(ion => {\n                const zi = Math.abs(ion.charge);\n                let e_i_adj_f_mEqkg = ion.equivalentsAdjusted; \/\/ mEq\/kg\n                const e_i_adj_f_Eqkg = e_i_adj_f_mEqkg \/ 1000; \/\/ Eq\/kg\n                const n_i_molkg = e_i_adj_f_Eqkg \/ zi; \/\/ mol\/kg\n                ion.molesPerKg = n_i_molkg; \/\/ store without rounding yet\n            });\n\n            \/\/ Sum total moles per kg excluding gypsum\n            let totalMolesExcludingGypsum = 0;\n            correctedIons.forEach(ion => {\n                totalMolesExcludingGypsum += ion.molesPerKg;\n            });\n\n            \/\/ Calculate mole fractions\n            correctedIons.forEach(ion => {\n                ion.moleFraction = ion.molesPerKg \/ totalMolesExcludingGypsum;\n            });\n\n            \/\/ Build ECOS\/RUNSALT input data table in specified order\n            let ionOrder = ['chloride', 'nitrate', 'sulfate', 'sodium', 'potassium', 'magnesium', 'calcium'];\n\n            let ecosTableRows = '';\n            ionOrder.forEach(ionId => {\n                let ion = correctedIons.find(i => i.id === ionId);\n                ecosTableRows += `\n                    <tr>\n                        <td>\\\\(${ion.symbol}\\\\)<\/td>\n                        <td>${ion.molesPerKg.toFixed(9)}<\/td>\n                        <td>${ion.moleFraction.toFixed(9)}<\/td>\n                    <\/tr>\n                `;\n            });\n\n            const ecosDiv = document.getElementById('ecos-results');\n            ecosDiv.innerHTML = `\n                <h2>7. ECOS\/RUNSALT Input Data<\/h2>\n                <div class=\"notes\">\n                    <p>The following data can be used as direct input for the ECOS\/RUNSALT program, which can be downloaded from <a href=\"http:\/\/science.sdf-eu.org\/runsalt\/\" target=\"_blank\">http:\/\/science.sdf-eu.org\/runsalt\/<\/a>. For more information on how to use the model, see <a href=\"https:\/\/www.mdpi.com\/1963466\" target=\"_blank\">https:\/\/www.mdpi.com\/1963466<\/a>.<\/p>\n                    <p>The model will show the behaviour of the mixture under different environmental conditions, the mixture can be classified into a type, see <a href=\"https:\/\/www.nature.com\/articles\/s41598-023-40590-y\" target=\"_blank\">https:\/\/www.nature.com\/articles\/s41598-023-40590-y<\/a> for more information.<\/p>\n                    <p>Keep in mind that the results of the model do not include kinetic influences, for more information refer to <a href=\"https:\/\/pubs.acs.org\/doi\/10.1021\/acsomega.4c01486\" target=\"_blank\">https:\/\/pubs.acs.org\/doi\/10.1021\/acsomega.4c01486<\/a> and <a href=\"https:\/\/heritagesciencejournal.springeropen.com\/articles\/10.1186\/s40494-021-00514-3\" target=\"_blank\">https:\/\/heritagesciencejournal.springeropen.com\/articles\/10.1186\/s40494-021-00514-3<\/a>.<\/p>\n                    <p>The amounts are calculated based on the corrected data excluding gypsum and converted to moles per kilogram (mol\/kg) and mole fractions:<\/p>\n                <\/div>\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Ion<\/th>\n                            <th>Amount [mol\/kg]<\/th>\n                            <th>Mole Fraction<\/th>\n                        <\/tr>\n                    <\/thead>\n                    <tbody>\n                        ${ecosTableRows}\n                    <\/tbody>\n                <\/table>\n            `;\n\n            renderMath();\n        }\n\n        \/\/ Function to allow user to override and proceed with Pathway I\n        function overrideCalculations() {\n            blockFurtherCalculations = false;\n            const overrideBtn = document.getElementById('overrideButton');\n            if (overrideBtn) {\n                overrideBtn.style.display = 'none';\n            }\n            \/\/ Since user overrides, proceed with Pathway I\n            let eCatTotal = 0;\n            let eAniTotal = 0;\n\n            ions.forEach(ion => {\n                if (ion.type === 'cation') {\n                    eCatTotal += ion.equivalents;\n                } else {\n                    eAniTotal += ion.equivalents;\n                }\n            });\n\n            calculateWithPathwayI(eCatTotal, eAniTotal);\n        }\n\n        \/\/ Ensure MathJax is typeset after updates\n        function renderMath() {\n            if (window.MathJax) {\n                MathJax.startup.promise.then(() => {\n                    MathJax.typesetPromise();\n                }).catch((err) => console.error('MathJax typeset failed: ', err));\n            }\n        }\n    <\/script>\n<\/body>\n<\/html>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The calculations used in this application are detailed in Charge balance calculations for mixed salt systems applied to a large dataset from the built environment | Scientific Data (nature.com). Use of this tool is at your own risk, and the accuracy of the results depends on the correctness of the data you enter. Users are &hellip;<\/p>\n<p class=\"read-more\"> <a class=\"\" href=\"https:\/\/predict.kikirpa.be\/index.php\/tools\/moisture-and-salt-sample-data-analysis-tool\/\"> <span class=\"screen-reader-text\">Salt Content Calculator<\/span> Read More &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":105,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"default","site-content-layout":"default","ast-global-header-display":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","footnotes":""},"class_list":["post-190040","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/pages\/190040","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/comments?post=190040"}],"version-history":[{"count":62,"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/pages\/190040\/revisions"}],"predecessor-version":[{"id":243174,"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/pages\/190040\/revisions\/243174"}],"up":[{"embeddable":true,"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/pages\/105"}],"wp:attachment":[{"href":"https:\/\/predict.kikirpa.be\/index.php\/wp-json\/wp\/v2\/media?parent=190040"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}