Модуль:Химия
| ||
---|---|---|
Тематические статьи | ||
Техническая справка | ||
Тэги MediaWiki: | ||
Общие правила | ||
Модуль для расчётов, касающихся физической химии.
группа
- По атомному номеру элемента возвращает группу по ИЮПАК, которой он принадлежит
молярная масса
- Функция для вывода молярной массы вещества по формуле
оформить формулу
- Функция для оформления химической формулы
период
- По атомному номеру элемента возвращает период периодической системы, которому он принадлежит
электронная конфигурация
- Функция для вывода электронной конфигурации элемента с данным атомным номером
электроотрицательность
- По атомному номеру элемента его возвращает электроотрицательность
local function contains (stack, needle)
if type (stack) ~= 'table' then
return stack == needle
else
for _, val in ipairs (stack) do
if val == needle then
return true
end
end
return false
end
end -- local function contains (stack, needle)
local function load (args, names)
if type (names) ~= 'table' then
return args [names]
else
for _, val in ipairs (names) do
if args [val] then
return args [val]
end
end
end
end -- local function load (args, names)
local m = {}
local chemistryData = {
-- API:
apiElectronicConfiguration = "электронная конфигурация",
argAtomicNumber = 1,
argStart = 2,
argShells = 3,
argSep = "разделитель",
apiMolarMass = "молярная масса",
argFormula = 1,
apiPeriod = "период",
apiGroup = "группа",
apiShowFormula = "оформить формулу",
argSort = "sort",
argCharge = "charge",
apiContains = 'содержит',
argProperty = {'свойство', 'property'},
apiElectronegativity = 'электроотрицательность',
apiMeltingPoint = 'температура плавления',
apiBoilingPoint = 'температура кипения',
apiVanDerWaals = 'вандерваальсов радиус',
apiCovalentRadius = 'ковалентный радиус',
apiIonisationEnergy = 'энергия ионизации',
apiClarke = 'кларк',
apiDiscoveryYear = 'год',
apiTable = 'таблица',
-- Ошибки:
errorMissingNumber = "Передайте атомный номер",
errorNonNumeric = "Все параметры должны быть числами",
errorNonPositive = "Атомный номер должен быть положителен",
errorNonInteger = "Все параметры должны быть целыми",
errorShellsNegative = "Число показываемых оболочек должно быть неотрицательным",
errorMissingFormula = "Передайте химическую формулу",
errorWrongFormula = "Недопустимый символ в химической формуле",
errorUnknownElement = "Неизвестный элемент",
errorTooManyOP = "Слишком много открывающих скобок в формуле",
errorTooManyCP = "Слишком много закрывающих скобок в формуле",
errorNonNumericAtoms = "Количество атомов должно быть числом",
errorNonPositiveAtoms = "Количество атомов должно быть положительно",
errorUnexpectedNumber = "Здесь не ожидается число",
errorWrongCharge = "Неверное значение заряда иона",
errorMissingProperty = 'Передайте название свойства SMW',
-- Орбитальные квантовые числа:
l = { [0] = "s"
, [1] = "p"
, [2] = "d"
, [3] = "f"
, [4] = "g"
, [5] = "h"
, [6] = "i" },
-- Исключения из правила Клечковского (разреженные массивы с перемещениями электронов):
exceptions = {
-- Cr, Cu, Nb, Mo, Ru, Rh, Pd, Ag, Pt, Au (6s -> 5d):
[24] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Cr
, [29] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Cu
, [41] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Nb
, [42] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Mo
, [44] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Ru
, [45] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Rh
, [46] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Pd
, [47] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Ag
, [78] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Pt
, [79] = {[5] = {[2] = 1}, [6] = {[0] = -1}} -- Au
-- Ac, Th, Pa, U, Np, Cm (5f -> 6d):
, [89] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Ac
, [90] = {[6] = {[2] = 2}, [5] = {[3] = -2}} -- Th
, [91] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Pa
, [92] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- U
, [93] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Np
, [96] = {[6] = {[2] = 1}, [5] = {[3] = -1}} -- Cm
-- Lr
,[103] = {[7] = {[1] = 1}, [6] = {[2] = -1}} -- Lr
} ,
-- Элементы по номеру:
elements_by_no = {
'H', 'He',
'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne',
'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar',
'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr',
'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe',
'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn',
'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og'
}, -- elements_by_no
-- Атомные массы, названия, цвета и порядок вывода (позже брать из БД):
elements = {
H = {mass = 1.00794, name = "Водород", color = "777", order = 120}
, He = {mass = 4.002602, name = "Гелий", color = "30602e", order = 130}
, Li = {mass = 6.941, name = "Литий", color = "800080", order = 140}
, Be = {mass = 9.012182, name = "Бериллий", color = "30602e", order = 150}
, B = {mass = 10.811, name = "Бор (элемент)", color = "30602e", order = 160}
, C = {mass = 12.0107, name = "Углерод", color = "111", order = 110}
, N = {mass = 14.00674, name = "Азот", color = "0000cc", order = 170}
, O = {mass = 15.9994, name = "Кислород", color = "f00000", order = 180}
, F = {mass = 18.9984032, name = "Фтор", color = "30602e", order = 190}
, Ne = {mass = 20.1797, name = "Неон", color = "30602e", order = 200}
, Na = {mass = 22.98976928, name = "Натрий", color = "800080", order = 330}
, Mg = {mass = 24.3050, name = "Магний", color = "4E1563", order = 420}
, Al = {mass = 26.9815386, name = "Алюминий", color = "800080", order = 380}
, Si = {mass = 28.0855, name = "Кремний", color = "694E19", order = 430}
, P = {mass = 30.973762, name = "Фосфор", color = "d2701e", order = 220}
, S = {mass = 32.066, name = "Сера", color = "ff8800", order = 210}
, Cl = {mass = 35.4527, name = "Хлор", color = "228b22", order = 230}
, Ar = {mass = 39.948, name = "Аргон", color = "30602e", order = 205}
, K = {mass = 39.0983, name = "Калий", color = "48206A", order = 310}
, Ca = {mass = 40.078, name = "Кальций", color = "48206A", order = 315}
, Sc = {mass = 44.955912, name = 'Скандий', order = 1021}
, Ti = {mass = 47.867, name = "Титан (элемент)", color = "800080", order = 410}
, V = {mass = 50.9415, name = 'Ванадий', order = 1023}
, Cr = {mass = 51.9961, name = "Криптон", color = "48206A", order = 207}
, Mn = {mass = 54.938045, name = "Марганец", color = "4E1563", order = 320}
, Fe = {mass = 55.845, name = "Железо", color = "800080", order = 400}
, Co = {mass = 58.933195, name = "Кобальт", color = "353A5A", order = 270}
, Ni = {mass = 58.6934, name = 'Никель', order = 1028}
, Cu = {mass = 63.546, name = "Медь", color = "800080", order = 280}
, Zn = {mass = 65.39, name = "Цинк", color = "800080", order = 390}
, Ga = {mass = 69.723, name = 'Галлий', order = 1031}
, Ge = {mass = 72.61, name = 'Германий', order = 1032}
, As = {mass = 74.92160, name = "Мышьяк", color = "654778", order = 250}
, Se = {mass = 78.96, name = "Селен", color = "694E19", order = 350}
, Br = {mass = 79.904, name = "Бром", color = "8b4513", order = 240}
, Kr = {mass = 83.80, name = 'Криптон', order = 1036}
, Rb = {mass = 85.4678, name = 'Рубидий', order = 1037}
, Sr = {mass = 87.62, name = "Стронций", color = "0E430E", order = 360}
, Y = {mass = 88.90585, name = 'Иттрий', order = 1039}
, Zr = {mass = 91.224, name = 'Цирконий', order = 1040}
, Nb = {mass = 92.90638, name = 'Ниобий', order = 1041}
, Mo = {mass = 95.94, name = 'Молибден', order = 1042}
, Tc = {mass = 97.9072, name = "Технеций", color = "1E4F54", order = 370}
, Ru = {mass = 101.07, name = 'Рутений', order = 1044}
, Rh = {mass = 102.90550, name = 'Родий', order = 1045}
, Pd = {mass = 106.42, name = 'Палладий', order = 1046}
, Ag = {mass = 107.8682, name = 'Серебро', order = 1047}
, Cd = {mass = 112.411, name = 'Кадмий', order = 1048}
, In = {mass = 114.818, name = 'Индий', order = 1049}
, Sn = {mass = 118.710, name = 'Олово', order = 1050}
, Sb = {mass = 121.760, name = 'Сурьма', order = 1051}
, Te = {mass = 127.60, name = 'Теллурий', order = 1052}
, I = {mass = 126.90447, name = "Иод", color = "4A0B4A", order = 300}
, Xe = {mass = 131.29, name = 'Ксенон', order = 1054}
, Cs = {mass = 132.9054519, name = 'Цезий', order = 1055}
, Ba = {mass = 137.327, name = 'Барий', order = 1056}
, Hf = {mass = 178.49, name = 'Гафний', order = 1057}
, Ta = {mass = 180.94788, name = 'Тантал', order = 1058}
, W = {mass = 183.84, name = 'Вольфрам', order = 1059}
, Re = {mass = 186.207, name = 'Рений', order = 1060}
, Os = {mass = 190.23, name = 'Осмий', order = 1061}
, Ir = {mass = 192.217, name = 'Иридий', order = 1062}
, Pt = {mass = 195.084, name = "Платина", color = "15354F", order = 340}
, Au = {mass = 196.966569, name = "Золото", color = "800080", order = 260}
, Hg = {mass = 200.59, name = 'Ртуть', order = 1065}
, Tl = {mass = 204.3833, name = 'Таллий', order = 1066}
, Pb = {mass = 207.2, name = 'Свинец', order = 1067}
, Bi = {mass = 208.98040, name = 'Висмут', order = 1068}
, Po = {mass = 208.9824, name = 'Полоний', order = 1069}
, At = {mass = 209.9871, name = 'Астат', order = 1070}
, Rn = {mass = 222.0176, name = 'Радон', order = 1071}
, La = {mass = 138.90547, name = 'Лантан', order = 1072}
, Ce = {mass = 140.116, name = 'Церий', order = 1073}
, Pr = {mass = 140.90765, name = 'Протактиний', order = 1074}
, Nd = {mass = 144.242, name = 'Неодим', order = 1075}
, Pm = {mass = 144.9127, name = 'Празеодим', order = 1076}
, Sm = {mass = 150.36, name = 'Самарий', order = 1077}
, Eu = {mass = 151.964, name = 'Европий', order = 1078}
, Gd = {mass = 157.25, name = "Гадолиний", color = "400040", order = 290}
, Tb = {mass = 158.92535, name = 'Тербий', order = 1080}
, Dy = {mass = 162.500, name = 'Диспрозий', order = 1081}
, Ho = {mass = 164.93032, name = 'Гольмий', order = 1082}
, Er = {mass = 167.259, name = 'Эрбий', order = 1083}
, Tm = {mass = 168.93421, name = 'Тулий', order = 1084}
, Yb = {mass = 173.04, name = 'Иттербий', order = 1085}
, Lu = {mass = 174.967, name = 'Лютеций', order = 1086}
, Fr = {mass = 223.0197, name = 'Франций', order = 1087}
, Ra = {mass = 226.0254, name = 'Радий', order = 1088}
, Rf = {mass = 263.1125, name = 'Резерфордий', order = 1089}
, Db = {mass = 262.1144, name = 'Дубний', order = 1090}
, Sg = {mass = 266.1219, name = 'Сиборгий', order = 1091}
, Bh = {mass = 264.1247, name = 'Борий', order = 1092}
, Hs = {mass = 269.1341, name = 'Хассий', order = 1093}
, Mt = {mass = 268.1388, name = 'Мейтнерий', order = 1094}
, Ds = {mass = 272.1463, name = 'Дармштадтий', order = 1095}
, Rg = {mass = 272.1535, name = 'Рентгений', order = 1096}
, Cn = {mass = 277.0, name = 'Коперниций', order = 1097}
, Nh = {mass = 284.0, name = 'Нихоний', order = 1098}
, Fl = {mass = 289.0, name = 'Флеровий', order = 1099}
, Mc = {mass = 288.0, name = 'Московий', order = 1100}
, Lv = {mass = 292.0, name = 'Ливерморий', order = 1101}
, Ts = {mass = 292.0, name = 'Тенессин', order = 1102}
, Og = {mass = 294, name = 'Оганесон', order = 1103}
, Ac = {mass = 227.0277, name = 'Актиний', order = 1104}
, Th = {mass = 232.03806, name = 'Торий', order = 1105}
, Pa = {mass = 231.03588, name = 'Протактиний', order = 1106}
, U = {mass = 238.02891, name = 'Уран', order = 1107}
, Np = {mass = 237.0482, name = 'Нептуний', order = 1108}
, Pu = {mass = 244.0642, name = 'Плутоний', order = 1109}
, Am = {mass = 243.0614, name = 'Америций', order = 1110}
, Cm = {mass = 247.0703, name = 'Кюрий', order = 1111}
, Bk = {mass = 247.0703, name = 'Берклий', order = 1112}
, Cf = {mass = 251.0796, name = 'Калифорний', order = 1113}
, Es = {mass = 252.0830, name = 'Эйншнейний', order = 1114}
, Fm = {mass = 257.0951, name = 'Фермий', order = 1115}
, Md = {mass = 258.0984, name = 'Менделевий', order = 1116}
, No = {mass = 259.1011, name = 'Нобелий', order = 1117}
, Lr = {mass = 262.110, name = 'Лоуренсий', order = 1118}
},
electronegativity = {
[1] = 2.2,
[3] = 0.98, [4] = 1.57, [5] = 2.04, [6] = 2.55, [7] = 3.04, [8] = 3.44, [9] = 3.98,
[11] = 0.93, [12] = 1.31, [13] = 1.61, [14] = 1.9, [15] = 2.19, [16] = 2.58, [17] = 3.16,
[19] = 0.82, [19] = 1.0, [20] = 1.36, [21] = 1.54, [22] = 1.63, [23] = 1.66, [24] = 1.55, [25] = 1.83, [26] = 1.88, [27] = 1.91, [28] = 1.9, [29] = 1.65, [30] = 1.81, [31] = 2.01, [33] = 2.18, [34] = 2.55, [36] = 2.96,
[38] = 0.82, [39] = 0.95, [40] = 1.22, [41] = 1.33, [42] = 1.6, [43] = 2.16, [44] = 1.9, [45] = 2.2, [46] = 2.28, [47] = 2.2, [48] = 1.93, [49] = 1.69, [50] = 1.78, [51] = 1.96, [53] = 2.05, [54] = 2.1,
[55] = 2.66, [56] = 2.6, [57] = 0.79, [58] = 0.89, [59] = 1.1, [60] = 1.12, [61] = 1.13, [62] = 1.14, [64] = 1.17, [66] = 1.2, [68] = 1.22, [69] = 1.23, [70] = 1.24, [71] = 1.25, [73] = 1.27, [74] = 1.3, [75] = 1.5, [76] = 2.36, [77] = 1.9, [78] = 2.2, [79] = 2.2, [80] = 2.28, [81] = 2.54, [82] = 2.0, [83] = 1.62, [84] = 2.33, [85] = 2.02, [86] = 2.0,
[87] = 2.2, [89] = 0.7, [90] = 0.89, [91] = 1.1, [92] = 1.3, [93] = 1.5, [94] = 1.38, [95] = 1.36, [96] = 1.28, [97] = 1.3, [98] = 1.3, [99] = 1.3, [100] = 1.3, [101] = 1.3, [102] = 1.3, [103] = 1.3, [104] = 1.3, [105] = 1.3
},
melting = {
-259, -272,
180, 1278, 2300, 3500, -210, -218, -220, -249,
98, 639, 660, 1410, 44, 113, -101, -189,
64, 839, 1539, 1660, 1890, 1857, 1245, 1535, 1495, 1453, 1083, 420, 30, 937, 816.8, 217, -7, -157,
39, 769, 1523, 1852, 2468, 2617, 2200, 2250, 1966, 1552, 962, 321, 157, 232, 630, 449, 114, -112,
29, 725, 920, 795, 935, 1010, 1100, 1072, 822, 1311, 1360, 1412, 1470, 1522, 1545, 824, 1656, 2150, 2996, 3410, 3180, 3045, 2410, 1772, 1064, -39, 303, 327, 271, 254, 302, -71,
27, 700, 1050, 1750, 1568, 1132, 640, 640, 994, 1340, 986, 900, 860, 1527, nil, 827, 1627,
}, -- melting
boiling = {
-253, -269,
1347, 2970, 2550, 4827, -196, -183, -188, -246,
883, 1090, 2467, 2355, 280, 445, -35, -186,
760, 1484, 2832, 3287, 3380, 2672, 1962, 2750, 2870, 2732, 2567, 907, 2403, 2830, 613, 685, 58.8, -153,
688, 1384, 3337, 4377, 4927, 4612, 4877, 3900, 3727, 2927, 2212, 765, 2000, 2270, 1750, 990, 184, -108,
678, 1140, 3469, 3257, 3127, 3127, 3000, 1900, 1597, 3233, 3041, 2562, 2720, 2510, 1727, 1466, 3315, 5400, 5425, 5660, 5627, 5027, 4527, 3827, 2807, 357, 1457, 1740, 1560, 962, 337, -62,
677, 1737, 3200, 4790, nil, 3818, 3902, 3235, 2607
}, -- boiling
vanderwaals = { -- paulings (?). Review!
[1] = 120, [2] = 122,
[5] = 208, [6] = 185, [7] = 154, [8] = 140, [9] = 135, [10] = 160,
[11] = 231, [13] = 205, [14] = 200, [15] = 190, [16] = 185, [17] = 181, [18] = 191,
[19] = 231, [33] = 200, [34] = 200, [35] = 195, [36] = 198, [37] = 244,
[51] = 220, [52] = 220, [53] = 215, [54] = 216, [55] = 262, [83] = 240
}, -- vanderwaals
covalent = { -- pm
30, 0,
123, 89, 88, 77, 70, 66, 58, 0,
157, 136, 125, 117, 110, 104, 99, 0,
203, 174, 144, 132, 122, 118, 117, 116.5, 116, 115, 117, 125, 125, 122, 121, 117, 114, 189,
216, 192, 162, 145, 134, 129, 127, 124, 125, 128, 134, 141, 150, 140, 141, 137, 133.3, 209,
235, 198, 169, 165, 165, 164, 163, 166, 185, 161, 159, 159, 158, 157, 156, 170, 156, 144, 134, 130, 128, 126, 126, 129, 134, 144, 155, 154, 152, 153, 145,
[90] = 165, [92] = 142
}, -- covalent
ionisation = { -- eV
13.5984, 24.5874,
5.3917, 9.3227, 8.298, 11.2603, 14.5341, 13.6181, 17.4228, 21.5645,
5.1391, 7.6462, 5.9858, 8.1517, 10.4867, 10.36, 12.9676, 15.7596,
4.3407, 6.1132, 6.5615, 6.8281, 6.7462, 6.7665, 7.434, 7.9024, 7.881, 7.6398, 7.7264, 9.3942, 5.9993, 7.8994, 9.7886, 9.7524, 11.8138, 13.9996,
4.1771, 5.6949, 6.2173, 6.6339, 6.7589, 7.0924, 7.28, 7.3605, 7.4589, 8.3369, 7.5762, 8.9938, 5.7864, 7.3439, 8.6084, 9.0096, 10.4513, 12.1298,
3.8939, 5.2117, 5.5769, 5.5387, 5.473, 5.525, 5.582, 5.6437, 5.6704, 6.1501, 5.8638, 5.9389, 6.0215, 6.1077, 6.1843, 6.2542, 5.4259, 6.8251, 7.5496, 7.864, 7.8335, 8.4382, 8.967, 8.9587, 9.2255, 10.4375, 6.1082, 7.4167, 7.2856, 8.417, 9.3, 10.7485,
4.0727, 5.2784, 5.17, 6.3067, 5.89, 6.1941, 6.2657, 6.0262, 5.9738, 5.9915, 6.1979, 6.2817, 6.42, 6.5, 6.58, 6.65, 4.9
}, -- ionisation
discovery_year = {
'1776', '1895',
'1817', '1797', '1808', '~ 1694', '1772', '1774', '1886', '1898',
'1807', '1755', '1825', '1824', '1669', 'древность', '1774', '1894',
'1807', '1808', '1879', '1791', '1830', '1797', '1774', '1774', '1735', '1751', '1751', 'древность', '1875', '1886', '1886', '1817', '1826', '1898',
'1861', '1790', '1794', '1789', '1801', '1781', '1937', '1844', '1803', '1803', 'древность', '1817', '1863', 'древность', 'древность', '1782',
'1811', '1898', '1860', '1808', '1839', '1803', '1885', '1885', '1945', '1879', '1901', '1880', '1843', '1886', '1867', '1842', '1879', '1878', '1907', '1923', '1802', '1783', '1925', '1803', '1803', '1735', 'древность', 'древность', '1861', 'древность', '~ 1400', '1898',
'1940', '1900', '1939', '1898', '1899', '1829', '1913', '1789', '1940', '1940', '1944', '1944', '1949', '1950', '1952', '1952', '1955', '1958', '1961', '1964', '1967', '1974', '1981', '1984', '1982', '1994', '1994', '1996', '1998', '1999', '2004', '2000',
'2009', '1999'
}, -- discovery_year
clarke = {
[1] = 0.0014,
[6] = 0.00094, [8] = 0.4671, [9] = 0.00029,
[11] = 0.0275, [12] = 0.0208, [13] = 0.0807, [14] = 0.2769, [15] = 0.0013, [16] = 0.00052, [17] = 0.00045,
[19] = 0.0258, [20] = 0.0365, [22] = 0.0062, [24] = 0.00035, [25] = 0.0009, [26] = 0.0505, [28] = 0.00019,
[40] = 0.00025, [56] = 0.0005
} -- clarke
, T_ELEM = 0 -- token types
, T_NUM = 1
, T_O = 2 -- open '('
, T_C = 3 -- close ')'
}
local lang = mw.language.getContentLanguage ()
local function formatChemistryError (message, ...)
if select('#', ... ) > 0 then
message = string.format (message, ...)
end
return "<span class=\"error\">" .. message .. "</span>"
end
-- Получение и санация параметров функций «электронная конфигурация», «период» и «группа»:
-- 1: Атомный номер:
local function loadAtomicNumber (no)
if not no then
return false, formatChemistryError (chemistryData.errorMissingNumber)
end
local result = tonumber (no)
if not result then
return false, formatChemistryError (chemistryData.errorNonNumeric, no)
end
if math.floor (result) ~= result then
return false, formatChemistryError (chemistryData.errorNonInteger, no)
end
if result <= 0 then
return false, formatChemistryError (chemistryData.errorNonPositive, no)
end
return true, result
end
-- 2: Начать с оболочки:
local function loadStart (no)
-- по умолчанию, 1:
if not no or no == 0 then
return true, 1
end
local result = tonumber (no)
if not result then
return false, formatChemistryError (chemistryData.errorNonNumeric, no)
end
if math.floor (no) ~= result then
return false, formatChemistryError (chemistryData.errorNonInteger, no)
end
return true, result
end
-- 3: Число показываемых оболочек:
local function loadShells (no)
-- по умолчанию, 0:
if not no then
return true, 0
end
local result = tonumber (no)
if not result then
return false, formatChemistryError (chemistryData.errorNonNumeric, no)
end
if math.floor (no) ~= result then
return false, formatChemistryError (chemistryData.errorNonInteger, no)
end
if result < 0 then
return false, formatChemistryError (chemistryData.errorShellsNegative, no)
end
return true, result
end
-- разделитель слоёв:
local function loadSep (str)
-- по умолчанию, пустая строка:
return true, str or ''
end
-- Период и группа элемента:
-- Период и группа (по ИЮПАК, 1988). Параметр -- санированный атомный номер:
local function implementPeriodAndGroup (no)
local period = 0
local group
local n = no
while n > 0 do
period = period + 1
-- Предполагаемая группа:
group = n
-- Число элементов в периоде :
n = n - 2 * (math.floor (period / 2) + 1) ^ 2
end
if period == 1 and group == 2 then
group = 18 -- He.
elseif period == 2 or period == 3 then
if group > 2 then
group = group + 10 -- нет d-электронов.
end
elseif period == 6 or period == 7 then
-- Все лантаноиды и актиноиды в одной группе 3:
if group > 3 and group <= 17 then
group = 3
elseif group > 17 then
group = group - 14
end
end
return period, group
end
-- Функция для периода и группы до санации параметра:
local function periodAndGroup (args)
-- Извлечение параметра «Атомный номер» (первого):
local ok
local number
ok, number = loadAtomicNumber (load (args, chemistryData.argAtomicNumber))
if not ok then
return number
end
return implementPeriodAndGroup (number)
end
-- Регистрация эспортируемых функций:
-- «период»:
m [chemistryData.apiPeriod] = function (frame)
local period, group = periodAndGroup (frame.args)
return period
end
-- «группа»:
m [chemistryData.apiGroup] = function (frame)
local period, group = periodAndGroup (frame.args)
return group
end
-- Вспомогательные функции для функции «электронная конфигурация»:
-- Создание пустых электронных оболочек:
local function createElectronShells ()
local electrons = {}
for n = 1, 7 do
electrons [n] = {}
for l = 0, n - 1 do
electrons [n] [l] = 0
end
electrons [n].total = 0
electrons [n].free_l = 0
end
return electrons
end
-- Находит первое свободное место с n + l = energy
local ceil, min = math.ceil, math.min
local function findSubshellForNplusL (electrons, energy)
local found = false
local l = 0
-- Поскольку l < n, на меньших n требуемого n + l не найти:
local n = ceil (energy / 2) - 1
while not found and n <= min (energy, #electrons - 1) do
n = n + 1
if electrons [n].free_l < n -- допустимо (n > l).
and electrons [n].free_l + n == energy -- найден подходящий уровень.
then
l = electrons [n].free_l
found = true -- нашли.
end
end
return found, n, l
end
-- Заселение электронных оболочек элемента № no:
local function populateElectronShells (no)
-- Создание пустых электронных оболочек:
local electrons = createElectronShells ()
-- оставшееся число электронов:
local el = no
-- Текущий слой и подслой:
local n = 1 -- главное квантовое число.
local l = 0 -- орбитальное квантовое число.
while el > 0 do
-- -l <= m <= l; s = -1/2 or 1/2:
if electrons [n] [l] >= 2 * (2 * l + 1) then
-- подслой полон; нужно найти другой:
-- отметить его как полный:
electrons [n].free_l = electrons [n].free_l + 1
-- Выбрать слой и подслой для·размещения электрона по·правилу Клечковского:
-- Выбор слоя, где есть место с теми же n + l:
local found
local new_n
local new_l
found, new_n, new_l = findSubshellForNplusL (electrons, n + l)
if found then
-- место найдено:
n = new_n
l = new_l
else
-- надо увеличить n + l:
found, n, l = findSubshellForNplusL (electrons, n + l + 1)
end
end
-- Подселяем электрон на выбранный подслой
electrons [n] [l] = electrons [n] [l] + 1
electrons [n].total = electrons [n].total + 1
el = el - 1
end
-- Внесение исключений из правила Клечковского:
if chemistryData.exceptions [no] then
-- Перемещение электронов:
for n, shell in pairs (chemistryData.exceptions [no]) do
for l, delta in pairs (shell) do
electrons [n] [l] = electrons [n] [l] + delta
end
end
end
return electrons
end
-- Электронная конфигурация (санированные параметры):
local function printElectronicConfiguration (no, start, shells, sep)
-- Получить электронную кофигурацию:
local electrons = populateElectronShells (no)
-- Оформление электронной конфигурации в виде строки:
local ret = ""
-- Выявление первого и последнего показываемого слоя с учётом их заполнения и переданных параметров:
-- Последний заполненный:
local last_full = #electrons
while electrons [last_full].total == 0 and last_full > 0 do
last_full = last_full - 1
end
-- Первый требуемый (с помощью отрицательных значений вывод с конца):
start = start or 1
local first = start
if start < 0 then
first = last_full + start + 1
end
-- Последний требуемый (0 -- все):
shells = shells or 0
local last
if shells ~= 0 then
last = first + shells - 1
else
last = last_full
end
-- Обход слоёв:
sep = sep or ''
for n = first, last do
local shell = electrons [n]
-- Разделитель:
if n > first then
ret = ret .. sep
end
ret = ret .. tostring (n)
-- Обход подслоёв:
for l = 0, #shell do
if shell [l] > 0 then
-- если на подслое есть электроны, добавить:
ret = ret .. "<em>" .. chemistryData.l [l] .. "</em>"
.. "<sup>" .. tostring (shell [l]) .. "</sup>"
end
end
end
return ret
end
-- Электронная конфигурация (нечистые параметры):
local function electronicConfiguration (args)
-- Извлечение параметра «Атомный номер» (первого):
local ok
local number
ok, number = loadAtomicNumber (load (args, chemistryData.argAtomicNumber))
if not ok then
return number
end
-- Извлечение параметра «Начать с оболочки» (второго):
local start
ok, start = loadStart (load (args, chemistryData.argStart))
if not ok then
return start
end
-- Извлечение параметра «Число оболочек» (третьего):
local shells
ok, shells = loadShells (load (args, chemistryData.argShells))
if not ok then
return shells
end
-- Извлечение параметра «разделитель»:
local sep
ok, sep = loadSep (load (args, chemistryData.argSep))
if not ok then
return sep
end
return printElectronicConfiguration (number, start, shells, sep)
end
-- Регистрация эспортируемых функций:
-- «электронная конфигурация»:
m [chemistryData.apiElectronicConfiguration] = function (frame)
return electronicConfiguration (frame.args)
end
-- Получение молярной массы по формуле:
-- H2O, NH3, CuSO4, Si(OH)4 и т.п.:
-- Получить один токен формулы f в виде итератора:
local match, len = mw.ustring.match, mw.ustring.len
local function item (f)
local i = 1
return function ()
local t, x = nil, nil
if i <= len (f) then
x = match (f, '^%u%l*', i);
t = chemistryData.T_ELEM -- элемент
if not x then x = match (f, '^%d+', i); t = chemistryData.T_NUM; end -- индекс
if not x then x = match (f, '^%(', i); t = chemistryData.T_O; end -- (
if not x then x = match (f, '^%)', i); t = chemistryData.T_C; end -- )
if x then i = i + len (x)
else
i = i + 999
return false, formatChemistryError (chemistryData.errorWrongFormula .. " " .. f)
end
end
return t, x
end
end
-- Преобразовать строковую формулу в массив:
local gsub = mw.ustring.gsub
local function parseFormula (str)
local stack = {{}}
local f = gsub (gsub (str, "</?sub>", ""), "_", "")
local t, x
for t, x in item (f) do
if t == chemistryData.T_ELEM then
if chemistryData.elements [x] then
-- Кладём после последнего элемента последнего элемента стэка:
stack [#stack] [#stack [#stack] + 1] = {x, 1}
else
return false, formatChemistryError (chemistryData.errorUnknownElement .. " " .. x)
end
elseif t == chemistryData.T_NUM then
-- Исправляем количество в последнем элементе последнего элемента стэка:
stack [#stack] [#stack [#stack]] [2] = tonumber (x)
elseif t == chemistryData.T_O then
-- (:
-- поместить в стэк:
stack [#stack + 1] = {}
elseif t == chemistryData.T_C then
-- ):
-- вытолкнуть из стека (переместить на уровень ниже, превратив предыдущий уровень в иерархию):
if #stack > 1 then
stack [#stack - 1] [#stack [#stack - 1] + 1] = {stack [#stack], 1}
stack [#stack] = nil
else
return false, formatChemistryError (chemistryData.errorTooManyCP .. " " .. str)
end
else
return false, formatChemistryError (chemistryData.errorWrongFormula .. " " .. str)
end
end
if #stack == 1 then
-- единственный штатный возврат. Скобки точно сбалансированы:
return true, stack [1]
else
return false, formatChemistryError (chemistryData.errorTooManyOP .. " " .. str)
end
end
-- Молярная масса. Получает уже разобранную формулу:
local function molarMass (parsed)
local ret = 0
local mass = 0
for i = 1, table.maxn (parsed) do
if parsed [i] then
local element = parsed [i] [1]
if type (element) == "string" then
-- похоже на элемент:
if chemistryData.elements [element] then
-- элемент найден:
mass = chemistryData.elements [element].mass
else
-- нет такого элемента. Это, вообще, возможно?:
return formatChemistryError (chemistryData.errorUnknownElement .. " " .. element)
end
else
-- радикал:
mass = molarMass (element)
end
ret = ret + mass * parsed [i] [2]
end
end
return ret
end
-- Молярная масса. Функция получает неразобранную формулу в виде строки:
local function molarMassString (str)
local ok, parsed = parseFormula (str)
if not ok then
return parsed -- уже содержит оформленную ошибку.
end
return molarMass (parsed)
end
-- Молярная масса. Функция получает сырые параметры:
local function molarMassRaw (args)
local formula = load (args, chemistryData.argFormula)
if formula and formula ~= '' then
return molarMassString (formula)
else
-- Параметр "формула" не передан:
return formatChemistryError (chemistryData.errorMissingFormula)
end
end
-- Регистрация эспортируемых функций:
-- «молярная масса»:
m [chemistryData.apiMolarMass] = function (frame)
local mass = molarMassRaw (frame.args)
if type (mass) == 'number' then
mass = lang:formatNum (mass)
end
return mass
end
-- Регистрация списка содержащихся элементов:
local function set_elements (formula, property)
local elements = {}
for i = 1, table.maxn (formula) do
if formula [i] then
local element = formula [i] [1]
if type (element) == 'string' then
local name
-- Похоже на элемент?
if chemistryData.elements [element] then
-- элемент найден:
elements [#elements + 1] = chemistryData.elements [element].name
else
-- нет такого элемента. Это, вообще, возможно?:
return formatChemistryError (chemistryData.errorUnknownElement .. " " .. element)
end
else
-- радикал:
local radical = set_elements (element)
for radical_element, is_in in pairs (radical) do
if is_in then
elements [#elements + 1] = radical_element
end
end
end
end
end
mw.smw.set {[property] = elements}
return ''
end -- local function set_elements (formula, property)
-- Регистрация эспортируемых функций:
-- «содержит»:
m [chemistryData.apiContains] = function (frame)
local formula = load (frame.args, chemistryData.argFormula)
local property = load (frame.args, chemistryData.argProperty)
if not formula or formula == '' then
-- Параметр "формула" не передан:
return formatChemistryError (chemistryData.errorMissingFormula)
end
local ok, parsed = parseFormula (formula)
if not ok then
return parsed -- уже содержит оформленную ошибку.
end
if not property then
-- Не задано свойство:
return formatChemistryError (chemistryData.errorMissingProperty)
end
return set_elements (parsed, property)
end -- m [chemistryData.apiContains] = function (frame)
-- оформить формулу (санированные параметры):
local function formula (elements, charge)
local laidout = ''
local offset_charge
for i = 1, table.maxn (elements) do
local element = elements [i]
-- Do not replace with for i, element in ipairs (elements) do!
if element then
local radical = ''
if type (element [1]) == "string" then
-- one-atom radical:
local color = "000000"
local name = "Химический элемент"
local element_data = chemistryData.elements [element [1]]
if element_data then
color = element_data.color or '000000'
name = element_data.name or element [1]
end
radical = '[[' .. name
.. '|<span style="color: #' .. color .. '; font-weight: bold">'
.. elements [i] [1] .. '</span>]]'
elseif type (elements [i] [1]) == "table" then
-- many-atom radical:
radical = formula (element [1])
if element [2] > 1 then
-- () needed:
radical = "(" .. radical .. ")"
end
end
laidout = laidout .. radical
-- Index is only needed when it is greater than 1:
if (element [2] or 1) > 1 then
laidout = laidout .. "<sub>" .. tostring (element [2]) .. "</sub>"
offset_charge = true
else
offset_charge = false
end
end
end -- for i = 1, #elements
-- Заряд иона:
if charge and charge ~= "" then
local charge_string = "<sup"
-- Заряд иона над последним индексом:
if offset_charge then
charge_string = charge_string .. ' style="margin-left:-0.5em"'
end
charge_string = charge_string .. ">" .. tostring (charge) .. "</sup>"
laidout = laidout .. charge_string
end
return laidout
end -- local function formula (elements, charge)
local find = mw.ustring.find
-- оформить формулу (нечистые параметры):
local function showFormula (args)
local elements = {}
local counter = 1
local position = 1
local number_expected = false
-- Принудительная сортировка, заряд иона и свойство SMW:
local force_sort, charge = false, ''
-- Именно так, более простой способ не работает:
local params = {}
for key, val in pairs (args) do
-- Принудительная сортировка:
if contains (chemistryData.argSort, key) then
force_sort = true
-- Заряд иона:
elseif contains (chemistryData.argCharge, key) then
if find (val, "^%d*[+-]$") then
charge = val
else
return formatChemistryError (chemistryData.errorWrongCharge .. ": " .. tostring (val))
end
-- Элемент:
else
params [key] = val
end
end
for key, val in pairs (params) do
-- Cast types:
if tonumber (key) then key = tonumber (key) end
if tonumber (val) then val = tonumber (val) end
-- Different types of the current parametre:
if type (key) == "number" then
if type (val) == "string" then
if number_expected then
counter = counter + 1
number_expected = false
end
if force_sort then
-- принудительная сортировка:
-- Принятая позиция элемента:
if match (val, "^%u%l*$") then
-- Размещаем элемент где принято:
position = chemistryData.elements [val].order
else
-- радикалы в конце:
position = 2000 + counter
end
else
-- пользовательская сортировка:
position = counter
end
if not match (val, "^%u%l*$") then
-- it's a whole formula:
ok, val = parseFormula (val)
if not ok then
-- разбор формулы не удался:
return val -- здесь теперь сообщение об ошибке.
end
end
elements [position] = {val, 1}
number_expected = true -- also way to show ().
elseif type (val) == "number" then
if number_expected then
elements [position] [2] = val
counter = counter + 1
number_expected = false
else
return formatChemistryError (chemistryData.errorUnexpectedNumber .. ": " .. tostring (val))
end
end
elseif type (key) == "string" then
-- Принятая позиция элемента:
if match (key, "^%u%l*$") then
-- Размещаем элемент где принято:
position = chemistryData.elements [key].order
else
-- Это многоатомный радикал:
ok, key = parseFormula (key)
if not ok then
-- разбор формулы не удался:
return key -- здесь теперь сообщение об ошибке.
end
-- Ставим его в конец:
position = 2000 + counter
end
if number_expected then
counter = counter + 1
number_expected = false
end
if type (val) == "number" then
if val <= 0 then
return formatChemistryError (chemistryData.errorNonPositiveAtoms .. ": " .. tostring (key) .. " = " .. tostring (val))
end
elseif val == "" or val == nil then
-- А сюда управление хоть раз передастся?
val = 1
number_expected = true
else
return formatChemistryError (chemistryData.errorNonNumericAtoms .. ": " .. tostring (key) .. " = " .. val)
end
elements [position] = {key, val}
end
end
return formula (elements, charge)
end
-- Регистрация эспортируемых функций:
-- «оформить формулу»:
m [chemistryData.apiShowFormula] = function (frame)
local nextfunc, static, cur = pairs (frame.args)
if nextfunc (static, cur) == nil then
--if not (frame.args and next (frame.args)) then
-- аргументы не переданы. Использовать аргументы шаблона:
return showFormula (frame:getParent ().args)
else
-- переданы аргументы:
return showFormula (frame.args)
end
end
-- Электроотрицательность:
local function electronegativity (no)
return chemistryData.electronegativity [no]
end
m [chemistryData.apiElectronegativity] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
local en = electronegativity (result)
return en and lang:formatNum (en) or '—'
else
return result
end
end -- m [chemistryData.apiElectronegativity] = function (frame)
-- Энергия ионизации:
local function ionisation (no)
return chemistryData.ionisation [no]
end
m [chemistryData.apiIonisationEnergy] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
local ie = ionisation (result)
return ie and lang:formatNum (ie) .. ' эВ' or '—'
else
return result
end
end -- m [chemistryData.apiIonisationEnergy] = function (frame)
-- Температура плавления:
local function melting_point (no)
return chemistryData.melting [no]
end
m [chemistryData.apiMeltingPoint] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
local mp = melting_point (result)
return mp and (lang:formatNum (mp) .. ' °C') or '—'
else
return result
end
end -- m [chemistryData.apiMeltingPoint] = function (frame)
-- Температура кипения:
local function boiling_point (no)
return chemistryData.boiling [no]
end
m [chemistryData.apiBoilingPoint] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
local bp = boiling_point (result)
return bp and (lang:formatNum (bp) .. ' °C') or '—'
else
return result
end
end -- m [chemistryData.apiBoilingPoint] = function (frame)
-- Вандерваальсов радиус:
local function vanderwaals (no)
return chemistryData.vanderwaals [no]
end
m [chemistryData.apiVanDerWaals] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
local vdwr = vanderwaals (result)
return vdwr and lang:formatNum (vdwr) or '—'
else
return result
end
end -- m [chemistryData.apiVanDerWaals] = function (frame)
-- Ковалентный радиус:
local function covalent (no)
return chemistryData.covalent [no]
end
m [chemistryData.apiCovalentRadius] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
local cv = covalent (result)
return cv and lang:formatNum (cv) .. ' пм' or '—'
else
return result
end
end -- m [chemistryData.apiCovalentRadius] = function (frame)
-- Год открытия:
local function discovery_year (no)
return chemistryData.discovery_year [no]
end
m [chemistryData.apiDiscoveryYear] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
return discovery_year (result)
else
return result
end
end -- m [chemistryData.apiDiscoveryYear] = function (frame)
-- Кларк (в земной коре):
local function clarke (no)
return chemistryData.clarke [no]
end
m [chemistryData.apiClarke] = function (frame)
local success, result = loadAtomicNumber (frame.args [1])
if success then
local cl = clarke (result)
return cl and lang:formatNum (cl * 100) .. '%' or '—'
else
return result
end
end -- m [chemistryData.apiClarke] = function (frame)
local function print_table ()
local result = '{| class="sortable wikitable" style="text-align: left;" cellpadding="0" cellspacing="0"\n'
result = result .. '! № || Символ || Название || Год открытия || Период || Группа || Масса '
.. '|| [[Электроотрицательность]] || [[Энергия ионизации]] '
.. '|| [[Температура плавления|t плавления]] || [[Температура кипения|t кипения]] '
.. '|| [[Вандерваальсов радиус]] '
.. '|| Электронная конфигурация || [[Число Кларка|Кларк]] || Порядок || Цвет\n'
local ordered = {}
for no, symbol in pairs (chemistryData.elements_by_no) do
local data = chemistryData.elements [symbol] or {}
result = result .. '|-\n'
result = result .. '| ' .. tostring (no) .. ' || '
result = result .. showFormula {symbol}
result = result .. ' || '
result = result .. (data.name or '')
result = result .. ' || '
result = result .. '[[' .. (discovery_year (no) or '') .. ']]'
result = result .. ' || '
local period, group = implementPeriodAndGroup (no)
result = result .. tostring (period)
result = result .. ' || '
result = result .. tostring (group)
result = result .. ' || '
result = result .. (data.mass and lang:formatNum (data.mass) .. ' а.е.м.' or '—')
result = result .. ' || '
local en = electronegativity (no)
result = result .. (en and lang:formatNum (en) or '—')
result = result .. ' || '
local ie = ionisation (no)
result = result .. (ie and lang:formatNum (ie) .. ' эВ' or '—')
result = result .. ' || '
local mp = melting_point (no)
result = result .. (mp and (lang:formatNum (mp) .. ' °C') or '—')
result = result .. ' || '
local bp = boiling_point (no)
result = result .. (bp and (lang:formatNum (bp) .. ' °C') or '—')
result = result .. ' || '
local vdwr = vanderwaals (no)
result = result .. (vdwr and lang:formatNum (vdwr) or '—')
result = result .. ' || '
local cv = covalent (no)
result = result .. (cv and lang:formatNum (cv) .. ' пм' or '—')
result = result .. ' || '
result = result .. printElectronicConfiguration (no)
result = result .. ' || '
local cl = clarke (no)
result = result .. (cl and lang:formatNum (cl * 100) .. '%' or '—')
result = result .. ' || '
result = result .. tostring (data.order or 0)
result = result .. ' || '
result = result .. (data.color or '000000')
result = result .. '\n'
end
result = result .. '|}'
return result
end -- local function print_table ()
-- Регистрация экспортируемых функций:
-- «молярная масса»:
m [chemistryData.apiTable] = function (frame)
return print_table ()
end
m.test = function (key)
return showFormula (key)
end
-- Последняя строка. Экспорт функций из модуля:
return m