From 3cd13aa53e2a50e521be36a2e46e28df09b93421 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Sun, 1 Jan 2023 19:29:42 +0100 Subject: [PATCH] add massPercentage() (#7) * add massPercentage --- AtomicWeight.cpp | 105 +++++++++--------- AtomicWeight.h | 31 +++--- CHANGELOG.md | 10 +- README.md | 29 +++-- .../atomic_weight_massPercentage.ino | 79 +++++++++++++ keywords.txt | 1 + library.json | 2 +- library.properties | 2 +- test/unit_test_001.cpp | 35 +++++- 9 files changed, 216 insertions(+), 78 deletions(-) create mode 100644 examples/atomic_weight_massPercentage/atomic_weight_massPercentage.ino diff --git a/AtomicWeight.cpp b/AtomicWeight.cpp index a267cbf..58250de 100644 --- a/AtomicWeight.cpp +++ b/AtomicWeight.cpp @@ -2,7 +2,7 @@ // FILE: AtomicWeight.cpp // AUTHOR: Rob Tillaart // DATE: 2022-03-09 -// VERSION: 0.1.1 +// VERSION: 0.1.3 // PURPOSE: Arduino library for atomic weights // URL: https://github.com/RobTillaart/AtomicWeight @@ -144,7 +144,7 @@ elements[119] = }; -PTOE::PTOE(uint8_t size) +PTOE::PTOE(const uint8_t size) { _size = size; } @@ -156,51 +156,84 @@ uint8_t PTOE::size() } -uint8_t PTOE::electrons(uint8_t el) +uint8_t PTOE::electrons(const uint8_t el) { return el; } -uint8_t PTOE::neutrons(uint8_t el) +uint8_t PTOE::neutrons(const uint8_t el) { return round(weight(el) - el); } -uint8_t PTOE::protons(uint8_t el) +uint8_t PTOE::protons(const uint8_t el) { return el; } -float PTOE::weight(uint8_t el) +float PTOE::weight(const uint8_t el) { return elements[el].weight * _weightFactor; } -float PTOE::weight(const char * formula) +float PTOE::weight(const char * formula, const char * el) { - return weight((char*) formula); + p = (char *)formula; + return _weight('\0', el); } -float PTOE::weight(char * formula) +float PTOE::massPercentage(const char * formula, const char * el) { - p = formula; - return _weight('\0'); + float total = weight(formula); + if (total == 0) return 0; + p = (char *)formula; + return 100.0 * _weight('\0', el) / total; } -float PTOE::_weight(char sep) +char * PTOE::name(const uint8_t el) +{ + return elements[el].name; +} + + +uint8_t PTOE::find(const char * abbrev) +{ + // how about caching here? + for (uint8_t i = 0; i < _size; i++) + { + if (strcmp(elements[i].name, abbrev) == 0) return i; + } + return 255; +} + + +//////////////////////////////////////////////////////////////// +// +// DEBUG +// +float PTOE::weightFactor() +{ + return _weightFactor; +} + + +//////////////////////////////////////////////////////////////// +// +// PRIVATE +// +float PTOE::_weight(const char sep, const char * el) { float sum = 0; float w = 0; char elem[3] = { 0, 0, 0 }; int count = 0; - // char *p = formula; while (*p != sep) { w = 0; @@ -208,8 +241,7 @@ float PTOE::_weight(char sep) if (*p == '(') { p++; // skip '(' - w = _weight(')'); - // Serial.println(w); + w = _weight(')', el); p++; // skip ')' } else @@ -224,9 +256,13 @@ float PTOE::_weight(char sep) elem[1] = *p; p++; } - int z = find(elem); - if (z == 255) return 0; // fail - w = weight(z); + // can be optimized + if ((el == NULL) || (strcmp(elem, el) == 0)) + { + int z = find(elem); + if (z == 255) return 0; // fail + w = weight(z); + } } count = 0; @@ -249,38 +285,5 @@ float PTOE::_weight(char sep) } -char * PTOE::name(uint8_t el) -{ - return elements[el].name; -} - - -uint8_t PTOE::find(const char * abbrev) -{ - return find((char *) abbrev); -} - - -uint8_t PTOE::find(char * abbrev) -{ - for (uint8_t i = 0; i < _size; i++) - { - if (strcmp(elements[i].name, abbrev) == 0) return i; - } - return 255; -} - - -//////////////////////////////////////////////////////////////// -// -// DEBUG -// -float PTOE::weightFactor() -{ - return _weightFactor; -} - - - // -- END OF FILE -- diff --git a/AtomicWeight.h b/AtomicWeight.h index 1bfd2a7..78c2081 100644 --- a/AtomicWeight.h +++ b/AtomicWeight.h @@ -3,14 +3,14 @@ // FILE: AtomicWeight.h // AUTHOR: Rob Tillaart // DATE: 2022-03-09 -// VERSION: 0.1.2 +// VERSION: 0.1.3 // PURPOSE: Arduino library for atomic weights // URL: https://github.com/RobTillaart/AtomicWeight #include "Arduino.h" -#define ATOMIC_WEIGHT_LIB_VERSION (F("0.1.2")) +#define ATOMIC_WEIGHT_LIB_VERSION (F("0.1.3")) ///////////////////////////////////////////////////////////////////////// @@ -20,23 +20,26 @@ class PTOE { public: - PTOE(uint8_t size = 118); // all by default + PTOE(const uint8_t size = 118); // all by default uint8_t size(); - uint8_t electrons(uint8_t el); - uint8_t neutrons(uint8_t el); - uint8_t protons(uint8_t el); + uint8_t electrons(const uint8_t el); + uint8_t neutrons(const uint8_t el); + uint8_t protons(const uint8_t el); + // weight of one atom + float weight(const uint8_t el); - float weight(uint8_t el); - float weight(const char * formula); - float weight(char * formula); + // if (el != NULL) weights one element in a formula, e.g el == "H" + // if (el == NULL) weights the whole formula + float weight(const char * formula, const char * el = NULL); + + // mass percentage of one element in a formula. + float massPercentage(const char * formula, const char * el); - - char * name(uint8_t el); + char * name(const uint8_t el); uint8_t find(const char * abbrev); - uint8_t find(char * abbrev); // DEBUG @@ -47,11 +50,11 @@ class PTOE uint8_t _size; const float _weightFactor = 1.0 / 222.909; - float _weight(char sep); + // if (el == NULL) ==> whole weight otherwise only of element. + float _weight(char sep, const char * el); char *p; // for _weight(). }; - // -- END OF FILE -- diff --git a/CHANGELOG.md b/CHANGELOG.md index 208c5dd..33f014f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.1.3] - 2023-01-01 +- refactor interface +- add **weight(formula, element)** +- add **massPercentage(formula, element)** +- fix version number in .cpp +- update readme.md. +- update keywords.txt + + ## [0.1.2] - 2023-01-01 - add weight(formula) group () support - rewrote example - update readme.md. - add unit tests - ## [0.1.1] - 2022-12-30 - fix offset in some functions - move code to .cpp file diff --git a/README.md b/README.md index 9ce71c1..540cf1d 100644 --- a/README.md +++ b/README.md @@ -47,22 +47,27 @@ The parameter **element** in the following functions is 0..118. - **uint8_t protons(uint8_t element)** returns the number of protons of the element. - **float weight(uint8_t element)** returns the weight of the element. The error < 0.3%, table uses "weight compression". -- **float weight(char \* formula)** returns the weight of a molecule e.g. "H2O". -Returns 0 if it cannot parse the formula given. -Cannot parse complex formulas with brackets () in it. +- **float weight(char \* formula, char \* abbreviation == NULL)** see below. + - If (el != NULL) returns the total weight of one element in a formula + - if (el == NULL) returns the weight of the whole formula + - Returns 0 if it cannot parse the formula given. +- **float massPercentage(char \* formula, char \* abbreviation)** +Returns mass percentage of a selected element in a formula + - **uint8_t find(char \* abbreviation)** returns the element number. - **char \* name(uint8_t element)** returns the abbreviation of element. #### weight -The **weight(int n)** function returns the weight of a single atom. -The **weight(formula)** function is meant to calculate the weight of a molecule. +The **weight(int n)** call returns the weight of a single atom (by index). +The **weight(formula)** call is meant to calculate the weight of a molecule. +A molecule defined as one or more atoms. The latter function does not care about the order of the atoms. So "C6H6" is equal to "H6C6" or even "CCCCCCHHHHHH" or "C3H3C3H3" etc. -Elements are defined as 1 or two characters long. -The first must be uppercase, the second must be lowercase. +Elements are defined as one or two characters long. +The first must be upper case, the (optional) second must be lower case. If no number is provided the count of 1 is assumed. The functions returns a float, so to get the integer weight, one should use **round()**. @@ -80,6 +85,11 @@ Valid formula's might look as: - "C6(COOH)2" compound molecule, with repeating groups - "YBa2Cu3O7" some superconductor-ish material +(Since 0.1.3) +The **weight(formula, element)** function is meant to calculate the total weight of one element +in a molecule. E.g one can weigh the H atoms in H2O (2 of 18). + + #### debug @@ -109,12 +119,13 @@ See examples - liquid, gas, solid, unknown (2 bits per element) = ~30 bytes - (short) table of English names - which ones ? -- function **float massPercentage("H2O", "H")** ~10% - function **float atomicPercentage("H2O", "H")** ~33% - performance functions - especially **find()** ? - case (in)sensitive **find()** -- is there a faster data structure. +- is there a faster data structure? + - search by nr is O(1) + - search by name is O(n) #### wont (unless) diff --git a/examples/atomic_weight_massPercentage/atomic_weight_massPercentage.ino b/examples/atomic_weight_massPercentage/atomic_weight_massPercentage.ino new file mode 100644 index 0000000..0ff3b33 --- /dev/null +++ b/examples/atomic_weight_massPercentage/atomic_weight_massPercentage.ino @@ -0,0 +1,79 @@ +// FILE: atomic_weight_formula.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo +// URL: https://github.com/RobTillaart/AtomicWeight + +#include "Arduino.h" +#include "AtomicWeight.h" + + +PTOE ptoe; + +char formula0[24] = "C6H6O6"; +char formula1[24] = "((COH)3)2"; +char formula2[24] = "H2SO4"; +char formula3[24] = "CuO2"; +// char formula4[24] = "(COH)3(COH)2COH"; +// char formula4[24] = "(CH)6O6"; +char formula4[24] = "xH2"; // fails => 0; + + + +void setup() +{ + Serial.begin(115200); + while (!Serial); + Serial.println(__FILE__); + Serial.print("ATOMIC_WEIGHT_LIB_VERSION: "); + Serial.println(ATOMIC_WEIGHT_LIB_VERSION); + + Serial.print("C"); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage("C", "C")); + + Serial.print("C6"); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage("C6", "C")); + + Serial.print("He6"); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage("He6", "C")); + + Serial.print("NaCl"); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage("NaCl", "Na")); + + Serial.print("NaCl"); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage("NaCl", "Cl")); + + Serial.print(formula0); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage(formula0, "H")); + + Serial.print(formula1); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage(formula1, "H")); + + Serial.print(formula2); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage(formula2, "H")); + + Serial.print(formula3); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage(formula3, "H")); + + Serial.print(formula4); + Serial.print(" \t"); + Serial.println(ptoe.massPercentage(formula4, "H")); + +} + + +void loop() +{ +} + + + +// -- END OF FILE -- diff --git a/keywords.txt b/keywords.txt index 3b1a0de..c3339ca 100644 --- a/keywords.txt +++ b/keywords.txt @@ -12,6 +12,7 @@ electrons KEYWORD2 protons KEYWORD2 neutrons KEYWORD2 weight KEYWORD2 +massPercentage KEYWORD2 name KEYWORD2 find KEYWORD2 diff --git a/library.json b/library.json index d69d8fd..b02fbe6 100644 --- a/library.json +++ b/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/AtomicWeight.git" }, - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/library.properties b/library.properties index bf457f6..1276871 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AtomicWeight -version=0.1.2 +version=0.1.3 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for AtomicWeight diff --git a/test/unit_test_001.cpp b/test/unit_test_001.cpp index 951e92d..ac6e1e4 100644 --- a/test/unit_test_001.cpp +++ b/test/unit_test_001.cpp @@ -111,7 +111,7 @@ unittest(test_basic_atom) } -unittest(test_weight_formula) +unittest(test_weight_formula_I) { PTOE ptoe; assertEqualFloat( 22.9914, ptoe.weight("Na"), 0.1); @@ -124,6 +124,39 @@ unittest(test_weight_formula) } +unittest(test_weight_formula_II) +{ + PTOE ptoe; + assertEqualFloat( 22.9914, ptoe.weight("NaCl", "Na"), 0.1); + assertEqualFloat( 35.4539, ptoe.weight("NaCl", "Cl"), 0.1); + + assertEqualFloat( 40.0791, ptoe.weight("CaCO3", "Ca"), 0.1); + assertEqualFloat( 12.0094, ptoe.weight("CaCO3", "C"), 0.1); + assertEqualFloat( 47.9927, ptoe.weight("CaCO3", "O"), 0.1); + + assertEqualFloat( 12.0094, ptoe.weight("C(O(H2)2)3", "C"), 0.1); + assertEqualFloat( 47.9927, ptoe.weight("C(O(H2)2)3", "O"), 0.1); + assertEqualFloat( 12.1126, ptoe.weight("C(O(H2)2)3", "H"), 0.1); +} + + +unittest(test_massPercentage) +{ + PTOE ptoe; + assertEqualFloat( 100.000, ptoe.massPercentage("Cl2", "Cl"), 0.1); + assertEqualFloat( 39.3383, ptoe.massPercentage("NaCl", "Na"), 0.1); + assertEqualFloat( 60.6617, ptoe.massPercentage("NaCl", "Cl"), 0.1); + + assertEqualFloat( 40.0466, ptoe.massPercentage("CaCO3", "Ca"), 0.1); + assertEqualFloat( 11.9996, ptoe.massPercentage("CaCO3", "C"), 0.1); + assertEqualFloat( 47.9537, ptoe.massPercentage("CaCO3", "O"), 0.1); + + assertEqualFloat( 16.6532, ptoe.massPercentage("C(O(H2)2)3", "C"), 0.1); + assertEqualFloat( 66.5505, ptoe.massPercentage("C(O(H2)2)3", "O"), 0.1); + assertEqualFloat( 16.7963, ptoe.massPercentage("C(O(H2)2)3", "H"), 0.1); +} + + unittest_main()