0.3.0 AtomicWeight

This commit is contained in:
Rob Tillaart 2024-08-27 18:21:02 +02:00
parent 6391a6afcc
commit a1e696709e
10 changed files with 315 additions and 70 deletions

View File

@ -2,7 +2,7 @@
// FILE: AtomicWeight.cpp
// AUTHOR: Rob Tillaart
// DATE: 2022-03-09
// VERSION: 0.2.2
// VERSION: 0.3.0
// PURPOSE: Arduino library for atomic weights
// URL: https://github.com/RobTillaart/AtomicWeight
@ -98,6 +98,17 @@ float PTOE::massPercentage(const char * formula, const char * abbrev)
}
float PTOE::weightEV(const uint8_t element)
{
return weight(element) * DALTON2EV;
}
float PTOE::weightEV(const char * formula, const char * abbrev)
{
return weight(formula, abbrev) * DALTON2EV;
}
////////////////////////////////////////////////////////////////
//
@ -115,6 +126,12 @@ float PTOE::grams2moles(const char * formula, float grams)
}
float PTOE::dalton2EV(float Dalton)
{
return Dalton * DALTON2EV;
}
////////////////////////////////////////////////////////////////
//
// SPLIT FORMULA IN ELEMENTS
@ -245,7 +262,7 @@ float PTOE::_weight(const char separator, const char * abbrev)
float sum = 0;
float w = 0;
char elem[3] = { 0, 0, 0 };
uint32_t count = 0;
float count = 0;
while (*p != separator)
{
@ -285,6 +302,17 @@ float PTOE::_weight(const char separator, const char * abbrev)
count = count * 10 + (*p - '0');
p++;
}
if (*p == '.') // floating point numbers
{
p++; // skip decimal .
float divider = 0.1;
while (isdigit(*p))
{
count += (*p - '0') * divider;
divider *= 0.1;
p++;
}
}
// correct for no digits
if (count == 0) count = 1;
@ -297,11 +325,11 @@ float PTOE::_weight(const char separator, const char * abbrev)
}
uint32_t PTOE::_count(const char separator, const char * abbrev)
float PTOE::_count(const char separator, const char * abbrev)
{
uint32_t sum = 0;
float sum = 0;
char elem[3] = { 0, 0, 0 };
uint32_t count = 0;
float count = 0;
int w = 0;
while (*p != separator)
@ -342,6 +370,17 @@ uint32_t PTOE::_count(const char separator, const char * abbrev)
count = count * 10 + (*p - '0');
p++;
}
if (*p == '.') // floating point numbers
{
p++; // skip decimal .
float divider = 0.1;
while (isdigit(*p))
{
count += (*p - '0') * divider;
divider *= 0.1;
p++;
}
}
// correct for no digits
if (count == 0) count = 1;

View File

