2022-12-31 12:30:42 -05:00
|
|
|
//
|
|
|
|
// FILE: AtomicWeight.cpp
|
|
|
|
// AUTHOR: Rob Tillaart
|
|
|
|
// DATE: 2022-03-09
|
2023-04-15 14:15:18 -04:00
|
|
|
// VERSION: 0.2.0
|
2022-12-31 12:30:42 -05:00
|
|
|
// PURPOSE: Arduino library for atomic weights
|
|
|
|
// URL: https://github.com/RobTillaart/AtomicWeight
|
|
|
|
|
|
|
|
|
|
|
|
#include "AtomicWeight.h"
|
2023-04-15 14:15:18 -04:00
|
|
|
#include "elements_uint16.h"
|
2022-12-31 12:30:42 -05:00
|
|
|
|
|
|
|
|
2023-04-15 14:15:18 -04:00
|
|
|
PTOE::PTOE(const uint8_t size)
|
|
|
|
{
|
|
|
|
_size = size;
|
|
|
|
_found = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
2022-12-31 12:30:42 -05:00
|
|
|
//
|
2023-04-15 14:15:18 -04:00
|
|
|
// BASIC
|
2022-12-31 12:30:42 -05:00
|
|
|
//
|
2023-04-15 14:15:18 -04:00
|
|
|
uint8_t PTOE::size()
|
|
|
|
{
|
|
|
|
return _size;
|
|
|
|
}
|
2022-12-31 12:30:42 -05:00
|
|
|
|
|
|
|
|
2023-04-15 14:15:18 -04:00
|
|
|
char * PTOE::name(const uint8_t el)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
// catch out of range.
|
|
|
|
if (el > _size) return NULL;
|
|
|
|
return elements[el].name;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-15 14:15:18 -04:00
|
|
|
uint8_t PTOE::find(const char * abbrev)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
// case insensitive?
|
|
|
|
// caching?
|
|
|
|
// param check?
|
|
|
|
// uint8_t len = strlen(abbrev);
|
|
|
|
// if ((len == 1) || (len == 2))
|
|
|
|
// {
|
|
|
|
for (uint8_t i = 0; i < _size; i++)
|
|
|
|
{
|
|
|
|
if (strcmp(elements[i].name, abbrev) == 0) return i;
|
|
|
|
}
|
|
|
|
// }
|
|
|
|
return 255;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-02 07:02:36 -05:00
|
|
|
uint8_t PTOE::electrons(const uint8_t el)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
return el;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-02 07:02:36 -05:00
|
|
|
uint8_t PTOE::neutrons(const uint8_t el)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
return round(weight(el)) - el;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-02 07:02:36 -05:00
|
|
|
uint8_t PTOE::protons(const uint8_t el)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
return el;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-15 14:15:18 -04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// WEIGHT
|
|
|
|
//
|
2023-01-02 07:02:36 -05:00
|
|
|
float PTOE::weight(const uint8_t el)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
if (el > _size) return 0; // catch out of range.
|
|
|
|
return elements[el].weight * ATOMIC_WEIGHT_FACTOR;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-14 07:34:00 -04:00
|
|
|
float PTOE::weight(const char * formula, const char * abbrev)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
p = (char *)formula;
|
|
|
|
return _weight('\0', abbrev);
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-14 07:34:00 -04:00
|
|
|
float PTOE::massPercentage(const char * formula, const char * abbrev)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
float total = weight(formula);
|
|
|
|
if (total == 0) return 0;
|
|
|
|
p = (char *)formula;
|
|
|
|
return 100.0 * _weight('\0', abbrev) / total;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-02 07:02:36 -05:00
|
|
|
|
2023-04-14 07:34:00 -04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// CONVERSION
|
|
|
|
//
|
|
|
|
float PTOE::moles2grams(const char * formula, float moles)
|
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
return moles * weight(formula);
|
2023-04-14 07:34:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float PTOE::grams2moles(const char * formula, float grams)
|
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
return grams / weight(formula);
|
2023-04-14 07:34:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-02 07:02:36 -05:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2023-04-15 14:15:18 -04:00
|
|
|
// SPLIT FORMULA IN ELEMENTS
|
2023-01-02 07:02:36 -05:00
|
|
|
//
|
2023-04-15 14:15:18 -04:00
|
|
|
uint8_t PTOE::splitElements(const char * formula)
|
|
|
|
{
|
|
|
|
uint8_t count = 0;
|
|
|
|
char elem[3] = { 0, 0, 0 };
|
|
|
|
|
|
|
|
char * p = (char *) formula;
|
|
|
|
while (*p != '\0')
|
|
|
|
{
|
|
|
|
// SKIP non element info
|
|
|
|
if (*p == '(')
|
|
|
|
{
|
|
|
|
p++; // skip '('
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*p == ')')
|
|
|
|
{
|
|
|
|
p++; // skip ')'
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (isdigit(*p))
|
2023-01-02 07:02:36 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
p++; // skip digit
|
|
|
|
continue;
|
2023-01-02 07:02:36 -05:00
|
|
|
}
|
|
|
|
|
2023-04-15 14:15:18 -04:00
|
|
|
// GET ELEMENT := [ Upper | Upper,lower ]
|
|
|
|
elem[0] = 0;
|
|
|
|
elem[1] = 0;
|
|
|
|
if (! isupper(*p)) return 0; // fail
|
|
|
|
elem[0] = *p;
|
|
|
|
p++;
|
|
|
|
if (islower(*p))
|
|
|
|
{
|
|
|
|
elem[1] = *p;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
// FIND INDEX OF ELEMENT
|
|
|
|
int z = find(elem);
|
|
|
|
if (z == 255)
|
|
|
|
{
|
|
|
|
return 0; // fail
|
|
|
|
}
|
2023-01-02 07:02:36 -05:00
|
|
|
|
2023-04-15 14:15:18 -04:00
|
|
|
// DO WE HAVE IDENTIFIED IT ALREADY?
|
|
|
|
bool found = false;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
if (_splitList[i] == z)
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((found == false) && (count < ATOMIC_WEIGHT_MAX_SPLIT_LIST))
|
2023-04-12 10:52:57 -04:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
_splitList[count] = z;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// // DEBUG
|
|
|
|
// for (int i = 0; i < count; i++)
|
|
|
|
// {
|
|
|
|
// Serial.print(i);
|
|
|
|
// Serial.print('\t');
|
|
|
|
// Serial.print(_splitList[i]);
|
|
|
|
// Serial.print('\t');
|
|
|
|
// Serial.println(name(_splitList[i]));
|
|
|
|
// }
|
|
|
|
|
|
|
|
_found = count;
|
|
|
|
return count;
|
2023-04-12 10:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t PTOE::element(uint8_t el)
|
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
if (el >= _found) return 255;
|
|
|
|
return _splitList[el];
|
2023-04-12 10:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-15 14:15:18 -04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// COUNT
|
|
|
|
//
|
2023-04-12 10:52:57 -04:00
|
|
|
uint32_t PTOE::count(const char * formula, const char * el)
|
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
p = (char *)formula;
|
|
|
|
return _count('\0', el);
|
2023-04-12 10:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float PTOE::atomPercentage(const char * formula, const char * el)
|
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
float total = count(formula);
|
|
|
|
if (total == 0) return 0;
|
|
|
|
p = (char *)formula;
|
|
|
|
return 100.0 * _count('\0', el) / total;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// DEBUG
|
|
|
|
//
|
|
|
|
float PTOE::weightFactor()
|
|
|
|
{
|
|
|
|
return ATOMIC_WEIGHT_FACTOR;
|
2023-04-12 10:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-02 07:02:36 -05:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// PRIVATE
|
|
|
|
//
|
2023-04-14 07:34:00 -04:00
|
|
|
float PTOE::_weight(const char sep, const char * abbrev)
|
2022-12-31 12:30:42 -05:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
float sum = 0;
|
|
|
|
float w = 0;
|
|
|
|
char elem[3] = { 0, 0, 0 };
|
|
|
|
uint32_t count = 0;
|
|
|
|
|
|
|
|
while (*p != sep)
|
|
|
|
{
|
|
|
|
w = 0;
|
|
|
|
// HANDLE GROUP (...)
|
|
|
|
if (*p == '(')
|
|
|
|
{
|
|
|
|
p++; // skip '('
|
|
|
|
w = _weight(')', abbrev);
|
|
|
|
p++; // skip ')'
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// GET ELEMENT := [ Upper | Upper,lower ]
|
|
|
|
elem[1] = 0;
|
|
|
|
if (! isupper(*p)) return 0; // fail
|
|
|
|
elem[0] = *p;
|
|
|
|
p++;
|
|
|
|
if (islower(*p))
|
|
|
|
{
|
|
|
|
elem[1] = *p;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
// can be optimized?
|
|
|
|
if ((abbrev == NULL) || (strcmp(elem, abbrev) == 0))
|
|
|
|
{
|
|
|
|
int z = find(elem);
|
|
|
|
if (z == 255) return 0; // fail
|
|
|
|
w = weight(z);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
// get optional digits
|
|
|
|
while (isdigit(*p))
|
|
|
|
{
|
|
|
|
count = count * 10 + (*p - '0');
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
// correct for no digits
|
|
|
|
if (count == 0) count = 1;
|
|
|
|
|
|
|
|
// DEBUG
|
|
|
|
// Serial.println(w);
|
|
|
|
// Serial.println(count);
|
|
|
|
|
|
|
|
sum += (w * count);
|
|
|
|
}
|
|
|
|
return sum;
|
2022-12-31 12:30:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-14 07:34:00 -04:00
|
|
|
uint32_t PTOE::_count(const char sep, const char * abbrev)
|
2023-04-12 10:52:57 -04:00
|
|
|
{
|
2023-04-15 14:15:18 -04:00
|
|
|
uint32_t sum = 0;
|
|
|
|
char elem[3] = { 0, 0, 0 };
|
|
|
|
uint32_t count = 0;
|
|
|
|
int w = 0;
|
|
|
|
|
|
|
|
while (*p != sep)
|
|
|
|
{
|
|
|
|
// HANDLE GROUP (...)
|
|
|
|
if (*p == '(')
|
|
|
|
{
|
|
|
|
p++; // skip '('
|
|
|
|
w = _count(')', abbrev);
|
|
|
|
p++; // skip ')'
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
w = 0;
|
|
|
|
// GET ELEMENT := [ Upper | Upper,lower ]
|
|
|
|
elem[1] = 0;
|
|
|
|
if (! isupper(*p)) return 0; // fail
|
|
|
|
elem[0] = *p;
|
|
|
|
p++;
|
|
|
|
if (islower(*p))
|
|
|
|
{
|
|
|
|
elem[1] = *p;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
// can be optimized
|
|
|
|
if ((abbrev == NULL) || (strcmp(elem, abbrev) == 0))
|
|
|
|
{
|
|
|
|
int z = find(elem);
|
|
|
|
if (z == 255) return 0; // fail
|
|
|
|
w = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
// get optional digits
|
|
|
|
while (isdigit(*p))
|
|
|
|
{
|
|
|
|
count = count * 10 + (*p - '0');
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
// correct for no digits
|
|
|
|
if (count == 0) count = 1;
|
|
|
|
|
|
|
|
// DEBUG
|
|
|
|
// Serial.println(w);
|
|
|
|
// Serial.println(count);
|
|
|
|
|
|
|
|
sum += w * count;
|
|
|
|
}
|
|
|
|
return sum;
|
2023-04-12 10:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -- END OF FILE --
|
2022-12-31 12:30:42 -05:00
|
|
|
|