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.
Files changed (119) hide show
  1. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__init__.py +10 -0
  2. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/__init__.cpython-36.pyc +0 -0
  3. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/_version.cpython-36.pyc +0 -0
  4. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/alteration.cpython-36.pyc +0 -0
  5. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/classification.cpython-36.pyc +0 -0
  6. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/compositions.cpython-36.pyc +0 -0
  7. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/geochem.cpython-36.pyc +0 -0
  8. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/melts.cpython-36.pyc +0 -0
  9. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/norm.cpython-36.pyc +0 -0
  10. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/normalisation.cpython-36.pyc +0 -0
  11. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/plot.cpython-36.pyc +0 -0
  12. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/_version.py +21 -0
  13. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/alteration.py +66 -0
  14. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/classification.py +222 -0
  15. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__init__.py +9 -0
  16. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/__init__.cpython-36.pyc +0 -0
  17. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/aggregate.cpython-36.pyc +0 -0
  18. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/codata.cpython-36.pyc +0 -0
  19. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/impute.cpython-36.pyc +0 -0
  20. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/renorm.cpython-36.pyc +0 -0
  21. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/aggregate.py +391 -0
  22. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/codata.py +266 -0
  23. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/impute.py +82 -0
  24. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/renorm.py +40 -0
  25. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/compositions.py +524 -0
  26. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_CFB_Dataset_List.csv +42 -0
  27. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_Convergent_Dataset_List.csv +42 -0
  28. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OBFB_Dataset_List.csv +5 -0
  29. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OIB_Dataset_List.csv +49 -0
  30. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OceanicPlateau_Dataset_List.csv +18 -0
  31. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/contents.json +1 -0
  32. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-35.pyc +0 -0
  33. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-36.pyc +0 -0
  34. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/env.py +1063 -0
  35. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ba.modelfield +0 -0
  36. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Bs.modelfield +0 -0
  37. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.F.modelfield +0 -0
  38. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O1.modelfield +0 -0
  39. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O2.modelfield +0 -0
  40. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O3.modelfield +0 -0
  41. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Pc.modelfield +0 -0
  42. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ph.modelfield +0 -0
  43. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.R.modelfield +0 -0
  44. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S1.modelfield +0 -0
  45. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S2.modelfield +0 -0
  46. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S3.modelfield +0 -0
  47. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T1.modelfield +0 -0
  48. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T2.modelfield +0 -0
  49. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U1.modelfield +0 -0
  50. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U2.modelfield +0 -0
  51. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U3.modelfield +0 -0
  52. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.modelfields +0 -0
  53. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.nan.modelfield +0 -0
  54. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.none.modelfield +0 -0
  55. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS.clsf.gz +0 -0
  56. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/aphanitic.clsf.gz +0 -0
  57. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/gabbroic.clsf.gz +0 -0
  58. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/peralkalinity.clsf.gz +0 -0
  59. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/phaneritic.clsf.gz +0 -0
  60. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/ultramafic.clsf.gz +0 -0
  61. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/CH_PalmeONeill2014.csv +95 -0
  62. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DDMM_WorkmanHart2005.csv +105 -0
  63. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DMM_WorkmanHart2005.csv +105 -0
  64. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DM_SaltersStrake2004.csv +95 -0
  65. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/EDMM_WorkmanHart2005.csv +105 -0
  66. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/PM_PalmeONeill2014.csv +95 -0
  67. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/timescale/geotimescale_spans.csv +180 -0
  68. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/geochem.py +821 -0
  69. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/melts.py +92 -0
  70. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__init__.py +10 -0
  71. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/__init__.cpython-36.pyc +0 -0
  72. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/db.cpython-36.pyc +0 -0
  73. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/ions.cpython-36.pyc +0 -0
  74. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/mineral.cpython-36.pyc +0 -0
  75. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/sites.cpython-36.pyc +0 -0
  76. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/db.py +88 -0
  77. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/ions.py +78 -0
  78. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/mineral.py +587 -0
  79. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/sites.py +134 -0
  80. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/norm.py +224 -0
  81. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/normalisation.py +204 -0
  82. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/plot.py +514 -0
  83. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__init__.py +13 -0
  84. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/__init__.cpython-36.pyc +0 -0
  85. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/database.cpython-36.pyc +0 -0
  86. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/env.cpython-36.pyc +0 -0
  87. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/general.cpython-36.pyc +0 -0
  88. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/georoc.cpython-36.pyc +0 -0
  89. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/math.cpython-36.pyc +0 -0
  90. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/melts.cpython-36.pyc +0 -0
  91. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multip.cpython-36.pyc +0 -0
  92. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multiprocessing.cpython-36.pyc +0 -0
  93. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/pd.cpython-36.pyc +0 -0
  94. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/plot.cpython-36.pyc +0 -0
  95. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/skl.cpython-36.pyc +0 -0
  96. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/spatial.cpython-36.pyc +0 -0
  97. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/text.cpython-36.pyc +0 -0
  98. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/time.cpython-36.pyc +0 -0
  99. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/wfs.cpython-36.pyc +0 -0
  100. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/database.py +88 -0
  101. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/env.py +81 -0
  102. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/general.py +266 -0
  103. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/georoc.py +444 -0
  104. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/math.py +371 -0
  105. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/melts.py +397 -0
  106. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multip.py +29 -0
  107. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multiprocessing.py +29 -0
  108. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/pd.py +214 -0
  109. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/plot.py +345 -0
  110. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/skl.py +847 -0
  111. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/spatial.py +91 -0
  112. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/text.py +207 -0
  113. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/time.py +224 -0
  114. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/wfs.py +10 -0
  115. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/PKG-INFO +61 -0
  116. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/SOURCES.txt +83 -0
  117. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/dependency_links.txt +1 -0
  118. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/requires.txt +47 -0
  119. 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