@ -3,7 +3,7 @@
// FILE: AtomicWeight.h
// AUTHOR: Rob Tillaart
// DATE: 2022-03-09
// VERSION: 0.2.2
// VERSION: 0.3.0
// PURPOSE: Arduino library for atomic weights
// URL: https://github.com/RobTillaart/AtomicWeight
@ -11,7 +11,7 @@
#include "Arduino.h"
#define ATOMIC_WEIGHT_LIB_VERSION (F("0.2.2"))
#define ATOMIC_WEIGHT_LIB_VERSION (F("0.3.0"))
#ifndef ATOMIC_WEIGHT_MAX_SPLIT_LIST
@ -20,13 +20,12 @@
// Miscellaneous related constants.
const float AVOGADRO = 6.02214076e+23; // 1.0 / DALTON.
const float DALTON = 1.66053907e-24; // weight in grams of one nucleon.
const float ELEKTRON_VOLT_JOULE = 1.602176565e-19; // eV in Joule
const float ELEKTRON_VOLT_GRAM = 1.7826619e-39; // eV in grams
const float DALTON_EV = DALTON / ELEKTRON_VOLT_GRAM;
const float DALTON_JOULE = DALTON / ELEKTRON_VOLT_JOULE;
const float AVOGADRO = 6.02214076e+23; // 1.0 / DALTON.
const float DALTON = 1.66053907e-24; // weight in grams of one nucleon.
const float PROTON_WEIGHT = 1.6726231e-24; //
const float NEUTRON_WEIGHT = 1.6749286e-24; //
const float ELECTRON_WEIGHT = 9.10938356e-28; // weight in grams of one electron.
const float DALTON2EV = 931494697.25613; //
/////////////////////////////////////////////////////////////////////////
@ -41,31 +40,33 @@ public:
// BASIC
char * name(const uint8_t element);
uint8_t find(const char * abbrev);
char * name(const uint8_t element);
uint8_t find(const char * abbrev);
uint8_t electrons(const uint8_t element);
uint8_t neutrons(const uint8_t element);
uint8_t protons(const uint8_t element);
uint8_t electrons(const uint8_t element);
uint8_t neutrons(const uint8_t element);
uint8_t protons(const uint8_t element);
// WEIGHT of one atom
float weight(const uint8_t element);
float weight(const uint8_t element);
// if (element != NULL) weights one element in a formula, e.g element == "H"
// if (element == NULL) weights the whole formula
float weight(const char * formula, const char * abbrev = NULL);
float weight(const char * formula, const char * abbrev = NULL);
// mass percentage of one element in a formula.
float massPercentage(const char * formula, const char * abbrev);
float massPercentage(const char * formula, const char * abbrev);
// mass in electron volt
float weightEV(const uint8_t element);
float weightEV(const char * formula, const char * abbrev = NULL);
// CONVERSION
float moles2grams(const char * formula, float moles = 1.0);
float grams2moles(const char * formula, float grams = 1.0);
float moles2grams(const char * formula, float moles = 1.0);
float grams2moles(const char * formula, float grams = 1.0);
float dalton2EV(float Dalton);
// SPLIT FORMULA IN ELEMENTS
uint8_t splitElements(const char * formula);
uint8_t element(uint8_t element);
uint8_t splitElements(const char * formula);
uint8_t element(uint8_t element);
// COUNT
@ -73,7 +74,7 @@ public:
// if (element == NULL) count all atoms in the whole formula
uint32_t count(const char * formula, const char * element = NULL);
// atom percentage of one element in a formula.
float atomPercentage(const char * formula, const char * element);
float atomPercentage(const char * formula, const char * element);
// DEBUG
@ -85,7 +86,7 @@ private:
// if (element == NULL) ==> whole weight otherwise only of element.
float _weight(char separator, const char * abbrev);
uint32_t _count(const char separator, const char * abbrev);
float _count(const char separator, const char * abbrev);
char *p; // for _weight() and _count()
// for splitElements

View File

@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.3.0] - 2024-08-27
- support float indices e.g. "(Mg0.4Fe1.6)2.0SiO4" == Olivine
- update **atomic_weight_formula.ino**
- add **minerals.h** (short list)
- add **atomic_weight_minerals.ino**
- update / clean up constants
- add **weightEV()**
- add **weightEV()**
- add **dalton2EV()**
- update readme.md
----
## [0.2.2] - 2024-04-07
- update GitHub actions
- refactor internal names for readability

View File

