diff --git a/MANIFEST.in b/MANIFEST.in index d33c584..27927ae 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include *.txt -recursive-include doc *.txt +recursive-include doc * +include glasspy/data/datafiles/* diff --git a/README.md b/README.md index c838e76..e1752b8 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ GlassPy is a Python module for scientists working with glass materials. The aim is to provide classes and functions written in Python for materials scientists working with glass and non-crystalline materials. The hope is that with an open and collaborative project, we can build a reliable toolset to support faster and reproducible research on this topic. ## How to install -The source code is hosted on GitHub at: https://github.com/drcassar/glasspy. +The source code is hosted on GitHub at https://github.com/drcassar/glasspy. Binary installers for the latest released version are available at the [Python Package Index](https://pypi.org/project/glasspy/). To install GlassPy using pip run @@ -20,11 +20,10 @@ To install the latest development version of GlassPy run ```sh pip install --upgrade git+git://github.com/drcassar/glasspy ``` - ## Development -GlassPy was born as a personal tool back in 2013 when I started coding with Python. It is based on a colection of MATLAB code that I wrote for the Glass State graduate course of 2010 and for the numerical analysis during my PhD. +GlassPy was born as a personal tool back in 2013 when I started coding with Python. It is based on a collection of MATLAB code that I wrote for the Glass State graduate course of 2010 and the numerical analysis during my PhD. -Right now, I'm sorting all my code and adequately documenting it to build this Python module. My personal objective is to increase the reproducibility of my research and hopefully be useful for researchers working in the field of glass science. +Right now, I'm sorting all my code and adequately documenting it to build this Python module. My personal objective is to increase my research's reproducibility and hopefully be useful for researchers working in the field of glass science. ## Documentation There is no documentation right now, but all the functions have detailed docstring. @@ -42,12 +41,26 @@ Some examples are provided as notebooks in Google Colab (they run in the cloud, - [SciPy](https://www.scipy.org/) - [Pandas](https://pandas.pydata.org/) - [lmfit](https://lmfit.github.io/lmfit-py/) +- [chemparse](https://pypi.org/project/chemparse/) ## Other python repositories for glass science - [RelaxPy](https://github.com/Mauro-Glass-Group/RelaxPy) - Module to compute glass relaxation kinetics. - [PyGlass](https://github.com/jrafolsr/PyGlass) - Module to simulate the specific heat signature of glasses with a specified thermal treatment following the Tool-Narayanaswamy-Moynihan model. -## License +## SciGlass database licence +[ODbL](https://github.com/drcassar/glasspy/blob/master/glasspy/data/datafiles/LICENCE_sciglass) + +ODC Open Database License (ODbL) + +Copyright (c) 2019 EPAM Systems + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## GlassPy license [GPL](https://github.com/drcassar/glasspy/blob/master/LICENSE) GlassPy, Python module for scientists working with glass materials. Copyright (C) 2019-2020 Daniel Roberto Cassar diff --git a/README_PyPI.md b/README_PyPI.md index d84cb4a..88c7aa0 100644 --- a/README_PyPI.md +++ b/README_PyPI.md @@ -5,7 +5,7 @@ GlassPy is a Python module for scientists working with glass materials. The aim is to provide classes and functions written in Python for materials scientists working with glass and non-crystalline materials. The hope is that with an open and collaborative project, we can build a reliable toolset to support faster and reproducible research on this topic. ## How to install -The source code is hosted on GitHub at: https://github.com/drcassar/glasspy. +The source code is hosted on GitHub at https://github.com/drcassar/glasspy. Binary installers for the latest released version are available at the [Python Package Index](https://pypi.org/project/glasspy/). To install GlassPy using pip run @@ -18,11 +18,10 @@ To install the latest development version of GlassPy run ```sh pip install --upgrade git+git://github.com/drcassar/glasspy ``` - ## Development -GlassPy was born as a personal tool back in 2013 when I started coding with Python. It is based on a colection of MATLAB code that I wrote for the Glass State graduate course of 2010 and for the numerical analysis during my PhD. +GlassPy was born as a personal tool back in 2013 when I started coding with Python. It is based on a collection of MATLAB code that I wrote for the Glass State graduate course of 2010 and the numerical analysis during my PhD. -Right now, I'm sorting all my code and adequately documenting it to build this Python module. My personal objective is to increase the reproducibility of my research and hopefully be useful for researchers working in the field of glass science. +Right now, I'm sorting all my code and adequately documenting it to build this Python module. My personal objective is to increase my research's reproducibility and hopefully be useful for researchers working in the field of glass science. ## Documentation There is no documentation right now, but all the functions have detailed docstring. @@ -40,12 +39,26 @@ Some examples are provided as notebooks in Google Colab (they run in the cloud, - [SciPy](https://www.scipy.org/) - [Pandas](https://pandas.pydata.org/) - [lmfit](https://lmfit.github.io/lmfit-py/) +- [chemparse](https://pypi.org/project/chemparse/) ## Other python repositories for glass science - [RelaxPy](https://github.com/Mauro-Glass-Group/RelaxPy) - Module to compute glass relaxation kinetics. - [PyGlass](https://github.com/jrafolsr/PyGlass) - Module to simulate the specific heat signature of glasses with a specified thermal treatment following the Tool-Narayanaswamy-Moynihan model. -## License +## SciGlass database licence +[ODbL](https://github.com/drcassar/glasspy/blob/master/glasspy/data/datafiles/LICENCE_sciglass) + +ODC Open Database License (ODbL) + +Copyright (c) 2019 EPAM Systems + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## GlassPy license [GPL](https://github.com/drcassar/glasspy/blob/master/LICENSE) GlassPy, Python module for scientists working with glass materials. Copyright (C) 2019-2020 Daniel Roberto Cassar diff --git a/glasspy/data/analysis.py b/glasspy/data/analysis.py index 6966fe4..2ab858f 100644 --- a/glasspy/data/analysis.py +++ b/glasspy/data/analysis.py @@ -2,20 +2,22 @@ from scipy.spatial.distance import cdist -def relativeNeighborhoodDeviation(X, - Y, - distance_threshold, - metric='euclidean'): +def relativeNeighborhoodDeviation( + X, + Y, + distance_threshold, + metric='euclidean', +): '''Computes the Relative Neighbourhood Deviation (RND). - RND is used to check the intrinsic deviation in the data. An example of it - being used can be seen in Figure 3 from Ref. [1]. + RND is used to check the intrinsic deviation in the data. See Ref. [1] for + an example. Parameters ---------- X : n-d array - Values of the features (or independent variable). This function uses a - lot of RAM depending on the size of X. + Values of the features (or independent variable). Beware! This function + uses a lot of RAM depending on the size of X. Y : 1-d array Values of the target (or dependent variable). diff --git a/glasspy/data/datafiles/LICENSE_sciglass b/glasspy/data/datafiles/LICENSE_sciglass new file mode 100644 index 0000000..57feb8f --- /dev/null +++ b/glasspy/data/datafiles/LICENSE_sciglass @@ -0,0 +1,21 @@ +ODC Open Database License (ODbL) + +Copyright (c) 2019 EPAM Systems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/glasspy/data/datafiles/sciglass.csv.xz b/glasspy/data/datafiles/sciglass.csv.xz new file mode 100644 index 0000000..43a329c Binary files /dev/null and b/glasspy/data/datafiles/sciglass.csv.xz differ diff --git a/glasspy/data/datafiles/sciglass_atfrac.csv.xz b/glasspy/data/datafiles/sciglass_atfrac.csv.xz new file mode 100644 index 0000000..140eb3b Binary files /dev/null and b/glasspy/data/datafiles/sciglass_atfrac.csv.xz differ diff --git a/glasspy/data/datafiles/sciglass_comp.csv.xz b/glasspy/data/datafiles/sciglass_comp.csv.xz new file mode 100644 index 0000000..70b6126 Binary files /dev/null and b/glasspy/data/datafiles/sciglass_comp.csv.xz differ diff --git a/glasspy/data/datafiles/viscosity_at_frac.csv.xz b/glasspy/data/datafiles/viscosity_at_frac.csv.xz new file mode 100644 index 0000000..567aa83 Binary files /dev/null and b/glasspy/data/datafiles/viscosity_at_frac.csv.xz differ diff --git a/glasspy/data/datafiles/viscosity_compounds.csv.xz b/glasspy/data/datafiles/viscosity_compounds.csv.xz new file mode 100644 index 0000000..7941431 Binary files /dev/null and b/glasspy/data/datafiles/viscosity_compounds.csv.xz differ diff --git a/glasspy/data/load.py b/glasspy/data/load.py new file mode 100644 index 0000000..78165b6 --- /dev/null +++ b/glasspy/data/load.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 + +import pandas as pd +import numpy as np +import os + +from .manipulate import removeColumnsWithOnlyZerosMultiIndex + +__cur_path = os.path.dirname(__file__) +SCIGLASS_DATABASE_PATH = os.path.join(__cur_path, 'datafiles/sciglass.csv.xz') +SCIGLASS_COMP_DATABASE_PATH = os.path.join(__cur_path, 'datafiles/sciglass_comp.csv.xz') +SCIGLASS_ATFRAC_DATABASE_PATH = os.path.join(__cur_path, 'datafiles/sciglass_atfrac.csv.xz') + + +def sciglass(load_compounds=False, load_atomic_fraction=True): + """Load SciGlass data into a pandas DataFrame + + SciGlass is a database of glass properties Copyright (c) 2019 EPAM Systems + and licensed under ODC Open Database License (ODbL). The database is hosted + on GitHub [1]. A portion of the SciGlass database is shipped with GlassPy, + so no additional downloads are necessary. + + This function returns a MultiIndex pandas DataFrame. The first-level + indexes are: + at_frac : relative to the atomic fraction of the chemical elements that + make the glass. Only available if "load_atomic_fraction" is True. + + comp : relative to the chemical compounds that make the glass. Only + available if "load_compounds" is True. + + meta : metadata. + + prop : properties. + + The property column names are: + + RefractiveIndex : refractive index measured at wavelenght of 589.3 nm. + Dimensionless. + + AbbeNumber : Abbe number. Dimensionless. + + CTE : linear coefficient of thermal expansion below the glass transition + temperature. Unit: K^{-1}. + + ElasticModulus : Elastic of Young's Modulus. Unit: GPa. + + Tg : glass transition temperature. Unit: K. + + Tliquidus: liquidus temperature. Unit: K. + + T0 to T12 : "Tn" is the temperature where the base-10 logarithm of + viscosity (in Pa.s) is "n". Example: T4 is the temperature where + log10(viscosity) = 4. Unit: K. + + ViscosityAt773K to ViscosityAt2473K : value of base-10 logarithm of + viscosity (in Pa.s) at a certain temperature. Example: + ViscosityAt1073K is the log10(viscosity) at 1073 Kelvin. + Dimensionless. + + Parameters + ---------- + load_compounds : bool, False + If True then chemical compounds are loaded and added to the DataFrame + + load_atomic_fraction : bool, True + If True then the atomic fractions are loaded and added to the DataFrame + + Returns + ------- + data : pandas DataFrame + MultiIndex DataFrame containing a portion of the SciGlass database. + + References + ---------- + [1] Epam/SciGlass. 2019. EPAM Systems, 2019. + https://github.com/epam/SciGlass. + + """ + data = pd.read_csv(SCIGLASS_DATABASE_PATH, index_col=0) + metadata_index = ['ChemicalAnalysis', 'Author', 'Year'] + property_index = np.array(sorted(set(data.columns) - set(metadata_index))) + d = {} + + if load_atomic_fraction: + data_af = pd.read_csv(SCIGLASS_ATFRAC_DATABASE_PATH, index_col=0) + data['NumberChemicalElements'] = data_af.astype('bool').sum(axis=1) + metadata_index.append('NumberChemicalElements') + d['at_frac'] = data_af + + if load_compounds: + data_c = pd.read_csv(SCIGLASS_COMP_DATABASE_PATH, index_col=0) + data['NumberCompounds'] = data_c.astype('bool').sum(axis=1) + metadata_index.append('NumberCompounds') + d['comp'] = data_c + + d['meta'] = data[metadata_index] + d['prop'] = data[property_index] + data = pd.concat(d, axis=1) + + return data + + +def sciglassOxides( + minimum_fraction_oxygen=0.3, + elements_to_remove=['S', 'H', 'C', 'Pt', 'Au', 'F', 'Cl', 'N', 'Br', 'I'], + load_compounds=False, +): + '''Load only the oxides from SciGlass database into a pandas DataFrame + + The default settings of this function follow the definion of an oxide glass + used in [1]. These can be changed with the parameters of the function. + + SciGlass is a database of glass properties Copyright (c) 2019 EPAM Systems + and licensed under ODC Open Database License (ODbL). The database is hosted + on GitHub [1]. A portion of the SciGlass database is shipped with GlassPy, + so no additional downloads are necessary. + + This function returns a MultiIndex pandas DataFrame. The first-level + indexes are: + at_frac : relative to the atomic fraction of the chemical elements that + make the glass. Only available if "load_atomic_fraction" is True. + + comp : relative to the chemical compounds that make the glass. Only + available if "load_compounds" is True. + + meta : metadata. + + prop : properties. + + The property column names are: + + RefractiveIndex : refractive index measured at wavelenght of 589.3 nm. + Dimensionless. + + AbbeNumber : Abbe number. Dimensionless. + + CTE : linear coefficient of thermal expansion below the glass transition + temperature. Unit: K^{-1}. + + ElasticModulus : Elastic of Young's Modulus. Unit: GPa. + + Tg : glass transition temperature. Unit: K. + + Tliquidus: liquidus temperature. Unit: K. + + T0 to T12 : "Tn" is the temperature where the base-10 logarithm of + viscosity (in Pa.s) is "n". Example: T4 is the temperature where + log10(viscosity) = 4. Unit: K. + + ViscosityAt773K to ViscosityAt2473K : value of base-10 logarithm of + viscosity (in Pa.s) at a certain temperature. Example: + ViscosityAt1073K is the log10(viscosity) at 1073 Kelvin. + Dimensionless. + + Parameters + ---------- + minimum_fraction_oxygen : float + Minimum atomic fraction of oxygen for the glass to be considered an + oxide. A value between 0 and 1 is expected. + + elements_to_remove : list or 1-d array or False + Iterable with the chemical elements (strings) that must not be present + in the glass in. If None then no chemical element is removed. Default + value is ['S', 'H', 'C', 'Pt', 'Au', 'F', 'Cl', 'N', 'Br', 'I']. + + load_compounds : bool + If True then chemical compounds are loaded and added to the DataFrame. + Default value is False + + Returns + ------- + data : pandas DataFrame + MultiIndex DataFrame containing a portion of the SciGlass database. + + References + ---------- + [1] Alcobaça, E., Mastelini, S.M., Botari, T., Pimentel, B.A., Cassar, D.R., + de Carvalho, A.C.P. de L.F., and Zanotto, E.D. (2020). Explainable + Machine Learning Algorithms For Predicting Glass Transition + Temperatures. Acta Materialia 188, 92–100. + + [2] Epam/SciGlass. 2019. EPAM Systems, 2019. + https://github.com/epam/SciGlass. + + ''' + data = sciglass(load_compounds, load_atomic_fraction=True) + logic = data['at_frac']['O'] >= minimum_fraction_oxygen + data = data.loc[data[logic].index] + + if elements_to_remove: + for el in elements_to_remove: + logic = data['at_frac'][el] == 0 + data = data.loc[data[logic].index] + + data = removeColumnsWithOnlyZerosMultiIndex(data, 'at_frac') + + if load_compounds: + data = removeColumnsWithOnlyZerosMultiIndex(data, 'comp') + + return data diff --git a/glasspy/data/manipulate.py b/glasspy/data/manipulate.py new file mode 100644 index 0000000..63715c0 --- /dev/null +++ b/glasspy/data/manipulate.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +def removeColumnsWithOnlyZerosMultiIndex(data, first_index): + '''Remove columns with only zeros in MultiIndex pandas DataFrames + + Parameters + ---------- + data : DataFrame + MultiIndex dataframe + + first_index : string + Name of the first level index to search for columns with only zeroes. + + Returns + ------- + data_clean : DataFrame + DataFrame with columns with only zeroes removed. + + ''' + nonzero_cols_bool = data[first_index].sum(axis=0).astype(bool) + zero_cols = data[first_index].columns.values[~nonzero_cols_bool] + drop_cols = [(first_index, col) for col in zero_cols] + data_clean = data.drop(drop_cols, axis=1) + + return data_clean diff --git a/glasspy/data/viscosity.py b/glasspy/data/viscosity.py new file mode 100644 index 0000000..32fe5bc --- /dev/null +++ b/glasspy/data/viscosity.py @@ -0,0 +1,179 @@ +import numpy as np +import pandas as pd +import os +from chemparse import parse_formula + +from .load import sciglass + + +__cur_path = os.path.dirname(__file__) +VISCOSITY_AT_FRAC = os.path.join(__cur_path, 'datafiles/viscosity_at_frac.csv.xz') +VISCOSITY_COMPOUND = os.path.join(__cur_path, 'datafiles/viscosity_compounds.csv.xz') + + +def genViscosityTable(compounds=False): + '''Generates a viscosity table from the SciGlass database + + Parameters + ---------- + compounds : bool, False + If True, then the chemical compounds are returned, but not the atomic + fractions. The opposite happens if False. + + Returns + ------- + data : pandas DataFrame + DataFrame containing all viscosity data from the SciGlass database. + + ''' + if compounds: + c_index = 'comp' + load_compounds = True + load_atomic_fraction = False + else: + c_index = 'at_frac' + load_compounds = False + load_atomic_fraction = True + + sg_data = sciglass( + load_compounds=load_compounds, + load_atomic_fraction=load_atomic_fraction, + ) + + # Temperatures with a fixed viscosity value + Tviscos = np.arange(0, 13) + df_lst = [] + for logvisc in Tviscos: + d = sg_data.dropna(subset=[('prop', f'T{logvisc}')]) + comp = d[c_index].copy() + comp['temperature'] = d[('prop', f'T{logvisc}')] + comp['log_viscosity'] = logvisc + comp['author'] = d[('meta', 'Author')] + comp['year'] = d[('meta', 'Year')] + df_lst.append(comp) + data1 = pd.concat(df_lst) + + # Viscosity at a fixed temperature + viscoT = np.arange(0, 1700, 100) + 873 + df_lst = [] + for T in viscoT: + if f'ViscosityAt{T}K' in d['prop'].columns: + d = sg_data.dropna(subset=[('prop', f'ViscosityAt{T}K')]) + comp = d[c_index].copy() + comp['temperature'] = T + comp['log_viscosity'] = d[('prop', f'ViscosityAt{T}K')] + comp['author'] = d[('meta', 'Author')] + comp['year'] = d[('meta', 'Year')] + df_lst.append(comp) + data2 = pd.concat(df_lst) + + data = pd.concat([data1, data2], sort=False) + nonzero_cols_bool = data.sum(axis=0).astype(bool) + zero_cols = data.columns.values[~nonzero_cols_bool] + data = data.drop(zero_cols, axis=1) + + return data + + +def loadViscosityTable(compounds=False): + '''Loads a viscosity table from the SciGlass database + + This function returns the sabe DataFrame as genViscosityTable, but is + faster. + + Parameters + ---------- + compounds : bool, False + If True, then the chemical compounds are returned, but not the atomic + fractions. The opposite happens if False. + + Returns + ------- + data : pandas DataFrame + DataFrame containing all viscosity data from the SciGlass database. + + ''' + if compounds: + path = VISCOSITY_COMPOUND + else: + path = VISCOSITY_AT_FRAC + + data = pd.read_csv(path, index_col=0) + + return data + + +def viscosityFromString(chemical_formula, decimal_round=3, viscosity_df=None): + '''Query viscosity data from SciGlass from a string + + Parameters + ---------- + chemical_formula : string + String of the chemical formula for the query. + + decimal_round : integer, optional + Decimal place to round the chemical composition for the query. Default + value is 3. + + viscosity_df : pandas DataFrame or None + If a DataFrame is supplied, then it is used for the query. If None then + the SciGlass viscosity dataset is used. Note that the provided DataFrame + must be in atomic fraction and have the last four columns with names + 'T', 'log_visc', 'Author', and 'Year'. + + Returns + ------- + data : pandas DataFrame + DataFrame with the result of the query. The columns are "temperature" + for the temperature in Kelvin, "log_viscosity" for the base-10 logarithm + of viscosity (taken from viscosity measured in Pa.s), "Author" for the + name of the first author of the original source, and "Year" for the year + of publication of the original source. + + Info + ---- + The string for the chemical formula must be an acceptable string for the + module chemparse [1], examples include simple strings with integers such as + "SiO2", strings with fractional stoichiometry such as "C1.5O3", and strings + with non-nested parentheses such as "(LiO2)1(SiO2)2". + + References + ---------- + [1] https://pypi.org/project/chemparse/ + + ''' + def parseFormulaNorm(formula, sum_total=1, round_=False): + dic = parse_formula(formula) + sum_values = sum(dic.values()) + + if round_: + norm_dic = {k : round(v * sum_total / sum_values, round_) + for k,v in dic.items()} + else: + norm_dic = {k : v / sum_values for k,v in dic.items()} + + return norm_dic + + non_chem_col = ['temperature', 'log_viscosity', 'author', 'year'] + + if viscosity_df is None: + data = loadViscosityTable(compounds=False) + else: + data = viscosity_df.copy() + + atoms = list(set(data.columns.values) - set(non_chem_col)) + data[atoms] = data[atoms].round(decimal_round).copy() + + cdic = parseFormulaNorm(chemical_formula, 1, decimal_round) + + for at in cdic: + logic = data[at] == cdic[at] + data = data[logic] + + for at in set(atoms) - set(cdic): + logic = data[at] == 0 + data = data[logic] + + data = data[non_chem_col] + + return data diff --git a/glasspy/viscosity/regression.py b/glasspy/viscosity/regression.py index 61b51b6..c1150c4 100644 --- a/glasspy/viscosity/regression.py +++ b/glasspy/viscosity/regression.py @@ -354,7 +354,6 @@ class MYEGA(_BaseViscosityRegression): Parameters ---------- - autofit : boolean, optional 'True' if the regression should be performed during the Class initiation. 'False' otherwise. Default value is True. @@ -466,7 +465,6 @@ class VFT(_BaseViscosityRegression): Parameters ---------- - autofit : boolean, optional 'True' if the regression should be performed during the Class initiation. 'False' otherwise. Default value is True. @@ -576,13 +574,127 @@ def fit(self, weights=None, params=None, fitmethod='leastsq'): return fitresult, model +class AM(_BaseViscosityRegression): + ''' + Class for performing the AM regression. + + Parameters + ---------- + autofit : boolean, optional + 'True' if the regression should be performed during the Class initiation. + 'False' otherwise. Default value is True. + + table : pandas DataFrame, optional, must be a named argument + DataFrame with a 'temperature' column and a 'log_viscosity' column. A + RuntimeError is raised if the class is initiated without a table *or* + without both temperature and log_viscosity arguments. + + temperature : array_like, optional, must be a named argument + Temperature in Kelvin. A RuntimeError is raised if the class is initiated + without a table *or* without both time and density arguments. If + 'table' is given then this argument is ignored. + + log_viscosity : array_like, optional, must be a named argument + Base-10 logarithm of viscosity. It is highly recommended to use + viscosity in units of Pascal second. A RuntimeError is raised if the + class is initiated without a table *or* without both time and density + arguments. If 'table' is given then this argument is ignored. + + ''' + def __init__(self, autofit=True, **kwargs): + _BaseViscosityRegression.__init__(self, **kwargs) + + def __str__(self): + return 'AM' + + def getModel(self, guess_T12, guess_fragility, guess_log_eta_inf): + ''' + Creates a model for regression. + + Parameters + ---------- + guess_T12 : float + Guess for the temperature were the viscosity is 10^12 Pa.s. + + guess_fragility : float + Guess for the fragility index. + + guess_log_eta_inf : array_like, optional + Guess for the base-10 logarithm of the infinite viscosity. + + Notes + ----- + The parameters 'T0' and 'A' are also added in the model paremeters. + + Returns + ------- + model : instance of lmfit's Model class. + + ''' + model = Model(eq.AM_alt, name=self.__str__()) + + model.set_param_hint('T12', vary=True, min=0, value=guess_T12) + model.set_param_hint('m', vary=True, min=0, value=guess_fragility) + model.set_param_hint( + 'log_eta_inf', + vary=True, + max=11.99, + value=guess_log_eta_inf + ) + model.set_param_hint( + 'alpha', + vary=False, + expr=r'm / (12 - log_eta_inf)', + ) + model.set_param_hint( + 'beta', + vary=False, + expr=r'T12 * (log(10) * (12 - log_eta_inf))**((12 - log_eta_inf)/m)', + ) + + return model + + def fit(self, weights=None, params=None, fitmethod='leastsq'): + ''' + Regression of the viscosity data. + + Parameters + ---------- + weights : array_like or None, optional + The weights of log_viscosity to use during the regression. If None + then no weights are applied. Default value is None. + + params : instance of lmfit's Parameters class or None, optional + Optional Parameters instance to pass to the fit function. If None + then the model will generate the Parameters class during fitting. + Default value is None. + + fitmethod : str, optional + Method to use for the regression. See lmfit's documentation for + more information. Default value is 'leastsq'. + + Returns + ------- + fitresult : instance of lmfit's ModelResult class + Result of the regression. See lmfit for documentation on the + ModelResult class. + + model : instance of lmfit's Model class. + + ''' + guess_T12, guess_fragility, guess_log_eta_inf = self.guess() + model = self.getModel(guess_T12, guess_fragility, guess_log_eta_inf) + fitresult = super().fit(model, weights, params, fitmethod) + + return fitresult, model + + class CLU(_BaseViscosityRegression): ''' Class for performing the CLU regression. Parameters ---------- - autofit : boolean, optional 'True' if the regression should be performed during the Class initiation. 'False' otherwise. Default value is True. @@ -697,7 +809,6 @@ class BS(_BaseViscosityRegression): Parameters ---------- - autofit : boolean, optional 'True' if the regression should be performed during the Class initiation. 'False' otherwise. Default value is True. @@ -814,7 +925,6 @@ class Dienes(_BaseViscosityRegression): Parameters ---------- - autofit : boolean, optional 'True' if the regression should be performed during the Class initiation. 'False' otherwise. Default value is True. @@ -943,7 +1053,6 @@ class DML(_BaseViscosityRegression): Parameters ---------- - autofit : boolean, optional 'True' if the regression should be performed during the Class initiation. 'False' otherwise. Default value is True. diff --git a/setup.py b/setup.py index 9c3a3d0..b8b998d 100644 --- a/setup.py +++ b/setup.py @@ -5,20 +5,26 @@ setuptools.setup( name='glasspy', - version='0.2', + version='0.3', author='Daniel Roberto Cassar', - author_email='daniel.r.cassar@gmail.com', + author_email='contact@danielcassar.com.br', description='Python module for scientists working with glass materials', long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/drcassar/glasspy", packages=setuptools.find_packages(), install_requires=[ - 'numpy>=1.18', 'scipy>=1.3', 'pandas>=1.0.0', 'lmfit>=1.0.0' + 'numpy>=1.16', + 'scipy>=1.2', + 'pandas>=1.0.0', + 'lmfit>=1.0.0', + 'chemparse>=0.1.0', ], keywords='glass, non-crystalline materials', classifiers=[ - "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: OS Independent", "Development Status :: 2 - Pre-Alpha", @@ -28,4 +34,5 @@ ], license='GPL', python_requires='>=3.6', + include_package_data=True, )