pyrolite 0.0.14__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__init__.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/_version.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/alteration.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/classification.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/compositions.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/geochem.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/melts.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/norm.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/normalisation.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/plot.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/_version.py +21 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/alteration.py +66 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/classification.py +222 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__init__.py +9 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/aggregate.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/codata.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/impute.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/renorm.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/aggregate.py +391 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/codata.py +266 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/impute.py +82 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/renorm.py +40 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/compositions.py +524 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_CFB_Dataset_List.csv +42 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_Convergent_Dataset_List.csv +42 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OBFB_Dataset_List.csv +5 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OIB_Dataset_List.csv +49 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OceanicPlateau_Dataset_List.csv +18 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/contents.json +1 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-35.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/env.py +1063 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ba.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Bs.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.F.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Pc.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ph.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.R.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.modelfields +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.nan.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.none.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/aphanitic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/gabbroic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/peralkalinity.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/phaneritic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/ultramafic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/CH_PalmeONeill2014.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DDMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DM_SaltersStrake2004.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/EDMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/PM_PalmeONeill2014.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/timescale/geotimescale_spans.csv +180 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/geochem.py +821 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/melts.py +92 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__init__.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/db.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/ions.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/mineral.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/sites.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/db.py +88 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/ions.py +78 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/mineral.py +587 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/sites.py +134 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/norm.py +224 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/normalisation.py +204 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/plot.py +514 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__init__.py +13 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/database.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/env.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/general.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/georoc.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/math.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/melts.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multip.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multiprocessing.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/pd.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/plot.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/skl.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/spatial.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/text.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/time.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/wfs.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/database.py +88 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/env.py +81 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/general.py +266 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/georoc.py +444 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/math.py +371 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/melts.py +397 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multip.py +29 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multiprocessing.py +29 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/pd.py +214 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/plot.py +345 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/skl.py +847 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/spatial.py +91 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/text.py +207 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/time.py +224 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/wfs.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/PKG-INFO +61 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/SOURCES.txt +83 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/dependency_links.txt +1 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/requires.txt +47 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from .ions import __default_charges__
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Site(object):
|
|
9
|
+
"""
|
|
10
|
+
Class for specifying mineral sites, including coordination information.
|
|
11
|
+
|
|
12
|
+
Will be used for partitioning and affinity calculations for estimating mineral
|
|
13
|
+
site chemistry.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, name=None, coordination=0, affinities={}):
|
|
17
|
+
if name is None:
|
|
18
|
+
name = self.__class__.__name__
|
|
19
|
+
self.name = name
|
|
20
|
+
self.coordination = coordination
|
|
21
|
+
self.affinities = affinities
|
|
22
|
+
self.occupancy = None
|
|
23
|
+
self.anionic = False
|
|
24
|
+
self.cationic = False
|
|
25
|
+
self.oxygen = False
|
|
26
|
+
|
|
27
|
+
def __str__(self):
|
|
28
|
+
if self.coordination:
|
|
29
|
+
return """[{}]{}""".format(self.name, self.coordination)
|
|
30
|
+
else:
|
|
31
|
+
return """{}""".format(self.name)
|
|
32
|
+
|
|
33
|
+
def __repr__(self):
|
|
34
|
+
if self.coordination:
|
|
35
|
+
return """{}("{}", {})""".format(
|
|
36
|
+
self.__class__.__name__, self.name, self.coordination
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
return """{}("{}")""".format(self.__class__.__name__, self.name)
|
|
40
|
+
|
|
41
|
+
def __eq__(self, other):
|
|
42
|
+
"""Check for equality between two sites."""
|
|
43
|
+
# check that the duck quacks/is a Site
|
|
44
|
+
pretest = (
|
|
45
|
+
hasattr(other, "name")
|
|
46
|
+
& hasattr(other, "coordination")
|
|
47
|
+
& hasattr(other, "affinities")
|
|
48
|
+
)
|
|
49
|
+
if pretest:
|
|
50
|
+
# Check for attribute equalilty
|
|
51
|
+
conds = (
|
|
52
|
+
(self.__class__.__name__ == other.__class__.__name__)
|
|
53
|
+
& (self.name == other.name)
|
|
54
|
+
& (self.coordination == other.coordination)
|
|
55
|
+
& (self.affinities == other.affinities)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return conds
|
|
59
|
+
else:
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
def __hash__(self):
|
|
63
|
+
return hash(self.__repr__().encode("UTF-8"))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class MX(Site):
|
|
67
|
+
"""
|
|
68
|
+
Octahedrally coordinated M site.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(self, name="M", coordination=8, *args, **kwargs):
|
|
72
|
+
super().__init__(name, coordination, *args, **kwargs)
|
|
73
|
+
self.cationic = True
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TX(Site):
|
|
77
|
+
"""
|
|
78
|
+
Tetrahedrally coordinated T site.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
name="T",
|
|
84
|
+
coordination=4,
|
|
85
|
+
affinities={"Si{4+}": 0, "Al{3+}": 1, "Fe{3+}": 2},
|
|
86
|
+
*args,
|
|
87
|
+
**kwargs
|
|
88
|
+
):
|
|
89
|
+
super().__init__(name, coordination, *args, **kwargs)
|
|
90
|
+
self.cationic = True
|
|
91
|
+
self.affinities = affinities
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class IX(Site):
|
|
95
|
+
"""
|
|
96
|
+
Dodecahedrally coordinated I site.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def __init__(self, name="I", coordination=12, *args, **kwargs):
|
|
100
|
+
super().__init__(name, coordination, *args, **kwargs)
|
|
101
|
+
self.cationic = True
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class VX(Site):
|
|
105
|
+
"""
|
|
106
|
+
Vacancy site.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def __init__(self, name="V", coordination=0, *args, **kwargs):
|
|
110
|
+
super().__init__(name, coordination, *args, **kwargs)
|
|
111
|
+
self.cationic = True
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class OX(Site):
|
|
115
|
+
"""
|
|
116
|
+
Oxygen site.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def __init__(
|
|
120
|
+
self, name="O", coordination=0, affinities={"O{2-}": 0}, *args, **kwargs
|
|
121
|
+
):
|
|
122
|
+
super().__init__(name, coordination, *args, **kwargs)
|
|
123
|
+
self.oxygen = True
|
|
124
|
+
self.affinities = affinities
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class AX(Site):
|
|
128
|
+
"""
|
|
129
|
+
Anion site.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
def __init__(self, name="A", coordination=0, *args, **kwargs):
|
|
133
|
+
super().__init__(name, coordination, *args, **kwargs)
|
|
134
|
+
self.anionic = True
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import os, sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import platform
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
from .comp import *
|
|
7
|
+
from .util.pd import to_frame, to_numeric
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
RELMASSS_UNITS = {
|
|
14
|
+
"%": 10 ** -2,
|
|
15
|
+
"pct": 10 ** -2,
|
|
16
|
+
"wt%": 10 ** -2,
|
|
17
|
+
"ppm": 10 ** -6,
|
|
18
|
+
"ppb": 10 ** -9,
|
|
19
|
+
"ppt": 10 ** -12,
|
|
20
|
+
"ppq": 10 ** -15,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def scale_multiplier(in_unit, target_unit="ppm"):
|
|
25
|
+
"""
|
|
26
|
+
Provides the scale difference between to mass units.
|
|
27
|
+
|
|
28
|
+
Todo: implement different inputs - string, list, pandas series
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
in_unit: current units
|
|
33
|
+
Units to be converted from
|
|
34
|
+
target_unit: target mass unit, ppm
|
|
35
|
+
Units to scale to.
|
|
36
|
+
"""
|
|
37
|
+
in_unit = str(in_unit).lower()
|
|
38
|
+
target_unit = str(target_unit).lower()
|
|
39
|
+
if (
|
|
40
|
+
not pd.isna(in_unit)
|
|
41
|
+
and (in_unit in RELMASSS_UNITS.keys())
|
|
42
|
+
and (target_unit in RELMASSS_UNITS.keys())
|
|
43
|
+
):
|
|
44
|
+
scale = RELMASSS_UNITS[in_unit] / RELMASSS_UNITS[target_unit]
|
|
45
|
+
else:
|
|
46
|
+
unkn = [i for i in [in_unit, target_unit] if i not in RELMASSS_UNITS]
|
|
47
|
+
logger.debug("Units not known: {}. Defaulting to unity.".format(unkn))
|
|
48
|
+
scale = 1.0
|
|
49
|
+
return scale
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class RefComp:
|
|
53
|
+
"""
|
|
54
|
+
Reference compositional model object, principally used for normalisation.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, filename, **kwargs):
|
|
58
|
+
self.data = pd.read_csv(filename, **kwargs)
|
|
59
|
+
self.data = self.data.set_index("var")
|
|
60
|
+
self.original_data = self.data.copy(deep=True) # preserve unaltered record
|
|
61
|
+
# self.add_oxides()
|
|
62
|
+
self.collect_vars()
|
|
63
|
+
self.set_units()
|
|
64
|
+
# self.aggregate_oxides() yet to be implemented
|
|
65
|
+
|
|
66
|
+
def aggregate_oxides(self, form="oxide"):
|
|
67
|
+
"""
|
|
68
|
+
Compositional models typically include elements in both oxide and
|
|
69
|
+
elemental form, typically divided into 'majors' and 'traces'.
|
|
70
|
+
|
|
71
|
+
For the purposes of normalisation - we need
|
|
72
|
+
i) to be able to access values of the form found in the dataset,
|
|
73
|
+
ii) for original values and uncertanties to be preserved, and
|
|
74
|
+
iii) for closure to be preserved.
|
|
75
|
+
|
|
76
|
+
There are multiple ways to acheive this - one is to create linked
|
|
77
|
+
element-oxide tables, and another is to force working in one format
|
|
78
|
+
(i.e. Al2O3 (wt%) --> Al (ppm))
|
|
79
|
+
"""
|
|
80
|
+
# identify cations to be aggregated
|
|
81
|
+
|
|
82
|
+
# for cation in cations:
|
|
83
|
+
# scale function
|
|
84
|
+
# aggregate_cation(df: pd.DataFrame, cation, form=form, unit_scale=None)
|
|
85
|
+
raise NotImplementedError("This issue has yet to be addressed.")
|
|
86
|
+
|
|
87
|
+
def collect_vars(
|
|
88
|
+
self,
|
|
89
|
+
headers=["Reservoir", "Reference", "ModelName", "ModelType"],
|
|
90
|
+
floatvars=["value", "unc_2sigma", "constraint_value"],
|
|
91
|
+
):
|
|
92
|
+
self.vars = [
|
|
93
|
+
i
|
|
94
|
+
for i in self.data.index
|
|
95
|
+
if (not pd.isna(self.data.loc[i, "value"])) and (i not in headers)
|
|
96
|
+
]
|
|
97
|
+
self.data.loc[self.vars, floatvars] = self.data.loc[self.vars, floatvars].apply(
|
|
98
|
+
to_numeric
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def set_units(self, to="ppm"):
|
|
102
|
+
v = self.vars
|
|
103
|
+
self.data.loc[v, "scale"] = self.data.loc[v, "units"].apply(
|
|
104
|
+
scale_multiplier, target_unit=to
|
|
105
|
+
)
|
|
106
|
+
self.data.loc[v, "units"] = to
|
|
107
|
+
self.data.loc[v, "value"] = self.data.loc[v, "value"] * self.data.loc[
|
|
108
|
+
v, "scale"
|
|
109
|
+
].astype(np.float)
|
|
110
|
+
|
|
111
|
+
def normalize(self, df, aux_cols=["LOD", "2SE"]):
|
|
112
|
+
"""
|
|
113
|
+
Normalize the values within a dataframe to the refererence composition.
|
|
114
|
+
Here we create indexes for normalisation of values and any auxilary
|
|
115
|
+
values (e.g. uncertainty).
|
|
116
|
+
|
|
117
|
+
## TODO: Implement uncertainty propagation
|
|
118
|
+
"""
|
|
119
|
+
dfc = to_frame(df.copy(deep=True))
|
|
120
|
+
|
|
121
|
+
cols = [c for c in dfc.columns if c in self.vars]
|
|
122
|
+
_cols = set(cols)
|
|
123
|
+
if len(cols) != len(_cols):
|
|
124
|
+
msg = "Duplicated columns in dataframe."
|
|
125
|
+
logger.warn(msg)
|
|
126
|
+
cols = list(_cols)
|
|
127
|
+
|
|
128
|
+
divisor = self.data.loc[cols, "value"].values
|
|
129
|
+
|
|
130
|
+
dfc.loc[:, cols] = np.divide(dfc.loc[:, cols].values, divisor)
|
|
131
|
+
return dfc
|
|
132
|
+
|
|
133
|
+
def denormalize(self, df, aux_cols=["LOD", "2SE"]):
|
|
134
|
+
"""
|
|
135
|
+
Unnormalize the values within a dataframe back to true composition.
|
|
136
|
+
"""
|
|
137
|
+
dfc = to_frame(df.copy(deep=True))
|
|
138
|
+
|
|
139
|
+
cols = [c for c in dfc.columns if c in self.vars]
|
|
140
|
+
_cols = set(cols)
|
|
141
|
+
if len(cols) != len(_cols):
|
|
142
|
+
msg = "Duplicated columns in dataframe."
|
|
143
|
+
logger.warn(msg)
|
|
144
|
+
cols = list(_cols)
|
|
145
|
+
|
|
146
|
+
multiplier = self.data.loc[cols, "value"].values
|
|
147
|
+
|
|
148
|
+
dfc.loc[:, cols] *= multiplier
|
|
149
|
+
return dfc
|
|
150
|
+
|
|
151
|
+
def ratio(self, ratio):
|
|
152
|
+
"""Calculates an elemental ratio."""
|
|
153
|
+
try:
|
|
154
|
+
assert "/" in ratio
|
|
155
|
+
num, den = ratio.split("/")
|
|
156
|
+
return self.data.loc[num, "value"] / self.data.loc[den, "value"]
|
|
157
|
+
except:
|
|
158
|
+
return np.nan
|
|
159
|
+
|
|
160
|
+
def __getattr__(self, var):
|
|
161
|
+
"""
|
|
162
|
+
Allow access to model values via attribute e.g. Model.Si
|
|
163
|
+
"""
|
|
164
|
+
if not isinstance(var, str):
|
|
165
|
+
var = str(var)
|
|
166
|
+
if var in self.data.index:
|
|
167
|
+
return self.data.loc[var, "value"]
|
|
168
|
+
else:
|
|
169
|
+
return np.nan
|
|
170
|
+
|
|
171
|
+
def __getitem__(self, vars):
|
|
172
|
+
"""
|
|
173
|
+
Allow access to model values via [] indexing e.g. Model['Si', 'Cr'].
|
|
174
|
+
Currently not implemented for ratios.
|
|
175
|
+
"""
|
|
176
|
+
if (
|
|
177
|
+
isinstance(vars, list)
|
|
178
|
+
or isinstance(vars, pd.Index)
|
|
179
|
+
or isinstance(vars, np.ndarray)
|
|
180
|
+
):
|
|
181
|
+
vars = [v if isinstance(v, str) else str(v) for v in vars]
|
|
182
|
+
elif not isinstance(vars, str):
|
|
183
|
+
vars = str(vars)
|
|
184
|
+
return self.data.loc[vars, ["value", "unc_2sigma", "units"]]
|
|
185
|
+
|
|
186
|
+
def __repr__(self):
|
|
187
|
+
return "Model of " + self.Reservoir + " (" + self.Reference + ")"
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def ReferenceCompositions(directory=None, formats=["csv"], **kwargs):
|
|
191
|
+
"""
|
|
192
|
+
Build all reference models in a given directory.
|
|
193
|
+
|
|
194
|
+
Here we use either the input directory, or the default data directory
|
|
195
|
+
within this module.
|
|
196
|
+
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
directory: file directory, None
|
|
200
|
+
Location of reference data files.
|
|
201
|
+
formats: reference data formats, csv
|
|
202
|
+
List of potential data formats to draw from.
|
|
203
|
+
Currently only csv will work.
|
|
204
|
+
"""
|
|
205
|
+
if platform.system() == "Windows":
|
|
206
|
+
kwargs["encoding"] = kwargs.get("encoding", None) or "cp1252"
|
|
207
|
+
else:
|
|
208
|
+
kwargs["encoding"] = kwargs.get("encoding", None) or "cp1252"
|
|
209
|
+
|
|
210
|
+
curr_dir = os.path.realpath(__file__)
|
|
211
|
+
module_dir = Path(sys.modules["pyrolite"].__file__).parent
|
|
212
|
+
directory = directory or (Path(module_dir) / "data" / "refcomp").resolve()
|
|
213
|
+
|
|
214
|
+
assert directory.exists() and directory.is_dir()
|
|
215
|
+
|
|
216
|
+
files = []
|
|
217
|
+
for fmt in formats:
|
|
218
|
+
files.extend(directory.glob("./*." + fmt))
|
|
219
|
+
|
|
220
|
+
comps = {}
|
|
221
|
+
for f in files:
|
|
222
|
+
r = RefComp(f, **kwargs)
|
|
223
|
+
comps[r.ModelName] = r
|
|
224
|
+
return comps
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import os, sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import platform
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy as np
|
|
6
|
+
from .compositions import *
|
|
7
|
+
from .util.pd import to_frame, to_numeric
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
RELMASSS_UNITS = {
|
|
14
|
+
'%': 10**-2,
|
|
15
|
+
'wt%': 10**-2,
|
|
16
|
+
'ppm': 10**-6,
|
|
17
|
+
'ppb': 10**-9,
|
|
18
|
+
'ppt': 10**-12,
|
|
19
|
+
'ppq': 10**-15,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def scale_multiplier(in_unit, target_unit='ppm'):
|
|
24
|
+
"""
|
|
25
|
+
Provides the scale difference between to mass units.
|
|
26
|
+
|
|
27
|
+
Todo: implement different inputs - string, list, pandas series
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
in_unit: current units
|
|
32
|
+
Units to be converted from
|
|
33
|
+
target_unit: target mass unit, ppm
|
|
34
|
+
Units to scale to.
|
|
35
|
+
"""
|
|
36
|
+
in_unit = str(in_unit).lower()
|
|
37
|
+
target_unit = str(target_unit).lower()
|
|
38
|
+
if not pd.isna(in_unit) and \
|
|
39
|
+
(in_unit in RELMASSS_UNITS.keys()) and \
|
|
40
|
+
(target_unit in RELMASSS_UNITS.keys()):
|
|
41
|
+
scale = RELMASSS_UNITS[in_unit] / RELMASSS_UNITS[target_unit]
|
|
42
|
+
else:
|
|
43
|
+
unkn = [i for i in [in_unit, target_unit] if i not in RELMASSS_UNITS]
|
|
44
|
+
logger.info("Units not known: {}. Defaulting to unity.".format(unkn))
|
|
45
|
+
scale = 1.
|
|
46
|
+
return scale
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RefComp:
|
|
50
|
+
"""
|
|
51
|
+
Reference compositional model object, principally used for normalisation.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, filename, **kwargs):
|
|
55
|
+
self.data = pd.read_csv(filename, **kwargs)
|
|
56
|
+
self.data = self.data.set_index('var')
|
|
57
|
+
self.original_data = self.data.copy() # preserve unaltered record
|
|
58
|
+
#self.add_oxides()
|
|
59
|
+
self.collect_vars()
|
|
60
|
+
self.set_units()
|
|
61
|
+
# self.aggregate_oxides() yet to be implemented
|
|
62
|
+
|
|
63
|
+
def aggregate_oxides(self, form='oxide'):
|
|
64
|
+
"""
|
|
65
|
+
Compositional models typically include elements in both oxide and
|
|
66
|
+
elemental form, typically divided into 'majors' and 'traces'.
|
|
67
|
+
|
|
68
|
+
For the purposes of normalisation - we need
|
|
69
|
+
i) to be able to access values of the form found in the dataset,
|
|
70
|
+
ii) for original values and uncertanties to be preserved, and
|
|
71
|
+
iii) for closure to be preserved.
|
|
72
|
+
|
|
73
|
+
There are multiple ways to acheive this - one is to create linked
|
|
74
|
+
element-oxide tables, and another is to force working in one format
|
|
75
|
+
(i.e. Al2O3 (wt%) --> Al (ppm))
|
|
76
|
+
"""
|
|
77
|
+
# identify cations to be aggregated
|
|
78
|
+
|
|
79
|
+
# for cation in cations:
|
|
80
|
+
# scale function
|
|
81
|
+
# aggregate_cation(df: pd.DataFrame, cation, form=form, unit_scale=None)
|
|
82
|
+
raise NotImplementedError('This issue has yet to be addressed.')
|
|
83
|
+
|
|
84
|
+
def collect_vars(self,
|
|
85
|
+
headers=['Reservoir',
|
|
86
|
+
'Reference',
|
|
87
|
+
'ModelName',
|
|
88
|
+
'ModelType'],
|
|
89
|
+
floatvars=['value',
|
|
90
|
+
'unc_2sigma',
|
|
91
|
+
'constraint_value']):
|
|
92
|
+
self.vars = [i for i in self.data.index
|
|
93
|
+
if (not pd.isna(self.data.loc[i, 'value']))
|
|
94
|
+
and (i not in headers)]
|
|
95
|
+
self.data.loc[self.vars,
|
|
96
|
+
floatvars] = to_numeric(self.data.loc[self.vars,
|
|
97
|
+
floatvars],
|
|
98
|
+
errors='coerce')
|
|
99
|
+
|
|
100
|
+
def set_units(self, to='ppm'):
|
|
101
|
+
v = self.vars
|
|
102
|
+
self.data.loc[v, 'scale'] = \
|
|
103
|
+
self.data.loc[v, 'units'].apply(scale_multiplier,
|
|
104
|
+
target_unit=to)
|
|
105
|
+
self.data.loc[v, 'units'] = to
|
|
106
|
+
self.data.loc[v, 'value'] = self.data.loc[v, 'value'] * \
|
|
107
|
+
self.data.loc[v, 'scale'].astype(np.float)
|
|
108
|
+
|
|
109
|
+
def normalize(self, df, aux_cols=["LOD","2SE"]):
|
|
110
|
+
"""
|
|
111
|
+
Normalize the values within a dataframe to the refererence composition.
|
|
112
|
+
Here we create indexes for normalisation of values and any auxilary
|
|
113
|
+
values (e.g. uncertainty).
|
|
114
|
+
|
|
115
|
+
## TODO: Implement uncertainty propagation
|
|
116
|
+
"""
|
|
117
|
+
dfc = to_frame(df.copy())
|
|
118
|
+
|
|
119
|
+
cols = [c for c in dfc.columns if c in self.vars]
|
|
120
|
+
_cols = set(cols)
|
|
121
|
+
if len(cols) != len(_cols):
|
|
122
|
+
msg = 'Duplicated columns in dataframe.'
|
|
123
|
+
logger.warn(msg)
|
|
124
|
+
cols = list(_cols)
|
|
125
|
+
|
|
126
|
+
divisor = self.data.loc[cols, 'value'].values
|
|
127
|
+
|
|
128
|
+
dfc.loc[:, cols] = np.divide(dfc.loc[:, cols].values,
|
|
129
|
+
divisor)
|
|
130
|
+
return dfc
|
|
131
|
+
|
|
132
|
+
def ratio(self, ratio):
|
|
133
|
+
"""Calculates an elemental ratio."""
|
|
134
|
+
try:
|
|
135
|
+
assert "/" in ratio
|
|
136
|
+
num, den = ratio.split('/')
|
|
137
|
+
return self.data.loc[num, 'value'] / self.data.loc[den, 'value']
|
|
138
|
+
except:
|
|
139
|
+
return np.nan
|
|
140
|
+
|
|
141
|
+
def __getattr__(self, var):
|
|
142
|
+
"""
|
|
143
|
+
Allow access to model values via attribute e.g. Model.Si
|
|
144
|
+
"""
|
|
145
|
+
if not isinstance(var, str):
|
|
146
|
+
var = str(var)
|
|
147
|
+
if var in self.data.index:
|
|
148
|
+
return self.data.loc[var, 'value']
|
|
149
|
+
else:
|
|
150
|
+
return np.nan
|
|
151
|
+
|
|
152
|
+
def __getitem__(self, vars):
|
|
153
|
+
"""
|
|
154
|
+
Allow access to model values via [] indexing e.g. Model['Si', 'Cr'].
|
|
155
|
+
Currently not implemented for ratios.
|
|
156
|
+
"""
|
|
157
|
+
if isinstance(vars, list) or \
|
|
158
|
+
isinstance(vars, pd.Index) or \
|
|
159
|
+
isinstance(vars, np.ndarray):
|
|
160
|
+
vars = [v if isinstance(v, str) else str(v) for v in vars]
|
|
161
|
+
elif not isinstance(vars, str):
|
|
162
|
+
vars = str(vars)
|
|
163
|
+
return self.data.loc[vars, ['value', 'unc_2sigma', 'units']]
|
|
164
|
+
|
|
165
|
+
def __repr__(self):
|
|
166
|
+
return "Model of "+self.Reservoir+" ("+self.Reference+")"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def ReferenceCompositions(directory=None, formats=['csv'], **kwargs):
|
|
170
|
+
"""
|
|
171
|
+
Build all reference models in a given directory.
|
|
172
|
+
|
|
173
|
+
Here we use either the input directory, or the default data directory
|
|
174
|
+
within this module.
|
|
175
|
+
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
directory: file directory, None
|
|
179
|
+
Location of reference data files.
|
|
180
|
+
formats: reference data formats, csv
|
|
181
|
+
List of potential data formats to draw from.
|
|
182
|
+
Currently only csv will work.
|
|
183
|
+
"""
|
|
184
|
+
if platform.system() =='Windows':
|
|
185
|
+
kwargs['encoding'] = kwargs.get('encoding', None) or 'cp1252'
|
|
186
|
+
else:
|
|
187
|
+
kwargs['encoding'] = kwargs.get('encoding', None) or 'cp1252'
|
|
188
|
+
|
|
189
|
+
curr_dir = os.path.realpath(__file__)
|
|
190
|
+
module_dir = Path(sys.modules['pyrolite'].__file__).parent
|
|
191
|
+
directory = directory or \
|
|
192
|
+
(Path(module_dir) / "data" / "refcomp").resolve()
|
|
193
|
+
|
|
194
|
+
assert directory.exists() and directory.is_dir()
|
|
195
|
+
|
|
196
|
+
files = []
|
|
197
|
+
for fmt in formats:
|
|
198
|
+
files.extend(directory.glob("./*."+fmt))
|
|
199
|
+
|
|
200
|
+
comps = {}
|
|
201
|
+
for f in files:
|
|
202
|
+
r = RefComp(f, **kwargs)
|
|
203
|
+
comps[r.ModelName] = r
|
|
204
|
+
return comps
|