@ -11,11 +11,13 @@
# AtomicWeight
Arduino library for atomic weights, and related functions.
Arduino library for atomic weights from the periodic table of elements, and related functions.
## Description
**Experimental**
This library is mainly written to be used for educational purposes.
Of course are other applications possible.
Learning the **periodic table of elements**, the abbreviations and weights.
@ -45,7 +47,7 @@ Another application for the conversion functions is create lookup-tables, see ex
Note: the library is experimental. More testing is needed. Feedback welcome.
#### Internal
### Internal
The PTOE class uses a table with "scaled" weights to save RAM.
- it stores weights as **uint16_t**, instead of floats (saves 236 bytes).
@ -57,13 +59,12 @@ The PTOE class uses a table with "scaled" weights to save RAM.
- relative error per element is less than 0.09% (~40% better than previous 0.15%).
- **Breaking:** numbers are **not** compatible with 0.1.x version
**Version 0.1.x (for reference)**
- ATOMIC_WEIGHT_FACTOR = 1.0 / 222.909 == weight heaviest element(118) / 65535.
- relative error per element is less than 0.15%.
#### Related
### Related
List of formulae to play with.
- https://en.wikipedia.org/wiki/Glossary_of_chemical_formulae
@ -105,7 +106,7 @@ Note: the find function is case sensitive.
If the element is out of range **NULL** will be returned.
#### SplitElements
### SplitElements
- **uint8_t splitElements(const char \* formula)** split a formula in an internal list of elements.
Returns the number of different elements found.
@ -126,7 +127,7 @@ for (int i = 0; i < nr; i++)
}
```
#### AtomPercentage
### AtomPercentage
- **uint32_t count(const char \* formula, const char \* abbreviation = NULL)**
- If (abbreviation != NULL) returns the total atoms of one element in a formula.
@ -141,7 +142,7 @@ ap = PTOE.atomPercentage("H2SO4", "O");
```
#### Conversion grams moles
### Conversion grams moles
- **float moles2grams(const char \* formula, float moles = 1.0)**
Returns the amount of grams needed for a given amount of moles.
@ -158,7 +159,7 @@ grams = PTOE.moles2grams("KOH", 2.3);
```
#### Weight
### Weight
The unit of weight is **Daltons** (Da) or the atomic mass unit (amu), think of it as the number of nucleons.
A **Dalton** is defined as 1/12th of the weight of an Carbon atom.
@ -179,13 +180,19 @@ E.g one can weigh the H atoms in H2O (2 of 18).
aw = PTOE.weight("H2O", "H");
```
0.3.0 added conversion of weights to electronVolts.
#### Formulas
- **float weightEV(uint8_t element)**
- **float weightEV(char \* formula, char \* abbrev = NULL)**
### Formulas
All element abbreviations are one or two characters long.
The first char must be upper case, the (optional) second must be lower case.
(except for element 0, n == neutronium, which is added as placeholder).
Elements can be followed by a number indicating an amount, no number implies 1.
Since 0.3.0 these numbers may be floats (as such formulae can be found in minerals).
Formulas do not care about the order of the atoms.
So "C6H6" is equal to "H6C6" or even "CCCCCCHHHHHH" or "C3H3C3H3" etc.
@ -193,52 +200,54 @@ So "C6H6" is equal to "H6C6" or even "CCCCCCHHHHHH" or "C3H3C3H3" etc.
The formula parsing supports round brackets () to indicate groups in the formula.
The library does **not** support square brackets to indicate a group.
The library does **not** support \*6H20 to indicate hydration.
The library does **not** support e.g. \*6H20 to indicate hydration.
Valid formula's might look like:
- "B" = single element, Hydrogen, 1 atom.
- "Na" = single element, Sodium, 1 atom..
- "Na" = single element, Sodium, 1 atom.
- "C6" = single element, multiple times, Benzene.
- "H2SO4" = compound molecule, no groups (sulphuric acid).
- "C6(COOH)2" = repeating group, (artificial example).
- "(H2O)987" = 987 water molecules.
- "YBa2Cu3O7" = compound molecule, == some superconductor-ish material.
- "Ba((OH)4(COOH)2)3" - recursive repeating groups (artificial example).
- "(Mg0.4Fe1.6)2.0SiO4" == Olivine, float indices
Numbers of an element or a group should be between 1 and 2^32-1 (uint32_t).
However in practice values are relative small (< 20).
In theory the numbers of an element or a group should be between 1 and 2^20 (float).
In practice however, the values used are relative small (< 100 or 1000).
- zero (0) is mapped upon 1.
- very large numbers cause overflow when printing the output of some functions.
Use - https://github.com/RobTillaart/printHelpers if needed.
#### MassPercentage
### MassPercentage
The **massPercentage(formula, abbreviation)** function can determine the percentage of the weight
a selected element has in a formula, e.g. the weight of the Oxygen in **H2SO4**.
This is calculated by dividing the weight of the element by the total weight.
```cpp
mp = PTOE.massPercentage("H2SO4", "O");
float mp = PTOE.massPercentage("H2SO4", "O");
```
If you want to do that for all elements it might be more efficient to calculate the weight
of the whole formula once.
#### Avogadro, Dalton, electronVolt.
### Avogadro, Dalton, electronVolt.
The library provides the following (SI) constants:
- **const float AVOGADRO = 6.02214076e+23** number of particles in one mole.
- **const float DALTON = 1.66053907e-24** weight of one nucleon in grams.
- **const float DALTON = 1.66053907e-24** weight of one nucleon in grams (average).
- relation: DALTON \* AVOGADRO == 1.0
- **const float ELEKTRON_VOLT_JOULE = 1.602176565e-19** eV in Joule
- **const float ELEKTRON_VOLT_GRAM = 1.7826619e-39** eV in grams (E=Mc2)
- **const float DALTON_JOULE = 1.036427015e5** == DALTON / ELEKTRON_VOLT_JOULE.
- **const float DALTON_EV = 931.4940954e12** == DALTON / ELEKTRON_VOLT_GRAM.
- **const float PROTON_WEIGHT = 1.6726231e-24** weight in grams of an proton.
- **const float NEUTRON_WEIGHT = 1.6749286e-24** weight in grams of an neutron.
- **const float ELECTRON_WEIGHT = 9.10938356e-28** weight in grams of one electron.
- **const float DALTON2EV = 931494697.25613** e.g. 1 proton = 931 MeV.
Can be used to convert the atomic mass to electron volt.
These constants are not directly used in the library however they fit the scope of the library.
These constants are not all used in the library however they fit the scope of the library.
There will be functions based upon these constants in the future.
The **AVOGADRO** constant is the proportionality factor that relates the number of constituent particles
@ -250,7 +259,7 @@ Use https://github.com/RobTillaart/printHelpers to print numbers in the scientif
This will prevent printing **OVF** overflow or **0.000**.
#### Debug
### Debug
- **float weightFactor()** returns the weightFactor, that was used to
minimize the memory used for the elements mass lookup table.
@ -260,11 +269,8 @@ minimize the memory used for the elements mass lookup table.
#### Must
- improve documentation
- reorganize.
- float => double
- EV is at the end of range float...
- improve and reorganize documentation
- float => double for precision.
#### Should
@ -272,15 +278,12 @@ minimize the memory used for the elements mass lookup table.
- **uint32_t protons(formula)** worker, formula can be single element.
- **uint32_t neutrons(formula)** uses protons()
- **uint32_t electrons(formula)** uses protons()
- add weight of electron as constant. for completeness.
- functions around **AVOGADRO**, **DALTON** etc.
- **float weightEV(formula)**
- **float dalton2EV(float Dalton)** to express mass in eV.
- **float dalton2Joule(float Dalton)**
- handle Fe2+ Fe3+ (ignore number when encountering +)
#### Could
- support progmem formulas **weight(F("CaO2"))**?
- user could use a char buffer to copy.
- extend unit tests
- extend formula parser with error codes.
- which ones?
@ -292,6 +295,9 @@ minimize the memory used for the elements mass lookup table.
- ==> more memory...
- support \[] square brackets too.
- (NH4)2\[Pt(SCN)6]
- support spaces for readability?
- "Ba (OH)4 (COOH)11 SiO4" ==> after last digit
- special print function for formulae
- add a derived class PERIODIC_TABLE?
@ -326,6 +332,7 @@ minimize the memory used for the elements mass lookup table.
- evaporate point
- 2 bytes per temp 4 x 118 = 476 bytes
- compression 3 bytes for 2 temps 2x 12 bits = 0..4095 K = 354 bytes
- exponential notation floats? (H2O)1e30
## Support

View File

@ -17,6 +17,8 @@ char formula3[24] = "CuO2";
char formula4[24] = "(COH)3(COH)2COH";
char formula5[24] = "(CH)6O6";
char formula6[24] = "xH2"; // fails => 0;
char formula7[24] = "(CuO2)0.25";
char formula8[24] = "(Mg0.4Fe1.6)2.0SiO4"; // Olivine mineral
void setup()
@ -71,6 +73,14 @@ void setup()
Serial.print(" \t");
Serial.println(ptoe.weight(formula6));
Serial.print(formula7);
Serial.print(" \t");
Serial.println(ptoe.weight(formula7));
Serial.print(formula8);
Serial.print(" \t");
Serial.println(ptoe.weight(formula8));
Serial.print("()");
Serial.print(" \t");
Serial.println(ptoe.weight("()"));
@ -82,6 +92,10 @@ void setup()
Serial.print("(H2O)255");
Serial.print(" \t");
Serial.println(ptoe.weight("(H2O)255"));
Serial.print("(H2O)255.0");
Serial.print(" \t");
Serial.println(ptoe.weight("(H2O)255.0"));
}

View File

@ -0,0 +1,76 @@
// FILE: atomic_weight_minerals.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/AtomicWeight
#include "Arduino.h"
#include "AtomicWeight.h"
#include "minerals.h"
PTOE ptoe;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
Serial.println();
Serial.println("NAME\tWEIGHT\tFORMULA\n");
printMineral("ALBITE", ALBITE);
printMineral("ANORTHITE", ANORTHITE);
printMineral("MICROLINE", MICROLINE);
printMineral("QUARTZ", QUARTZ);
printMineral("NEPHELINE", NEPHELINE);
printMineral("KALSILITE", KALSILITE);
printMineral("LEUCITE", LEUCITE);
printMineral("AEGIRINE", AEGIRINE);
printMineral("SODALITE", SODALITE);
printMineral("ENSTATITE", ENSTATITE);
printMineral("FERROSILITE", FERROSILITE);
printMineral("PIGEONITE", PIGEONITE);
printMineral("DIOPSIDE", DIOPSIDE);
printMineral("WOLLASTONITE", WOLLASTONITE);
printMineral("TREMOLITE", TREMOLITE);
printMineral("MUSCOVITE", MUSCOVITE);
printMineral("PHOLOGOPITE", PHOLOGOPITE);
printMineral("FORSTERITE", FORSTERITE);
printMineral("FAYALITE", FAYALITE);
printMineral("ZIRCON", ZIRCON);
printMineral("AKERMANITE", AKERMANITE);
printMineral("MAGNETITE", MAGNETITE);
printMineral("ULVOSPINEL", ULVOSPINEL);
printMineral("ILMENITE", ILMENITE);
printMineral("SPINEL", SPINEL);
printMineral("CHROMITE", CHROMITE);
printMineral("HEMATITE", HEMATITE);
printMineral("CORUNDUM", CORUNDUM);
printMineral("RUTILE", RUTILE);
printMineral("URANINITE", URANINITE);
printMineral("PYRITE", PYRITE);
printMineral("CHALCOPYRITE", CHALCOPYRITE);
printMineral("HYDROXYAPATITE", HYDROXYAPATITE);
Serial.println("\ndone...");
}
void loop()
{
}
void printMineral(char * name, char * formula)
{
Serial.print(name);
Serial.print("\t");
Serial.print(ptoe.weight(formula));
Serial.print("\t");
Serial.println(formula);
}
// -- END OF FILE --

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/AtomicWeight.git"
},
"version": "0.2.2",
"version": "0.3.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=AtomicWeight
version=0.2.2
version=0.3.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for atomic weights, calculate massPercentage of elements in a formula.

View File

@ -0,0 +1,95 @@
#pragma once
//
// FILE: minerals.h
// AUTHOR: Rob Tillaart
// DATE: 2024-08-12
// PURPOSE: very short list of chemical formulae of minerals
// URL: https://github.com/RobTillaart/AtomicWeight
//
/////////////////////////////////////////////////////////////////////////
//
// The formulae are based upon Cornelis Klein, Anthony Philpotts book
// Earth Materials, introduction to Mineralogy and Petrology, chapter 7
// ISBN: 978-1-316-60885-2
//
// NOT SUPPORTED: ==> formulae commented
// NOT SUPPORTED: Fe2+ or Fe3+ (potential, could be ignored!)
// NOT SUPPORTED: comma operator (selection, should be made explicit)
// NOT SUPPORTED: Fe1-x (less than 1, should be made explicit)
//
// to be extended,
//
// 7.5
#define ALBITE "NaAlSi3O8"
#define ANORTHITE "CaAl2Si2O8"
// 7.6
#define MICROLINE "KAlSi3O8" // Orthoclase
// 7.7
#define QUARTZ "SiO2"
// 7.8
#define NEPHELINE "(Na3K)Al4(SiO4)"
#define KALSILITE "KAlSiO4"
// 7.9
#define LEUCITE "KAlSi2O6"
#define AEGIRINE "NaFeSi2O6" // 7.14
// 7.10
#define SODALITE "Na4Al3Si3O12Cl"
// 7.11
#define ENSTATITE "MgSiO3" // "(Mg1.0Fe0.0)SiO3"
#define FERROSILITE "FeSiO3" // "(Mg0.5Fe0.5)SiO3"
// 7.12
#define PIGEONITE "Ca0.25(MgFe)1.75Si2O6"
// 7.13
#define DIOPSIDE "CaMgSi2O6"
#define WOLLASTONITE "CaSiO3"
// 7.15
#define TREMOLITE "Ca2Mg5Si8O22(OH)2"
// 7.16
#define MUSCOVITE "KAl3Si3O10(OH)2"
// 7.17
#define PHOLOGOPITE "KMg3(AlSi3O10)(OH)2"
// 7.18
// #define BIOTITE "K(Mg,Fe)3(AlSi3O10)(OH)2"
// 7.19
// #define OLIVINE "(Mg,Fe)2SiO4"
#define FORSTERITE "Mg2SiO4"
#define FAYALITE "Fe2SiO4"
// 7.20
#define ZIRCON "ZrSiO4"
// 7.21
// #define TOUMALINE "(Na,Ca,K)(Fe,Mg,Al,Mn,Li)3(Al,Fe)6(BO3)3(Si6O18)(OH)3(O,OH,F)"
// #define SCHORL "(NaFe3Al6(BO3)3(Si6O18)(OH)3(O,OH,F)4"
// 7.22
// #define ALLANITE "(Ca,Ce)2(Al,Fe++,Fe+++)3(SiO4)(Si2O7)(OH)"
// 7.23
// #define MELITITE "(Ca,Na)2(Mg,Al)(Si,Al)2O7"
#define AKERMANITE "Ca2MgSi2O7"
// 7.24
#define MAGNETITE "Fe3O4"
#define ULVOSPINEL "Fe2TiO4"
#define ILMENITE "FeTiO3" // 7.27
#define SPINEL "MgAl2O4"
// 7.25
#define CHROMITE "FeCr2O4"
// 7.26
#define HEMATITE "Fe2O3"
#define CORUNDUM "Al2O3"
// 7.28
#define RUTILE "TiO2"
// 7.29
#define URANINITE "UO2"
// 7.30
#define PYRITE "FeS2"
// 7.31
// #define PYRRHOTITE "Fe1-xS" // x = 0..0.2
// 7.32
#define CHALCOPYRITE "CuFeS2"
// 7.33
// #define APATITE "Ca5(PO4)3(OH,F,Cl)
#define HYDROXYAPATITE "Ca5(PO4)3(OH)"
// -- END OF FILE --

View File

@ -52,10 +52,10 @@ unittest(test_constants)
assertEqualFloat(1.66053907e-24, DALTON, 1e-30);
assertEqualFloat(1.0, DALTON * AVOGADRO, 1e-5);
assertEqualFloat(1.602176565e-19, ELEKTRON_VOLT_JOULE, 1e-5);
assertEqualFloat(1.7826619e-39, ELEKTRON_VOLT_GRAM, 1e-5);
assertEqualFloat(DALTON / ELEKTRON_VOLT_GRAM, DALTON_EV, 1e-5);
assertEqualFloat(DALTON / ELEKTRON_VOLT_JOULE, DALTON_JOULE, 1e-5);
assertEqualFloat(1.6726231E-24, PROTON_WEIGHT, 1e-30);
assertEqualFloat(1.6749286E-24, NEUTRON_WEIGHT, 1e-30);
assertEqualFloat(9.10938356e-28, ELECTRON_WEIGHT, 1e-34);
assertEqualFloat(931494697.25613, DALTON2EV, 1e2);
}