From cae00936bb4eb50350bb63f55a00092d12f2bf41 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Tue, 9 Apr 2019 19:44:01 +0200 Subject: [PATCH 01/60] WIP: begin implementing symmetry function writer --- src/libnnp/version.h | 6 ++-- tools/python/write_symfunc.py | 53 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 tools/python/write_symfunc.py diff --git a/src/libnnp/version.h b/src/libnnp/version.h index b285a5af4..de90660dd 100644 --- a/src/libnnp/version.h +++ b/src/libnnp/version.h @@ -18,8 +18,8 @@ #define VERSION_H #define NNP_VERSION "2.0.0" -#define NNP_GIT_REV "98f117d8273b1747972a3ff1a66198defe1ad714" -#define NNP_GIT_REV_SHORT "98f117d" -#define NNP_GIT_BRANCH "master" +#define NNP_GIT_REV "62f67caed5fb85b19edf1be8ec565ea3568648d4" +#define NNP_GIT_REV_SHORT "62f67ca" +#define NNP_GIT_BRANCH "symfunc_paramgen" #endif diff --git a/tools/python/write_symfunc.py b/tools/python/write_symfunc.py new file mode 100644 index 000000000..434624c4a --- /dev/null +++ b/tools/python/write_symfunc.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +import numpy as np +import sys + +symfunc_list_radial = [{"type": 2, "element": "Cu", "neighbor": 'Cu'}, + {"type": 2, "element": "Cu", "neighbor": "S"}, + {"type": 2, "element": "S", "neighbor": "Cu"}, + {"type": 2, "element": "S", "neighbor": "S"}] + +symfunc_list_angular_narrow = [{"type": 3, "element": "Cu", "neighbor_1": "Cu", "neighbor_2": "Cu"}, + {"type": 3, "element": "Cu", "neighbor_1": "Cu", "neighbor_2": "S"}, + {"type": 3, "element": "Cu", "neighbor_1": "S", "neighbor_2": "Cu"}, + {"type": 3, "element": "Cu", "neighbor_1": "S", "neighbor_2": "S"}, + {"type": 3, "element": "S", "neighbor_1": "Cu", "neighbor_2": "Cu"}, + {"type": 3, "element": "S", "neighbor_1": "Cu", "neighbor_2": "S"}, + {"type": 3, "element": "S", "neighbor_1": "S", "neighbor_2": "Cu"}, + {"type": 3, "element": "S", "neighbor_1": "S", "neighbor_2": "S"}] + + +symfunc_list = symfunc_list_radial + symfunc_list_angular_narrow + +# get all unique symmetry function types contained in the list of symmetry functions +sf_types = set([sf['type'] for sf in symfunc_list]) +print(sf_types) + +# get all elements contained in the list of symmetry functions +elems = set([el['element'] for el in symfunc_list]) +print(elems) + +print() + + +sf_list_type_2 = [sf for sf in symfunc_list if sf['type']==2] +for central_elem in elems: + sys.stdout.write("# Radial symmetry functions for element {0:2s}\n".format(central_elem)) + sf_list_central = [sf for sf in sf_list_type_2 if sf['element']==central_elem] + for neighbor_elem in elems: + sf_list_neighbors = [sf for sf in sf_list_central if sf['neighbor']==neighbor_elem] + print(sf_list_neighbors) + sys.stdout.write('\n') + + +sf_list_type_3 = [sf for sf in symfunc_list if sf['type']==3] +for central_elem in elems: + sys.stdout.write("# Narrow angular symmetry functions for element {0:2s}\n".format(central_elem)) + sf_list_central = [sf for sf in sf_list_type_3 if sf['element']==central_elem] + for neighbor_elem_1 in elems: + sf_list_neighbors_1 = [sf for sf in sf_list_central if sf['neighbor_1']==neighbor_elem_1] + for neighbor_elem_2 in elems: + sf_list_neighbors_2 = [sf for sf in sf_list_central if sf['neighbor_2'] == neighbor_elem_2] + print(sf_list_neighbors_2) + sys.stdout.write('\n') \ No newline at end of file From 1311b936183bee0033ee2d2ac53480229e773efd Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 11 Apr 2019 09:38:29 +0200 Subject: [PATCH 02/60] Create classes for symmetry function descriptors. --- tools/python/SymFuncDescriptors.py | 72 ++++++++++++++++++++++++++++++ tools/python/write_symfunc.py | 52 +++++++++++---------- 2 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 tools/python/SymFuncDescriptors.py diff --git a/tools/python/SymFuncDescriptors.py b/tools/python/SymFuncDescriptors.py new file mode 100644 index 000000000..b98b58dce --- /dev/null +++ b/tools/python/SymFuncDescriptors.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +import numpy as np +import sys +import itertools + + +class SymFuncDescriptorRadial: + def __init__(self, central_element, neighbor_element, eta, r_cutoff, r_shift): + # radial symmetry functions are called type 2 + self.type = 12 + + self.central_element = central_element + self.neighbor_element = neighbor_element + self.eta = eta + self.r_cutoff = r_cutoff + self.r_shift = r_shift + + def get_descriptor_string(self): + descriptor_string = "symfunction_short {0:2s} {1:2d} {2:2s} {3:9.3E} {4:9.3E} {5:9.3E}".format( + self.central_element, self.type, self.neighbor_element, self.eta, self.r_shift, self.r_cutoff) + return descriptor_string + + +class SymFuncDescriptorAng: + def __init__(self, central_element, type_keyword, neighbor_element_1, neighbor_element_2, eta, lambd, zeta, r_cutoff, r_shift): + if type_keyword == 'narrow': + self.type = 3 + elif type_keyword == 'wide': + self.type = 9 + else: + raise(ValueError('type_keyword must be one of ["narrow", "wide"]')) + + self.central_element = central_element + # store neighbor elements in a set to make explicit that the order is irrelevant + self.neighbor_elements = {neighbor_element_1, neighbor_element_2} + self.eta = eta + self.r_cutoff = r_cutoff + self.r_shift = r_shift + self.lambd = lambd + self.zeta = zeta + + def get_descriptor_string(self): + if len(self.neighbor_elements) == 2: + neighbor_element_1 = sorted(self.neighbor_elements)[0] + neighbor_element_2 = sorted(self.neighbor_elements)[1] + elif len(self.neighbor_elements) == 1: + neighbor_element_1 = sorted(self.neighbor_elements)[0] + neighbor_element_2 = neighbor_element_1 + else: + raise(RuntimeError('Neighbor elements must be either the same or two different ones, but not more than two')) + + descriptor_string = "symfunction_short {0:2s} {1:2d} {2:2s} {3:2s} {4:9.3E} {5:2.0f} {6:9.3E} {7:9.3E} {8:9.3E}".format( + self.central_element, self.type, neighbor_element_1, neighbor_element_2, + self.eta, self.lambd, self.zeta, self.r_cutoff, self.r_shift) + return descriptor_string + + +sf_radial_1 = SymFuncDescriptorRadial(central_element='Cu', neighbor_element='S', eta=4., r_shift=5, r_cutoff=6) +sf_radial_2 = SymFuncDescriptorRadial(central_element='S', neighbor_element='S', eta=1., r_shift=2, r_cutoff=3) +sf_ang_narrow = SymFuncDescriptorAng(central_element='Cu', type_keyword='narrow', neighbor_element_1='S', neighbor_element_2='S', eta=4., lambd=1, zeta=.5, r_shift=5, r_cutoff=6) +sf_ang_wide = SymFuncDescriptorAng(central_element='Cu', type_keyword='wide', neighbor_element_1='S', neighbor_element_2='Cu', eta=4., lambd=1, zeta=.5, r_shift=5, r_cutoff=6) + + +print(sf_radial_1.get_descriptor_string()) +print(sf_radial_2.get_descriptor_string()) + +print(sf_ang_narrow.get_descriptor_string()) +print(sf_ang_wide.get_descriptor_string()) + + +print() \ No newline at end of file diff --git a/tools/python/write_symfunc.py b/tools/python/write_symfunc.py index 434624c4a..e9c3f4ff2 100644 --- a/tools/python/write_symfunc.py +++ b/tools/python/write_symfunc.py @@ -2,20 +2,21 @@ import numpy as np import sys +import itertools -symfunc_list_radial = [{"type": 2, "element": "Cu", "neighbor": 'Cu'}, - {"type": 2, "element": "Cu", "neighbor": "S"}, - {"type": 2, "element": "S", "neighbor": "Cu"}, - {"type": 2, "element": "S", "neighbor": "S"}] +symfunc_list_radial = [{"type": 2, "element": 'Cu', "neighbors": {'Cu'}}, + {"type": 2, "element": 'Cu', "neighbors": {'S'}}, + {"type": 2, "element": 'S', "neighbors": {'Cu'}}, + {"type": 2, "element": 'S', "neighbors": {'S'}}] + + +symfunc_list_angular_narrow = [{"type": 3, "element": 'Cu', "neighbors": {'Cu'}}, + {"type": 3, "element": 'Cu', "neighbors": {'S'}}, + {"type": 3, "element": 'Cu', "neighbors": {'Cu', 'S'}}, + {"type": 3, "element": 'S', "neighbors": {'Cu'}}, + {"type": 3, "element": 'S', "neighbors": {'S'}}, + {"type": 3, "element": 'S', "neighbors": {'Cu', 'S'}}] -symfunc_list_angular_narrow = [{"type": 3, "element": "Cu", "neighbor_1": "Cu", "neighbor_2": "Cu"}, - {"type": 3, "element": "Cu", "neighbor_1": "Cu", "neighbor_2": "S"}, - {"type": 3, "element": "Cu", "neighbor_1": "S", "neighbor_2": "Cu"}, - {"type": 3, "element": "Cu", "neighbor_1": "S", "neighbor_2": "S"}, - {"type": 3, "element": "S", "neighbor_1": "Cu", "neighbor_2": "Cu"}, - {"type": 3, "element": "S", "neighbor_1": "Cu", "neighbor_2": "S"}, - {"type": 3, "element": "S", "neighbor_1": "S", "neighbor_2": "Cu"}, - {"type": 3, "element": "S", "neighbor_1": "S", "neighbor_2": "S"}] symfunc_list = symfunc_list_radial + symfunc_list_angular_narrow @@ -24,13 +25,16 @@ sf_types = set([sf['type'] for sf in symfunc_list]) print(sf_types) -# get all elements contained in the list of symmetry functions +# get all unique elements contained in the list of symmetry functions elems = set([el['element'] for el in symfunc_list]) print(elems) -print() +# get all unique unordered pairs of two elements (including pairs of two elements that are the same) +elem_pairs = itertools.combinations_with_replacement(elems, 2) +print() + sf_list_type_2 = [sf for sf in symfunc_list if sf['type']==2] for central_elem in elems: sys.stdout.write("# Radial symmetry functions for element {0:2s}\n".format(central_elem)) @@ -41,13 +45,13 @@ sys.stdout.write('\n') -sf_list_type_3 = [sf for sf in symfunc_list if sf['type']==3] -for central_elem in elems: - sys.stdout.write("# Narrow angular symmetry functions for element {0:2s}\n".format(central_elem)) - sf_list_central = [sf for sf in sf_list_type_3 if sf['element']==central_elem] - for neighbor_elem_1 in elems: - sf_list_neighbors_1 = [sf for sf in sf_list_central if sf['neighbor_1']==neighbor_elem_1] - for neighbor_elem_2 in elems: - sf_list_neighbors_2 = [sf for sf in sf_list_central if sf['neighbor_2'] == neighbor_elem_2] - print(sf_list_neighbors_2) - sys.stdout.write('\n') \ No newline at end of file +# sf_list_type_3 = [sf for sf in symfunc_list if sf['type']==3] +# for central_elem in elems: +# sys.stdout.write("# Narrow angular symmetry functions for element {0:2s}\n".format(central_elem)) +# sf_list_central = [sf for sf in sf_list_type_3 if sf['element']==central_elem] +# for neighbor_elem_1 in elems: +# sf_list_neighbors_1 = [sf for sf in sf_list_central if sf['neighbor_1']==neighbor_elem_1] +# for neighbor_elem_2 in elems: +# sf_list_neighbors_2 = [sf for sf in sf_list_central if sf['neighbor_2'] == neighbor_elem_2] +# print(sf_list_neighbors_2) +# sys.stdout.write('\n') \ No newline at end of file From a03c1b29b552e976a044b6ba7b89f9bbc3a3eaa5 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 12 Apr 2019 11:01:45 +0200 Subject: [PATCH 03/60] Start work on class SymFuncParamGenerator. --- tools/python/SymFuncParamGenerator.py | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tools/python/SymFuncParamGenerator.py diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py new file mode 100644 index 000000000..0681b3c40 --- /dev/null +++ b/tools/python/SymFuncParamGenerator.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +import numpy as np +import sys +import itertools + + +class SymFuncParamGenerator: + def __init__(self, elements): + self.elements = elements + + self.sf_list_radial = [] + self.sf_list_ang_narrow = [] + self.sf_list_ang_wide = [] + + self.generation_info_radial = '' + self.generation_info_ang_narrow = '' + self.generation_info_ang_wide = '' + + def get_elements(self): + return self.elements + + def clear_radial(self): + self.sf_list_radial = [] + self.generation_info_radial = '' + + def clear_ang_narrow(self): + self.sf_list_ang_narrow = [] + self.generation_info_ang_narrow = '' + + def clear_ang_wide(self): + self.sf_list_ang_wide = [] + self.generation_info_ang_wide = '' + + def generate_params_radial(self): + + + + +elems = ['Cu', 'S'] + +myGenerator = SymFuncParamGenerator(elems) + +print(myGenerator.get_elements()) + + + + + + From 157a1ca3a1196087801ce732b299402fe7f100fa Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 15 Apr 2019 17:50:18 +0200 Subject: [PATCH 04/60] Begin radial parameter generation. Start implementing radial parameter generation method from 2018 'Imbalzano et al' paper --- tools/python/SymFuncParamGenerator.py | 55 ++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index 0681b3c40..430308f96 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -32,9 +32,47 @@ def clear_ang_wide(self): self.sf_list_ang_wide = [] self.generation_info_ang_wide = '' - def generate_params_radial(self): - - + def generate_radial_grid(self, method, mode, r_0, r_cutoff, nb_gridpoints): + if method == 'gastegger2018': + if mode == 'center': + pass + elif mode == 'shift': + pass + else: + raise (ValueError('invalid argument for "mode"')) + + elif method == 'imbalzano2018': + if mode == 'center': + nb_intervals = nb_gridpoints - 1 + gridpoint_indices = np.array(range(0, nb_intervals + 1)) + eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) / r_cutoff) ** 2 + rs_grid = np.zeros_like(eta_grid) + elif mode == 'shift': + # create extended auxiliary grid of r_shift values, that contains nb_gridpoints + 1 values + nb_intervals_extended = nb_gridpoints + gridpoint_indices_extended = np.array(range(0, nb_intervals_extended + 1)) + rs_grid_extended = r_cutoff / nb_intervals_extended ** ( + gridpoint_indices_extended / nb_intervals_extended) + # from pairs of neighboring r_shift values, compute eta values + # doing this for the nb_gridpoints + 1 values in the auxiliary grid ultimately gives... + # ...nb_gridpoints different values for eta + eta_grid = np.zeros(nb_gridpoints) + for idx in range(len(rs_grid_extended)-1): + eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 + eta_grid[idx] = eta_current + # create final grid of rs_shift values by excluding the first entry... + # ...(for which r_shift coincides with the cutoff radius) from the extended grid + rs_grid = rs_grid_extended[1:] + # reverse the order of r_shift and eta values so they are sorted in ascending order of r_shift... + # ...(not necessary, but makes it consistent with the other methods) + rs_grid = np.flip(rs_grid) + eta_grid = np.flip(eta_grid) + else: + raise (ValueError('invalid argument for "mode"')) + else: + raise (ValueError('invalid argument for "method"')) + + return rs_grid, eta_grid elems = ['Cu', 'S'] @@ -43,8 +81,13 @@ def generate_params_radial(self): print(myGenerator.get_elements()) +print('\ncenter mode') +a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='center', r_0=0, r_cutoff=6., nb_gridpoints=5) +print(a) +print(b) - - - +print('\nshift mode') +a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='shift', r_0=0, r_cutoff=6., nb_gridpoints=5) +print(a) +print(b) From 129620511de0dff1e776c0c8501346069ec58882 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 17 Apr 2019 14:52:12 +0200 Subject: [PATCH 05/60] Continue work on radial parameter generation. Add radial parameter generation method from 2018 'Gastegger et al.' paper. --- tools/python/SymFuncParamGenerator.py | 53 ++++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index 430308f96..d552308a1 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -3,6 +3,7 @@ import numpy as np import sys import itertools +import traceback class SymFuncParamGenerator: @@ -32,16 +33,33 @@ def clear_ang_wide(self): self.sf_list_ang_wide = [] self.generation_info_ang_wide = '' - def generate_radial_grid(self, method, mode, r_0, r_cutoff, nb_gridpoints): + def generate_radial_grid(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): if method == 'gastegger2018': + if r_lower is None: + raise TypeError('Argument r_lower is required for method "gastegger2018"') + + r_upper = r_cutoff - 0.5 # TODO: decide if hardcoding this (and in Angstrom!) is a good idea + # create auxiliary grid + grid = np.linspace(r_lower, r_upper, nb_gridpoints) + if mode == 'center': - pass + rs_grid = np.zeros(nb_gridpoints) + eta_grid = 1.0 / (2.0 * grid ** 2) elif mode == 'shift': - pass + rs_grid = grid + dr = (r_upper - r_lower) / (nb_gridpoints - 1) + eta_grid = np.full(nb_gridpoints, 1.0 / (2.0 * dr * dr)) else: - raise (ValueError('invalid argument for "mode"')) + raise ValueError('invalid argument for "mode"') elif method == 'imbalzano2018': + if r_lower is not None: + # TODO: decide if it makes sense to do the warning this way + sys.stderr.write( + 'Warning: argument r_lower is not used in method "imbalzano2018" and will be ignored.\n') + traceback.print_stack() + sys.stderr.flush() + if mode == 'center': nb_intervals = nb_gridpoints - 1 gridpoint_indices = np.array(range(0, nb_intervals + 1)) @@ -57,37 +75,46 @@ def generate_radial_grid(self, method, mode, r_0, r_cutoff, nb_gridpoints): # doing this for the nb_gridpoints + 1 values in the auxiliary grid ultimately gives... # ...nb_gridpoints different values for eta eta_grid = np.zeros(nb_gridpoints) - for idx in range(len(rs_grid_extended)-1): + for idx in range(len(rs_grid_extended) - 1): eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 eta_grid[idx] = eta_current # create final grid of rs_shift values by excluding the first entry... # ...(for which r_shift coincides with the cutoff radius) from the extended grid rs_grid = rs_grid_extended[1:] # reverse the order of r_shift and eta values so they are sorted in ascending order of r_shift... - # ...(not necessary, but makes it consistent with the other methods) + # ...(not necessary, but makes the output consistent with the other methods) rs_grid = np.flip(rs_grid) eta_grid = np.flip(eta_grid) else: - raise (ValueError('invalid argument for "mode"')) + raise ValueError('invalid argument for "mode"') else: - raise (ValueError('invalid argument for "method"')) + raise ValueError('invalid argument for "method"') return rs_grid, eta_grid elems = ['Cu', 'S'] - myGenerator = SymFuncParamGenerator(elems) print(myGenerator.get_elements()) -print('\ncenter mode') -a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='center', r_0=0, r_cutoff=6., nb_gridpoints=5) +print('\ngastegger2018 center mode') +a, b = myGenerator.generate_radial_grid(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=9, + r_lower=1.5) print(a) print(b) -print('\nshift mode') -a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='shift', r_0=0, r_cutoff=6., nb_gridpoints=5) +print('\ngastegger2018 shift mode') +a, b = myGenerator.generate_radial_grid(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) print(a) print(b) +print('\nimbalzano2018 center mode') +a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='center', r_cutoff=6., nb_gridpoints=5) +print(a) +print(b) + +print('\nimbalzano2018 shift mode') +a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) +print(a) +print(b) From e0e8c2c4181874574eba6a7b497c8f40651c77c9 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 18 Apr 2019 11:09:57 +0200 Subject: [PATCH 06/60] Began reworking storage of symfunc params. r_shift, eta, zeta now stored in individual arrays, information on radial parameter generation settings stored in dictionary. --- tools/python/SymFuncParamGenerator.py | 97 +++++++++++++++------------ 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index d552308a1..1f962692f 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -10,43 +10,43 @@ class SymFuncParamGenerator: def __init__(self, elements): self.elements = elements - self.sf_list_radial = [] - self.sf_list_ang_narrow = [] - self.sf_list_ang_wide = [] + self.r_shift_grid = None + self.eta_grid = None - self.generation_info_radial = '' - self.generation_info_ang_narrow = '' - self.generation_info_ang_wide = '' + self.r_cutoff = None + self.symfunc_type = None + self.radial_grid_info = None + + self.lambdas = None + self.zetas = [-1.0, 1.0] def get_elements(self): return self.elements - def clear_radial(self): - self.sf_list_radial = [] - self.generation_info_radial = '' - - def clear_ang_narrow(self): - self.sf_list_ang_narrow = [] - self.generation_info_ang_narrow = '' + def clear_all(self): + # TODO: make this do something... + pass - def clear_ang_wide(self): - self.sf_list_ang_wide = [] - self.generation_info_ang_wide = '' + def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): + # store infos on radial parameter generation settings (that are independent of method) + self.radial_grid_info = {'method': method, 'mode': mode, 'r_cutoff': r_cutoff, 'nb_gridpoints': nb_gridpoints} - def generate_radial_grid(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): if method == 'gastegger2018': if r_lower is None: raise TypeError('Argument r_lower is required for method "gastegger2018"') r_upper = r_cutoff - 0.5 # TODO: decide if hardcoding this (and in Angstrom!) is a good idea + # store settings that are unique to this method + self.radial_grid_info.update({'r_lower': r_lower, 'r_upper': r_upper}) + # create auxiliary grid grid = np.linspace(r_lower, r_upper, nb_gridpoints) if mode == 'center': - rs_grid = np.zeros(nb_gridpoints) + r_shift_grid = np.zeros(nb_gridpoints) eta_grid = 1.0 / (2.0 * grid ** 2) elif mode == 'shift': - rs_grid = grid + r_shift_grid = grid dr = (r_upper - r_lower) / (nb_gridpoints - 1) eta_grid = np.full(nb_gridpoints, 1.0 / (2.0 * dr * dr)) else: @@ -54,7 +54,7 @@ def generate_radial_grid(self, method, mode, r_cutoff, nb_gridpoints, r_lower=No elif method == 'imbalzano2018': if r_lower is not None: - # TODO: decide if it makes sense to do the warning this way + # TODO: decide if necessary to do this warning and if doing it this way makes sense sys.stderr.write( 'Warning: argument r_lower is not used in method "imbalzano2018" and will be ignored.\n') traceback.print_stack() @@ -64,57 +64,70 @@ def generate_radial_grid(self, method, mode, r_cutoff, nb_gridpoints, r_lower=No nb_intervals = nb_gridpoints - 1 gridpoint_indices = np.array(range(0, nb_intervals + 1)) eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) / r_cutoff) ** 2 - rs_grid = np.zeros_like(eta_grid) + r_shift_grid = np.zeros_like(eta_grid) elif mode == 'shift': # create extended auxiliary grid of r_shift values, that contains nb_gridpoints + 1 values nb_intervals_extended = nb_gridpoints gridpoint_indices_extended = np.array(range(0, nb_intervals_extended + 1)) rs_grid_extended = r_cutoff / nb_intervals_extended ** ( gridpoint_indices_extended / nb_intervals_extended) - # from pairs of neighboring r_shift values, compute eta values + # from pairs of neighboring r_shift values, compute eta values. # doing this for the nb_gridpoints + 1 values in the auxiliary grid ultimately gives... # ...nb_gridpoints different values for eta eta_grid = np.zeros(nb_gridpoints) for idx in range(len(rs_grid_extended) - 1): eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 eta_grid[idx] = eta_current - # create final grid of rs_shift values by excluding the first entry... + # create final grid of r_shift values by excluding the first entry... # ...(for which r_shift coincides with the cutoff radius) from the extended grid - rs_grid = rs_grid_extended[1:] - # reverse the order of r_shift and eta values so they are sorted in ascending order of r_shift... + r_shift_grid = rs_grid_extended[1:] + # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift... # ...(not necessary, but makes the output consistent with the other methods) - rs_grid = np.flip(rs_grid) + r_shift_grid = np.flip(r_shift_grid) eta_grid = np.flip(eta_grid) else: raise ValueError('invalid argument for "mode"') else: raise ValueError('invalid argument for "method"') - return rs_grid, eta_grid + self.r_shift_grid = r_shift_grid + self.eta_grid = eta_grid + + def set_zetas(self, zeta_values): + self.zetas = zeta_values + + def set_symfunc_type(self, symfunc_type): + self.symfunc_type = symfunc_type + + def write_generation_info(self): + pass + + def write_parameter_strings(self): + pass elems = ['Cu', 'S'] -myGenerator = SymFuncParamGenerator(elems) +myGen = SymFuncParamGenerator(elems) -print(myGenerator.get_elements()) +print(myGen.get_elements()) print('\ngastegger2018 center mode') -a, b = myGenerator.generate_radial_grid(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=9, - r_lower=1.5) -print(a) -print(b) +myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=9, + r_lower=1.5) +print(myGen.r_shift_grid) +print(myGen.eta_grid) print('\ngastegger2018 shift mode') -a, b = myGenerator.generate_radial_grid(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) -print(a) -print(b) +myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) +print(myGen.r_shift_grid) +print(myGen.eta_grid) print('\nimbalzano2018 center mode') -a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='center', r_cutoff=6., nb_gridpoints=5) -print(a) -print(b) +myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) +print(myGen.r_shift_grid) +print(myGen.eta_grid) print('\nimbalzano2018 shift mode') -a, b = myGenerator.generate_radial_grid(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) -print(a) -print(b) +myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) +print(myGen.r_shift_grid) +print(myGen.eta_grid) From f3d07180d6d6b4a1898b04e0a224d7935e93d47a Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 18 Apr 2019 15:24:09 +0200 Subject: [PATCH 07/60] Implemented method for writing generation settings --- tools/python/SymFuncParamGenerator.py | 67 ++++++++++++++++++++------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index 1f962692f..d8c0f1ec4 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -10,6 +10,8 @@ class SymFuncParamGenerator: def __init__(self, elements): self.elements = elements + # TODO: add dictionary that matches sf type strings with the corresponding numbers + self.r_shift_grid = None self.eta_grid = None @@ -17,8 +19,8 @@ def __init__(self, elements): self.symfunc_type = None self.radial_grid_info = None - self.lambdas = None - self.zetas = [-1.0, 1.0] + self.lambdas = np.array([-1.0, 1.0]) + self.zetas = None def get_elements(self): return self.elements @@ -27,6 +29,11 @@ def clear_all(self): # TODO: make this do something... pass + def set_symfunc_type(self, symfunc_type): + # TODO: 1) make this raise an error if invalid type is given + # TODO: 2) set zetas to None if a radial type is given? + self.symfunc_type = symfunc_type + def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): # store infos on radial parameter generation settings (that are independent of method) self.radial_grid_info = {'method': method, 'mode': mode, 'r_cutoff': r_cutoff, 'nb_gridpoints': nb_gridpoints} @@ -94,13 +101,38 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= self.eta_grid = eta_grid def set_zetas(self, zeta_values): - self.zetas = zeta_values + self.zetas = np.array(zeta_values) - def set_symfunc_type(self, symfunc_type): - self.symfunc_type = symfunc_type + def check_completeness(self): + if self.radial_grid_info is None: + raise TypeError('No radial grid has been generated.') + if self.symfunc_type is None: + raise TypeError('Symmetry function type not set.') + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.zetas is None: + raise TypeError('zeta values not set.') def write_generation_info(self): - pass + self.check_completeness() + type_descriptions = dict(radial='Radial', + angular_narrow='Narrow angular', + angular_wide='Wide angular', + weighted_radial='Weighted radial', + weighted_angular='Weighted angular') + + sys.stdout.write( + "# {} symmetry function set, generated with parameters:\n".format(type_descriptions[self.symfunc_type])) + for key, value in self.radial_grid_info.items(): + sys.stdout.write('# {0:13s} = {1}\n'.format(key, value)) + # set numpy print precision to lower number of decimal places for the following outputs + np.set_printoptions(precision=4) + sys.stdout.write('# r_shift_grid = {}\n'.format(self.r_shift_grid)) + sys.stdout.write('# eta_grid = {}\n'.format(self.eta_grid)) + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + sys.stdout.write('# lambdas = {}\n'.format(self.lambdas)) + sys.stdout.write('# zetas = {}\n'.format(self.zetas)) + # reset numpy print precision to default + np.set_printoptions(precision=8) def write_parameter_strings(self): pass @@ -109,25 +141,26 @@ def write_parameter_strings(self): elems = ['Cu', 'S'] myGen = SymFuncParamGenerator(elems) -print(myGen.get_elements()) - -print('\ngastegger2018 center mode') +print('gastegger2018 center mode') myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) -print(myGen.r_shift_grid) -print(myGen.eta_grid) +myGen.set_symfunc_type('angular_narrow') +myGen.set_zetas([1.0, 6.0]) +myGen.write_generation_info() print('\ngastegger2018 shift mode') myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) -print(myGen.r_shift_grid) -print(myGen.eta_grid) +myGen.set_symfunc_type('angular_narrow') +myGen.set_zetas([1.0, 6.0]) +myGen.write_generation_info() print('\nimbalzano2018 center mode') myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) -print(myGen.r_shift_grid) -print(myGen.eta_grid) +myGen.set_symfunc_type('weighted_radial') +myGen.set_zetas([1.0, 6.0]) +myGen.write_generation_info() print('\nimbalzano2018 shift mode') myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) -print(myGen.r_shift_grid) -print(myGen.eta_grid) +myGen.set_symfunc_type('radial') +myGen.write_generation_info() From 3260c36431f46b970e4d98f0d3ea2a8c2622a34f Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 18 Apr 2019 16:00:59 +0200 Subject: [PATCH 08/60] Add check for correct input when setting sf type. --- tools/python/SymFuncParamGenerator.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index d8c0f1ec4..eacf5d98b 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -7,11 +7,15 @@ class SymFuncParamGenerator: + symfunc_type_numbers = dict(radial=2, + angular_narrow=3, + angular_wide=9, + weighted_radial=12, + weighted_angular=13) + def __init__(self, elements): self.elements = elements - # TODO: add dictionary that matches sf type strings with the corresponding numbers - self.r_shift_grid = None self.eta_grid = None @@ -30,8 +34,9 @@ def clear_all(self): pass def set_symfunc_type(self, symfunc_type): - # TODO: 1) make this raise an error if invalid type is given - # TODO: 2) set zetas to None if a radial type is given? + # TODO: set zetas to None if a radial type is given? + if not symfunc_type in self.symfunc_type_numbers.keys(): + raise ValueError('Invalid symmetry function type given.') self.symfunc_type = symfunc_type def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): From cb445cdefa7a5cef025fa54fc13274742050ad41 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 19 Apr 2019 13:09:20 +0200 Subject: [PATCH 09/60] Make check for correct symfunc type display permitted values in error message. --- tools/python/SymFuncParamGenerator.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index eacf5d98b..d9eff3013 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -30,13 +30,14 @@ def get_elements(self): return self.elements def clear_all(self): - # TODO: make this do something... + # TODO: either make this do something or remove... pass def set_symfunc_type(self, symfunc_type): # TODO: set zetas to None if a radial type is given? if not symfunc_type in self.symfunc_type_numbers.keys(): - raise ValueError('Invalid symmetry function type given.') + raise ValueError('Invalid symmetry function type given. Must be one of {}'.format( + list(self.symfunc_type_numbers.keys()))) self.symfunc_type = symfunc_type def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): From 2de0465debbe5fafb77c6cd8443a72a585afd8b9 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 21 Apr 2019 22:34:07 +0200 Subject: [PATCH 10/60] Begin implementation of writing the sf parameters. Implement method for constructing the necessary element combinations depending on sf type (done) and begin implementing method for writing sf parameters in format required for input.nn (WIP, so far only iteration over element combinations, but not over sf parameters, is implemented). --- tools/python/SymFuncParamGenerator.py | 135 +++++++++++++++++++------- 1 file changed, 98 insertions(+), 37 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index d9eff3013..628745b65 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -7,6 +7,7 @@ class SymFuncParamGenerator: + # TODO: might want to rename that variable symfunc_type_numbers = dict(radial=2, angular_narrow=3, angular_wide=9, @@ -14,6 +15,7 @@ class SymFuncParamGenerator: weighted_angular=13) def __init__(self, elements): + # TODO: consider checking if valid input for elements self.elements = elements self.r_shift_grid = None @@ -33,16 +35,22 @@ def clear_all(self): # TODO: either make this do something or remove... pass - def set_symfunc_type(self, symfunc_type): - # TODO: set zetas to None if a radial type is given? - if not symfunc_type in self.symfunc_type_numbers.keys(): - raise ValueError('Invalid symmetry function type given. Must be one of {}'.format( + def check_symfunc_type(self): + if not self.symfunc_type in self.symfunc_type_numbers.keys(): + raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) - self.symfunc_type = symfunc_type + def set_symfunc_type(self, symfunc_type): + # TODO: set zetas to None if a radial type is given ?? + self.symfunc_type = symfunc_type + self.check_symfunc_type() + # def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): # store infos on radial parameter generation settings (that are independent of method) - self.radial_grid_info = {'method': method, 'mode': mode, 'r_cutoff': r_cutoff, 'nb_gridpoints': nb_gridpoints} + self.radial_grid_info = dict(method=method, + mode=mode, + r_cutoff=r_cutoff, + nb_gridpoints=nb_gridpoints) if method == 'gastegger2018': if r_lower is None: @@ -109,7 +117,8 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= def set_zetas(self, zeta_values): self.zetas = np.array(zeta_values) - def check_completeness(self): + def check_all_settings(self): + self.check_symfunc_type() if self.radial_grid_info is None: raise TypeError('No radial grid has been generated.') if self.symfunc_type is None: @@ -119,7 +128,7 @@ def check_completeness(self): raise TypeError('zeta values not set.') def write_generation_info(self): - self.check_completeness() + self.check_all_settings() type_descriptions = dict(radial='Radial', angular_narrow='Narrow angular', angular_wide='Wide angular', @@ -140,33 +149,85 @@ def write_generation_info(self): # reset numpy print precision to default np.set_printoptions(precision=8) - def write_parameter_strings(self): - pass + def create_element_combinations(self): + self.check_symfunc_type() + combinations = [] + + if self.symfunc_type == 'radial': + for elem_central in self.elements: + for elem_neighbor in self.elements: + combinations.append((elem_central, elem_neighbor)) + elif self.symfunc_type in ['angular_narrow', 'angular_wide']: + for elem_central in self.elements: + for pair_of_neighbors in itertools.combinations_with_replacement(self.elements, 2): + comb = (elem_central,) + pair_of_neighbors + combinations.append(comb) + elif self.symfunc_type in ['weighted_radial', 'weighted_angular']: + for elem_central in self.elements: + combinations.append((elem_central,)) + + return combinations - -elems = ['Cu', 'S'] -myGen = SymFuncParamGenerator(elems) - -print('gastegger2018 center mode') -myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=9, - r_lower=1.5) -myGen.set_symfunc_type('angular_narrow') -myGen.set_zetas([1.0, 6.0]) -myGen.write_generation_info() - -print('\ngastegger2018 shift mode') -myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) -myGen.set_symfunc_type('angular_narrow') -myGen.set_zetas([1.0, 6.0]) -myGen.write_generation_info() - -print('\nimbalzano2018 center mode') -myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) -myGen.set_symfunc_type('weighted_radial') -myGen.set_zetas([1.0, 6.0]) -myGen.write_generation_info() - -print('\nimbalzano2018 shift mode') -myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) -myGen.set_symfunc_type('radial') -myGen.write_generation_info() + def write_parameter_strings(self): + self.check_all_settings() + element_combinations = self.create_element_combinations() + + if self.symfunc_type == 'radial': + for comb in element_combinations: + # TODO: replace with meaningful loop over sf parameters + for sth in range(6): + sys.stdout.write(f'{comb[0]:2s} {comb[1]:2s} {sth}\n') + sys.stdout.write('\n') + elif self.symfunc_type in ['angular_narrow', 'angular_wide']: + for comb in element_combinations: + # TODO: replace with meaningful loop over sf parameters + for sth in range(6): + sys.stdout.write(f'{comb[0]:2s} {comb[1]:2s} {comb[2]:2s} {sth}\n') + sys.stdout.write('\n') + elif self.symfunc_type == 'weighted_radial': + for comb in element_combinations: + # TODO: replace with meaningful loop over sf parameters + for sth in range(6): + sys.stdout.write(f'{comb[0]:2s} {sth}\n') + sys.stdout.write('\n') + elif self.symfunc_type == 'weighted_radial': + for comb in element_combinations: + # TODO: replace with meaningful loop over sf parameters + for sth in range(6): + sys.stdout.write(f'{comb[0]:2s} {sth}\n') + sys.stdout.write('\n') + + + +if __name__ == '__main__': + # elems = ['S', 'Cu'] + elems = ['H', 'C', 'O'] + myGen = SymFuncParamGenerator(elems) + + # print('gastegger2018 center mode') + # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=9, + # r_lower=1.5) + # myGen.set_symfunc_type('angular_narrow') + # myGen.set_zetas([1.0, 6.0]) + # myGen.write_generation_info() + # + print('\ngastegger2018 shift mode') + myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) + myGen.set_symfunc_type('angular_narrow') + myGen.set_zetas([1.0, 6.0]) + myGen.write_generation_info() + # + # print('\nimbalzano2018 center mode') + # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) + # myGen.set_symfunc_type('weighted_radial') + # myGen.set_zetas([1.0, 6.0]) + # myGen.write_generation_info() + + # print('\nimbalzano2018 shift mode') + # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) + # myGen.set_symfunc_type('radial') + # myGen.write_generation_info() + + + print() + myGen.write_parameter_strings() From a627b0031adfa5a708889eeb74c0f166116b6d43 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 21 Apr 2019 23:47:24 +0200 Subject: [PATCH 11/60] Implement loops over sf parameters during writing. --- tools/python/SymFuncParamGenerator.py | 59 +++++++++++++++++---------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index 628745b65..766825c07 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -21,7 +21,6 @@ def __init__(self, elements): self.r_shift_grid = None self.eta_grid = None - self.r_cutoff = None self.symfunc_type = None self.radial_grid_info = None @@ -170,52 +169,62 @@ def create_element_combinations(self): def write_parameter_strings(self): self.check_all_settings() + element_combinations = self.create_element_combinations() + r_cutoff = self.radial_grid_info['r_cutoff'] + sf_number = self.symfunc_type_numbers[self.symfunc_type] if self.symfunc_type == 'radial': for comb in element_combinations: - # TODO: replace with meaningful loop over sf parameters - for sth in range(6): - sys.stdout.write(f'{comb[0]:2s} {comb[1]:2s} {sth}\n') + for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + sys.stdout.write( + f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') + elif self.symfunc_type in ['angular_narrow', 'angular_wide']: for comb in element_combinations: - # TODO: replace with meaningful loop over sf parameters - for sth in range(6): - sys.stdout.write(f'{comb[0]:2s} {comb[1]:2s} {comb[2]:2s} {sth}\n') + for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + for zeta in self.zetas: + for lambd in self.lambdas: + sys.stdout.write( + f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {comb[2]:2s} {eta:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} {rs:9.3E}\n') sys.stdout.write('\n') + elif self.symfunc_type == 'weighted_radial': for comb in element_combinations: - # TODO: replace with meaningful loop over sf parameters - for sth in range(6): - sys.stdout.write(f'{comb[0]:2s} {sth}\n') + for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + sys.stdout.write( + f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') - elif self.symfunc_type == 'weighted_radial': + + elif self.symfunc_type == 'weighted_angular': for comb in element_combinations: - # TODO: replace with meaningful loop over sf parameters - for sth in range(6): - sys.stdout.write(f'{comb[0]:2s} {sth}\n') + for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + for zeta in self.zetas: + for lambd in self.lambdas: + sys.stdout.write( + f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} \n') sys.stdout.write('\n') if __name__ == '__main__': - # elems = ['S', 'Cu'] - elems = ['H', 'C', 'O'] + elems = ['S', 'Cu'] + # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) # print('gastegger2018 center mode') - # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=9, + # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, # r_lower=1.5) # myGen.set_symfunc_type('angular_narrow') # myGen.set_zetas([1.0, 6.0]) # myGen.write_generation_info() # - print('\ngastegger2018 shift mode') - myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) - myGen.set_symfunc_type('angular_narrow') - myGen.set_zetas([1.0, 6.0]) - myGen.write_generation_info() + # print('\ngastegger2018 shift mode') + # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) + # myGen.set_symfunc_type('angular_narrow') + # myGen.set_zetas([1.0, 6.0]) + # myGen.write_generation_info() # # print('\nimbalzano2018 center mode') # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) @@ -223,6 +232,12 @@ def write_parameter_strings(self): # myGen.set_zetas([1.0, 6.0]) # myGen.write_generation_info() + print('\ngastegger2018 shift mode') + myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) + myGen.set_symfunc_type('weighted_angular') + myGen.set_zetas([1.0, 6.0]) + myGen.write_generation_info() + # print('\nimbalzano2018 shift mode') # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) # myGen.set_symfunc_type('radial') From 6ad3d06c64f35193f1dffcfd3986a1758bdfcdac Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 22 Apr 2019 17:53:07 +0200 Subject: [PATCH 12/60] Replace some regular strings with f strings. --- tools/python/SymFuncParamGenerator.py | 33 ++++++++++++++------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index 766825c07..c840b256b 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -43,7 +43,7 @@ def set_symfunc_type(self, symfunc_type): # TODO: set zetas to None if a radial type is given ?? self.symfunc_type = symfunc_type self.check_symfunc_type() - # + def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): # store infos on radial parameter generation settings (that are independent of method) self.radial_grid_info = dict(method=method, @@ -137,14 +137,14 @@ def write_generation_info(self): sys.stdout.write( "# {} symmetry function set, generated with parameters:\n".format(type_descriptions[self.symfunc_type])) for key, value in self.radial_grid_info.items(): - sys.stdout.write('# {0:13s} = {1}\n'.format(key, value)) + sys.stdout.write(f'# {key:13s} = {value}\n') # set numpy print precision to lower number of decimal places for the following outputs np.set_printoptions(precision=4) - sys.stdout.write('# r_shift_grid = {}\n'.format(self.r_shift_grid)) - sys.stdout.write('# eta_grid = {}\n'.format(self.eta_grid)) + sys.stdout.write(f'# r_shift_grid = {self.r_shift_grid}\n') + sys.stdout.write(f'# eta_grid = {self.eta_grid}\n') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - sys.stdout.write('# lambdas = {}\n'.format(self.lambdas)) - sys.stdout.write('# zetas = {}\n'.format(self.zetas)) + sys.stdout.write(f'# lambdas = {self.lambdas}\n') + sys.stdout.write(f'# zetas = {self.zetas}\n') # reset numpy print precision to default np.set_printoptions(precision=8) @@ -174,6 +174,7 @@ def write_parameter_strings(self): r_cutoff = self.radial_grid_info['r_cutoff'] sf_number = self.symfunc_type_numbers[self.symfunc_type] + # TODO: make some kind of linebreaks within the strings to keep code lines below 120 characters if self.symfunc_type == 'radial': for comb in element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): @@ -220,11 +221,11 @@ def write_parameter_strings(self): # myGen.set_zetas([1.0, 6.0]) # myGen.write_generation_info() # - # print('\ngastegger2018 shift mode') - # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) - # myGen.set_symfunc_type('angular_narrow') - # myGen.set_zetas([1.0, 6.0]) - # myGen.write_generation_info() + print('\ngastegger2018 shift mode') + myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) + myGen.set_symfunc_type('angular_narrow') + myGen.set_zetas([1.0, 6.0]) + myGen.write_generation_info() # # print('\nimbalzano2018 center mode') # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) @@ -232,11 +233,11 @@ def write_parameter_strings(self): # myGen.set_zetas([1.0, 6.0]) # myGen.write_generation_info() - print('\ngastegger2018 shift mode') - myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) - myGen.set_symfunc_type('weighted_angular') - myGen.set_zetas([1.0, 6.0]) - myGen.write_generation_info() + # print('\ngastegger2018 shift mode') + # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) + # myGen.set_symfunc_type('weighted_angular') + # myGen.set_zetas([1.0, 6.0]) + # myGen.write_generation_info() # print('\nimbalzano2018 shift mode') # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) From 01d895f63df4c356de250b1f496c6e16ea1ff05e Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Tue, 23 Apr 2019 10:53:31 +0200 Subject: [PATCH 13/60] Implement sf type and zeta setters via decorators. --- tools/python/SymFuncParamGenerator.py | 104 ++++++++++++++------------ 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index c840b256b..ef49eb1bf 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +# -*- coding: utf-8 -*- import numpy as np import sys @@ -21,29 +21,41 @@ def __init__(self, elements): self.r_shift_grid = None self.eta_grid = None - self.symfunc_type = None + self._symfunc_type = None self.radial_grid_info = None + # TODO: decide if there needs to be the option to change lambdas. If not, consider making it a class variable self.lambdas = np.array([-1.0, 1.0]) - self.zetas = None + self._zetas = None def get_elements(self): return self.elements - def clear_all(self): - # TODO: either make this do something or remove... - pass - def check_symfunc_type(self): - if not self.symfunc_type in self.symfunc_type_numbers.keys(): + if self._symfunc_type is None: + raise TypeError('No symmetry function type has been set.') + elif not self._symfunc_type in self.symfunc_type_numbers.keys(): raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) - def set_symfunc_type(self, symfunc_type): + @property + def symfunc_type(self): + return self._symfunc_type + + @symfunc_type.setter + def symfunc_type(self, value): # TODO: set zetas to None if a radial type is given ?? - self.symfunc_type = symfunc_type + self._symfunc_type = value self.check_symfunc_type() + @property + def zetas(self): + return self._zetas + + @zetas.setter + def zetas(self, zeta_values): + self._zetas = np.array(zeta_values) + def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): # store infos on radial parameter generation settings (that are independent of method) self.radial_grid_info = dict(method=method, @@ -113,17 +125,14 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= self.r_shift_grid = r_shift_grid self.eta_grid = eta_grid - def set_zetas(self, zeta_values): - self.zetas = np.array(zeta_values) - def check_all_settings(self): self.check_symfunc_type() if self.radial_grid_info is None: raise TypeError('No radial grid has been generated.') - if self.symfunc_type is None: + if self._symfunc_type is None: raise TypeError('Symmetry function type not set.') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - if self.zetas is None: + if self._symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self._zetas is None: raise TypeError('zeta values not set.') def write_generation_info(self): @@ -135,16 +144,17 @@ def write_generation_info(self): weighted_angular='Weighted angular') sys.stdout.write( - "# {} symmetry function set, generated with parameters:\n".format(type_descriptions[self.symfunc_type])) + '# {} symmetry function set, generated with parameters:\n'.format(type_descriptions[self._symfunc_type])) + sys.stdout.write(f'# elements = {self.elements}\n') for key, value in self.radial_grid_info.items(): sys.stdout.write(f'# {key:13s} = {value}\n') # set numpy print precision to lower number of decimal places for the following outputs np.set_printoptions(precision=4) sys.stdout.write(f'# r_shift_grid = {self.r_shift_grid}\n') sys.stdout.write(f'# eta_grid = {self.eta_grid}\n') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self._symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: sys.stdout.write(f'# lambdas = {self.lambdas}\n') - sys.stdout.write(f'# zetas = {self.zetas}\n') + sys.stdout.write(f'# zetas = {self._zetas}\n') # reset numpy print precision to default np.set_printoptions(precision=8) @@ -152,16 +162,16 @@ def create_element_combinations(self): self.check_symfunc_type() combinations = [] - if self.symfunc_type == 'radial': + if self._symfunc_type == 'radial': for elem_central in self.elements: for elem_neighbor in self.elements: combinations.append((elem_central, elem_neighbor)) - elif self.symfunc_type in ['angular_narrow', 'angular_wide']: + elif self._symfunc_type in ['angular_narrow', 'angular_wide']: for elem_central in self.elements: for pair_of_neighbors in itertools.combinations_with_replacement(self.elements, 2): comb = (elem_central,) + pair_of_neighbors combinations.append(comb) - elif self.symfunc_type in ['weighted_radial', 'weighted_angular']: + elif self._symfunc_type in ['weighted_radial', 'weighted_angular']: for elem_central in self.elements: combinations.append((elem_central,)) @@ -172,36 +182,36 @@ def write_parameter_strings(self): element_combinations = self.create_element_combinations() r_cutoff = self.radial_grid_info['r_cutoff'] - sf_number = self.symfunc_type_numbers[self.symfunc_type] + sf_number = self.symfunc_type_numbers[self._symfunc_type] # TODO: make some kind of linebreaks within the strings to keep code lines below 120 characters - if self.symfunc_type == 'radial': + if self._symfunc_type == 'radial': for comb in element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') - elif self.symfunc_type in ['angular_narrow', 'angular_wide']: + elif self._symfunc_type in ['angular_narrow', 'angular_wide']: for comb in element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): - for zeta in self.zetas: + for zeta in self._zetas: for lambd in self.lambdas: sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {comb[2]:2s} {eta:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} {rs:9.3E}\n') sys.stdout.write('\n') - elif self.symfunc_type == 'weighted_radial': + elif self._symfunc_type == 'weighted_radial': for comb in element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') - elif self.symfunc_type == 'weighted_angular': + elif self._symfunc_type == 'weighted_angular': for comb in element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): - for zeta in self.zetas: + for zeta in self._zetas: for lambd in self.lambdas: sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} \n') @@ -214,34 +224,32 @@ def write_parameter_strings(self): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - # print('gastegger2018 center mode') - # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, - # r_lower=1.5) - # myGen.set_symfunc_type('angular_narrow') - # myGen.set_zetas([1.0, 6.0]) + # print('\nimbalzano2018 shift mode') + # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) + # myGen.symfunc_type = 'radial' # myGen.write_generation_info() - # + print('\ngastegger2018 shift mode') myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) - myGen.set_symfunc_type('angular_narrow') - myGen.set_zetas([1.0, 6.0]) + myGen.symfunc_type = 'angular_narrow' + myGen.zetas = [1.0, 6.0] myGen.write_generation_info() - # + + # print('gastegger2018 center mode') + # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) + # myGen.symfunc_type = 'angular_wide' + # myGen.zetas = [1.0, 6.0] + # myGen.write_generation_info() + # print('\nimbalzano2018 center mode') # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) - # myGen.set_symfunc_type('weighted_radial') - # myGen.set_zetas([1.0, 6.0]) + # myGen.symfunc_type = 'weighted_radial' # myGen.write_generation_info() - + # # print('\ngastegger2018 shift mode') # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) - # myGen.set_symfunc_type('weighted_angular') - # myGen.set_zetas([1.0, 6.0]) - # myGen.write_generation_info() - - # print('\nimbalzano2018 shift mode') - # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) - # myGen.set_symfunc_type('radial') + # myGen.symfunc_type = 'weighted_angular' + # myGen.zetas = [1.0, 6.0] # myGen.write_generation_info() From 28a28156167d1e01ef84b7a71934789ce70ebb4b Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 24 Apr 2019 11:24:14 +0200 Subject: [PATCH 14/60] Begin systematic in-code documentation. --- tools/python/SymFuncParamGenerator.py | 189 ++++++++++++++++++++++---- 1 file changed, 162 insertions(+), 27 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index ef49eb1bf..d7454077f 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -7,6 +7,33 @@ class SymFuncParamGenerator: + """Tools for generation, storage, and writing in the format required by n2p2, of symmetry function parameter sets. + + Parameters + ---------- + elements : list of string + The chemical elements present in the system. + + Attributes + ---------- + symfunc_type_numbers : dict + Dictionary mapping strings specifying the symmetry function type to the + numbers used internally by n2p2 to distinguish symmetry function types. + lambdas : numpy.ndarray + Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. + elements : list of string + The chemical elements present in the system. Same as what was passed as parameter to constructor. + _symfunc_type : {'radial', 'angular_narrow', 'angular_wide', 'weighted_radial', 'weighted_angular'} or None + String specifying the symmetry function type. + _zetas : numpy.ndarray + Set of values for the parameter zeta of angular symmetry functions. + radial_grid_info : dict or None + Stores settings that were used for generating the symmetry function parameters r_shift and eta. + r_shift_grid : numpy.ndarray or None + The set of values for the symmetry function parameter r_shift that was generated. + eta_grid : numpy.ndarray or None + The set of values for the symmetry function parameter eta that was generated. +""" # TODO: might want to rename that variable symfunc_type_numbers = dict(radial=2, angular_narrow=3, @@ -15,23 +42,36 @@ class SymFuncParamGenerator: weighted_angular=13) def __init__(self, elements): + # TODO: decide if there needs to be the option to change lambdas. If not, consider making it a class variable + self.lambdas = np.array([-1.0, 1.0]) + # TODO: consider checking if valid input for elements self.elements = elements + self._symfunc_type = None + self._zetas = None + self.radial_grid_info = None self.r_shift_grid = None self.eta_grid = None - self._symfunc_type = None - self.radial_grid_info = None - - # TODO: decide if there needs to be the option to change lambdas. If not, consider making it a class variable - self.lambdas = np.array([-1.0, 1.0]) - self._zetas = None - def get_elements(self): return self.elements def check_symfunc_type(self): + """ + Check if a symmetry function type has been set and if it is a valid one. + + Raises + ------- + TypeError + If the symmmetry function type has not been set (i.e., it is None). + ValueError + If the symmmetry function type is invalid. + + Returns + ------- + None + """ if self._symfunc_type is None: raise TypeError('No symmetry function type has been set.') elif not self._symfunc_type in self.symfunc_type_numbers.keys(): @@ -45,6 +85,7 @@ def symfunc_type(self): @symfunc_type.setter def symfunc_type(self, value): # TODO: set zetas to None if a radial type is given ?? + # TODO: automatically generate element combinations (and store in member variable), when symfunc type is set ?? self._symfunc_type = value self.check_symfunc_type() @@ -53,10 +94,56 @@ def zetas(self): return self._zetas @zetas.setter - def zetas(self, zeta_values): - self._zetas = np.array(zeta_values) + def zetas(self, values): + self._zetas = np.array(values) def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): + """ + Generate a set of values for r_shift and eta. + + The generated values are then stored as arrays in the member variables r_shift_grid and eta_grid. + The entries are to be understood pairwise, i.e., the i-th entry of r_shift_grid + and the i-th entry of eta_grid belong to one symmetry function. + Besides the set of values for r_shift and eta, the settings that + were used for generating it are also stored in the dictionary radial_grid_info. + + Parameters + ---------- + method : {'gastegger2018', 'imbalzano2018'} + if method=='gastegger2018' use the parameter generation rules presented in [1]_, + if method=='imbalzano2018' use the parameter generation rules presented in [2]_ + mode : {'center', 'shift'} + Selects which parameter generation rule to use, on top of the method argument, + since there are again two different varieties presented in each of the two papers. + 'center' sets r_shift to zero for all symmetry functions, varying only eta. + 'shift' creates parameter sets where r_shift varies. + The exact implementation details differ depending on + the method parameter and are described in the papers. + r_cutoff : float + cutoff radius, at which the symmetry functions go to zero. + must be greater than zero. + nb_gridpoints : int + number of (r_shift, eta)-pairs to be created. + r_lower : float + lowest value of radial grid points. + required if method=='gastegger2018', ignored if method=='imbalzano2018'. + + Notes + ---------- + [1] https://doi.org/10.1063/1.5019667 + [2] https://doi.org/10.1063/1.5024611 + + The nomenclature from the papers was slightly adapted to make behavior + consistent across all options for method and mode: + nb_gridpoints universally specifies the number of (r_shift, eta)-pairs + that the method ultimately generates, not the number of points in a + preliminary auxiliary grid, or the number of intervals in the final grid. + + Returns + ------- + None + """ + # TODO: is this method the right place to pass the cutoff radius? Maybe even pass it to the constructor right away? # store infos on radial parameter generation settings (that are independent of method) self.radial_grid_info = dict(method=method, mode=mode, @@ -125,18 +212,37 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= self.r_shift_grid = r_shift_grid self.eta_grid = eta_grid - def check_all_settings(self): + def check_all(self): + """ + Check if a complete symmetry function set, with all required settings for writing, has been generated. + + Raises + ------- + TypeError + If no set of radial parameters (r_shift and eta) has been generated + TypeError + If an angular symmetry function type has been set, but no values for zeta were set. + + Returns + ------- + None + """ self.check_symfunc_type() - if self.radial_grid_info is None: + if self.radial_grid_info is None or self.r_shift_grid is None or self.eta_grid is None: raise TypeError('No radial grid has been generated.') - if self._symfunc_type is None: - raise TypeError('Symmetry function type not set.') if self._symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: if self._zetas is None: raise TypeError('zeta values not set.') def write_generation_info(self): - self.check_all_settings() + """ + Writes the settings used in generating the currently stored set of symmetry function parameters to stdout. + + Returns + ------- + None + """ + self.check_all() type_descriptions = dict(radial='Radial', angular_narrow='Narrow angular', angular_wide='Wide angular', @@ -158,7 +264,25 @@ def write_generation_info(self): # reset numpy print precision to default np.set_printoptions(precision=8) - def create_element_combinations(self): + def construct_element_combinations(self): + """ + Create necessary combinations of elements, depending on symmetry function type and the elements in the system. + + For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, + including of an element with itself. + For angular symmetry functions (narrow or wide), the combinations consist of all possible elements as the + central atom, and then again for each central element all possible unordered pairs of neighbor elements. + For weighted symmetry functions (radial or angular), the combinations run only over all possible + central elements, with neighbors not taken into account at this stage. + + Returns + ------- + combinations : list of tuple of string + Each tuple in the list represents one element combination. + Length of the individual tuples can be 1, 2 or 3, depending on symmetry function type. + Zero-th entry of tuples is always the type of the central atom, 1st and 2nd entry are neighbor atom types + (radial sf: one neighbor, angular sf: two neighbors, weighted sf: no neighbors) + """ self.check_symfunc_type() combinations = [] @@ -178,13 +302,24 @@ def create_element_combinations(self): return combinations def write_parameter_strings(self): - self.check_all_settings() + """ + Write symmetry function parameter sets to stdout, formatted as in the file 'input.nn' required by n2p2. - element_combinations = self.create_element_combinations() + Each line in the output corresponds to one symmetry function. + Output is formatted in blocks separated by blank lines, each block corresponding to one element combination. + Within each block, the other parameters are iterated over. + + Returns + ------- + None + """ + self.check_all() + + element_combinations = self.construct_element_combinations() r_cutoff = self.radial_grid_info['r_cutoff'] sf_number = self.symfunc_type_numbers[self._symfunc_type] - # TODO: make some kind of linebreaks within the strings to keep code lines below 120 characters + # TODO: make some kind of linebreaks within the strings to keep code lines below hard limit of 120 chars if self._symfunc_type == 'radial': for comb in element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): @@ -224,17 +359,17 @@ def write_parameter_strings(self): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - # print('\nimbalzano2018 shift mode') - # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) - # myGen.symfunc_type = 'radial' - # myGen.write_generation_info() - - print('\ngastegger2018 shift mode') - myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) - myGen.symfunc_type = 'angular_narrow' - myGen.zetas = [1.0, 6.0] + print('\nimbalzano2018 shift mode') + myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) + myGen.symfunc_type = 'radial' myGen.write_generation_info() + # print('\ngastegger2018 shift mode') + # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) + # myGen.symfunc_type = 'angular_narrow' + # myGen.zetas = [1.0, 6.0] + # myGen.write_generation_info() + # print('gastegger2018 center mode') # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) # myGen.symfunc_type = 'angular_wide' From 1280cecded17b83b8fea026da04f916e78d3a4e1 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 24 Apr 2019 13:32:37 +0200 Subject: [PATCH 15/60] Extend in-code documentation. --- tools/python/SymFuncParamGenerator.py | 46 +++++++++++++++------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index d7454077f..9c3180fca 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -23,17 +23,16 @@ class SymFuncParamGenerator: Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. elements : list of string The chemical elements present in the system. Same as what was passed as parameter to constructor. - _symfunc_type : {'radial', 'angular_narrow', 'angular_wide', 'weighted_radial', 'weighted_angular'} or None - String specifying the symmetry function type. - _zetas : numpy.ndarray - Set of values for the parameter zeta of angular symmetry functions. radial_grid_info : dict or None Stores settings that were used for generating the symmetry function parameters r_shift and eta. r_shift_grid : numpy.ndarray or None The set of values for the symmetry function parameter r_shift that was generated. eta_grid : numpy.ndarray or None The set of values for the symmetry function parameter eta that was generated. -""" + symfunc_type + zetas + """ + # TODO: might want to rename that variable symfunc_type_numbers = dict(radial=2, angular_narrow=3, @@ -56,10 +55,9 @@ def __init__(self, elements): def get_elements(self): return self.elements - + def check_symfunc_type(self): - """ - Check if a symmetry function type has been set and if it is a valid one. + """Check if a symmetry function type has been set and if it is a valid one. Raises ------- @@ -80,6 +78,10 @@ def check_symfunc_type(self): @property def symfunc_type(self): + """Type of symmetry function for which parameters are to be generated (`str`). + + When the setter for this is called it also checks the validity of the input. + """ return self._symfunc_type @symfunc_type.setter @@ -91,6 +93,8 @@ def symfunc_type(self, value): @property def zetas(self): + """Set of values for the parameter zeta of angular symmetry functions (`numpy.ndarray`). + """ return self._zetas @zetas.setter @@ -98,14 +102,14 @@ def zetas(self, values): self._zetas = np.array(values) def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): - """ - Generate a set of values for r_shift and eta. + """Generate a set of values for r_shift and eta. - The generated values are then stored as arrays in the member variables r_shift_grid and eta_grid. + Such a set of values is required for any symmetry function type. + The generated values are stored as arrays in the member variables r_shift_grid and eta_grid. The entries are to be understood pairwise, i.e., the i-th entry of r_shift_grid and the i-th entry of eta_grid belong to one symmetry function. Besides the set of values for r_shift and eta, the settings that - were used for generating it are also stored in the dictionary radial_grid_info. + were used for generating it are also stored, in the dictionary radial_grid_info. Parameters ---------- @@ -213,8 +217,7 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= self.eta_grid = eta_grid def check_all(self): - """ - Check if a complete symmetry function set, with all required settings for writing, has been generated. + """Check if a complete symmetry function set, with all required settings for writing, has been generated. Raises ------- @@ -235,8 +238,7 @@ def check_all(self): raise TypeError('zeta values not set.') def write_generation_info(self): - """ - Writes the settings used in generating the currently stored set of symmetry function parameters to stdout. + """Writes the settings used in generating the currently stored set of symmetry function parameters to stdout. Returns ------- @@ -265,8 +267,7 @@ def write_generation_info(self): np.set_printoptions(precision=8) def construct_element_combinations(self): - """ - Create necessary combinations of elements, depending on symmetry function type and the elements in the system. + """Create combinations of elements, depending on symmetry function type and the elements in the system. For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, including of an element with itself. @@ -302,8 +303,7 @@ def construct_element_combinations(self): return combinations def write_parameter_strings(self): - """ - Write symmetry function parameter sets to stdout, formatted as in the file 'input.nn' required by n2p2. + """Write symmetry function parameter sets to stdout, formatted as in the file 'input.nn' required by n2p2. Each line in the output corresponds to one symmetry function. Output is formatted in blocks separated by blank lines, each block corresponding to one element combination. @@ -354,7 +354,7 @@ def write_parameter_strings(self): -if __name__ == '__main__': +def main(): elems = ['S', 'Cu'] # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) @@ -390,3 +390,7 @@ def write_parameter_strings(self): print() myGen.write_parameter_strings() + + +if __name__ == '__main__': + main() From 8274717b030cacee5850b7cf329c9d71f24abcde Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 24 Apr 2019 16:37:05 +0200 Subject: [PATCH 16/60] Make elements and element combinations into properties. --- tools/python/SymFuncParamGenerator.py | 87 ++++++++++++++++----------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index 9c3180fca..cf0134174 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -21,14 +21,14 @@ class SymFuncParamGenerator: numbers used internally by n2p2 to distinguish symmetry function types. lambdas : numpy.ndarray Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. - elements : list of string - The chemical elements present in the system. Same as what was passed as parameter to constructor. radial_grid_info : dict or None Stores settings that were used for generating the symmetry function parameters r_shift and eta. r_shift_grid : numpy.ndarray or None The set of values for the symmetry function parameter r_shift that was generated. eta_grid : numpy.ndarray or None The set of values for the symmetry function parameter eta that was generated. + elements + element_combinations symfunc_type zetas """ @@ -45,7 +45,8 @@ def __init__(self, elements): self.lambdas = np.array([-1.0, 1.0]) # TODO: consider checking if valid input for elements - self.elements = elements + self._elements = elements + self._element_combinations = None self._symfunc_type = None self._zetas = None @@ -53,43 +54,38 @@ def __init__(self, elements): self.r_shift_grid = None self.eta_grid = None - def get_elements(self): - return self.elements - - def check_symfunc_type(self): - """Check if a symmetry function type has been set and if it is a valid one. + @property + def elements(self): + """The chemical elements present in the system (list of string, read-only). + """ + return self._elements - Raises - ------- - TypeError - If the symmmetry function type has not been set (i.e., it is None). - ValueError - If the symmmetry function type is invalid. + @property + def element_combinations(self): + """Combinations of elements (list of tuple of string, read-only). - Returns - ------- - None + This is computed and set automatically by the setter for symfunc_type. """ - if self._symfunc_type is None: - raise TypeError('No symmetry function type has been set.') - elif not self._symfunc_type in self.symfunc_type_numbers.keys(): - raise ValueError('Invalid symmetry function type. Must be one of {}'.format( - list(self.symfunc_type_numbers.keys()))) + return self._element_combinations @property def symfunc_type(self): """Type of symmetry function for which parameters are to be generated (`str`). - When the setter for this is called it also checks the validity of the input. + When the setter for this is called it also checks the validity of + the input, builds the necessary element combinations for the given + symmetry function type, and stores it to member variable. """ return self._symfunc_type @symfunc_type.setter def symfunc_type(self, value): # TODO: set zetas to None if a radial type is given ?? - # TODO: automatically generate element combinations (and store in member variable), when symfunc type is set ?? self._symfunc_type = value self.check_symfunc_type() + # once symmetry function type has been set and found to be valid, + # build and store the element combinations + self._element_combinations = self.construct_element_combinations() @property def zetas(self): @@ -101,6 +97,26 @@ def zetas(self): def zetas(self, values): self._zetas = np.array(values) + def check_symfunc_type(self): + """Check if a symmetry function type has been set and if it is a valid one. + + Raises + ------- + TypeError + If the symmetry function type has not been set (i.e., it is None). + ValueError + If the symmetry function type is invalid. + + Returns + ------- + None + """ + if self._symfunc_type is None: + raise TypeError('No symmetry function type has been set.') + elif not self._symfunc_type in self.symfunc_type_numbers.keys(): + raise ValueError('Invalid symmetry function type. Must be one of {}'.format( + list(self.symfunc_type_numbers.keys()))) + def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): """Generate a set of values for r_shift and eta. @@ -195,14 +211,14 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= rs_grid_extended = r_cutoff / nb_intervals_extended ** ( gridpoint_indices_extended / nb_intervals_extended) # from pairs of neighboring r_shift values, compute eta values. - # doing this for the nb_gridpoints + 1 values in the auxiliary grid ultimately gives... - # ...nb_gridpoints different values for eta + # doing this for the nb_gridpoints + 1 values in the auxiliary + # grid ultimately gives nb_gridpoints different values for eta. eta_grid = np.zeros(nb_gridpoints) for idx in range(len(rs_grid_extended) - 1): eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 eta_grid[idx] = eta_current - # create final grid of r_shift values by excluding the first entry... - # ...(for which r_shift coincides with the cutoff radius) from the extended grid + # create final grid of r_shift values by excluding the first entry + # (for which r_shift coincides with the cutoff radius) from the extended grid r_shift_grid = rs_grid_extended[1:] # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift... # ...(not necessary, but makes the output consistent with the other methods) @@ -315,20 +331,19 @@ def write_parameter_strings(self): """ self.check_all() - element_combinations = self.construct_element_combinations() r_cutoff = self.radial_grid_info['r_cutoff'] - sf_number = self.symfunc_type_numbers[self._symfunc_type] + sf_number = self.symfunc_type_numbers[self.symfunc_type] # TODO: make some kind of linebreaks within the strings to keep code lines below hard limit of 120 chars if self._symfunc_type == 'radial': - for comb in element_combinations: + for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') elif self._symfunc_type in ['angular_narrow', 'angular_wide']: - for comb in element_combinations: + for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): for zeta in self._zetas: for lambd in self.lambdas: @@ -337,14 +352,14 @@ def write_parameter_strings(self): sys.stdout.write('\n') elif self._symfunc_type == 'weighted_radial': - for comb in element_combinations: + for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') elif self._symfunc_type == 'weighted_angular': - for comb in element_combinations: + for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): for zeta in self._zetas: for lambd in self.lambdas: @@ -380,7 +395,7 @@ def main(): # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) # myGen.symfunc_type = 'weighted_radial' # myGen.write_generation_info() - # + # print('\ngastegger2018 shift mode') # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) # myGen.symfunc_type = 'weighted_angular' @@ -391,6 +406,8 @@ def main(): print() myGen.write_parameter_strings() + print(myGen.element_combinations) + if __name__ == '__main__': main() From 5615862f694cd5f235fd4a00b722b35978c4a0c1 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 24 Apr 2019 16:51:14 +0200 Subject: [PATCH 17/60] Remove file SymFuncDescriptors.py. Also rename method create_element_combinations to find_element_combinations. --- tools/python/SymFuncDescriptors.py | 72 --------------------------- tools/python/SymFuncParamGenerator.py | 4 +- 2 files changed, 2 insertions(+), 74 deletions(-) delete mode 100644 tools/python/SymFuncDescriptors.py diff --git a/tools/python/SymFuncDescriptors.py b/tools/python/SymFuncDescriptors.py deleted file mode 100644 index b98b58dce..000000000 --- a/tools/python/SymFuncDescriptors.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python - -import numpy as np -import sys -import itertools - - -class SymFuncDescriptorRadial: - def __init__(self, central_element, neighbor_element, eta, r_cutoff, r_shift): - # radial symmetry functions are called type 2 - self.type = 12 - - self.central_element = central_element - self.neighbor_element = neighbor_element - self.eta = eta - self.r_cutoff = r_cutoff - self.r_shift = r_shift - - def get_descriptor_string(self): - descriptor_string = "symfunction_short {0:2s} {1:2d} {2:2s} {3:9.3E} {4:9.3E} {5:9.3E}".format( - self.central_element, self.type, self.neighbor_element, self.eta, self.r_shift, self.r_cutoff) - return descriptor_string - - -class SymFuncDescriptorAng: - def __init__(self, central_element, type_keyword, neighbor_element_1, neighbor_element_2, eta, lambd, zeta, r_cutoff, r_shift): - if type_keyword == 'narrow': - self.type = 3 - elif type_keyword == 'wide': - self.type = 9 - else: - raise(ValueError('type_keyword must be one of ["narrow", "wide"]')) - - self.central_element = central_element - # store neighbor elements in a set to make explicit that the order is irrelevant - self.neighbor_elements = {neighbor_element_1, neighbor_element_2} - self.eta = eta - self.r_cutoff = r_cutoff - self.r_shift = r_shift - self.lambd = lambd - self.zeta = zeta - - def get_descriptor_string(self): - if len(self.neighbor_elements) == 2: - neighbor_element_1 = sorted(self.neighbor_elements)[0] - neighbor_element_2 = sorted(self.neighbor_elements)[1] - elif len(self.neighbor_elements) == 1: - neighbor_element_1 = sorted(self.neighbor_elements)[0] - neighbor_element_2 = neighbor_element_1 - else: - raise(RuntimeError('Neighbor elements must be either the same or two different ones, but not more than two')) - - descriptor_string = "symfunction_short {0:2s} {1:2d} {2:2s} {3:2s} {4:9.3E} {5:2.0f} {6:9.3E} {7:9.3E} {8:9.3E}".format( - self.central_element, self.type, neighbor_element_1, neighbor_element_2, - self.eta, self.lambd, self.zeta, self.r_cutoff, self.r_shift) - return descriptor_string - - -sf_radial_1 = SymFuncDescriptorRadial(central_element='Cu', neighbor_element='S', eta=4., r_shift=5, r_cutoff=6) -sf_radial_2 = SymFuncDescriptorRadial(central_element='S', neighbor_element='S', eta=1., r_shift=2, r_cutoff=3) -sf_ang_narrow = SymFuncDescriptorAng(central_element='Cu', type_keyword='narrow', neighbor_element_1='S', neighbor_element_2='S', eta=4., lambd=1, zeta=.5, r_shift=5, r_cutoff=6) -sf_ang_wide = SymFuncDescriptorAng(central_element='Cu', type_keyword='wide', neighbor_element_1='S', neighbor_element_2='Cu', eta=4., lambd=1, zeta=.5, r_shift=5, r_cutoff=6) - - -print(sf_radial_1.get_descriptor_string()) -print(sf_radial_2.get_descriptor_string()) - -print(sf_ang_narrow.get_descriptor_string()) -print(sf_ang_wide.get_descriptor_string()) - - -print() \ No newline at end of file diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index cf0134174..e037485eb 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -85,7 +85,7 @@ def symfunc_type(self, value): self.check_symfunc_type() # once symmetry function type has been set and found to be valid, # build and store the element combinations - self._element_combinations = self.construct_element_combinations() + self._element_combinations = self.find_element_combinations() @property def zetas(self): @@ -282,7 +282,7 @@ def write_generation_info(self): # reset numpy print precision to default np.set_printoptions(precision=8) - def construct_element_combinations(self): + def find_element_combinations(self): """Create combinations of elements, depending on symmetry function type and the elements in the system. For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, From d4d42788927a73e05d217ca03b841f565018e296 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 24 Apr 2019 16:55:21 +0200 Subject: [PATCH 18/60] Remove file write_symfunc.py --- tools/python/write_symfunc.py | 57 ----------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 tools/python/write_symfunc.py diff --git a/tools/python/write_symfunc.py b/tools/python/write_symfunc.py deleted file mode 100644 index e9c3f4ff2..000000000 --- a/tools/python/write_symfunc.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python - -import numpy as np -import sys -import itertools - -symfunc_list_radial = [{"type": 2, "element": 'Cu', "neighbors": {'Cu'}}, - {"type": 2, "element": 'Cu', "neighbors": {'S'}}, - {"type": 2, "element": 'S', "neighbors": {'Cu'}}, - {"type": 2, "element": 'S', "neighbors": {'S'}}] - - -symfunc_list_angular_narrow = [{"type": 3, "element": 'Cu', "neighbors": {'Cu'}}, - {"type": 3, "element": 'Cu', "neighbors": {'S'}}, - {"type": 3, "element": 'Cu', "neighbors": {'Cu', 'S'}}, - {"type": 3, "element": 'S', "neighbors": {'Cu'}}, - {"type": 3, "element": 'S', "neighbors": {'S'}}, - {"type": 3, "element": 'S', "neighbors": {'Cu', 'S'}}] - - - -symfunc_list = symfunc_list_radial + symfunc_list_angular_narrow - -# get all unique symmetry function types contained in the list of symmetry functions -sf_types = set([sf['type'] for sf in symfunc_list]) -print(sf_types) - -# get all unique elements contained in the list of symmetry functions -elems = set([el['element'] for el in symfunc_list]) -print(elems) - -# get all unique unordered pairs of two elements (including pairs of two elements that are the same) -elem_pairs = itertools.combinations_with_replacement(elems, 2) - - -print() - -sf_list_type_2 = [sf for sf in symfunc_list if sf['type']==2] -for central_elem in elems: - sys.stdout.write("# Radial symmetry functions for element {0:2s}\n".format(central_elem)) - sf_list_central = [sf for sf in sf_list_type_2 if sf['element']==central_elem] - for neighbor_elem in elems: - sf_list_neighbors = [sf for sf in sf_list_central if sf['neighbor']==neighbor_elem] - print(sf_list_neighbors) - sys.stdout.write('\n') - - -# sf_list_type_3 = [sf for sf in symfunc_list if sf['type']==3] -# for central_elem in elems: -# sys.stdout.write("# Narrow angular symmetry functions for element {0:2s}\n".format(central_elem)) -# sf_list_central = [sf for sf in sf_list_type_3 if sf['element']==central_elem] -# for neighbor_elem_1 in elems: -# sf_list_neighbors_1 = [sf for sf in sf_list_central if sf['neighbor_1']==neighbor_elem_1] -# for neighbor_elem_2 in elems: -# sf_list_neighbors_2 = [sf for sf in sf_list_central if sf['neighbor_2'] == neighbor_elem_2] -# print(sf_list_neighbors_2) -# sys.stdout.write('\n') \ No newline at end of file From a3163e36ee7fbfe664b4ca688867303104b64970 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 25 Apr 2019 14:34:46 +0200 Subject: [PATCH 19/60] Add argument r_upper to radial param generation method. Also add checks if values of r_lower, r_upper, r_cutoff are positive and valid in relation to each other. --- tools/python/SymFuncParamGenerator.py | 73 ++++++++++++++++++--------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index e037485eb..d653c7956 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -42,6 +42,7 @@ class SymFuncParamGenerator: def __init__(self, elements): # TODO: decide if there needs to be the option to change lambdas. If not, consider making it a class variable + # -> can probably be fixed to [-1, 1] self.lambdas = np.array([-1.0, 1.0]) # TODO: consider checking if valid input for elements @@ -80,7 +81,7 @@ def symfunc_type(self): @symfunc_type.setter def symfunc_type(self, value): - # TODO: set zetas to None if a radial type is given ?? + # TODO: set zetas to None if a radial type is given ?? -> why not self._symfunc_type = value self.check_symfunc_type() # once symmetry function type has been set and found to be valid, @@ -117,7 +118,7 @@ def check_symfunc_type(self): raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) - def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None): + def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None, r_upper=None): """Generate a set of values for r_shift and eta. Such a set of values is required for any symmetry function type. @@ -140,30 +141,37 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= The exact implementation details differ depending on the method parameter and are described in the papers. r_cutoff : float - cutoff radius, at which the symmetry functions go to zero. - must be greater than zero. + Cutoff radius, at which the symmetry functions go to zero. + Must be greater than zero. nb_gridpoints : int number of (r_shift, eta)-pairs to be created. r_lower : float lowest value of radial grid points. - required if method=='gastegger2018', ignored if method=='imbalzano2018'. + required if method=='gastegger2018'. + ignored if method=='imbalzano2018'. + r_upper : float, optional + largest value of radial grid points. + optional if method=='gastegger2018, defaults to cutoff radius if not given. + ignored if method=='imbalzano2018'. Notes ---------- [1] https://doi.org/10.1063/1.5019667 [2] https://doi.org/10.1063/1.5024611 - The nomenclature from the papers was slightly adapted to make behavior - consistent across all options for method and mode: - nb_gridpoints universally specifies the number of (r_shift, eta)-pairs - that the method ultimately generates, not the number of points in a - preliminary auxiliary grid, or the number of intervals in the final grid. + The parameter nb_gridpoints universally specifies the number of + (r_shift, eta)-pairs ultimately generated, not the number of + intervals between points in a grid of r_shift values, or the + number of points in some auxiliary grid. + This constitutes a slight modification of the nomenclature + from the papers, for the sake of consistent behavior across all + options for method and mode. Returns ------- None """ - # TODO: is this method the right place to pass the cutoff radius? Maybe even pass it to the constructor right away? + # TODO: add checks for r_lower, r_upper greater zero and less equal r_cutoff # store infos on radial parameter generation settings (that are independent of method) self.radial_grid_info = dict(method=method, mode=mode, @@ -173,8 +181,14 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= if method == 'gastegger2018': if r_lower is None: raise TypeError('Argument r_lower is required for method "gastegger2018"') + if r_upper is None: + # by default, set largest value of radial grid to cutoff radius + r_upper = r_cutoff + + # Check relationship between different radii parameters + if not 0 < r_lower < r_upper <= r_cutoff: + raise ValueError('Invalid arguments. It is required that 0 < r_lower < r_upper <= r_cutoff.') - r_upper = r_cutoff - 0.5 # TODO: decide if hardcoding this (and in Angstrom!) is a good idea # store settings that are unique to this method self.radial_grid_info.update({'r_lower': r_lower, 'r_upper': r_upper}) @@ -193,11 +207,18 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= elif method == 'imbalzano2018': if r_lower is not None: - # TODO: decide if necessary to do this warning and if doing it this way makes sense sys.stderr.write( 'Warning: argument r_lower is not used in method "imbalzano2018" and will be ignored.\n') traceback.print_stack() sys.stderr.flush() + if r_upper is not None: + sys.stderr.write( + 'Warning: argument r_upper is not used in method "imbalzano2018" and will be ignored.\n') + traceback.print_stack() + sys.stderr.flush() + + if not r_cutoff > 0: + raise ValueError('Invalid argument for r_cutoff. Must be greater than zero.') if mode == 'center': nb_intervals = nb_gridpoints - 1 @@ -205,6 +226,7 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) / r_cutoff) ** 2 r_shift_grid = np.zeros_like(eta_grid) elif mode == 'shift': + # TODO: somehow mention that shift mode for angular symfuncs is actually not discussed in the paper # create extended auxiliary grid of r_shift values, that contains nb_gridpoints + 1 values nb_intervals_extended = nb_gridpoints gridpoint_indices_extended = np.array(range(0, nb_intervals_extended + 1)) @@ -220,8 +242,8 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= # create final grid of r_shift values by excluding the first entry # (for which r_shift coincides with the cutoff radius) from the extended grid r_shift_grid = rs_grid_extended[1:] - # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift... - # ...(not necessary, but makes the output consistent with the other methods) + # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift + # (not necessary, but makes the output consistent with the other methods) r_shift_grid = np.flip(r_shift_grid) eta_grid = np.flip(eta_grid) else: @@ -247,10 +269,11 @@ def check_all(self): None """ self.check_symfunc_type() + # TODO: consider removing the check for radial_grid_info (since a user might want to directly set r_shift and eta values on their own, in which case no info would have been generated if self.radial_grid_info is None or self.r_shift_grid is None or self.eta_grid is None: raise TypeError('No radial grid has been generated.') - if self._symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - if self._zetas is None: + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.zetas is None: raise TypeError('zeta values not set.') def write_generation_info(self): @@ -303,16 +326,16 @@ def find_element_combinations(self): self.check_symfunc_type() combinations = [] - if self._symfunc_type == 'radial': + if self.symfunc_type == 'radial': for elem_central in self.elements: for elem_neighbor in self.elements: combinations.append((elem_central, elem_neighbor)) - elif self._symfunc_type in ['angular_narrow', 'angular_wide']: + elif self.symfunc_type in ['angular_narrow', 'angular_wide']: for elem_central in self.elements: for pair_of_neighbors in itertools.combinations_with_replacement(self.elements, 2): comb = (elem_central,) + pair_of_neighbors combinations.append(comb) - elif self._symfunc_type in ['weighted_radial', 'weighted_angular']: + elif self.symfunc_type in ['weighted_radial', 'weighted_angular']: for elem_central in self.elements: combinations.append((elem_central,)) @@ -374,8 +397,14 @@ def main(): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) + # print('\nimbalzano2018 shift mode') + # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) + # myGen.symfunc_type = 'radial' + # myGen.write_generation_info() + print('\nimbalzano2018 shift mode') - myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) + myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=5, r_lower=1.5, + r_upper=5.5) myGen.symfunc_type = 'radial' myGen.write_generation_info() @@ -406,8 +435,6 @@ def main(): print() myGen.write_parameter_strings() - print(myGen.element_combinations) - if __name__ == '__main__': main() From 5655ae68e094100c1b18e5fc042806e2c6aa75ce Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 26 Apr 2019 22:38:29 +0200 Subject: [PATCH 20/60] Rework and extend in-code documentation. --- tools/python/SymFuncParamGenerator.py | 103 ++++++++++++++++---------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index d653c7956..ce1f1c05d 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -76,17 +76,25 @@ def symfunc_type(self): When the setter for this is called it also checks the validity of the input, builds the necessary element combinations for the given symmetry function type, and stores it to member variable. + + If the given symmetry function type is a radial one, + the setter also clears any preexisting zetas + (i.e., sets the member variable zetas to None). """ return self._symfunc_type @symfunc_type.setter def symfunc_type(self, value): - # TODO: set zetas to None if a radial type is given ?? -> why not self._symfunc_type = value self.check_symfunc_type() # once symmetry function type has been set and found to be valid, # build and store the element combinations self._element_combinations = self.find_element_combinations() + # Clear any previous zeta values, if the given symfunc type is a radial one + if self.symfunc_type in ['radial', 'weighted_radial']: + # set the member variable explicitly (with underscore) instead of + # calling setter, because the setter would put None into an array + self._zetas = None @property def zetas(self): @@ -112,16 +120,24 @@ def check_symfunc_type(self): ------- None """ - if self._symfunc_type is None: + if self.symfunc_type is None: raise TypeError('No symmetry function type has been set.') - elif not self._symfunc_type in self.symfunc_type_numbers.keys(): + elif not self.symfunc_type in self.symfunc_type_numbers.keys(): raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) - def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower=None, r_upper=None): + def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, + r_lower=None, r_upper=None): + # TODO: maybe rename the argument 'method' to 'rule' or something to avoid confusion in documentation as to whether I'm referring to the argument called 'method' or the class method + # TODO: consider renaming nb_gridpoints """Generate a set of values for r_shift and eta. Such a set of values is required for any symmetry function type. + Its generation is independent of the symmetry function type + and the angular symmetry function parameters zeta and lambda. + + Rules for parameter generation are implemented based on [1]_ and [2]_. + The generated values are stored as arrays in the member variables r_shift_grid and eta_grid. The entries are to be understood pairwise, i.e., the i-th entry of r_shift_grid and the i-th entry of eta_grid belong to one symmetry function. @@ -131,8 +147,8 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= Parameters ---------- method : {'gastegger2018', 'imbalzano2018'} - if method=='gastegger2018' use the parameter generation rules presented in [1]_, - if method=='imbalzano2018' use the parameter generation rules presented in [2]_ + If method=='gastegger2018' use the parameter generation rules presented in [1]_. + If method=='imbalzano2018' use the parameter generation rules presented in [2]_. mode : {'center', 'shift'} Selects which parameter generation rule to use, on top of the method argument, since there are again two different varieties presented in each of the two papers. @@ -141,7 +157,7 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= The exact implementation details differ depending on the method parameter and are described in the papers. r_cutoff : float - Cutoff radius, at which the symmetry functions go to zero. + Cutoff radius, at which symmetry functions go to zero. Must be greater than zero. nb_gridpoints : int number of (r_shift, eta)-pairs to be created. @@ -163,16 +179,29 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= (r_shift, eta)-pairs ultimately generated, not the number of intervals between points in a grid of r_shift values, or the number of points in some auxiliary grid. - This constitutes a slight modification of the nomenclature - from the papers, for the sake of consistent behavior across all - options for method and mode. + This constitutes a slight modification of the nomenclature from the + papers, for the sake of consistent behavior across all options for + method and mode. + + While the parameter generation by this method does not itself + depend on symmetry function type, be aware of the exact mathematical + expressions for the different symmetry function types and how the + parameters r_shift and eta appear slightly differently in each of them. + + All this method does is implement the rules described in the two + papers for generating values of the symmetry function parameters + r_shift and eta. As far as this module is concerned, these can then + be used (with the above caveat) in combination with any symmetry + function type. However, this does not imply that their use with all + the different types of symmetry functions is actually discussed in + the papers or was necessarily intended by the authors. Returns ------- None """ - # TODO: add checks for r_lower, r_upper greater zero and less equal r_cutoff - # store infos on radial parameter generation settings (that are independent of method) + # store those infos on radial parameter generation settings that are + # independent of method self.radial_grid_info = dict(method=method, mode=mode, r_cutoff=r_cutoff, @@ -185,7 +214,7 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, r_lower= # by default, set largest value of radial grid to cutoff radius r_upper = r_cutoff - # Check relationship between different radii parameters + # Check relationship between different radii parameters is correct if not 0 < r_lower < r_upper <= r_cutoff: raise ValueError('Invalid arguments. It is required that 0 < r_lower < r_upper <= r_cutoff.') @@ -262,18 +291,20 @@ def check_all(self): TypeError If no set of radial parameters (r_shift and eta) has been generated TypeError - If an angular symmetry function type has been set, but no values for zeta were set. + If an angular symmetry function type has been set, but no values + for zeta were set. Returns ------- None """ self.check_symfunc_type() - # TODO: consider removing the check for radial_grid_info (since a user might want to directly set r_shift and eta values on their own, in which case no info would have been generated + # TODO: consider removing the check for radial_grid_info (since a user might want to directly set r_shift and eta values on their own, in which case no info would have been generated) + # -> but how to handle setting of r_cutoff in that case? if self.radial_grid_info is None or self.r_shift_grid is None or self.eta_grid is None: raise TypeError('No radial grid has been generated.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - if self.zetas is None: + if self._zetas is None: raise TypeError('zeta values not set.') def write_generation_info(self): @@ -291,7 +322,7 @@ def write_generation_info(self): weighted_angular='Weighted angular') sys.stdout.write( - '# {} symmetry function set, generated with parameters:\n'.format(type_descriptions[self._symfunc_type])) + '# {} symmetry function set, generated with parameters:\n'.format(type_descriptions[self.symfunc_type])) sys.stdout.write(f'# elements = {self.elements}\n') for key, value in self.radial_grid_info.items(): sys.stdout.write(f'# {key:13s} = {value}\n') @@ -299,9 +330,9 @@ def write_generation_info(self): np.set_printoptions(precision=4) sys.stdout.write(f'# r_shift_grid = {self.r_shift_grid}\n') sys.stdout.write(f'# eta_grid = {self.eta_grid}\n') - if self._symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: sys.stdout.write(f'# lambdas = {self.lambdas}\n') - sys.stdout.write(f'# zetas = {self._zetas}\n') + sys.stdout.write(f'# zetas = {self.zetas}\n') # reset numpy print precision to default np.set_printoptions(precision=8) @@ -357,34 +388,33 @@ def write_parameter_strings(self): r_cutoff = self.radial_grid_info['r_cutoff'] sf_number = self.symfunc_type_numbers[self.symfunc_type] - # TODO: make some kind of linebreaks within the strings to keep code lines below hard limit of 120 chars - if self._symfunc_type == 'radial': + if self.symfunc_type == 'radial': for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') - elif self._symfunc_type in ['angular_narrow', 'angular_wide']: + elif self.symfunc_type in ['angular_narrow', 'angular_wide']: for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): - for zeta in self._zetas: + for zeta in self.zetas: for lambd in self.lambdas: sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {comb[2]:2s} {eta:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} {rs:9.3E}\n') sys.stdout.write('\n') - elif self._symfunc_type == 'weighted_radial': + elif self.symfunc_type == 'weighted_radial': for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') sys.stdout.write('\n') - elif self._symfunc_type == 'weighted_angular': + elif self.symfunc_type == 'weighted_angular': for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): - for zeta in self._zetas: + for zeta in self.zetas: for lambd in self.lambdas: sys.stdout.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} \n') @@ -397,41 +427,38 @@ def main(): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - # print('\nimbalzano2018 shift mode') - # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) - # myGen.symfunc_type = 'radial' - # myGen.write_generation_info() - print('\nimbalzano2018 shift mode') - myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=5, r_lower=1.5, - r_upper=5.5) + myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) myGen.symfunc_type = 'radial' - myGen.write_generation_info() + + # print('\nimbalzano2018 shift mode') + # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=5, r_lower=1.5, + # r_upper=5.5) + # myGen.zetas = [1.0, 6.0] + # myGen.symfunc_type = 'radial' # print('\ngastegger2018 shift mode') # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) # myGen.symfunc_type = 'angular_narrow' # myGen.zetas = [1.0, 6.0] - # myGen.write_generation_info() + # print(myGen.zetas) # print('gastegger2018 center mode') # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) # myGen.symfunc_type = 'angular_wide' # myGen.zetas = [1.0, 6.0] - # myGen.write_generation_info() # print('\nimbalzano2018 center mode') # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) # myGen.symfunc_type = 'weighted_radial' - # myGen.write_generation_info() # print('\ngastegger2018 shift mode') # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) # myGen.symfunc_type = 'weighted_angular' # myGen.zetas = [1.0, 6.0] - # myGen.write_generation_info() + myGen.write_generation_info() print() myGen.write_parameter_strings() From 44bf848c51ed81f152037aa84da95c827d9fc5e2 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 26 Apr 2019 23:01:38 +0200 Subject: [PATCH 21/60] Make lambdas into class variable. --- tools/python/SymFuncParamGenerator.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index ce1f1c05d..67d6a68a5 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -39,12 +39,9 @@ class SymFuncParamGenerator: angular_wide=9, weighted_radial=12, weighted_angular=13) + lambdas = np.array([-1.0, 1.0]) def __init__(self, elements): - # TODO: decide if there needs to be the option to change lambdas. If not, consider making it a class variable - # -> can probably be fixed to [-1, 1] - self.lambdas = np.array([-1.0, 1.0]) - # TODO: consider checking if valid input for elements self._elements = elements self._element_combinations = None @@ -335,6 +332,7 @@ def write_generation_info(self): sys.stdout.write(f'# zetas = {self.zetas}\n') # reset numpy print precision to default np.set_printoptions(precision=8) + sys.stdout.write('\n') def find_element_combinations(self): """Create combinations of elements, depending on symmetry function type and the elements in the system. @@ -427,9 +425,9 @@ def main(): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - print('\nimbalzano2018 shift mode') - myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) - myGen.symfunc_type = 'radial' + # print('\nimbalzano2018 shift mode') + # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) + # myGen.symfunc_type = 'radial' # print('\nimbalzano2018 shift mode') # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=5, r_lower=1.5, @@ -443,10 +441,10 @@ def main(): # myGen.zetas = [1.0, 6.0] # print(myGen.zetas) - # print('gastegger2018 center mode') - # myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) - # myGen.symfunc_type = 'angular_wide' - # myGen.zetas = [1.0, 6.0] + print('gastegger2018 center mode') + myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) + myGen.symfunc_type = 'angular_wide' + myGen.zetas = [1.0, 6.0] # print('\nimbalzano2018 center mode') # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) @@ -459,7 +457,6 @@ def main(): myGen.write_generation_info() - print() myGen.write_parameter_strings() From 3adc365bea621bba90c685e75c77b0448034951c Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sat, 27 Apr 2019 13:54:39 +0200 Subject: [PATCH 22/60] Rename some variables; modify in-code documentation. --- tools/python/SymFuncParamGenerator.py | 118 ++++++++++++++------------ 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index 67d6a68a5..f550db7bd 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -33,7 +33,6 @@ class SymFuncParamGenerator: zetas """ - # TODO: might want to rename that variable symfunc_type_numbers = dict(radial=2, angular_narrow=3, angular_wide=9, @@ -123,10 +122,8 @@ def check_symfunc_type(self): raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) - def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, + def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, r_lower=None, r_upper=None): - # TODO: maybe rename the argument 'method' to 'rule' or something to avoid confusion in documentation as to whether I'm referring to the argument called 'method' or the class method - # TODO: consider renaming nb_gridpoints """Generate a set of values for r_shift and eta. Such a set of values is required for any symmetry function type. @@ -140,52 +137,53 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, and the i-th entry of eta_grid belong to one symmetry function. Besides the set of values for r_shift and eta, the settings that were used for generating it are also stored, in the dictionary radial_grid_info. + # TODO: rethink use of radial_grid_info Parameters ---------- - method : {'gastegger2018', 'imbalzano2018'} - If method=='gastegger2018' use the parameter generation rules presented in [1]_. - If method=='imbalzano2018' use the parameter generation rules presented in [2]_. + rule : {'gastegger2018', 'imbalzano2018'} + If rule=='gastegger2018' use the parameter generation rules presented in [1]_. + If rule=='imbalzano2018' use the parameter generation rules presented in [2]_. mode : {'center', 'shift'} - Selects which parameter generation rule to use, on top of the method argument, + Selects which parameter generation procedure to use, on top of the rule argument, since there are again two different varieties presented in each of the two papers. 'center' sets r_shift to zero for all symmetry functions, varying only eta. 'shift' creates parameter sets where r_shift varies. The exact implementation details differ depending on - the method parameter and are described in the papers. + the rule parameter and are described in the papers. r_cutoff : float Cutoff radius, at which symmetry functions go to zero. Must be greater than zero. - nb_gridpoints : int - number of (r_shift, eta)-pairs to be created. + nb_param_pairs : int + Number of (r_shift, eta)-pairs to be generated. r_lower : float - lowest value of radial grid points. - required if method=='gastegger2018'. - ignored if method=='imbalzano2018'. + lowest value in grid of r_shift values. + required if rule=='gastegger2018'. + ignored if rule=='imbalzano2018'. r_upper : float, optional - largest value of radial grid points. - optional if method=='gastegger2018, defaults to cutoff radius if not given. - ignored if method=='imbalzano2018'. + largest value in grid of r_shift values. + optional if rule=='gastegger2018, defaults to cutoff radius if not given. + ignored if rule=='imbalzano2018'. Notes ---------- [1] https://doi.org/10.1063/1.5019667 [2] https://doi.org/10.1063/1.5024611 - The parameter nb_gridpoints universally specifies the number of + The parameter nb_param_pairs invariably specifies the number of (r_shift, eta)-pairs ultimately generated, not the number of intervals between points in a grid of r_shift values, or the number of points in some auxiliary grid. - This constitutes a slight modification of the nomenclature from the - papers, for the sake of consistent behavior across all options for - method and mode. + This constitutes a slight modification of the nomenclature in [2], + for the sake of consistent behavior across all options for rule and + mode. While the parameter generation by this method does not itself depend on symmetry function type, be aware of the exact mathematical expressions for the different symmetry function types and how the parameters r_shift and eta appear slightly differently in each of them. - All this method does is implement the rules described in the two + All this method does is implement the procedures described in the two papers for generating values of the symmetry function parameters r_shift and eta. As far as this module is concerned, these can then be used (with the above caveat) in combination with any symmetry @@ -198,48 +196,50 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, None """ # store those infos on radial parameter generation settings that are - # independent of method - self.radial_grid_info = dict(method=method, + # independent of rule + self.radial_grid_info = dict(rule=rule, mode=mode, r_cutoff=r_cutoff, - nb_gridpoints=nb_gridpoints) + nb_param_pairs=nb_param_pairs) - if method == 'gastegger2018': + if rule == 'gastegger2018': if r_lower is None: - raise TypeError('Argument r_lower is required for method "gastegger2018"') + raise TypeError('Argument r_lower is required for rule "gastegger2018"') if r_upper is None: # by default, set largest value of radial grid to cutoff radius r_upper = r_cutoff # Check relationship between different radii parameters is correct + # TODO: actually, this check may be too strong since for shift mode, r_lower can in fact be zero if not 0 < r_lower < r_upper <= r_cutoff: raise ValueError('Invalid arguments. It is required that 0 < r_lower < r_upper <= r_cutoff.') - # store settings that are unique to this method + # store settings that are unique to this rule self.radial_grid_info.update({'r_lower': r_lower, 'r_upper': r_upper}) # create auxiliary grid - grid = np.linspace(r_lower, r_upper, nb_gridpoints) + grid = np.linspace(r_lower, r_upper, nb_param_pairs) if mode == 'center': - r_shift_grid = np.zeros(nb_gridpoints) + r_shift_grid = np.zeros(nb_param_pairs) eta_grid = 1.0 / (2.0 * grid ** 2) elif mode == 'shift': r_shift_grid = grid - dr = (r_upper - r_lower) / (nb_gridpoints - 1) - eta_grid = np.full(nb_gridpoints, 1.0 / (2.0 * dr * dr)) + # equidistant grid spacing + dr = (r_upper - r_lower) / (nb_param_pairs - 1) + eta_grid = np.full(nb_param_pairs, 1.0 / (2.0 * dr * dr)) else: raise ValueError('invalid argument for "mode"') - elif method == 'imbalzano2018': + elif rule == 'imbalzano2018': if r_lower is not None: sys.stderr.write( - 'Warning: argument r_lower is not used in method "imbalzano2018" and will be ignored.\n') + 'Warning: argument r_lower is not used in rule "imbalzano2018" and will be ignored.\n') traceback.print_stack() sys.stderr.flush() if r_upper is not None: sys.stderr.write( - 'Warning: argument r_upper is not used in method "imbalzano2018" and will be ignored.\n') + 'Warning: argument r_upper is not used in rule "imbalzano2018" and will be ignored.\n') traceback.print_stack() sys.stderr.flush() @@ -247,21 +247,21 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, raise ValueError('Invalid argument for r_cutoff. Must be greater than zero.') if mode == 'center': - nb_intervals = nb_gridpoints - 1 + nb_intervals = nb_param_pairs - 1 gridpoint_indices = np.array(range(0, nb_intervals + 1)) eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) / r_cutoff) ** 2 r_shift_grid = np.zeros_like(eta_grid) elif mode == 'shift': - # TODO: somehow mention that shift mode for angular symfuncs is actually not discussed in the paper - # create extended auxiliary grid of r_shift values, that contains nb_gridpoints + 1 values - nb_intervals_extended = nb_gridpoints + # create extended auxiliary grid of r_shift values, + # that contains nb_param_pairs + 1 values + nb_intervals_extended = nb_param_pairs gridpoint_indices_extended = np.array(range(0, nb_intervals_extended + 1)) rs_grid_extended = r_cutoff / nb_intervals_extended ** ( gridpoint_indices_extended / nb_intervals_extended) # from pairs of neighboring r_shift values, compute eta values. - # doing this for the nb_gridpoints + 1 values in the auxiliary - # grid ultimately gives nb_gridpoints different values for eta. - eta_grid = np.zeros(nb_gridpoints) + # doing this for the nb_param_pairs + 1 values in the auxiliary + # grid ultimately gives nb_param_pairs different values for eta. + eta_grid = np.zeros(nb_param_pairs) for idx in range(len(rs_grid_extended) - 1): eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 eta_grid[idx] = eta_current @@ -269,13 +269,13 @@ def generate_radial_params(self, method, mode, r_cutoff, nb_gridpoints, # (for which r_shift coincides with the cutoff radius) from the extended grid r_shift_grid = rs_grid_extended[1:] # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift - # (not necessary, but makes the output consistent with the other methods) + # (not necessary, but makes the output consistent with the other options) r_shift_grid = np.flip(r_shift_grid) eta_grid = np.flip(eta_grid) else: raise ValueError('invalid argument for "mode"') else: - raise ValueError('invalid argument for "method"') + raise ValueError('invalid argument for "rule"') self.r_shift_grid = r_shift_grid self.eta_grid = eta_grid @@ -426,34 +426,40 @@ def main(): myGen = SymFuncParamGenerator(elems) # print('\nimbalzano2018 shift mode') - # myGen.generate_radial_params(method='imbalzano2018', mode='shift', r_cutoff=6., nb_gridpoints=5) + # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', + # r_cutoff=6., nb_param_pairs=5) # myGen.symfunc_type = 'radial' # print('\nimbalzano2018 shift mode') - # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=5, r_lower=1.5, + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # r_cutoff=6., nb_param_pairs=5, r_lower=1.5, # r_upper=5.5) # myGen.zetas = [1.0, 6.0] # myGen.symfunc_type = 'radial' # print('\ngastegger2018 shift mode') - # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=9, r_lower=1.5) + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # r_cutoff=6., nb_param_pairs=9, r_lower=1.5) # myGen.symfunc_type = 'angular_narrow' # myGen.zetas = [1.0, 6.0] # print(myGen.zetas) - print('gastegger2018 center mode') - myGen.generate_radial_params(method='gastegger2018', mode='center', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) - myGen.symfunc_type = 'angular_wide' - myGen.zetas = [1.0, 6.0] + # print('gastegger2018 center mode') + # myGen.generate_radial_params(rule='gastegger2018', mode='center', + # r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + # myGen.symfunc_type = 'angular_wide' + # myGen.zetas = [1.0, 6.0] # print('\nimbalzano2018 center mode') - # myGen.generate_radial_params(method='imbalzano2018', mode='center', r_cutoff=5., nb_gridpoints=5) + # myGen.generate_radial_params(rule='imbalzano2018', mode='center', + # r_cutoff=5., nb_param_pairs=5) # myGen.symfunc_type = 'weighted_radial' - # print('\ngastegger2018 shift mode') - # myGen.generate_radial_params(method='gastegger2018', mode='shift', r_cutoff=6., nb_gridpoints=3, r_lower=1.5) - # myGen.symfunc_type = 'weighted_angular' - # myGen.zetas = [1.0, 6.0] + print('\ngastegger2018 shift mode') + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + myGen.symfunc_type = 'weighted_angular' + myGen.zetas = [1.0, 6.0] myGen.write_generation_info() From a52e249963d58f3a0ce1640bc5da2f5f39f555a4 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 29 Apr 2019 11:23:34 +0200 Subject: [PATCH 23/60] Allow r_lower=0 for 'gastegger2018', method 'shift'. --- tools/python/SymFuncParamGenerator.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index f550db7bd..b82311164 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -103,7 +103,7 @@ def zetas(self, values): self._zetas = np.array(values) def check_symfunc_type(self): - """Check if a symmetry function type has been set and if it is a valid one. + """Check if a symmetry function type has been set and if it is valid. Raises ------- @@ -157,12 +157,14 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, nb_param_pairs : int Number of (r_shift, eta)-pairs to be generated. r_lower : float - lowest value in grid of r_shift values. + lowest value in the radial grid from which r_shift and eta values + are computed. required if rule=='gastegger2018'. ignored if rule=='imbalzano2018'. r_upper : float, optional - largest value in grid of r_shift values. - optional if rule=='gastegger2018, defaults to cutoff radius if not given. + largest value in the radial grid from which r_shift and eta + values are computed. + optional if rule=='gastegger2018, defaults to r_cutoff if not given. ignored if rule=='imbalzano2018'. Notes @@ -209,11 +211,6 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, # by default, set largest value of radial grid to cutoff radius r_upper = r_cutoff - # Check relationship between different radii parameters is correct - # TODO: actually, this check may be too strong since for shift mode, r_lower can in fact be zero - if not 0 < r_lower < r_upper <= r_cutoff: - raise ValueError('Invalid arguments. It is required that 0 < r_lower < r_upper <= r_cutoff.') - # store settings that are unique to this rule self.radial_grid_info.update({'r_lower': r_lower, 'r_upper': r_upper}) @@ -221,11 +218,17 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, grid = np.linspace(r_lower, r_upper, nb_param_pairs) if mode == 'center': + # r_lower = 0 is not allowed, because it leads to division by zero + if not 0 < r_lower < r_upper <= r_cutoff: + raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 < r_lower < r_upper <= r_cutoff.') r_shift_grid = np.zeros(nb_param_pairs) eta_grid = 1.0 / (2.0 * grid ** 2) elif mode == 'shift': + # conversely, in shift mode, r_lower = 0 is possible + if not 0 <= r_lower < r_upper <= r_cutoff: + raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 <= r_lower < r_upper <= r_cutoff.') r_shift_grid = grid - # equidistant grid spacing + # compute the equidistant grid spacing dr = (r_upper - r_lower) / (nb_param_pairs - 1) eta_grid = np.full(nb_param_pairs, 1.0 / (2.0 * dr * dr)) else: From 073c4a475605e06d56343e30d2ab01026e54b09a Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 29 Apr 2019 12:26:18 +0200 Subject: [PATCH 24/60] Clean up output of method write_generation_info(). Also rename to write_parameter_info(). --- tools/python/SymFuncParamGenerator.py | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index b82311164..e4b438102 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -198,7 +198,7 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, None """ # store those infos on radial parameter generation settings that are - # independent of rule + # independent of the rule argument self.radial_grid_info = dict(rule=rule, mode=mode, r_cutoff=r_cutoff, @@ -307,7 +307,7 @@ def check_all(self): if self._zetas is None: raise TypeError('zeta values not set.') - def write_generation_info(self): + def write_parameter_info(self): """Writes the settings used in generating the currently stored set of symmetry function parameters to stdout. Returns @@ -321,18 +321,24 @@ def write_generation_info(self): weighted_radial='Weighted radial', weighted_angular='Weighted angular') + sys.stdout.write('#########################################################################\n') sys.stdout.write( - '# {} symmetry function set, generated with parameters:\n'.format(type_descriptions[self.symfunc_type])) - sys.stdout.write(f'# elements = {self.elements}\n') + f'# {type_descriptions[self.symfunc_type]} symmetry function set, ' + f'for elements {self.elements}\n') + sys.stdout.write('#########################################################################\n') + + sys.stdout.write('# Radial parameters were generated using the following settings:\n') for key, value in self.radial_grid_info.items(): - sys.stdout.write(f'# {key:13s} = {value}\n') + sys.stdout.write(f'# {key:14s} = {value}\n') + + sys.stdout.write('# Sets of values for parameters:\n') # set numpy print precision to lower number of decimal places for the following outputs np.set_printoptions(precision=4) - sys.stdout.write(f'# r_shift_grid = {self.r_shift_grid}\n') - sys.stdout.write(f'# eta_grid = {self.eta_grid}\n') + sys.stdout.write(f'# r_shift_grid = {self.r_shift_grid}\n') + sys.stdout.write(f'# eta_grid = {self.eta_grid}\n') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - sys.stdout.write(f'# lambdas = {self.lambdas}\n') - sys.stdout.write(f'# zetas = {self.zetas}\n') + sys.stdout.write(f'# lambdas = {self.lambdas}\n') + sys.stdout.write(f'# zetas = {self.zetas}\n') # reset numpy print precision to default np.set_printoptions(precision=8) sys.stdout.write('\n') @@ -429,34 +435,32 @@ def main(): myGen = SymFuncParamGenerator(elems) # print('\nimbalzano2018 shift mode') + # myGen.symfunc_type = 'radial' # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', # r_cutoff=6., nb_param_pairs=5) - # myGen.symfunc_type = 'radial' # print('\nimbalzano2018 shift mode') + # myGen.symfunc_type = 'radial' # myGen.generate_radial_params(rule='gastegger2018', mode='shift', # r_cutoff=6., nb_param_pairs=5, r_lower=1.5, # r_upper=5.5) - # myGen.zetas = [1.0, 6.0] - # myGen.symfunc_type = 'radial' # print('\ngastegger2018 shift mode') + # myGen.symfunc_type = 'angular_narrow' # myGen.generate_radial_params(rule='gastegger2018', mode='shift', # r_cutoff=6., nb_param_pairs=9, r_lower=1.5) - # myGen.symfunc_type = 'angular_narrow' # myGen.zetas = [1.0, 6.0] - # print(myGen.zetas) # print('gastegger2018 center mode') + # myGen.symfunc_type = 'angular_wide' # myGen.generate_radial_params(rule='gastegger2018', mode='center', # r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - # myGen.symfunc_type = 'angular_wide' # myGen.zetas = [1.0, 6.0] # print('\nimbalzano2018 center mode') + # myGen.symfunc_type = 'weighted_radial' # myGen.generate_radial_params(rule='imbalzano2018', mode='center', # r_cutoff=5., nb_param_pairs=5) - # myGen.symfunc_type = 'weighted_radial' print('\ngastegger2018 shift mode') myGen.generate_radial_params(rule='gastegger2018', mode='shift', @@ -465,7 +469,7 @@ def main(): myGen.zetas = [1.0, 6.0] - myGen.write_generation_info() + myGen.write_parameter_info() myGen.write_parameter_strings() From 53d92ea7a9895139d3cb58dc195afa6e74ad7edd Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 1 May 2019 15:53:45 +0200 Subject: [PATCH 25/60] Add write-to-file option to write_parameter_info(). --- tools/python/SymFuncParamGenerator.py | 77 +++++++++++++++++---------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index e4b438102..af88e08b7 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -300,15 +300,21 @@ def check_all(self): """ self.check_symfunc_type() # TODO: consider removing the check for radial_grid_info (since a user might want to directly set r_shift and eta values on their own, in which case no info would have been generated) - # -> but how to handle setting of r_cutoff in that case? + # -> but how to handle setting (and storing) of r_cutoff in that case? if self.radial_grid_info is None or self.r_shift_grid is None or self.eta_grid is None: raise TypeError('No radial grid has been generated.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: if self._zetas is None: raise TypeError('zeta values not set.') - def write_parameter_info(self): - """Writes the settings used in generating the currently stored set of symmetry function parameters to stdout. + def write_parameter_info(self, file=None): + """Write settings used in generating the currently stored set of symmetry function parameters. + + Parameters + ---------- + file : path-like, optional + The file to write the settings information to, using append mode. + If not specified, write to sys.stdout instead. Returns ------- @@ -321,27 +327,39 @@ def write_parameter_info(self): weighted_radial='Weighted radial', weighted_angular='Weighted angular') - sys.stdout.write('#########################################################################\n') - sys.stdout.write( + # depending on presence of file parameter, either direct output + # to stdout, or open the specified file + if file is None: + handle = sys.stdout + else: + handle = open(file, 'a') + + handle.write('#########################################################################\n') + handle.write( f'# {type_descriptions[self.symfunc_type]} symmetry function set, ' f'for elements {self.elements}\n') - sys.stdout.write('#########################################################################\n') + handle.write('#########################################################################\n') - sys.stdout.write('# Radial parameters were generated using the following settings:\n') + handle.write('# Radial parameters were generated using the following settings:\n') for key, value in self.radial_grid_info.items(): - sys.stdout.write(f'# {key:14s} = {value}\n') + handle.write(f'# {key:14s} = {value}\n') - sys.stdout.write('# Sets of values for parameters:\n') + handle.write('# Sets of values for parameters:\n') # set numpy print precision to lower number of decimal places for the following outputs np.set_printoptions(precision=4) - sys.stdout.write(f'# r_shift_grid = {self.r_shift_grid}\n') - sys.stdout.write(f'# eta_grid = {self.eta_grid}\n') + handle.write(f'# r_shift_grid = {self.r_shift_grid}\n') + handle.write(f'# eta_grid = {self.eta_grid}\n') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - sys.stdout.write(f'# lambdas = {self.lambdas}\n') - sys.stdout.write(f'# zetas = {self.zetas}\n') + handle.write(f'# lambdas = {self.lambdas}\n') + handle.write(f'# zetas = {self.zetas}\n') # reset numpy print precision to default np.set_printoptions(precision=8) - sys.stdout.write('\n') + handle.write('\n') + + # close the file again (unless writing to sys.stdout, + # which does not need to be closed in the same sense as a file object) + if handle is not sys.stdout: + handle.close() def find_element_combinations(self): """Create combinations of elements, depending on symmetry function type and the elements in the system. @@ -383,7 +401,8 @@ def write_parameter_strings(self): """Write symmetry function parameter sets to stdout, formatted as in the file 'input.nn' required by n2p2. Each line in the output corresponds to one symmetry function. - Output is formatted in blocks separated by blank lines, each block corresponding to one element combination. + Output is formatted in blocks separated by blank lines, each block + corresponding to one element combination. Within each block, the other parameters are iterated over. Returns @@ -434,39 +453,39 @@ def main(): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - # print('\nimbalzano2018 shift mode') + # # imbalzano2018 shift mode # myGen.symfunc_type = 'radial' # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', # r_cutoff=6., nb_param_pairs=5) - # print('\nimbalzano2018 shift mode') + # # imbalzano2018 shift mode # myGen.symfunc_type = 'radial' # myGen.generate_radial_params(rule='gastegger2018', mode='shift', # r_cutoff=6., nb_param_pairs=5, r_lower=1.5, # r_upper=5.5) - # print('\ngastegger2018 shift mode') + # # gastegger2018 shift mode # myGen.symfunc_type = 'angular_narrow' # myGen.generate_radial_params(rule='gastegger2018', mode='shift', # r_cutoff=6., nb_param_pairs=9, r_lower=1.5) # myGen.zetas = [1.0, 6.0] - # print('gastegger2018 center mode') - # myGen.symfunc_type = 'angular_wide' - # myGen.generate_radial_params(rule='gastegger2018', mode='center', - # r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - # myGen.zetas = [1.0, 6.0] + # gastegger2018 center mode + myGen.symfunc_type = 'angular_wide' + myGen.generate_radial_params(rule='gastegger2018', mode='center', + r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + myGen.zetas = [1.0, 6.0] - # print('\nimbalzano2018 center mode') + # # imbalzano2018 center mode # myGen.symfunc_type = 'weighted_radial' # myGen.generate_radial_params(rule='imbalzano2018', mode='center', # r_cutoff=5., nb_param_pairs=5) - print('\ngastegger2018 shift mode') - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - myGen.symfunc_type = 'weighted_angular' - myGen.zetas = [1.0, 6.0] + # # gastegger2018 shift mode + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + # myGen.symfunc_type = 'weighted_angular' + # myGen.zetas = [1.0, 6.0] myGen.write_parameter_info() From 208358cc578095e2a18a1fb64843956748953634 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 1 May 2019 17:03:30 +0200 Subject: [PATCH 26/60] Add write-to-file option to write_parameter_strings(). --- tools/python/SymFuncParamGenerator.py | 58 ++++++++++++++++++--------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/SymFuncParamGenerator.py index af88e08b7..47668ad56 100644 --- a/tools/python/SymFuncParamGenerator.py +++ b/tools/python/SymFuncParamGenerator.py @@ -280,6 +280,7 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, else: raise ValueError('invalid argument for "rule"') + # store the generated parameter sets self.r_shift_grid = r_shift_grid self.eta_grid = eta_grid @@ -357,7 +358,7 @@ def write_parameter_info(self, file=None): handle.write('\n') # close the file again (unless writing to sys.stdout, - # which does not need to be closed in the same sense as a file object) + # which should not be closed) if handle is not sys.stdout: handle.close() @@ -397,55 +398,72 @@ def find_element_combinations(self): return combinations - def write_parameter_strings(self): - """Write symmetry function parameter sets to stdout, formatted as in the file 'input.nn' required by n2p2. + def write_parameter_strings(self, file=None): + """Write symmetry function parameter sets, formatted as n2p2 requires. Each line in the output corresponds to one symmetry function. Output is formatted in blocks separated by blank lines, each block corresponding to one element combination. Within each block, the other parameters are iterated over. + Parameters + ---------- + file : path-like, optional + The file to write the parameter strings to, using append mode. + If not specified, write to sys.stdout instead. + Returns ------- None """ self.check_all() + # depending on presence of file parameter, either direct output + # to stdout, or open the specified file + if file is None: + handle = sys.stdout + else: + handle = open(file, 'a') + r_cutoff = self.radial_grid_info['r_cutoff'] sf_number = self.symfunc_type_numbers[self.symfunc_type] if self.symfunc_type == 'radial': for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): - sys.stdout.write( + handle.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') - sys.stdout.write('\n') + handle.write('\n') elif self.symfunc_type in ['angular_narrow', 'angular_wide']: for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): for zeta in self.zetas: for lambd in self.lambdas: - sys.stdout.write( + handle.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {comb[2]:2s} {eta:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} {rs:9.3E}\n') - sys.stdout.write('\n') + handle.write('\n') elif self.symfunc_type == 'weighted_radial': for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): - sys.stdout.write( + handle.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') - sys.stdout.write('\n') + handle.write('\n') elif self.symfunc_type == 'weighted_angular': for comb in self.element_combinations: for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): for zeta in self.zetas: for lambd in self.lambdas: - sys.stdout.write( + handle.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} \n') - sys.stdout.write('\n') + handle.write('\n') + # close the file again (unless writing to sys.stdout, + # which should not be closed) + if handle is not sys.stdout: + handle.close() def main(): @@ -453,10 +471,10 @@ def main(): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - # # imbalzano2018 shift mode - # myGen.symfunc_type = 'radial' - # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - # r_cutoff=6., nb_param_pairs=5) + # imbalzano2018 shift mode + myGen.symfunc_type = 'radial' + myGen.generate_radial_params(rule='imbalzano2018', mode='shift', + r_cutoff=6., nb_param_pairs=5) # # imbalzano2018 shift mode # myGen.symfunc_type = 'radial' @@ -470,11 +488,11 @@ def main(): # r_cutoff=6., nb_param_pairs=9, r_lower=1.5) # myGen.zetas = [1.0, 6.0] - # gastegger2018 center mode - myGen.symfunc_type = 'angular_wide' - myGen.generate_radial_params(rule='gastegger2018', mode='center', - r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - myGen.zetas = [1.0, 6.0] + # # gastegger2018 center mode + # myGen.symfunc_type = 'angular_wide' + # myGen.generate_radial_params(rule='gastegger2018', mode='center', + # r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + # myGen.zetas = [1.0, 6.0] # # imbalzano2018 center mode # myGen.symfunc_type = 'weighted_radial' From b1c014529c855cbf85af241fdb4bc776b7082714 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 1 May 2019 18:47:24 +0200 Subject: [PATCH 27/60] Reorganize folder structure. --- tools/python/{ => symfunc_paramgen/src}/SymFuncParamGenerator.py | 0 .../{ => symfunc_paramgen/src}/generate-acsf-angular_narrow.py | 0 .../{ => symfunc_paramgen/src}/generate-acsf-angular_wide.py | 0 tools/python/{ => symfunc_paramgen/src}/generate-acsf-radial.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tools/python/{ => symfunc_paramgen/src}/SymFuncParamGenerator.py (100%) rename tools/python/{ => symfunc_paramgen/src}/generate-acsf-angular_narrow.py (100%) rename tools/python/{ => symfunc_paramgen/src}/generate-acsf-angular_wide.py (100%) rename tools/python/{ => symfunc_paramgen/src}/generate-acsf-radial.py (100%) diff --git a/tools/python/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py similarity index 100% rename from tools/python/SymFuncParamGenerator.py rename to tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py diff --git a/tools/python/generate-acsf-angular_narrow.py b/tools/python/symfunc_paramgen/src/generate-acsf-angular_narrow.py similarity index 100% rename from tools/python/generate-acsf-angular_narrow.py rename to tools/python/symfunc_paramgen/src/generate-acsf-angular_narrow.py diff --git a/tools/python/generate-acsf-angular_wide.py b/tools/python/symfunc_paramgen/src/generate-acsf-angular_wide.py similarity index 100% rename from tools/python/generate-acsf-angular_wide.py rename to tools/python/symfunc_paramgen/src/generate-acsf-angular_wide.py diff --git a/tools/python/generate-acsf-radial.py b/tools/python/symfunc_paramgen/src/generate-acsf-radial.py similarity index 100% rename from tools/python/generate-acsf-radial.py rename to tools/python/symfunc_paramgen/src/generate-acsf-radial.py From 8b4c0a5df4fdf1fb14d3bc53110a6572fc5da196 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 2 May 2019 12:53:20 +0200 Subject: [PATCH 28/60] Add first basic tests. --- .../src/SymFuncParamGenerator.py | 78 +-- .../tests/reference_outputs.txt | 475 ++++++++++++++++++ .../symfunc_paramgen/tests/test_outputs.py | 80 +++ 3 files changed, 600 insertions(+), 33 deletions(-) create mode 100644 tools/python/symfunc_paramgen/tests/reference_outputs.txt create mode 100644 tools/python/symfunc_paramgen/tests/test_outputs.py diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 47668ad56..9a706e881 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -176,7 +176,7 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, (r_shift, eta)-pairs ultimately generated, not the number of intervals between points in a grid of r_shift values, or the number of points in some auxiliary grid. - This constitutes a slight modification of the nomenclature in [2], + This constitutes a slight modification of the nomenclature in [2]_, for the sake of consistent behavior across all options for rule and mode. @@ -475,39 +475,51 @@ def main(): myGen.symfunc_type = 'radial' myGen.generate_radial_params(rule='imbalzano2018', mode='shift', r_cutoff=6., nb_param_pairs=5) + myGen.write_parameter_info('outfile.txt') + myGen.write_parameter_strings('outfile.txt') - # # imbalzano2018 shift mode - # myGen.symfunc_type = 'radial' - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # r_cutoff=6., nb_param_pairs=5, r_lower=1.5, - # r_upper=5.5) - - # # gastegger2018 shift mode - # myGen.symfunc_type = 'angular_narrow' - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # r_cutoff=6., nb_param_pairs=9, r_lower=1.5) - # myGen.zetas = [1.0, 6.0] - - # # gastegger2018 center mode - # myGen.symfunc_type = 'angular_wide' - # myGen.generate_radial_params(rule='gastegger2018', mode='center', - # r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - # myGen.zetas = [1.0, 6.0] - - # # imbalzano2018 center mode - # myGen.symfunc_type = 'weighted_radial' - # myGen.generate_radial_params(rule='imbalzano2018', mode='center', - # r_cutoff=5., nb_param_pairs=5) - - # # gastegger2018 shift mode - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - # myGen.symfunc_type = 'weighted_angular' - # myGen.zetas = [1.0, 6.0] - - - myGen.write_parameter_info() - myGen.write_parameter_strings() + # imbalzano2018 shift mode + myGen.symfunc_type = 'radial' + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + r_cutoff=6., nb_param_pairs=5, r_lower=1.5, + r_upper=5.5) + myGen.write_parameter_info('outfile.txt') + myGen.write_parameter_strings('outfile.txt') + + # gastegger2018 shift mode + myGen.symfunc_type = 'angular_narrow' + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + r_cutoff=6., nb_param_pairs=9, r_lower=1.5) + myGen.zetas = [1.0, 6.0] + myGen.write_parameter_info('outfile.txt') + myGen.write_parameter_strings('outfile.txt') + + # gastegger2018 center mode + myGen.symfunc_type = 'angular_wide' + myGen.generate_radial_params(rule='gastegger2018', mode='center', + r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + myGen.zetas = [1.0, 6.0] + myGen.write_parameter_info('outfile.txt') + myGen.write_parameter_strings('outfile.txt') + + # imbalzano2018 center mode + myGen.symfunc_type = 'weighted_radial' + myGen.generate_radial_params(rule='imbalzano2018', mode='center', + r_cutoff=5., nb_param_pairs=5) + myGen.write_parameter_info('outfile.txt') + myGen.write_parameter_strings('outfile.txt') + + # gastegger2018 shift mode + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + myGen.symfunc_type = 'weighted_angular' + myGen.zetas = [1.0, 6.0] + myGen.write_parameter_info('outfile.txt') + myGen.write_parameter_strings('outfile.txt') + + + # myGen.write_parameter_info() + # myGen.write_parameter_strings() if __name__ == '__main__': diff --git a/tools/python/symfunc_paramgen/tests/reference_outputs.txt b/tools/python/symfunc_paramgen/tests/reference_outputs.txt new file mode 100644 index 000000000..5c02055c5 --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/reference_outputs.txt @@ -0,0 +1,475 @@ +# Outputs generated at commit b1c014529c855cbf85af241fdb4bc776b7082714, +# to detect possible future changes. +# +######################################################################### +# Radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# Radial parameters were generated using the following settings: +# rule = imbalzano2018 +# mode = shift +# r_cutoff = 6.0 +# nb_param_pairs = 5 +# Sets of values for parameters: +# r_shift_grid = [1.2 1.6557 2.2844 3.1518 4.3487] +# eta_grid = [4.816 2.5299 1.329 0.6981 0.3667] + +symfunction_short S 2 S 4.816E+00 1.200E+00 6.000E+00 +symfunction_short S 2 S 2.530E+00 1.656E+00 6.000E+00 +symfunction_short S 2 S 1.329E+00 2.284E+00 6.000E+00 +symfunction_short S 2 S 6.981E-01 3.152E+00 6.000E+00 +symfunction_short S 2 S 3.667E-01 4.349E+00 6.000E+00 + +symfunction_short S 2 Cu 4.816E+00 1.200E+00 6.000E+00 +symfunction_short S 2 Cu 2.530E+00 1.656E+00 6.000E+00 +symfunction_short S 2 Cu 1.329E+00 2.284E+00 6.000E+00 +symfunction_short S 2 Cu 6.981E-01 3.152E+00 6.000E+00 +symfunction_short S 2 Cu 3.667E-01 4.349E+00 6.000E+00 + +symfunction_short Cu 2 S 4.816E+00 1.200E+00 6.000E+00 +symfunction_short Cu 2 S 2.530E+00 1.656E+00 6.000E+00 +symfunction_short Cu 2 S 1.329E+00 2.284E+00 6.000E+00 +symfunction_short Cu 2 S 6.981E-01 3.152E+00 6.000E+00 +symfunction_short Cu 2 S 3.667E-01 4.349E+00 6.000E+00 + +symfunction_short Cu 2 Cu 4.816E+00 1.200E+00 6.000E+00 +symfunction_short Cu 2 Cu 2.530E+00 1.656E+00 6.000E+00 +symfunction_short Cu 2 Cu 1.329E+00 2.284E+00 6.000E+00 +symfunction_short Cu 2 Cu 6.981E-01 3.152E+00 6.000E+00 +symfunction_short Cu 2 Cu 3.667E-01 4.349E+00 6.000E+00 + +######################################################################### +# Radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# Radial parameters were generated using the following settings: +# rule = gastegger2018 +# mode = shift +# r_cutoff = 6.0 +# nb_param_pairs = 5 +# r_lower = 1.5 +# r_upper = 5.5 +# Sets of values for parameters: +# r_shift_grid = [1.5 2.5 3.5 4.5 5.5] +# eta_grid = [0.5 0.5 0.5 0.5 0.5] + +symfunction_short S 2 S 5.000E-01 1.500E+00 6.000E+00 +symfunction_short S 2 S 5.000E-01 2.500E+00 6.000E+00 +symfunction_short S 2 S 5.000E-01 3.500E+00 6.000E+00 +symfunction_short S 2 S 5.000E-01 4.500E+00 6.000E+00 +symfunction_short S 2 S 5.000E-01 5.500E+00 6.000E+00 + +symfunction_short S 2 Cu 5.000E-01 1.500E+00 6.000E+00 +symfunction_short S 2 Cu 5.000E-01 2.500E+00 6.000E+00 +symfunction_short S 2 Cu 5.000E-01 3.500E+00 6.000E+00 +symfunction_short S 2 Cu 5.000E-01 4.500E+00 6.000E+00 +symfunction_short S 2 Cu 5.000E-01 5.500E+00 6.000E+00 + +symfunction_short Cu 2 S 5.000E-01 1.500E+00 6.000E+00 +symfunction_short Cu 2 S 5.000E-01 2.500E+00 6.000E+00 +symfunction_short Cu 2 S 5.000E-01 3.500E+00 6.000E+00 +symfunction_short Cu 2 S 5.000E-01 4.500E+00 6.000E+00 +symfunction_short Cu 2 S 5.000E-01 5.500E+00 6.000E+00 + +symfunction_short Cu 2 Cu 5.000E-01 1.500E+00 6.000E+00 +symfunction_short Cu 2 Cu 5.000E-01 2.500E+00 6.000E+00 +symfunction_short Cu 2 Cu 5.000E-01 3.500E+00 6.000E+00 +symfunction_short Cu 2 Cu 5.000E-01 4.500E+00 6.000E+00 +symfunction_short Cu 2 Cu 5.000E-01 5.500E+00 6.000E+00 + +######################################################################### +# Narrow angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# Radial parameters were generated using the following settings: +# rule = gastegger2018 +# mode = shift +# r_cutoff = 6.0 +# nb_param_pairs = 9 +# r_lower = 1.5 +# r_upper = 6.0 +# Sets of values for parameters: +# r_shift_grid = [1.5 2.0625 2.625 3.1875 3.75 4.3125 4.875 5.4375 6. ] +# eta_grid = [1.5802 1.5802 1.5802 1.5802 1.5802 1.5802 1.5802 1.5802 1.5802] +# lambdas = [-1. 1.] +# zetas = [1. 6.] + +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 + +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 + +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 +symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 + +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 + +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 + +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 +symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 + +######################################################################### +# Wide angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# Radial parameters were generated using the following settings: +# rule = gastegger2018 +# mode = center +# r_cutoff = 6.0 +# nb_param_pairs = 3 +# r_lower = 1.5 +# r_upper = 6.0 +# Sets of values for parameters: +# r_shift_grid = [0. 0. 0.] +# eta_grid = [0.2222 0.0356 0.0139] +# lambdas = [-1. 1.] +# zetas = [1. 6.] + +symfunction_short S 9 S S 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S S 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 + +symfunction_short S 9 S Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 S Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 + +symfunction_short S 9 Cu Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short S 9 Cu Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 + +symfunction_short Cu 9 S S 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S S 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 + +symfunction_short Cu 9 S Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 S Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 + +symfunction_short Cu 9 Cu Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 +symfunction_short Cu 9 Cu Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 + +######################################################################### +# Weighted radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# Radial parameters were generated using the following settings: +# rule = imbalzano2018 +# mode = center +# r_cutoff = 5.0 +# nb_param_pairs = 5 +# Sets of values for parameters: +# r_shift_grid = [0. 0. 0. 0. 0.] +# eta_grid = [0.04 0.08 0.16 0.32 0.64] + +symfunction_short S 12 4.000E-02 0.000E+00 5.000E+00 +symfunction_short S 12 8.000E-02 0.000E+00 5.000E+00 +symfunction_short S 12 1.600E-01 0.000E+00 5.000E+00 +symfunction_short S 12 3.200E-01 0.000E+00 5.000E+00 +symfunction_short S 12 6.400E-01 0.000E+00 5.000E+00 + +symfunction_short Cu 12 4.000E-02 0.000E+00 5.000E+00 +symfunction_short Cu 12 8.000E-02 0.000E+00 5.000E+00 +symfunction_short Cu 12 1.600E-01 0.000E+00 5.000E+00 +symfunction_short Cu 12 3.200E-01 0.000E+00 5.000E+00 +symfunction_short Cu 12 6.400E-01 0.000E+00 5.000E+00 + +######################################################################### +# Weighted angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# Radial parameters were generated using the following settings: +# rule = gastegger2018 +# mode = shift +# r_cutoff = 6.0 +# nb_param_pairs = 3 +# r_lower = 1.5 +# r_upper = 6.0 +# Sets of values for parameters: +# r_shift_grid = [1.5 3.75 6. ] +# eta_grid = [0.0988 0.0988 0.0988] +# lambdas = [-1. 1.] +# zetas = [1. 6.] + +symfunction_short S 13 9.877E-02 1.500E+00 -1 1.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 1.500E+00 1 1.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 1.500E+00 -1 6.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 1.500E+00 1 6.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 3.750E+00 -1 1.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 3.750E+00 1 1.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 3.750E+00 -1 6.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 3.750E+00 1 6.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 6.000E+00 -1 1.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 6.000E+00 1 1.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 6.000E+00 -1 6.000E+00 6.000E+00 +symfunction_short S 13 9.877E-02 6.000E+00 1 6.000E+00 6.000E+00 + +symfunction_short Cu 13 9.877E-02 1.500E+00 -1 1.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 1.500E+00 1 1.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 1.500E+00 -1 6.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 1.500E+00 1 6.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 3.750E+00 -1 1.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 3.750E+00 1 1.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 3.750E+00 -1 6.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 3.750E+00 1 6.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 6.000E+00 -1 1.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 6.000E+00 1 1.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 6.000E+00 -1 6.000E+00 6.000E+00 +symfunction_short Cu 13 9.877E-02 6.000E+00 1 6.000E+00 6.000E+00 + diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py new file mode 100644 index 000000000..5b607605b --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -0,0 +1,80 @@ +import sys +sys.path.append('../src') + +import pytest +import os +import SymFuncParamGenerator as sfpg +import filecmp + + +def test_element_combinations(): + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + myGen.symfunc_type = 'radial' + assert myGen.element_combinations == [('S', 'S'), ('S', 'Cu'), ('Cu', 'S'), ('Cu', 'Cu')] + + +def isnotcomment(line): + if line[0] == '#': + return False + return True + + +def test_output(tmpdir): + '''To detect changes in parameter generation and writing, compared to older versions. + + ''' + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + + outfile_path = os.path.join(tmpdir, 'outfile.txt') + + myGen.symfunc_type = 'radial' + myGen.generate_radial_params(rule='imbalzano2018', mode='shift', + r_cutoff=6., nb_param_pairs=5) + myGen.write_parameter_info(outfile_path) + myGen.write_parameter_strings(outfile_path) + + myGen.symfunc_type = 'radial' + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + r_cutoff=6., nb_param_pairs=5, r_lower=1.5, + r_upper=5.5) + myGen.write_parameter_info(outfile_path) + myGen.write_parameter_strings(outfile_path) + + myGen.symfunc_type = 'angular_narrow' + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + r_cutoff=6., nb_param_pairs=9, r_lower=1.5) + myGen.zetas = [1.0, 6.0] + myGen.write_parameter_info(outfile_path) + myGen.write_parameter_strings(outfile_path) + + myGen.symfunc_type = 'angular_wide' + myGen.generate_radial_params(rule='gastegger2018', mode='center', + r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + myGen.zetas = [1.0, 6.0] + myGen.write_parameter_info(outfile_path) + myGen.write_parameter_strings(outfile_path) + + myGen.symfunc_type = 'weighted_radial' + myGen.generate_radial_params(rule='imbalzano2018', mode='center', + r_cutoff=5., nb_param_pairs=5) + myGen.write_parameter_info(outfile_path) + myGen.write_parameter_strings(outfile_path) + + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + myGen.symfunc_type = 'weighted_angular' + myGen.zetas = [1.0, 6.0] + myGen.write_parameter_info(outfile_path) + myGen.write_parameter_strings(outfile_path) + + # ignore comment lines, so the test does not immediately fail when only + # the parameter informations are changed (which I would like to keep just + # for keeping track of the settings used in the reference output file, but + # are otherwise not essential) + with open(outfile_path) as f_out, open('reference_outputs.txt') as f_reference: + f_reference = filter(isnotcomment, f_reference) + f_out = filter(isnotcomment, f_out) + assert all(x == y for x, y in zip(f_out, f_reference)) + From 71aa988cf627d7fda1eab4112076862d0f986631 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 2 May 2019 22:06:38 +0200 Subject: [PATCH 29/60] Set r_cutoff independently of radial parameter generation. --- .../src/SymFuncParamGenerator.py | 173 +++++++++++------- .../symfunc_paramgen/tests/test_outputs.py | 21 ++- 2 files changed, 121 insertions(+), 73 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 9a706e881..c7b95000c 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -45,6 +45,7 @@ def __init__(self, elements): self._elements = elements self._element_combinations = None self._symfunc_type = None + self._r_cutoff = None self._zetas = None self.radial_grid_info = None @@ -92,6 +93,19 @@ def symfunc_type(self, value): # calling setter, because the setter would put None into an array self._zetas = None + @property + def r_cutoff(self): + '''Cutoff radius, at which symmetry functions go to zero (float). + + Must be greater than zero. + ''' + return self._r_cutoff + + @r_cutoff.setter + def r_cutoff(self, value): + self._r_cutoff = value + self.check_rcutoff() + @property def zetas(self): """Set of values for the parameter zeta of angular symmetry functions (`numpy.ndarray`). @@ -106,7 +120,7 @@ def check_symfunc_type(self): """Check if a symmetry function type has been set and if it is valid. Raises - ------- + ------ TypeError If the symmetry function type has not been set (i.e., it is None). ValueError @@ -122,11 +136,34 @@ def check_symfunc_type(self): raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) - def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, + def check_rcutoff(self): + """Check if the cutoff radius has been set and if it is valid. + + Raises + ------ + TypeError + If the cutoff radius has not been set (i.e., it is None). + ValueError + If the cutoff radius is not greater than zero. + + Returns + ------- + None + """ + if self.r_cutoff is None: + raise TypeError('No cutoff radius has been set.') + elif not self.r_cutoff > 0: + raise ValueError('Invalid cutoff radius. ' + 'Must be greater than zero.') + + def generate_radial_params(self, rule, mode, nb_param_pairs, r_lower=None, r_upper=None): """Generate a set of values for r_shift and eta. - Such a set of values is required for any symmetry function type. + Requires that the cutoff radius have been set before. + + Such a set of (r_shift, eta)-values is required for any + symmetry function type. Its generation is independent of the symmetry function type and the angular symmetry function parameters zeta and lambda. @@ -137,7 +174,6 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, and the i-th entry of eta_grid belong to one symmetry function. Besides the set of values for r_shift and eta, the settings that were used for generating it are also stored, in the dictionary radial_grid_info. - # TODO: rethink use of radial_grid_info Parameters ---------- @@ -151,9 +187,6 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, 'shift' creates parameter sets where r_shift varies. The exact implementation details differ depending on the rule parameter and are described in the papers. - r_cutoff : float - Cutoff radius, at which symmetry functions go to zero. - Must be greater than zero. nb_param_pairs : int Number of (r_shift, eta)-pairs to be generated. r_lower : float @@ -162,13 +195,23 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, required if rule=='gastegger2018'. ignored if rule=='imbalzano2018'. r_upper : float, optional - largest value in the radial grid from which r_shift and eta + Largest value in the radial grid from which r_shift and eta values are computed. - optional if rule=='gastegger2018, defaults to r_cutoff if not given. - ignored if rule=='imbalzano2018'. + Optional if rule=='gastegger2018, defaults to cutoff radius if not + given. + Ignored if rule=='imbalzano2018'. + + Raises + ------ + TypeError + If parameter r_lower is not given, when using rule 'gastegger2018'. + ValueError + If illegal relation between r_lower, r_upper, r_cutoff. + ValueError + If invalid argument for parameter rule or mode. Notes - ---------- + ----- [1] https://doi.org/10.1063/1.5019667 [2] https://doi.org/10.1063/1.5024611 @@ -197,13 +240,20 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, ------- None """ + + # Check if cutoff radius has been set and is greater than zero + # TODO: Maybe replace this generic check with one that makes clear in its error message that the correct + # way is to set cutoff radius before radial parameter generation, instead of generic error message ?? + self.check_rcutoff() + # store those infos on radial parameter generation settings that are # independent of the rule argument self.radial_grid_info = dict(rule=rule, mode=mode, - r_cutoff=r_cutoff, nb_param_pairs=nb_param_pairs) + r_cutoff = self.r_cutoff + if rule == 'gastegger2018': if r_lower is None: raise TypeError('Argument r_lower is required for rule "gastegger2018"') @@ -224,7 +274,7 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, r_shift_grid = np.zeros(nb_param_pairs) eta_grid = 1.0 / (2.0 * grid ** 2) elif mode == 'shift': - # conversely, in shift mode, r_lower = 0 is possible + # on the other hand, in shift mode, r_lower = 0 is possible if not 0 <= r_lower < r_upper <= r_cutoff: raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 <= r_lower < r_upper <= r_cutoff.') r_shift_grid = grid @@ -246,9 +296,6 @@ def generate_radial_params(self, rule, mode, r_cutoff, nb_param_pairs, traceback.print_stack() sys.stderr.flush() - if not r_cutoff > 0: - raise ValueError('Invalid argument for r_cutoff. Must be greater than zero.') - if mode == 'center': nb_intervals = nb_param_pairs - 1 gridpoint_indices = np.array(range(0, nb_intervals + 1)) @@ -288,7 +335,7 @@ def check_all(self): """Check if a complete symmetry function set, with all required settings for writing, has been generated. Raises - ------- + ------ TypeError If no set of radial parameters (r_shift and eta) has been generated TypeError @@ -301,7 +348,6 @@ def check_all(self): """ self.check_symfunc_type() # TODO: consider removing the check for radial_grid_info (since a user might want to directly set r_shift and eta values on their own, in which case no info would have been generated) - # -> but how to handle setting (and storing) of r_cutoff in that case? if self.radial_grid_info is None or self.r_shift_grid is None or self.eta_grid is None: raise TypeError('No radial grid has been generated.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: @@ -321,6 +367,7 @@ def write_parameter_info(self, file=None): ------- None """ + # TODO: rethink the layout of the info that is written self.check_all() type_descriptions = dict(radial='Radial', angular_narrow='Narrow angular', @@ -335,12 +382,15 @@ def write_parameter_info(self, file=None): else: handle = open(file, 'a') + handle.write('#########################################################################\n') handle.write( f'# {type_descriptions[self.symfunc_type]} symmetry function set, ' f'for elements {self.elements}\n') handle.write('#########################################################################\n') + handle.write(f'# r_cutoff = {self.r_cutoff}\n') + handle.write('# Radial parameters were generated using the following settings:\n') for key, value in self.radial_grid_info.items(): handle.write(f'# {key:14s} = {value}\n') @@ -425,7 +475,7 @@ def write_parameter_strings(self, file=None): else: handle = open(file, 'a') - r_cutoff = self.radial_grid_info['r_cutoff'] + r_cutoff = self.r_cutoff sf_number = self.symfunc_type_numbers[self.symfunc_type] if self.symfunc_type == 'radial': @@ -473,53 +523,46 @@ def main(): # imbalzano2018 shift mode myGen.symfunc_type = 'radial' + myGen.r_cutoff = 6. myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - r_cutoff=6., nb_param_pairs=5) - myGen.write_parameter_info('outfile.txt') - myGen.write_parameter_strings('outfile.txt') - - # imbalzano2018 shift mode - myGen.symfunc_type = 'radial' - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - r_cutoff=6., nb_param_pairs=5, r_lower=1.5, - r_upper=5.5) - myGen.write_parameter_info('outfile.txt') - myGen.write_parameter_strings('outfile.txt') - - # gastegger2018 shift mode - myGen.symfunc_type = 'angular_narrow' - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - r_cutoff=6., nb_param_pairs=9, r_lower=1.5) - myGen.zetas = [1.0, 6.0] - myGen.write_parameter_info('outfile.txt') - myGen.write_parameter_strings('outfile.txt') - - # gastegger2018 center mode - myGen.symfunc_type = 'angular_wide' - myGen.generate_radial_params(rule='gastegger2018', mode='center', - r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - myGen.zetas = [1.0, 6.0] - myGen.write_parameter_info('outfile.txt') - myGen.write_parameter_strings('outfile.txt') - - # imbalzano2018 center mode - myGen.symfunc_type = 'weighted_radial' - myGen.generate_radial_params(rule='imbalzano2018', mode='center', - r_cutoff=5., nb_param_pairs=5) - myGen.write_parameter_info('outfile.txt') - myGen.write_parameter_strings('outfile.txt') - - # gastegger2018 shift mode - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - r_cutoff=6., nb_param_pairs=3, r_lower=1.5) - myGen.symfunc_type = 'weighted_angular' - myGen.zetas = [1.0, 6.0] - myGen.write_parameter_info('outfile.txt') - myGen.write_parameter_strings('outfile.txt') - - - # myGen.write_parameter_info() - # myGen.write_parameter_strings() + nb_param_pairs=5) + + # # imbalzano2018 shift mode + # myGen.symfunc_type = 'radial' + # myGen.r_cutoff = 6. + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) + + # # gastegger2018 shift mode + # myGen.symfunc_type = 'angular_narrow' + # myGen.r_cutoff = 6. + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # nb_param_pairs=9, r_lower=1.5) + # myGen.zetas = [1.0, 6.0] + + # # gastegger2018 center mode + # myGen.symfunc_type = 'angular_wide' + # myGen.r_cutoff = 6. + # myGen.generate_radial_params(rule='gastegger2018', mode='center', + # nb_param_pairs=3, r_lower=1.5) + # myGen.zetas = [1.0, 6.0] + + # # imbalzano2018 center mode + # myGen.symfunc_type = 'weighted_radial' + # myGen.r_cutoff = 5. + # myGen.generate_radial_params(rule='imbalzano2018', mode='center', + # nb_param_pairs=5) + + # # gastegger2018 shift mode + # myGen.r_cutoff = 6. + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # nb_param_pairs=3, r_lower=1.5) + # myGen.symfunc_type = 'weighted_angular' + # myGen.zetas = [1.0, 6.0] + + + myGen.write_parameter_info() + myGen.write_parameter_strings() if __name__ == '__main__': diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index 5b607605b..c0e7eb67a 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -30,41 +30,46 @@ def test_output(tmpdir): outfile_path = os.path.join(tmpdir, 'outfile.txt') myGen.symfunc_type = 'radial' + myGen.r_cutoff = 6. myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - r_cutoff=6., nb_param_pairs=5) + nb_param_pairs=5) myGen.write_parameter_info(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'radial' + myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='shift', - r_cutoff=6., nb_param_pairs=5, r_lower=1.5, - r_upper=5.5) + nb_param_pairs=5, r_lower=1.5, r_upper=5.5) myGen.write_parameter_info(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'angular_narrow' + myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='shift', - r_cutoff=6., nb_param_pairs=9, r_lower=1.5) + nb_param_pairs=9, r_lower=1.5) myGen.zetas = [1.0, 6.0] myGen.write_parameter_info(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'angular_wide' + myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='center', - r_cutoff=6., nb_param_pairs=3, r_lower=1.5) + nb_param_pairs=3, r_lower=1.5) myGen.zetas = [1.0, 6.0] myGen.write_parameter_info(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'weighted_radial' + myGen.r_cutoff = 5. myGen.generate_radial_params(rule='imbalzano2018', mode='center', - r_cutoff=5., nb_param_pairs=5) + nb_param_pairs=5) myGen.write_parameter_info(outfile_path) myGen.write_parameter_strings(outfile_path) - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - r_cutoff=6., nb_param_pairs=3, r_lower=1.5) myGen.symfunc_type = 'weighted_angular' + myGen.r_cutoff = 6. + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + nb_param_pairs=3, r_lower=1.5) myGen.zetas = [1.0, 6.0] myGen.write_parameter_info(outfile_path) myGen.write_parameter_strings(outfile_path) From ef145d8d07a59bd2894e7bbf51363bcb9a992d49 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 3 May 2019 14:42:09 +0200 Subject: [PATCH 30/60] Add method for setting custom r_shift and eta values. --- .../src/SymFuncParamGenerator.py | 137 ++++++++++++------ 1 file changed, 91 insertions(+), 46 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index c7b95000c..4f7a446af 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -21,7 +21,7 @@ class SymFuncParamGenerator: numbers used internally by n2p2 to distinguish symmetry function types. lambdas : numpy.ndarray Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. - radial_grid_info : dict or None + radial_param_settings : dict or None Stores settings that were used for generating the symmetry function parameters r_shift and eta. r_shift_grid : numpy.ndarray or None The set of values for the symmetry function parameter r_shift that was generated. @@ -48,7 +48,8 @@ def __init__(self, elements): self._r_cutoff = None self._zetas = None - self.radial_grid_info = None + # TODO: rename? + self.radial_param_settings = None self.r_shift_grid = None self.eta_grid = None @@ -131,7 +132,7 @@ def check_symfunc_type(self): None """ if self.symfunc_type is None: - raise TypeError('No symmetry function type has been set.') + raise TypeError('Symmetry function type not set.') elif not self.symfunc_type in self.symfunc_type_numbers.keys(): raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) @@ -151,7 +152,7 @@ def check_rcutoff(self): None """ if self.r_cutoff is None: - raise TypeError('No cutoff radius has been set.') + raise TypeError('Cutoff radius not set.') elif not self.r_cutoff > 0: raise ValueError('Invalid cutoff radius. ' 'Must be greater than zero.') @@ -173,7 +174,7 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, The entries are to be understood pairwise, i.e., the i-th entry of r_shift_grid and the i-th entry of eta_grid belong to one symmetry function. Besides the set of values for r_shift and eta, the settings that - were used for generating it are also stored, in the dictionary radial_grid_info. + were used for generating it are also stored, in the dictionary radial_param_settings. Parameters ---------- @@ -208,7 +209,7 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, ValueError If illegal relation between r_lower, r_upper, r_cutoff. ValueError - If invalid argument for parameter rule or mode. + If invalid argument for parameters rule or mode. Notes ----- @@ -240,7 +241,6 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, ------- None """ - # Check if cutoff radius has been set and is greater than zero # TODO: Maybe replace this generic check with one that makes clear in its error message that the correct # way is to set cutoff radius before radial parameter generation, instead of generic error message ?? @@ -248,9 +248,9 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, # store those infos on radial parameter generation settings that are # independent of the rule argument - self.radial_grid_info = dict(rule=rule, - mode=mode, - nb_param_pairs=nb_param_pairs) + self.radial_param_settings = dict(rule=rule, + mode=mode, + nb_param_pairs=nb_param_pairs) r_cutoff = self.r_cutoff @@ -261,14 +261,15 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, # by default, set largest value of radial grid to cutoff radius r_upper = r_cutoff - # store settings that are unique to this rule - self.radial_grid_info.update({'r_lower': r_lower, 'r_upper': r_upper}) + # store those settings that are unique to this rule + self.radial_param_settings.update({'r_lower': r_lower, 'r_upper': r_upper}) # create auxiliary grid grid = np.linspace(r_lower, r_upper, nb_param_pairs) if mode == 'center': - # r_lower = 0 is not allowed, because it leads to division by zero + # r_lower = 0 is not allowed in center mode, + # because it causes division by zero if not 0 < r_lower < r_upper <= r_cutoff: raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 < r_lower < r_upper <= r_cutoff.') r_shift_grid = np.zeros(nb_param_pairs) @@ -331,13 +332,56 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, self.r_shift_grid = r_shift_grid self.eta_grid = eta_grid + def set_radial_params_manually(self, r_shift_values, eta_values): + """Set custom r_shift and eta, bypassing the class's generation method. + + The parameters r_shift_values and eta_values must have the same + length and their entries are to be understood pairwise, i.e., + the i-th entry of r_shift_values and the i-th entry of eta_values + together belong to one symmetry function. + + Parameters + ---------- + r_shift_values : sequence of float or 1D-array + Set of values for the symmetry function parameter r_shift. + eta_values : sequence of float or 1D-array + Set of values for the symmetry function parameter eta. + + Raises + ------ + TypeError + If r_shift_values and eta_values do not have equal length. + + Notes + ----- + Setting r_shift and eta manually via this method instead of using the + method generate_radial_params somewhat defeats the purpose of the + class as a generator of symmetry function parameter values. However, + it might still be useful, in case one wants to use custom values for + r_shift and eta, for which the generation is not implemented as a + class method, while still benefiting from the parameter writing + functionality of the class. + + Returns + ------- + None + """ + if len(r_shift_values) != len(eta_values): + raise TypeError('Sets of values for r_shift and eta must have same length.') + self.radial_param_settings = None + self.r_shift_grid = np.array(r_shift_values) + self.eta_grid = np.array(eta_values) + + # TODO: rename (to check_essentials or something similar) def check_all(self): - """Check if a complete symmetry function set, with all required settings for writing, has been generated. + """Check if all data required for writing symmetry function sets are present and valid. Raises ------ TypeError - If no set of radial parameters (r_shift and eta) has been generated + If values for r_shift or eta are not set. + TypeError + If sets of values for r_shift and eta do not have equal length. TypeError If an angular symmetry function type has been set, but no values for zeta were set. @@ -347,13 +391,20 @@ def check_all(self): None """ self.check_symfunc_type() - # TODO: consider removing the check for radial_grid_info (since a user might want to directly set r_shift and eta values on their own, in which case no info would have been generated) - if self.radial_grid_info is None or self.r_shift_grid is None or self.eta_grid is None: - raise TypeError('No radial grid has been generated.') + self.check_rcutoff() + + if self.r_shift_grid is None: + raise TypeError('Values for r_shift not set.') + if self.eta_grid is None: + raise TypeError('Values for eta not set.') + if len(self.r_shift_grid) != len(self.eta_grid): + raise TypeError('Sets of values for r_shift and eta must have same length.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - if self._zetas is None: - raise TypeError('zeta values not set.') + if self.zetas is None: + raise TypeError(f'Values for zeta not set (required for symmetry' + f' function type {self.symfunc_type}).') + # TODO: rename? (write_settings maybe) def write_parameter_info(self, file=None): """Write settings used in generating the currently stored set of symmetry function parameters. @@ -376,12 +427,8 @@ def write_parameter_info(self, file=None): weighted_angular='Weighted angular') # depending on presence of file parameter, either direct output - # to stdout, or open the specified file - if file is None: - handle = sys.stdout - else: - handle = open(file, 'a') - + # to stdout, or open the specified file, in append mode + handle = open(file, 'a') if file is not None else sys.stdout handle.write('#########################################################################\n') handle.write( @@ -391,9 +438,17 @@ def write_parameter_info(self, file=None): handle.write(f'# r_cutoff = {self.r_cutoff}\n') - handle.write('# Radial parameters were generated using the following settings:\n') - for key, value in self.radial_grid_info.items(): - handle.write(f'# {key:14s} = {value}\n') + # depending on whether radial parameters were generated using the method + # or custom-set (indicated by presence or absence of radial parameter + # generation settings), write the settings used or not + if self.radial_param_settings is not None: + handle.write('# The following settings were used for generating sets\n') + handle.write('# of values for the radial parameters r_shift and eta:\n') + for key, value in self.radial_param_settings.items(): + handle.write(f'# {key:14s} = {value}\n') + else: + handle.write('# A custom set of values was used for the radial parameters r_shift and eta.\n') + handle.write('# Thus, there are no settings on radial parameter generation available for display.\n') handle.write('# Sets of values for parameters:\n') # set numpy print precision to lower number of decimal places for the following outputs @@ -469,11 +524,8 @@ def write_parameter_strings(self, file=None): self.check_all() # depending on presence of file parameter, either direct output - # to stdout, or open the specified file - if file is None: - handle = sys.stdout - else: - handle = open(file, 'a') + # to stdout, or open the specified file, in append mode + handle = open(file, 'a') if file is not None else sys.stdout r_cutoff = self.r_cutoff sf_number = self.symfunc_type_numbers[self.symfunc_type] @@ -521,39 +573,32 @@ def main(): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - # imbalzano2018 shift mode myGen.symfunc_type = 'radial' myGen.r_cutoff = 6. - myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - nb_param_pairs=5) + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + nb_param_pairs=5, r_lower=1.5, r_upper=5.5) - # # imbalzano2018 shift mode # myGen.symfunc_type = 'radial' # myGen.r_cutoff = 6. - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) + # myGen.set_radial_params_manually([11,22,33,44,55], [55,44,33,22,11]) - # # gastegger2018 shift mode # myGen.symfunc_type = 'angular_narrow' # myGen.r_cutoff = 6. - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # nb_param_pairs=9, r_lower=1.5) + # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', + # nb_param_pairs=3) # myGen.zetas = [1.0, 6.0] - # # gastegger2018 center mode # myGen.symfunc_type = 'angular_wide' # myGen.r_cutoff = 6. # myGen.generate_radial_params(rule='gastegger2018', mode='center', # nb_param_pairs=3, r_lower=1.5) # myGen.zetas = [1.0, 6.0] - # # imbalzano2018 center mode # myGen.symfunc_type = 'weighted_radial' # myGen.r_cutoff = 5. # myGen.generate_radial_params(rule='imbalzano2018', mode='center', # nb_param_pairs=5) - # # gastegger2018 shift mode # myGen.r_cutoff = 6. # myGen.generate_radial_params(rule='gastegger2018', mode='shift', # nb_param_pairs=3, r_lower=1.5) From 062ef5ef7efe0a2f1849888287d3a4e81dc8f75e Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 3 May 2019 14:58:27 +0200 Subject: [PATCH 31/60] Check for nb_param_pairs >= 2 in generate_radial_params. --- tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 4f7a446af..8cf365e73 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -204,6 +204,8 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, Raises ------ + ValueError + If nb_param_pairs is not two or greater. TypeError If parameter r_lower is not given, when using rule 'gastegger2018'. ValueError @@ -246,6 +248,9 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, # way is to set cutoff radius before radial parameter generation, instead of generic error message ?? self.check_rcutoff() + if not nb_param_pairs >= 2: + raise ValueError('nb_param_pairs must be two or greater.') + # store those infos on radial parameter generation settings that are # independent of the rule argument self.radial_param_settings = dict(rule=rule, From 5f7e447e866e0d0419a04edd23fc15ea7fdd26cb Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 5 May 2019 18:05:35 +0200 Subject: [PATCH 32/60] Do some renaming; extend tests. --- .../src/SymFuncParamGenerator.py | 75 ++++++------ .../symfunc_paramgen/tests/test_outputs.py | 110 ++++++++++++++++-- 2 files changed, 144 insertions(+), 41 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 8cf365e73..956529bec 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -21,8 +21,9 @@ class SymFuncParamGenerator: numbers used internally by n2p2 to distinguish symmetry function types. lambdas : numpy.ndarray Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. - radial_param_settings : dict or None - Stores settings that were used for generating the symmetry function parameters r_shift and eta. + radial_paramgen_settings : dict or None + Stores settings that were used in generating the symmetry function parameters r_shift and eta + using the class method provided for that purpose. r_shift_grid : numpy.ndarray or None The set of values for the symmetry function parameter r_shift that was generated. eta_grid : numpy.ndarray or None @@ -48,8 +49,7 @@ def __init__(self, elements): self._r_cutoff = None self._zetas = None - # TODO: rename? - self.radial_param_settings = None + self.radial_paramgen_settings = None self.r_shift_grid = None self.eta_grid = None @@ -104,6 +104,8 @@ def r_cutoff(self): @r_cutoff.setter def r_cutoff(self, value): + # TODO: it is a problem that this can be modified after calling generate_radial_params, + # without any notification that the cutoff radius now is no longer the one used before for generating r_shift, eta self._r_cutoff = value self.check_rcutoff() @@ -157,7 +159,7 @@ def check_rcutoff(self): raise ValueError('Invalid cutoff radius. ' 'Must be greater than zero.') - def generate_radial_params(self, rule, mode, nb_param_pairs, + def generate_radial_params(self, rule, mode, nb_param_pairs: int, r_lower=None, r_upper=None): """Generate a set of values for r_shift and eta. @@ -174,7 +176,7 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, The entries are to be understood pairwise, i.e., the i-th entry of r_shift_grid and the i-th entry of eta_grid belong to one symmetry function. Besides the set of values for r_shift and eta, the settings that - were used for generating it are also stored, in the dictionary radial_param_settings. + were used for generating it are also stored, in the dictionary radial_paramgen_settings. Parameters ---------- @@ -253,9 +255,9 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, # store those infos on radial parameter generation settings that are # independent of the rule argument - self.radial_param_settings = dict(rule=rule, - mode=mode, - nb_param_pairs=nb_param_pairs) + self.radial_paramgen_settings = dict(rule=rule, + mode=mode, + nb_param_pairs=nb_param_pairs) r_cutoff = self.r_cutoff @@ -267,7 +269,7 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, r_upper = r_cutoff # store those settings that are unique to this rule - self.radial_param_settings.update({'r_lower': r_lower, 'r_upper': r_upper}) + self.radial_paramgen_settings.update({'r_lower': r_lower, 'r_upper': r_upper}) # create auxiliary grid grid = np.linspace(r_lower, r_upper, nb_param_pairs) @@ -291,16 +293,17 @@ def generate_radial_params(self, rule, mode, nb_param_pairs, raise ValueError('invalid argument for "mode"') elif rule == 'imbalzano2018': + # TODO: rethink these warnings (might not want to print the whole stack) if r_lower is not None: sys.stderr.write( 'Warning: argument r_lower is not used in rule "imbalzano2018" and will be ignored.\n') - traceback.print_stack() - sys.stderr.flush() + # traceback.print_stack() + # sys.stderr.flush() if r_upper is not None: sys.stderr.write( 'Warning: argument r_upper is not used in rule "imbalzano2018" and will be ignored.\n') - traceback.print_stack() - sys.stderr.flush() + # traceback.print_stack() + # sys.stderr.flush() if mode == 'center': nb_intervals = nb_param_pairs - 1 @@ -373,14 +376,20 @@ class method, while still benefiting from the parameter writing """ if len(r_shift_values) != len(eta_values): raise TypeError('Sets of values for r_shift and eta must have same length.') - self.radial_param_settings = None + self.radial_paramgen_settings = None self.r_shift_grid = np.array(r_shift_values) self.eta_grid = np.array(eta_values) - # TODO: rename (to check_essentials or something similar) - def check_all(self): + def check_writing_prerequisites(self): """Check if all data required for writing symmetry function sets are present and valid. + This comprises: + -) check if symmetry function type is present and valid. + -) check if cutoff radius is present and valid. + -) check for presence of values for r_shift and eta. + -) check if equal length of r_shift and eta values. + -) if angular symmetry function types, check for presence of zetas. + Raises ------ TypeError @@ -409,8 +418,7 @@ def check_all(self): raise TypeError(f'Values for zeta not set (required for symmetry' f' function type {self.symfunc_type}).') - # TODO: rename? (write_settings maybe) - def write_parameter_info(self, file=None): + def write_settings_overview(self, file=None): """Write settings used in generating the currently stored set of symmetry function parameters. Parameters @@ -423,8 +431,7 @@ def write_parameter_info(self, file=None): ------- None """ - # TODO: rethink the layout of the info that is written - self.check_all() + self.check_writing_prerequisites() type_descriptions = dict(radial='Radial', angular_narrow='Narrow angular', angular_wide='Wide angular', @@ -446,10 +453,10 @@ def write_parameter_info(self, file=None): # depending on whether radial parameters were generated using the method # or custom-set (indicated by presence or absence of radial parameter # generation settings), write the settings used or not - if self.radial_param_settings is not None: + if self.radial_paramgen_settings is not None: handle.write('# The following settings were used for generating sets\n') handle.write('# of values for the radial parameters r_shift and eta:\n') - for key, value in self.radial_param_settings.items(): + for key, value in self.radial_paramgen_settings.items(): handle.write(f'# {key:14s} = {value}\n') else: handle.write('# A custom set of values was used for the radial parameters r_shift and eta.\n') @@ -526,7 +533,7 @@ def write_parameter_strings(self, file=None): ------- None """ - self.check_all() + self.check_writing_prerequisites() # depending on presence of file parameter, either direct output # to stdout, or open the specified file, in append mode @@ -578,10 +585,10 @@ def main(): # elems = ['H', 'C', 'O'] myGen = SymFuncParamGenerator(elems) - myGen.symfunc_type = 'radial' - myGen.r_cutoff = 6. - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - nb_param_pairs=5, r_lower=1.5, r_upper=5.5) + # myGen.symfunc_type = 'radial' + # myGen.r_cutoff = 6. + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) # myGen.symfunc_type = 'radial' # myGen.r_cutoff = 6. @@ -604,14 +611,14 @@ def main(): # myGen.generate_radial_params(rule='imbalzano2018', mode='center', # nb_param_pairs=5) - # myGen.r_cutoff = 6. - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # nb_param_pairs=3, r_lower=1.5) - # myGen.symfunc_type = 'weighted_angular' - # myGen.zetas = [1.0, 6.0] + myGen.r_cutoff = 6. + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + nb_param_pairs=3, r_lower=1.5) + myGen.symfunc_type = 'weighted_angular' + myGen.zetas = [1.0, 6.0] - myGen.write_parameter_info() + myGen.write_settings_overview() myGen.write_parameter_strings() diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index c0e7eb67a..ea8ab4b7c 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -4,7 +4,6 @@ import pytest import os import SymFuncParamGenerator as sfpg -import filecmp def test_element_combinations(): @@ -33,14 +32,14 @@ def test_output(tmpdir): myGen.r_cutoff = 6. myGen.generate_radial_params(rule='imbalzano2018', mode='shift', nb_param_pairs=5) - myGen.write_parameter_info(outfile_path) + myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'radial' myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='shift', nb_param_pairs=5, r_lower=1.5, r_upper=5.5) - myGen.write_parameter_info(outfile_path) + myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'angular_narrow' @@ -48,7 +47,7 @@ def test_output(tmpdir): myGen.generate_radial_params(rule='gastegger2018', mode='shift', nb_param_pairs=9, r_lower=1.5) myGen.zetas = [1.0, 6.0] - myGen.write_parameter_info(outfile_path) + myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'angular_wide' @@ -56,14 +55,14 @@ def test_output(tmpdir): myGen.generate_radial_params(rule='gastegger2018', mode='center', nb_param_pairs=3, r_lower=1.5) myGen.zetas = [1.0, 6.0] - myGen.write_parameter_info(outfile_path) + myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'weighted_radial' myGen.r_cutoff = 5. myGen.generate_radial_params(rule='imbalzano2018', mode='center', nb_param_pairs=5) - myGen.write_parameter_info(outfile_path) + myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) myGen.symfunc_type = 'weighted_angular' @@ -71,7 +70,7 @@ def test_output(tmpdir): myGen.generate_radial_params(rule='gastegger2018', mode='shift', nb_param_pairs=3, r_lower=1.5) myGen.zetas = [1.0, 6.0] - myGen.write_parameter_info(outfile_path) + myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) # ignore comment lines, so the test does not immediately fail when only @@ -83,3 +82,100 @@ def test_output(tmpdir): f_out = filter(isnotcomment, f_out) assert all(x == y for x, y in zip(f_out, f_reference)) + +def test_setter_sf_type(): + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + with pytest.raises(ValueError): + myGen.symfunc_type = 'illegal_type' + + +def test_setter_rcutoff(): + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + with pytest.raises(ValueError): + myGen.r_cutoff = 0 + with pytest.raises(ValueError): + myGen.r_cutoff = -5 + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ + ('gastegger2018', 'center', 5, 1.5), + ('gastegger2018', 'shift', 5, 1.5), + ('imbalzano2018', 'center', 5, None), + ('imbalzano2018', 'shift', 5, None) +]) +def test_radial_paramgen_cutoff(rule, mode, nb_param_pairs, r_lower): + """Test for TypeError when generating radial params without having set r_cutoff. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + with pytest.raises(TypeError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ + ('bad_argument', 'center', 5, 1.5), + ('bad_argument', 'shift', 5, 1.5), + ('gastegger2018', 'bad_argument', 5, 1.5), + ('imbalzano2018', 'bad_argument', 5, None) +]) +def test_radial_paramgen_2(rule, mode, nb_param_pairs, r_lower): + """Test for ValueError when invalid arguments for rule or method. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + myGen.r_cutoff = 6. + with pytest.raises(ValueError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs", [ + ('gastegger2018', 'center', 5), + ('gastegger2018', 'shift', 5) +]) +def test_radial_paramgen_3(rule, mode, nb_param_pairs): + """Test for TypeError when omitting r_lower argument in rule 'gastegger2018' + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + myGen.r_cutoff = 6. + with pytest.raises(TypeError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs) + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ + ('gastegger2018', 'center', 1, 1.5), + ('gastegger2018', 'shift', 1, 1.5), + ('imbalzano2018', 'center', 1, None), + ('imbalzano2018', 'shift', 1, None) +]) +def test_radial_paramgen_4(rule, mode, nb_param_pairs, r_lower): + """Test for ValueError when nb_param_pairs less than two. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + myGen.r_cutoff = 6. + with pytest.raises(ValueError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ + ('gastegger2018', 'center', 1, 1.5), + ('gastegger2018', 'center', 1, 1.5), + ('gastegger2018', 'center', 1, None), + ('gastegger2018', 'shift', 1, None) +]) +def test_radial_paramgen_5(rule, mode, nb_param_pairs, r_lower): + """Test for ValueError when illegal relation between r_lower, r_upper, r_cutoff and zero. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elems) + myGen.r_cutoff = 6. + with pytest.raises(ValueError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) \ No newline at end of file From 6874118917fc0e90506126a083a8bd23e3d53ec5 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 5 May 2019 21:32:57 +0200 Subject: [PATCH 33/60] Make cutoff radius into constructor argument. --- .../src/SymFuncParamGenerator.py | 85 ++++-------- .../symfunc_paramgen/tests/test_outputs.py | 127 +++++++++++------- 2 files changed, 109 insertions(+), 103 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 956529bec..84a4ebbea 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -13,6 +13,9 @@ class SymFuncParamGenerator: ---------- elements : list of string The chemical elements present in the system. + r_cutoff : float + Cutoff radius, at which symmetry functions go to zero. + Must be greater than zero. Attributes ---------- @@ -30,6 +33,7 @@ class SymFuncParamGenerator: The set of values for the symmetry function parameter eta that was generated. elements element_combinations + r_cutoff symfunc_type zetas """ @@ -41,12 +45,17 @@ class SymFuncParamGenerator: weighted_angular=13) lambdas = np.array([-1.0, 1.0]) - def __init__(self, elements): + def __init__(self, elements, r_cutoff: float): # TODO: consider checking if valid input for elements self._elements = elements + if not r_cutoff > 0: + raise ValueError('Invalid cutoff radius given. ' + 'Must be greater than zero.') + else: + self._r_cutoff = r_cutoff + self._element_combinations = None self._symfunc_type = None - self._r_cutoff = None self._zetas = None self.radial_paramgen_settings = None @@ -96,19 +105,10 @@ def symfunc_type(self, value): @property def r_cutoff(self): - '''Cutoff radius, at which symmetry functions go to zero (float). - - Must be greater than zero. + '''Cutoff radius where symmetry functions go to zero (float, read-only). ''' return self._r_cutoff - @r_cutoff.setter - def r_cutoff(self, value): - # TODO: it is a problem that this can be modified after calling generate_radial_params, - # without any notification that the cutoff radius now is no longer the one used before for generating r_shift, eta - self._r_cutoff = value - self.check_rcutoff() - @property def zetas(self): """Set of values for the parameter zeta of angular symmetry functions (`numpy.ndarray`). @@ -135,36 +135,14 @@ def check_symfunc_type(self): """ if self.symfunc_type is None: raise TypeError('Symmetry function type not set.') - elif not self.symfunc_type in self.symfunc_type_numbers.keys(): + elif self.symfunc_type not in self.symfunc_type_numbers.keys(): raise ValueError('Invalid symmetry function type. Must be one of {}'.format( list(self.symfunc_type_numbers.keys()))) - def check_rcutoff(self): - """Check if the cutoff radius has been set and if it is valid. - - Raises - ------ - TypeError - If the cutoff radius has not been set (i.e., it is None). - ValueError - If the cutoff radius is not greater than zero. - - Returns - ------- - None - """ - if self.r_cutoff is None: - raise TypeError('Cutoff radius not set.') - elif not self.r_cutoff > 0: - raise ValueError('Invalid cutoff radius. ' - 'Must be greater than zero.') - def generate_radial_params(self, rule, mode, nb_param_pairs: int, r_lower=None, r_upper=None): """Generate a set of values for r_shift and eta. - Requires that the cutoff radius have been set before. - Such a set of (r_shift, eta)-values is required for any symmetry function type. Its generation is independent of the symmetry function type @@ -245,11 +223,6 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, ------- None """ - # Check if cutoff radius has been set and is greater than zero - # TODO: Maybe replace this generic check with one that makes clear in its error message that the correct - # way is to set cutoff radius before radial parameter generation, instead of generic error message ?? - self.check_rcutoff() - if not nb_param_pairs >= 2: raise ValueError('nb_param_pairs must be two or greater.') @@ -293,7 +266,7 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, raise ValueError('invalid argument for "mode"') elif rule == 'imbalzano2018': - # TODO: rethink these warnings (might not want to print the whole stack) + # TODO: rethink these warnings (might not want to print the whole stack, especially in the test the output becomes very unwieldy) if r_lower is not None: sys.stderr.write( 'Warning: argument r_lower is not used in rule "imbalzano2018" and will be ignored.\n') @@ -374,6 +347,7 @@ class method, while still benefiting from the parameter writing ------- None """ + # TODO: add checks on negative values, and values for r_shift greater than cutoff radius if len(r_shift_values) != len(eta_values): raise TypeError('Sets of values for r_shift and eta must have same length.') self.radial_paramgen_settings = None @@ -385,7 +359,6 @@ def check_writing_prerequisites(self): This comprises: -) check if symmetry function type is present and valid. - -) check if cutoff radius is present and valid. -) check for presence of values for r_shift and eta. -) check if equal length of r_shift and eta values. -) if angular symmetry function types, check for presence of zetas. @@ -405,7 +378,6 @@ def check_writing_prerequisites(self): None """ self.check_symfunc_type() - self.check_rcutoff() if self.r_shift_grid is None: raise TypeError('Values for r_shift not set.') @@ -583,39 +555,38 @@ def write_parameter_strings(self, file=None): def main(): elems = ['S', 'Cu'] # elems = ['H', 'C', 'O'] - myGen = SymFuncParamGenerator(elems) - # myGen.symfunc_type = 'radial' - # myGen.r_cutoff = 6. - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) + myGen = SymFuncParamGenerator(elements=elems, r_cutoff=6.) + myGen.symfunc_type = 'radial' + myGen.generate_radial_params(rule='gastegger2018', mode='shift', + nb_param_pairs=5, r_lower=1.5, r_upper=5.5) + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) # myGen.symfunc_type = 'radial' - # myGen.r_cutoff = 6. # myGen.set_radial_params_manually([11,22,33,44,55], [55,44,33,22,11]) + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) # myGen.symfunc_type = 'angular_narrow' - # myGen.r_cutoff = 6. # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', # nb_param_pairs=3) # myGen.zetas = [1.0, 6.0] + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) # myGen.symfunc_type = 'angular_wide' - # myGen.r_cutoff = 6. # myGen.generate_radial_params(rule='gastegger2018', mode='center', # nb_param_pairs=3, r_lower=1.5) # myGen.zetas = [1.0, 6.0] + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 5.) # myGen.symfunc_type = 'weighted_radial' - # myGen.r_cutoff = 5. # myGen.generate_radial_params(rule='imbalzano2018', mode='center', # nb_param_pairs=5) - myGen.r_cutoff = 6. - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - nb_param_pairs=3, r_lower=1.5) - myGen.symfunc_type = 'weighted_angular' - myGen.zetas = [1.0, 6.0] + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) + # myGen.symfunc_type = 'weighted_angular' + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # nb_param_pairs=3, r_lower=1.5) + # myGen.zetas = [1.0, 6.0] myGen.write_settings_overview() diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index ea8ab4b7c..126be53fb 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -1,6 +1,7 @@ import sys sys.path.append('../src') +import numpy as np import pytest import os import SymFuncParamGenerator as sfpg @@ -8,7 +9,7 @@ def test_element_combinations(): elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) myGen.symfunc_type = 'radial' assert myGen.element_combinations == [('S', 'S'), ('S', 'Cu'), ('Cu', 'S'), ('Cu', 'Cu')] @@ -24,49 +25,48 @@ def test_output(tmpdir): ''' elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) outfile_path = os.path.join(tmpdir, 'outfile.txt') + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) myGen.symfunc_type = 'radial' - myGen.r_cutoff = 6. myGen.generate_radial_params(rule='imbalzano2018', mode='shift', nb_param_pairs=5) myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) myGen.symfunc_type = 'radial' - myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='shift', nb_param_pairs=5, r_lower=1.5, r_upper=5.5) myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) myGen.symfunc_type = 'angular_narrow' - myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='shift', nb_param_pairs=9, r_lower=1.5) myGen.zetas = [1.0, 6.0] myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) myGen.symfunc_type = 'angular_wide' - myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='center', nb_param_pairs=3, r_lower=1.5) myGen.zetas = [1.0, 6.0] myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=5.) myGen.symfunc_type = 'weighted_radial' - myGen.r_cutoff = 5. myGen.generate_radial_params(rule='imbalzano2018', mode='center', nb_param_pairs=5) myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) myGen.symfunc_type = 'weighted_angular' - myGen.r_cutoff = 6. myGen.generate_radial_params(rule='gastegger2018', mode='shift', nb_param_pairs=3, r_lower=1.5) myGen.zetas = [1.0, 6.0] @@ -74,9 +74,9 @@ def test_output(tmpdir): myGen.write_parameter_strings(outfile_path) # ignore comment lines, so the test does not immediately fail when only - # the parameter informations are changed (which I would like to keep just + # the parameter information is changed (which I would like to keep just # for keeping track of the settings used in the reference output file, but - # are otherwise not essential) + # is otherwise not essential) with open(outfile_path) as f_out, open('reference_outputs.txt') as f_reference: f_reference = filter(isnotcomment, f_reference) f_out = filter(isnotcomment, f_out) @@ -85,35 +85,26 @@ def test_output(tmpdir): def test_setter_sf_type(): elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): myGen.symfunc_type = 'illegal_type' -def test_setter_rcutoff(): +def test_rcutoff(): elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) + # test for errors when cutoff radius not greater than zero with pytest.raises(ValueError): - myGen.r_cutoff = 0 + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=0) with pytest.raises(ValueError): - myGen.r_cutoff = -5 + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=-5) + # test if initializing and retrieving r_cutoff works as expected + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6) + assert myGen.r_cutoff == 6 + # test for AttributeError when trying to change r_cutoff afterwards + with pytest.raises(AttributeError): + myGen.r_cutoff = 10 -@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ - ('gastegger2018', 'center', 5, 1.5), - ('gastegger2018', 'shift', 5, 1.5), - ('imbalzano2018', 'center', 5, None), - ('imbalzano2018', 'shift', 5, None) -]) -def test_radial_paramgen_cutoff(rule, mode, nb_param_pairs, r_lower): - """Test for TypeError when generating radial params without having set r_cutoff. - """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) - with pytest.raises(TypeError): - myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs, r_lower=r_lower) - @pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ ('bad_argument', 'center', 5, 1.5), @@ -125,8 +116,7 @@ def test_radial_paramgen_2(rule, mode, nb_param_pairs, r_lower): """Test for ValueError when invalid arguments for rule or method. """ elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) - myGen.r_cutoff = 6. + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): myGen.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs, r_lower=r_lower) @@ -140,8 +130,7 @@ def test_radial_paramgen_3(rule, mode, nb_param_pairs): """Test for TypeError when omitting r_lower argument in rule 'gastegger2018' """ elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) - myGen.r_cutoff = 6. + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(TypeError): myGen.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs) @@ -157,25 +146,71 @@ def test_radial_paramgen_4(rule, mode, nb_param_pairs, r_lower): """Test for ValueError when nb_param_pairs less than two. """ elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) - myGen.r_cutoff = 6. + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): myGen.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs, r_lower=r_lower) -@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ - ('gastegger2018', 'center', 1, 1.5), - ('gastegger2018', 'center', 1, 1.5), - ('gastegger2018', 'center', 1, None), - ('gastegger2018', 'shift', 1, None) +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower,r_upper", [ + ('gastegger2018', 'center', 2, 0., 5.), + ('gastegger2018', 'center', 2, 0., None), + ('gastegger2018', 'center', 2, 5., 1.), + ('gastegger2018', 'center', 2, 7., None), + ('gastegger2018', 'center', 2, 1., 7.), + ('gastegger2018', 'shift', 2, -1., 5.), + ('gastegger2018', 'shift', 2, -1., None), + ('gastegger2018', 'shift', 2, 5., 1.), + ('gastegger2018', 'shift', 2, 7, None), + ('gastegger2018', 'shift', 2, 1., 7.) ]) -def test_radial_paramgen_5(rule, mode, nb_param_pairs, r_lower): - """Test for ValueError when illegal relation between r_lower, r_upper, r_cutoff and zero. +def test_radial_paramgen_5(rule, mode, nb_param_pairs, r_lower, r_upper): + """Test for ValueError when illegal relation between r_lower, r_upper, r_cutoff in rule 'gastegger2018' """ elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elems) - myGen.r_cutoff = 6. + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs, r_lower=r_lower) \ No newline at end of file + nb_param_pairs=nb_param_pairs, + r_lower=r_lower, r_upper=r_upper) + + +@pytest.mark.parametrize("symfunc_type,r_shift_grid,eta_grid,zetas", [ + (None, np.array([1,2,3]), np.array([4,5,6]), None), + ('radial', None, np.array([4,5,6]), None), + ('radial', np.array([1,2,3]), None, None), + ('angular_narrow', np.array([1,2,3]), np.array([4,5,6]), None), + ('angular_wide', np.array([1,2,3]), np.array([4,5,6]), None), + ('weighted_angular', np.array([1,2,3]), np.array([4,5,6]), None) +]) +def test_check_writing_prerequisites(symfunc_type, r_shift_grid, eta_grid, zetas): + """Test if error when writing parameters or settings while data are missing. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + + if symfunc_type is not None: + myGen.symfunc_type = symfunc_type + if r_shift_grid is not None: + myGen.r_shift_grid = r_shift_grid + if eta_grid is not None: + myGen.eta_grid = eta_grid + if zetas is not None: + myGen.zetas = zetas + + # test the completeness checker on its own + with pytest.raises(TypeError): + myGen.check_writing_prerequisites() + # test the method that call the completeness checker (someone might have removed it...) + with pytest.raises(TypeError): + myGen.write_settings_overview() + with pytest.raises(TypeError): + myGen.write_parameter_strings() + + + + + + + + From 4a9a1e6196afb36f361a6281e51a8b03f696e191 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 5 May 2019 22:10:09 +0200 Subject: [PATCH 34/60] Rework checks on presence and validity of settings. Setters now check only for validity, methods using the settings check only for presence. --- .../src/SymFuncParamGenerator.py | 32 +++++++++++-------- .../symfunc_paramgen/tests/test_outputs.py | 4 ++- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 84a4ebbea..8e754fd44 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -46,7 +46,6 @@ class SymFuncParamGenerator: lambdas = np.array([-1.0, 1.0]) def __init__(self, elements, r_cutoff: float): - # TODO: consider checking if valid input for elements self._elements = elements if not r_cutoff > 0: raise ValueError('Invalid cutoff radius given. ' @@ -87,18 +86,27 @@ def symfunc_type(self): If the given symmetry function type is a radial one, the setter also clears any preexisting zetas (i.e., sets the member variable zetas to None). + + Raises + ------ + ValueError + If invalid symmetry function type is given. """ return self._symfunc_type @symfunc_type.setter def symfunc_type(self, value): - self._symfunc_type = value - self.check_symfunc_type() + if value not in self.symfunc_type_numbers.keys(): + raise ValueError('Invalid symmetry function type. Must be one of {}'.format( + list(self.symfunc_type_numbers.keys()))) + else: + self._symfunc_type = value + # self.check_symfunc_type() # TODO: remove # once symmetry function type has been set and found to be valid, # build and store the element combinations self._element_combinations = self.find_element_combinations() # Clear any previous zeta values, if the given symfunc type is a radial one - if self.symfunc_type in ['radial', 'weighted_radial']: + if value in ['radial', 'weighted_radial']: # set the member variable explicitly (with underscore) instead of # calling setter, because the setter would put None into an array self._zetas = None @@ -117,27 +125,24 @@ def zetas(self): @zetas.setter def zetas(self, values): + # TODO: possibly add checks on values for zeta self._zetas = np.array(values) def check_symfunc_type(self): - """Check if a symmetry function type has been set and if it is valid. + """Check if a symmetry function type has been set. Raises ------ TypeError If the symmetry function type has not been set (i.e., it is None). - ValueError - If the symmetry function type is invalid. Returns ------- None """ + # TODO: consider changing the exception to ValueError or RuntimeError if self.symfunc_type is None: raise TypeError('Symmetry function type not set.') - elif self.symfunc_type not in self.symfunc_type_numbers.keys(): - raise ValueError('Invalid symmetry function type. Must be one of {}'.format( - list(self.symfunc_type_numbers.keys()))) def generate_radial_params(self, rule, mode, nb_param_pairs: int, r_lower=None, r_upper=None): @@ -367,8 +372,6 @@ def check_writing_prerequisites(self): ------ TypeError If values for r_shift or eta are not set. - TypeError - If sets of values for r_shift and eta do not have equal length. TypeError If an angular symmetry function type has been set, but no values for zeta were set. @@ -377,14 +380,15 @@ def check_writing_prerequisites(self): ------- None """ + # TODO: possibly change the exceptions to ValueError or RunTimeError (see https://stackoverflow.com/questions/10726919/what-error-to-raise-when-class-state-is-invalid) + # this would then also need to be changed in the tests + self.check_symfunc_type() if self.r_shift_grid is None: raise TypeError('Values for r_shift not set.') if self.eta_grid is None: raise TypeError('Values for eta not set.') - if len(self.r_shift_grid) != len(self.eta_grid): - raise TypeError('Sets of values for r_shift and eta must have same length.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: if self.zetas is None: raise TypeError(f'Values for zeta not set (required for symmetry' diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index 126be53fb..bb53f24e5 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -83,7 +83,9 @@ def test_output(tmpdir): assert all(x == y for x, y in zip(f_out, f_reference)) -def test_setter_sf_type(): +def test_setter_symfunc_type(): + """Test if error when trying to set invalid symmetry function type + """ elems = ['S', 'Cu'] myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): From 839323eefdf95ac47e43ded6a90adb6b9943b241 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 6 May 2019 14:04:35 +0200 Subject: [PATCH 35/60] Add optional arg to class-state-checking methods. When specified, this makes them print modified error message mentioning the name of the calling method. --- .../src/SymFuncParamGenerator.py | 105 ++++++++++++------ .../symfunc_paramgen/tests/test_outputs.py | 10 +- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 8e754fd44..58ee9938d 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -2,6 +2,7 @@ import numpy as np import sys +import inspect import itertools import traceback @@ -101,7 +102,6 @@ def symfunc_type(self, value): list(self.symfunc_type_numbers.keys()))) else: self._symfunc_type = value - # self.check_symfunc_type() # TODO: remove # once symmetry function type has been set and found to be valid, # build and store the element combinations self._element_combinations = self.find_element_combinations() @@ -128,9 +128,18 @@ def zetas(self, values): # TODO: possibly add checks on values for zeta self._zetas = np.array(values) - def check_symfunc_type(self): + def check_symfunc_type(self, calling_method_name=None): """Check if a symmetry function type has been set. + Parameters + ---------- + calling_method_name : string, optional + The name of another method that calls this method. + If this parameter is given, a modified error message is printed + by this method, mentioning the method from which it was called. + This should make it clearer to the user in which part + of their own code to look for an error. + Raises ------ TypeError @@ -140,9 +149,13 @@ def check_symfunc_type(self): ------- None """ - # TODO: consider changing the exception to ValueError or RuntimeError if self.symfunc_type is None: - raise TypeError('Symmetry function type not set.') + if calling_method_name is None: + raise ValueError('Symmetry function type not set.') + else: + raise ValueError(f'Symmetry function type not set. ' + f'Calling method {calling_method_name} requires' + f' that symmetry function type have been set before.') def generate_radial_params(self, rule, mode, nb_param_pairs: int, r_lower=None, r_upper=None): @@ -359,14 +372,22 @@ class method, while still benefiting from the parameter writing self.r_shift_grid = np.array(r_shift_values) self.eta_grid = np.array(eta_values) - def check_writing_prerequisites(self): - """Check if all data required for writing symmetry function sets are present and valid. + def check_writing_prerequisites(self, calling_method_name=None): + """Check if all data required for writing symmetry function sets are present. - This comprises: - -) check if symmetry function type is present and valid. - -) check for presence of values for r_shift and eta. - -) check if equal length of r_shift and eta values. - -) if angular symmetry function types, check for presence of zetas. + This comprises checking if the following have been set: + -) symmetry function type + -) values for r_shift and eta + -) values for zeta, if the symmetry function type is an angular one + + Parameters + ---------- + calling_method_name : string, optional + The name of another method that calls this method. + If this parameter is given, a modified error message is printed + by this method, mentioning the method from which it was called. + This should make it clearer to the user in which part + of their own code to look for an error. Raises ------ @@ -380,19 +401,26 @@ def check_writing_prerequisites(self): ------- None """ - # TODO: possibly change the exceptions to ValueError or RunTimeError (see https://stackoverflow.com/questions/10726919/what-error-to-raise-when-class-state-is-invalid) - # this would then also need to be changed in the tests - - self.check_symfunc_type() - - if self.r_shift_grid is None: - raise TypeError('Values for r_shift not set.') - if self.eta_grid is None: - raise TypeError('Values for eta not set.') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - if self.zetas is None: - raise TypeError(f'Values for zeta not set (required for symmetry' - f' function type {self.symfunc_type}).') + self.check_symfunc_type(calling_method_name=calling_method_name) + + if calling_method_name is None: + if self.r_shift_grid is None or self.eta_grid is None: + raise ValueError('Values for r_shift and/or eta not set.') + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.zetas is None: + raise ValueError(f'Values for zeta not set (required for symmetry' + f' function type {self.symfunc_type}).') + else: + if self.r_shift_grid is None or self.eta_grid is None: + raise ValueError(f'Values for r_shift and/or eta not set. ' + f'Calling method {calling_method_name} requires' + f' that values for r_shift and eta have been set before.') + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.zetas is None: + raise ValueError(f'Values for zeta not set. ' + f'Calling method {calling_method_name} requires' + f' zetas to have been set before, when using' + f' symmetry function type {self.symfunc_type}.') def write_settings_overview(self, file=None): """Write settings used in generating the currently stored set of symmetry function parameters. @@ -407,7 +435,9 @@ def write_settings_overview(self, file=None): ------- None """ - self.check_writing_prerequisites() + this_method_name = inspect.currentframe().f_code.co_name + self.check_writing_prerequisites(calling_method_name=this_method_name) + type_descriptions = dict(radial='Radial', angular_narrow='Narrow angular', angular_wide='Wide angular', @@ -473,7 +503,9 @@ def find_element_combinations(self): Zero-th entry of tuples is always the type of the central atom, 1st and 2nd entry are neighbor atom types (radial sf: one neighbor, angular sf: two neighbors, weighted sf: no neighbors) """ - self.check_symfunc_type() + this_method_name = inspect.currentframe().f_code.co_name + self.check_symfunc_type(calling_method_name=this_method_name) + combinations = [] if self.symfunc_type == 'radial': @@ -509,7 +541,8 @@ def write_parameter_strings(self, file=None): ------- None """ - self.check_writing_prerequisites() + this_method_name = inspect.currentframe().f_code.co_name + self.check_writing_prerequisites(calling_method_name=this_method_name) # depending on presence of file parameter, either direct output # to stdout, or open the specified file, in append mode @@ -560,20 +593,20 @@ def main(): elems = ['S', 'Cu'] # elems = ['H', 'C', 'O'] - myGen = SymFuncParamGenerator(elements=elems, r_cutoff=6.) - myGen.symfunc_type = 'radial' - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - nb_param_pairs=5, r_lower=1.5, r_upper=5.5) + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff=6.) + # myGen.symfunc_type = 'radial' + # myGen.generate_radial_params(rule='gastegger2018', mode='shift', + # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) # myGen.symfunc_type = 'radial' # myGen.set_radial_params_manually([11,22,33,44,55], [55,44,33,22,11]) - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - # myGen.symfunc_type = 'angular_narrow' - # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - # nb_param_pairs=3) - # myGen.zetas = [1.0, 6.0] + myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) + myGen.symfunc_type = 'angular_narrow' + myGen.generate_radial_params(rule='imbalzano2018', mode='shift', + nb_param_pairs=3) + myGen.zetas = [1.0, 6.0] # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) # myGen.symfunc_type = 'angular_wide' diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index bb53f24e5..55a326a89 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -200,13 +200,13 @@ def test_check_writing_prerequisites(symfunc_type, r_shift_grid, eta_grid, zetas if zetas is not None: myGen.zetas = zetas - # test the completeness checker on its own - with pytest.raises(TypeError): + # test the completeness checker on its own (without argument) + with pytest.raises(ValueError): myGen.check_writing_prerequisites() - # test the method that call the completeness checker (someone might have removed it...) - with pytest.raises(TypeError): + # test the methods that call the completeness checker (which call it with argument) + with pytest.raises(ValueError): myGen.write_settings_overview() - with pytest.raises(TypeError): + with pytest.raises(ValueError): myGen.write_parameter_strings() From 60fadc70f7ec102899979cb92b54d83923bd8efc Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 6 May 2019 17:56:43 +0200 Subject: [PATCH 36/60] Rename set_radial_params_manually, and check inputs. --- .../src/SymFuncParamGenerator.py | 82 +++++++++++-------- .../symfunc_paramgen/tests/test_outputs.py | 39 ++++++++- 2 files changed, 87 insertions(+), 34 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 58ee9938d..16b3a8ca7 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -28,9 +28,9 @@ class SymFuncParamGenerator: radial_paramgen_settings : dict or None Stores settings that were used in generating the symmetry function parameters r_shift and eta using the class method provided for that purpose. - r_shift_grid : numpy.ndarray or None + _r_shift_grid : numpy.ndarray or None The set of values for the symmetry function parameter r_shift that was generated. - eta_grid : numpy.ndarray or None + _eta_grid : numpy.ndarray or None The set of values for the symmetry function parameter eta that was generated. elements element_combinations @@ -58,9 +58,9 @@ def __init__(self, elements, r_cutoff: float): self._symfunc_type = None self._zetas = None + self._r_shift_grid = None + self._eta_grid = None self.radial_paramgen_settings = None - self.r_shift_grid = None - self.eta_grid = None @property def elements(self): @@ -128,6 +128,14 @@ def zetas(self, values): # TODO: possibly add checks on values for zeta self._zetas = np.array(values) + @property + def r_shift_grid(self): + return self._r_shift_grid + + @property + def eta_grid(self): + return self._eta_grid + def check_symfunc_type(self, calling_method_name=None): """Check if a symmetry function type has been set. @@ -168,9 +176,9 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, Rules for parameter generation are implemented based on [1]_ and [2]_. - The generated values are stored as arrays in the member variables r_shift_grid and eta_grid. - The entries are to be understood pairwise, i.e., the i-th entry of r_shift_grid - and the i-th entry of eta_grid belong to one symmetry function. + The generated values are stored as arrays in the member variables _r_shift_grid and _eta_grid. + The entries are to be understood pairwise, i.e., the i-th entry of _r_shift_grid + and the i-th entry of _eta_grid belong to one symmetry function. Besides the set of values for r_shift and eta, the settings that were used for generating it are also stored, in the dictionary radial_paramgen_settings. @@ -328,16 +336,17 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, raise ValueError('invalid argument for "rule"') # store the generated parameter sets - self.r_shift_grid = r_shift_grid - self.eta_grid = eta_grid + self._r_shift_grid = r_shift_grid + self._eta_grid = eta_grid - def set_radial_params_manually(self, r_shift_values, eta_values): + def set_custom_radial_params(self, r_shift_values, eta_values): """Set custom r_shift and eta, bypassing the class's generation method. The parameters r_shift_values and eta_values must have the same - length and their entries are to be understood pairwise, i.e., + length. + Ttheir entries are to be understood pairwise, i.e., the i-th entry of r_shift_values and the i-th entry of eta_values - together belong to one symmetry function. + belong together, describing one symmetry function. Parameters ---------- @@ -350,6 +359,8 @@ def set_radial_params_manually(self, r_shift_values, eta_values): ------ TypeError If r_shift_values and eta_values do not have equal length. + ValueError + If r_shift_values or eta_values contain non-positive entries. Notes ----- @@ -365,12 +376,19 @@ class method, while still benefiting from the parameter writing ------- None """ - # TODO: add checks on negative values, and values for r_shift greater than cutoff radius if len(r_shift_values) != len(eta_values): - raise TypeError('Sets of values for r_shift and eta must have same length.') + raise TypeError('r_shift_values and eta_values must have same length.') + if min(r_shift_values) <= 0: + raise ValueError('r_shift_values must all be greater than zero.') + if min(eta_values) <= 0: + raise ValueError('eta_values must all be greater than zero.') + # (re)set radial_paramgen_settings to None, indicating that custom + # values for (r_shift, eta) are used, rather than ones generated by + # class method. self.radial_paramgen_settings = None - self.r_shift_grid = np.array(r_shift_values) - self.eta_grid = np.array(eta_values) + # set the values + self._r_shift_grid = np.array(r_shift_values) + self._eta_grid = np.array(eta_values) def check_writing_prerequisites(self, calling_method_name=None): """Check if all data required for writing symmetry function sets are present. @@ -404,14 +422,14 @@ def check_writing_prerequisites(self, calling_method_name=None): self.check_symfunc_type(calling_method_name=calling_method_name) if calling_method_name is None: - if self.r_shift_grid is None or self.eta_grid is None: + if self._r_shift_grid is None or self._eta_grid is None: raise ValueError('Values for r_shift and/or eta not set.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: if self.zetas is None: raise ValueError(f'Values for zeta not set (required for symmetry' f' function type {self.symfunc_type}).') else: - if self.r_shift_grid is None or self.eta_grid is None: + if self._r_shift_grid is None or self._eta_grid is None: raise ValueError(f'Values for r_shift and/or eta not set. ' f'Calling method {calling_method_name} requires' f' that values for r_shift and eta have been set before.') @@ -471,8 +489,8 @@ def write_settings_overview(self, file=None): handle.write('# Sets of values for parameters:\n') # set numpy print precision to lower number of decimal places for the following outputs np.set_printoptions(precision=4) - handle.write(f'# r_shift_grid = {self.r_shift_grid}\n') - handle.write(f'# eta_grid = {self.eta_grid}\n') + handle.write(f'# r_shift_grid = {self._r_shift_grid}\n') + handle.write(f'# eta_grid = {self._eta_grid}\n') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: handle.write(f'# lambdas = {self.lambdas}\n') handle.write(f'# zetas = {self.zetas}\n') @@ -553,14 +571,14 @@ def write_parameter_strings(self, file=None): if self.symfunc_type == 'radial': for comb in self.element_combinations: - for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): handle.write( f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') handle.write('\n') elif self.symfunc_type in ['angular_narrow', 'angular_wide']: for comb in self.element_combinations: - for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): for zeta in self.zetas: for lambd in self.lambdas: handle.write( @@ -569,14 +587,14 @@ def write_parameter_strings(self, file=None): elif self.symfunc_type == 'weighted_radial': for comb in self.element_combinations: - for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): handle.write( f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') handle.write('\n') elif self.symfunc_type == 'weighted_angular': for comb in self.element_combinations: - for (eta, rs) in zip(self.eta_grid, self.r_shift_grid): + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): for zeta in self.zetas: for lambd in self.lambdas: handle.write( @@ -598,15 +616,15 @@ def main(): # myGen.generate_radial_params(rule='gastegger2018', mode='shift', # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - # myGen.symfunc_type = 'radial' - # myGen.set_radial_params_manually([11,22,33,44,55], [55,44,33,22,11]) - myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - myGen.symfunc_type = 'angular_narrow' - myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - nb_param_pairs=3) - myGen.zetas = [1.0, 6.0] + myGen.symfunc_type = 'radial' + myGen.set_custom_radial_params([11, 22, 33, 44, 55], [55, 44, 33, 22, 11]) + + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) + # myGen.symfunc_type = 'angular_narrow' + # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', + # nb_param_pairs=3) + # myGen.zetas = [1.0, 6.0] # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) # myGen.symfunc_type = 'angular_wide' diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index 55a326a89..aecbceb7f 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -194,9 +194,9 @@ def test_check_writing_prerequisites(symfunc_type, r_shift_grid, eta_grid, zetas if symfunc_type is not None: myGen.symfunc_type = symfunc_type if r_shift_grid is not None: - myGen.r_shift_grid = r_shift_grid + myGen._r_shift_grid = r_shift_grid if eta_grid is not None: - myGen.eta_grid = eta_grid + myGen._eta_grid = eta_grid if zetas is not None: myGen.zetas = zetas @@ -210,6 +210,41 @@ def test_check_writing_prerequisites(symfunc_type, r_shift_grid, eta_grid, zetas myGen.write_parameter_strings() +def test_set_custom_radial_params(): + """Test if set_custom_radial_params correctly raises exceptions and sets values. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + + # test for exception when unequal length + with pytest.raises(TypeError): + myGen.set_custom_radial_params([1.1, 2.2, 3.3], [4.4, 5.5]) + # test for exception when non-positive value in values for r_shift + with pytest.raises(ValueError): + myGen.set_custom_radial_params([0, 2.2, 3.3], [1.1, 2.2, 3.3]) + # test for exception when non-positive value in values for eta + with pytest.raises(ValueError): + myGen.set_custom_radial_params([1.1, 2.2, 3.3], [0, 2.2, 3.3]) + + # test if setting custom r_shift and eta values works correctly + myGen.set_custom_radial_params([1.1, 2.2, 3.3], [3.3, 2.2, 1.1]) + assert np.array_equal(myGen.r_shift_grid, np.array([1.1, 2.2, 3.3])) + assert np.array_equal(myGen.eta_grid, np.array([3.3, 2.2, 1.1])) + + # test if the dict containing radial parameter generation settings is + # correctly reset to None, when setting custom radial parameters + myGen.generate_radial_params(rule='imbalzano2018', mode='center', nb_param_pairs=3) + myGen.set_custom_radial_params([1.1, 2.2, 3.3], [3.3, 2.2, 1.1]) + assert myGen.radial_paramgen_settings is None + + + + + + + + + From 01a78f3eda4568ee190181f17962b3181049abe6 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Tue, 7 May 2019 17:07:30 +0200 Subject: [PATCH 37/60] Extend tests. --- .../src/SymFuncParamGenerator.py | 16 +- .../tests/test_generate_radial_params.py | 156 ++++++++++++++++++ .../symfunc_paramgen/tests/test_outputs.py | 104 ++++-------- 3 files changed, 194 insertions(+), 82 deletions(-) create mode 100644 tools/python/symfunc_paramgen/tests/test_generate_radial_params.py diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 16b3a8ca7..4b3b63ccd 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -616,9 +616,9 @@ def main(): # myGen.generate_radial_params(rule='gastegger2018', mode='shift', # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) - myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - myGen.symfunc_type = 'radial' - myGen.set_custom_radial_params([11, 22, 33, 44, 55], [55, 44, 33, 22, 11]) + # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) + # myGen.symfunc_type = 'radial' + # myGen.set_custom_radial_params([11, 22, 33, 44, 55], [55, 44, 33, 22, 11]) # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) # myGen.symfunc_type = 'angular_narrow' @@ -626,11 +626,11 @@ def main(): # nb_param_pairs=3) # myGen.zetas = [1.0, 6.0] - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - # myGen.symfunc_type = 'angular_wide' - # myGen.generate_radial_params(rule='gastegger2018', mode='center', - # nb_param_pairs=3, r_lower=1.5) - # myGen.zetas = [1.0, 6.0] + myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) + myGen.symfunc_type = 'angular_wide' + myGen.generate_radial_params(rule='gastegger2018', mode='center', + nb_param_pairs=3, r_lower=1.5) + myGen.zetas = [1.0, 6.0] # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 5.) # myGen.symfunc_type = 'weighted_radial' diff --git a/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py new file mode 100644 index 000000000..6d956c773 --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py @@ -0,0 +1,156 @@ +import sys +sys.path.append('../src') + +import numpy as np +import pytest +import os +import SymFuncParamGenerator as sfpg + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ + ('bad_argument', 'center', 5, 1.5), + ('bad_argument', 'shift', 5, 1.5), + ('gastegger2018', 'bad_argument', 5, 1.5), + ('imbalzano2018', 'bad_argument', 5, None) +]) +def test_errors_rule_mode(rule, mode, nb_param_pairs, r_lower): + """Test for ValueError when invalid arguments for rule or method. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + with pytest.raises(ValueError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs", [ + ('gastegger2018', 'center', 5), + ('gastegger2018', 'shift', 5) +]) +def test_errors_rlower(rule, mode, nb_param_pairs): + """Test for TypeError when omitting r_lower argument in rule 'gastegger2018' + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + with pytest.raises(TypeError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs) + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ + ('gastegger2018', 'center', 1, 1.5), + ('gastegger2018', 'shift', 1, 1.5), + ('imbalzano2018', 'center', 1, None), + ('imbalzano2018', 'shift', 1, None) +]) +def test_errors_nb_param_pairs(rule, mode, nb_param_pairs, r_lower): + """Test for ValueError when nb_param_pairs less than two. + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + with pytest.raises(ValueError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower,r_upper", [ + ('gastegger2018', 'center', 2, 0., 5.), + ('gastegger2018', 'center', 2, 0., None), + ('gastegger2018', 'center', 2, 5., 1.), + ('gastegger2018', 'center', 2, 7., None), + ('gastegger2018', 'center', 2, 1., 7.), + ('gastegger2018', 'shift', 2, -1., 5.), + ('gastegger2018', 'shift', 2, -1., None), + ('gastegger2018', 'shift', 2, 5., 1.), + ('gastegger2018', 'shift', 2, 7, None), + ('gastegger2018', 'shift', 2, 1., 7.) +]) +def test_errors_numerical_order(rule, mode, nb_param_pairs, r_lower, r_upper): + """Test for ValueError when illegal relation between r_lower, r_upper, r_cutoff in rule 'gastegger2018' + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + with pytest.raises(ValueError): + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, + r_lower=r_lower, r_upper=r_upper) + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower,r_upper,target_r_shift,target_eta", [ + ('gastegger2018', 'center', 3, 1., 5., + [0, 0, 0], + [1/2, 1/18, 1/50]), + ('gastegger2018', 'shift', 3, 1., 5., + [1, 3, 5], + [1/8, 1/8, 1/8]), + ('gastegger2018', 'center', 3, 1., None, + [0, 0, 0], + [1/2, 1/(2*3.5**2), 1/(2*6**2)]), + ('gastegger2018', 'shift', 3, 1., None, + [1, 3.5, 6], + [1/(2*2.5**2)]*3) +]) +def test_parameter_generation(rule, mode, nb_param_pairs, r_lower, r_upper, + target_r_shift, target_eta): + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + + # when passing r_upper + if r_upper is not None: + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, + r_lower=r_lower, r_upper=r_upper) + # when not passing r_upper, using default value of r_cutoff + else: + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, + r_lower=r_lower) + + # test if generated parameter sets match target values + assert np.allclose(myGen.r_shift_grid, np.array(target_r_shift)) + assert np.allclose(myGen.eta_grid, np.array(target_eta)) + + # test if settings have been correctly stored + assert myGen.radial_paramgen_settings['rule'] == rule + assert myGen.radial_paramgen_settings['mode'] == mode + assert myGen.radial_paramgen_settings['nb_param_pairs'] == nb_param_pairs + assert myGen.radial_paramgen_settings['r_lower'] == r_lower + if r_upper is not None: + assert myGen.radial_paramgen_settings['r_upper'] == r_upper + else: + assert myGen.radial_paramgen_settings['r_upper'] == myGen.r_cutoff + + +@pytest.mark.parametrize("rule,mode,nb_param_pairs,target_r_shift,target_eta", [ + ('imbalzano2018', 'center', 4, + [0, 0, 0, 0], + [1/36, 0.0577801, 0.1201874, 1/4]), + ('imbalzano2018', 'shift', 4, + [1.5, 2.1213203, 3.0, 4.2426407], + [2.5904121, 1.2952060, 0.6476030, 0.3238015]) +]) +def test_parameter_generation(rule, mode, nb_param_pairs, + target_r_shift, target_eta): + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + + myGen.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs) + + # test if generated parameter sets match target values + assert np.allclose(myGen.r_shift_grid, np.array(target_r_shift)) + assert np.allclose(myGen.eta_grid, np.array(target_eta)) + + # test if settings have been correctly stored + assert myGen.radial_paramgen_settings['rule'] == rule + assert myGen.radial_paramgen_settings['mode'] == mode + assert myGen.radial_paramgen_settings['nb_param_pairs'] == nb_param_pairs + + + + + + + + + + diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index aecbceb7f..4525ab503 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -7,11 +7,37 @@ import SymFuncParamGenerator as sfpg -def test_element_combinations(): - elems = ['S', 'Cu'] +@pytest.mark.parametrize("symfunc_type,target_combinations", [ + ('radial', + [('H', 'H'), ('H', 'C'), ('H', 'O'), + ('C', 'H'), ('C', 'C'), ('C', 'O'), + ('O', 'H'), ('O', 'C'), ('O', 'O')]), + ('angular_narrow', + [('H', 'H', 'H'), ('H', 'H', 'C'), ('H', 'H', 'O'), ('H', 'C', 'C'), + ('H', 'C', 'O'), ('H', 'O', 'O'), + ('C', 'H', 'H'), ('C', 'H', 'C'), ('C', 'H', 'O'), ('C', 'C', 'C'), + ('C', 'C', 'O'), ('C', 'O', 'O'), + ('O', 'H', 'H'), ('O', 'H', 'C'), ('O', 'H', 'O'), ('O', 'C', 'C'), + ('O', 'C', 'O'), ('O', 'O', 'O')]), + ('angular_wide', + [('H', 'H', 'H'), ('H', 'H', 'C'), ('H', 'H', 'O'), ('H', 'C', 'C'), + ('H', 'C', 'O'), ('H', 'O', 'O'), + ('C', 'H', 'H'), ('C', 'H', 'C'), ('C', 'H', 'O'), ('C', 'C', 'C'), + ('C', 'C', 'O'), ('C', 'O', 'O'), + ('O', 'H', 'H'), ('O', 'H', 'C'), ('O', 'H', 'O'), ('O', 'C', 'C'), + ('O', 'C', 'O'), ('O', 'O', 'O')]), + ('weighted_radial', + [('H',), ('C',), ('O',)]), + ('weighted_angular', + [('H',), ('C',), ('O',)]) +]) +def test_element_combinations(symfunc_type, target_combinations): + """Test if element combinations are correctly constructed. + """ + elems = ['H', 'C', 'O'] myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - myGen.symfunc_type = 'radial' - assert myGen.element_combinations == [('S', 'S'), ('S', 'Cu'), ('Cu', 'S'), ('Cu', 'Cu')] + myGen.symfunc_type = symfunc_type + assert myGen.element_combinations == target_combinations def isnotcomment(line): @@ -107,76 +133,6 @@ def test_rcutoff(): myGen.r_cutoff = 10 - -@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ - ('bad_argument', 'center', 5, 1.5), - ('bad_argument', 'shift', 5, 1.5), - ('gastegger2018', 'bad_argument', 5, 1.5), - ('imbalzano2018', 'bad_argument', 5, None) -]) -def test_radial_paramgen_2(rule, mode, nb_param_pairs, r_lower): - """Test for ValueError when invalid arguments for rule or method. - """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - with pytest.raises(ValueError): - myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs, r_lower=r_lower) - - -@pytest.mark.parametrize("rule,mode,nb_param_pairs", [ - ('gastegger2018', 'center', 5), - ('gastegger2018', 'shift', 5) -]) -def test_radial_paramgen_3(rule, mode, nb_param_pairs): - """Test for TypeError when omitting r_lower argument in rule 'gastegger2018' - """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - with pytest.raises(TypeError): - myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs) - - -@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ - ('gastegger2018', 'center', 1, 1.5), - ('gastegger2018', 'shift', 1, 1.5), - ('imbalzano2018', 'center', 1, None), - ('imbalzano2018', 'shift', 1, None) -]) -def test_radial_paramgen_4(rule, mode, nb_param_pairs, r_lower): - """Test for ValueError when nb_param_pairs less than two. - """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - with pytest.raises(ValueError): - myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs, r_lower=r_lower) - - -@pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower,r_upper", [ - ('gastegger2018', 'center', 2, 0., 5.), - ('gastegger2018', 'center', 2, 0., None), - ('gastegger2018', 'center', 2, 5., 1.), - ('gastegger2018', 'center', 2, 7., None), - ('gastegger2018', 'center', 2, 1., 7.), - ('gastegger2018', 'shift', 2, -1., 5.), - ('gastegger2018', 'shift', 2, -1., None), - ('gastegger2018', 'shift', 2, 5., 1.), - ('gastegger2018', 'shift', 2, 7, None), - ('gastegger2018', 'shift', 2, 1., 7.) -]) -def test_radial_paramgen_5(rule, mode, nb_param_pairs, r_lower, r_upper): - """Test for ValueError when illegal relation between r_lower, r_upper, r_cutoff in rule 'gastegger2018' - """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - with pytest.raises(ValueError): - myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs, - r_lower=r_lower, r_upper=r_upper) - - @pytest.mark.parametrize("symfunc_type,r_shift_grid,eta_grid,zetas", [ (None, np.array([1,2,3]), np.array([4,5,6]), None), ('radial', None, np.array([4,5,6]), None), From 93105d643223e3c5d290187049b32f2e6c6deeb1 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Tue, 7 May 2019 19:08:20 +0200 Subject: [PATCH 38/60] Rework warnings for unused r_lower and r_upper; Also extend tests. --- .../src/SymFuncParamGenerator.py | 68 ++++--------------- .../tests/test_generate_radial_params.py | 29 +++++++- .../symfunc_paramgen/tests/test_outputs.py | 8 +++ 3 files changed, 48 insertions(+), 57 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 4b3b63ccd..6541457cd 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -4,7 +4,7 @@ import sys import inspect import itertools -import traceback +import warnings class SymFuncParamGenerator: @@ -28,6 +28,8 @@ class SymFuncParamGenerator: radial_paramgen_settings : dict or None Stores settings that were used in generating the symmetry function parameters r_shift and eta using the class method provided for that purpose. + None, if no radial parameters have been generated yet, or if custom ones + (without using the method for generating radial parameters) were set. _r_shift_grid : numpy.ndarray or None The set of values for the symmetry function parameter r_shift that was generated. _eta_grid : numpy.ndarray or None @@ -292,17 +294,18 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, raise ValueError('invalid argument for "mode"') elif rule == 'imbalzano2018': - # TODO: rethink these warnings (might not want to print the whole stack, especially in the test the output becomes very unwieldy) if r_lower is not None: - sys.stderr.write( - 'Warning: argument r_lower is not used in rule "imbalzano2018" and will be ignored.\n') - # traceback.print_stack() - # sys.stderr.flush() + this_method_name = inspect.currentframe().f_code.co_name + warnings.warn(f'The argument r_lower to method' + f' {this_method_name} will be ignored,' + f' since it is unused when calling the method' + f' with rule="imbalzano2018".') if r_upper is not None: - sys.stderr.write( - 'Warning: argument r_upper is not used in rule "imbalzano2018" and will be ignored.\n') - # traceback.print_stack() - # sys.stderr.flush() + this_method_name = inspect.currentframe().f_code.co_name + warnings.warn(f'The argument r_upper to method' + f' {this_method_name} will be ignored,' + f' since it is unused when calling the method' + f' with rule="imbalzano2018".') if mode == 'center': nb_intervals = nb_param_pairs - 1 @@ -605,48 +608,3 @@ def write_parameter_strings(self, file=None): # which should not be closed) if handle is not sys.stdout: handle.close() - - -def main(): - elems = ['S', 'Cu'] - # elems = ['H', 'C', 'O'] - - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff=6.) - # myGen.symfunc_type = 'radial' - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # nb_param_pairs=5, r_lower=1.5, r_upper=5.5) - - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - # myGen.symfunc_type = 'radial' - # myGen.set_custom_radial_params([11, 22, 33, 44, 55], [55, 44, 33, 22, 11]) - - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - # myGen.symfunc_type = 'angular_narrow' - # myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - # nb_param_pairs=3) - # myGen.zetas = [1.0, 6.0] - - myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - myGen.symfunc_type = 'angular_wide' - myGen.generate_radial_params(rule='gastegger2018', mode='center', - nb_param_pairs=3, r_lower=1.5) - myGen.zetas = [1.0, 6.0] - - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 5.) - # myGen.symfunc_type = 'weighted_radial' - # myGen.generate_radial_params(rule='imbalzano2018', mode='center', - # nb_param_pairs=5) - - # myGen = SymFuncParamGenerator(elements=elems, r_cutoff = 6.) - # myGen.symfunc_type = 'weighted_angular' - # myGen.generate_radial_params(rule='gastegger2018', mode='shift', - # nb_param_pairs=3, r_lower=1.5) - # myGen.zetas = [1.0, 6.0] - - - myGen.write_settings_overview() - myGen.write_parameter_strings() - - -if __name__ == '__main__': - main() diff --git a/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py index 6d956c773..0f33ad031 100644 --- a/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py +++ b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py @@ -89,8 +89,10 @@ def test_errors_numerical_order(rule, mode, nb_param_pairs, r_lower, r_upper): [1, 3.5, 6], [1/(2*2.5**2)]*3) ]) -def test_parameter_generation(rule, mode, nb_param_pairs, r_lower, r_upper, +def test_parameter_generation_gastegger2018(rule, mode, nb_param_pairs, r_lower, r_upper, target_r_shift, target_eta): + """Test if generated r_shift and eta values match target values. + """ elems = ['S', 'Cu'] myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) @@ -128,8 +130,10 @@ def test_parameter_generation(rule, mode, nb_param_pairs, r_lower, r_upper, [1.5, 2.1213203, 3.0, 4.2426407], [2.5904121, 1.2952060, 0.6476030, 0.3238015]) ]) -def test_parameter_generation(rule, mode, nb_param_pairs, +def test_parameter_generation_imbalzano2018(rule, mode, nb_param_pairs, target_r_shift, target_eta): + """Test if generated r_shift and eta values match target values. + """ elems = ['S', 'Cu'] myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) @@ -146,6 +150,27 @@ def test_parameter_generation(rule, mode, nb_param_pairs, assert myGen.radial_paramgen_settings['nb_param_pairs'] == nb_param_pairs +@pytest.mark.parametrize("mode", ['center', 'shift']) +def test_warning_unused_args(mode): + """Test if warning when passing r_lower or r_upper while using rule 'imbalzano2018' + """ + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + + with pytest.warns(UserWarning): + myGen.generate_radial_params(rule='imbalzano2018', mode=mode, + nb_param_pairs=3, + r_lower=1) + with pytest.warns(UserWarning): + myGen.generate_radial_params(rule='imbalzano2018', mode=mode, + nb_param_pairs=3, + r_upper=5) + with pytest.warns(UserWarning): + myGen.generate_radial_params(rule='imbalzano2018', mode=mode, + nb_param_pairs=3, + r_lower=1, r_upper=5) + + diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index 4525ab503..5c8ccae01 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -137,8 +137,16 @@ def test_rcutoff(): (None, np.array([1,2,3]), np.array([4,5,6]), None), ('radial', None, np.array([4,5,6]), None), ('radial', np.array([1,2,3]), None, None), + ('weighted_radial', None, np.array([4, 5, 6]), None), + ('weighted_radial', np.array([1, 2, 3]), None, None), + ('angular_narrow', None, np.array([4,5,6]), np.array([1,4,9])), + ('angular_narrow', np.array([1,2,3]), None, np.array([1,4,9])), ('angular_narrow', np.array([1,2,3]), np.array([4,5,6]), None), + ('angular_wide', None, np.array([4,5,6]), np.array([1,4,9])), + ('angular_wide', np.array([1,2,3]), None, np.array([1,4,9])), ('angular_wide', np.array([1,2,3]), np.array([4,5,6]), None), + ('weighted_angular', None, np.array([4,5,6]), np.array([1,4,9])), + ('weighted_angular', np.array([1,2,3]), None, np.array([1,4,9])), ('weighted_angular', np.array([1,2,3]), np.array([4,5,6]), None) ]) def test_check_writing_prerequisites(symfunc_type, r_shift_grid, eta_grid, zetas): From 9eb941650bb2e511ce6807ddbba3dff4322d94ba Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Tue, 7 May 2019 22:16:04 +0200 Subject: [PATCH 39/60] Cleaner, dedicated test for parameter string writing. --- ...ference-output_write_parameter_strings.txt | 200 ++++++++ .../tests/reference_outputs.txt | 475 ------------------ .../symfunc_paramgen/tests/test_outputs.py | 71 +-- .../tests/test_write_parameter_strings.py | 66 +++ 4 files changed, 267 insertions(+), 545 deletions(-) create mode 100644 tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt delete mode 100644 tools/python/symfunc_paramgen/tests/reference_outputs.txt create mode 100644 tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py diff --git a/tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt b/tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt new file mode 100644 index 000000000..6dfce6b68 --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt @@ -0,0 +1,200 @@ +######################################################################### +# Radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] + +symfunction_short S 2 S 4.000E+00 1.000E+00 1.122E+01 +symfunction_short S 2 S 5.000E+00 2.000E+00 1.122E+01 + +symfunction_short S 2 Cu 4.000E+00 1.000E+00 1.122E+01 +symfunction_short S 2 Cu 5.000E+00 2.000E+00 1.122E+01 + +symfunction_short Cu 2 S 4.000E+00 1.000E+00 1.122E+01 +symfunction_short Cu 2 S 5.000E+00 2.000E+00 1.122E+01 + +symfunction_short Cu 2 Cu 4.000E+00 1.000E+00 1.122E+01 +symfunction_short Cu 2 Cu 5.000E+00 2.000E+00 1.122E+01 + +######################################################################### +# Weighted radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] + +symfunction_short S 12 4.000E+00 1.000E+00 1.122E+01 +symfunction_short S 12 5.000E+00 2.000E+00 1.122E+01 + +symfunction_short Cu 12 4.000E+00 1.000E+00 1.122E+01 +symfunction_short Cu 12 5.000E+00 2.000E+00 1.122E+01 + +######################################################################### +# Narrow angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +symfunction_short S 3 S S 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S S 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S S 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S S 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S S 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 S S 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 S S 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 S S 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short S 3 S Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 S Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 S Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 S Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 S Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short S 3 Cu Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 Cu Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 Cu Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 Cu Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 3 Cu Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 Cu Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 Cu Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short S 3 Cu Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short Cu 3 S S 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S S 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S S 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S S 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S S 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 S S 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 S S 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 S S 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short Cu 3 S Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 S Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 S Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 S Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 S Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short Cu 3 Cu Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 Cu Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 Cu Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 Cu Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 3 Cu Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 Cu Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 Cu Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 3 Cu Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +######################################################################### +# Wide angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +symfunction_short S 9 S S 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S S 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S S 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S S 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S S 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 S S 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 S S 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 S S 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short S 9 S Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 S Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 S Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 S Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 S Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short S 9 Cu Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 Cu Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 Cu Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 Cu Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short S 9 Cu Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 Cu Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 Cu Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short S 9 Cu Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short Cu 9 S S 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S S 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S S 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S S 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S S 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 S S 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 S S 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 S S 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short Cu 9 S Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 S Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 S Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 S Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 S Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +symfunction_short Cu 9 Cu Cu 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 Cu Cu 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 Cu Cu 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 Cu Cu 4.000E+00 1 7.500E+00 1.122E+01 1.000E+00 +symfunction_short Cu 9 Cu Cu 5.000E+00 -1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 Cu Cu 5.000E+00 1 5.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 Cu Cu 5.000E+00 -1 7.500E+00 1.122E+01 2.000E+00 +symfunction_short Cu 9 Cu Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 + +######################################################################### +# Weighted angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +symfunction_short S 13 4.000E+00 1.000E+00 -1 5.500E+00 1.122E+01 +symfunction_short S 13 4.000E+00 1.000E+00 1 5.500E+00 1.122E+01 +symfunction_short S 13 4.000E+00 1.000E+00 -1 7.500E+00 1.122E+01 +symfunction_short S 13 4.000E+00 1.000E+00 1 7.500E+00 1.122E+01 +symfunction_short S 13 5.000E+00 2.000E+00 -1 5.500E+00 1.122E+01 +symfunction_short S 13 5.000E+00 2.000E+00 1 5.500E+00 1.122E+01 +symfunction_short S 13 5.000E+00 2.000E+00 -1 7.500E+00 1.122E+01 +symfunction_short S 13 5.000E+00 2.000E+00 1 7.500E+00 1.122E+01 + +symfunction_short Cu 13 4.000E+00 1.000E+00 -1 5.500E+00 1.122E+01 +symfunction_short Cu 13 4.000E+00 1.000E+00 1 5.500E+00 1.122E+01 +symfunction_short Cu 13 4.000E+00 1.000E+00 -1 7.500E+00 1.122E+01 +symfunction_short Cu 13 4.000E+00 1.000E+00 1 7.500E+00 1.122E+01 +symfunction_short Cu 13 5.000E+00 2.000E+00 -1 5.500E+00 1.122E+01 +symfunction_short Cu 13 5.000E+00 2.000E+00 1 5.500E+00 1.122E+01 +symfunction_short Cu 13 5.000E+00 2.000E+00 -1 7.500E+00 1.122E+01 +symfunction_short Cu 13 5.000E+00 2.000E+00 1 7.500E+00 1.122E+01 + diff --git a/tools/python/symfunc_paramgen/tests/reference_outputs.txt b/tools/python/symfunc_paramgen/tests/reference_outputs.txt deleted file mode 100644 index 5c02055c5..000000000 --- a/tools/python/symfunc_paramgen/tests/reference_outputs.txt +++ /dev/null @@ -1,475 +0,0 @@ -# Outputs generated at commit b1c014529c855cbf85af241fdb4bc776b7082714, -# to detect possible future changes. -# -######################################################################### -# Radial symmetry function set, for elements ['S', 'Cu'] -######################################################################### -# Radial parameters were generated using the following settings: -# rule = imbalzano2018 -# mode = shift -# r_cutoff = 6.0 -# nb_param_pairs = 5 -# Sets of values for parameters: -# r_shift_grid = [1.2 1.6557 2.2844 3.1518 4.3487] -# eta_grid = [4.816 2.5299 1.329 0.6981 0.3667] - -symfunction_short S 2 S 4.816E+00 1.200E+00 6.000E+00 -symfunction_short S 2 S 2.530E+00 1.656E+00 6.000E+00 -symfunction_short S 2 S 1.329E+00 2.284E+00 6.000E+00 -symfunction_short S 2 S 6.981E-01 3.152E+00 6.000E+00 -symfunction_short S 2 S 3.667E-01 4.349E+00 6.000E+00 - -symfunction_short S 2 Cu 4.816E+00 1.200E+00 6.000E+00 -symfunction_short S 2 Cu 2.530E+00 1.656E+00 6.000E+00 -symfunction_short S 2 Cu 1.329E+00 2.284E+00 6.000E+00 -symfunction_short S 2 Cu 6.981E-01 3.152E+00 6.000E+00 -symfunction_short S 2 Cu 3.667E-01 4.349E+00 6.000E+00 - -symfunction_short Cu 2 S 4.816E+00 1.200E+00 6.000E+00 -symfunction_short Cu 2 S 2.530E+00 1.656E+00 6.000E+00 -symfunction_short Cu 2 S 1.329E+00 2.284E+00 6.000E+00 -symfunction_short Cu 2 S 6.981E-01 3.152E+00 6.000E+00 -symfunction_short Cu 2 S 3.667E-01 4.349E+00 6.000E+00 - -symfunction_short Cu 2 Cu 4.816E+00 1.200E+00 6.000E+00 -symfunction_short Cu 2 Cu 2.530E+00 1.656E+00 6.000E+00 -symfunction_short Cu 2 Cu 1.329E+00 2.284E+00 6.000E+00 -symfunction_short Cu 2 Cu 6.981E-01 3.152E+00 6.000E+00 -symfunction_short Cu 2 Cu 3.667E-01 4.349E+00 6.000E+00 - -######################################################################### -# Radial symmetry function set, for elements ['S', 'Cu'] -######################################################################### -# Radial parameters were generated using the following settings: -# rule = gastegger2018 -# mode = shift -# r_cutoff = 6.0 -# nb_param_pairs = 5 -# r_lower = 1.5 -# r_upper = 5.5 -# Sets of values for parameters: -# r_shift_grid = [1.5 2.5 3.5 4.5 5.5] -# eta_grid = [0.5 0.5 0.5 0.5 0.5] - -symfunction_short S 2 S 5.000E-01 1.500E+00 6.000E+00 -symfunction_short S 2 S 5.000E-01 2.500E+00 6.000E+00 -symfunction_short S 2 S 5.000E-01 3.500E+00 6.000E+00 -symfunction_short S 2 S 5.000E-01 4.500E+00 6.000E+00 -symfunction_short S 2 S 5.000E-01 5.500E+00 6.000E+00 - -symfunction_short S 2 Cu 5.000E-01 1.500E+00 6.000E+00 -symfunction_short S 2 Cu 5.000E-01 2.500E+00 6.000E+00 -symfunction_short S 2 Cu 5.000E-01 3.500E+00 6.000E+00 -symfunction_short S 2 Cu 5.000E-01 4.500E+00 6.000E+00 -symfunction_short S 2 Cu 5.000E-01 5.500E+00 6.000E+00 - -symfunction_short Cu 2 S 5.000E-01 1.500E+00 6.000E+00 -symfunction_short Cu 2 S 5.000E-01 2.500E+00 6.000E+00 -symfunction_short Cu 2 S 5.000E-01 3.500E+00 6.000E+00 -symfunction_short Cu 2 S 5.000E-01 4.500E+00 6.000E+00 -symfunction_short Cu 2 S 5.000E-01 5.500E+00 6.000E+00 - -symfunction_short Cu 2 Cu 5.000E-01 1.500E+00 6.000E+00 -symfunction_short Cu 2 Cu 5.000E-01 2.500E+00 6.000E+00 -symfunction_short Cu 2 Cu 5.000E-01 3.500E+00 6.000E+00 -symfunction_short Cu 2 Cu 5.000E-01 4.500E+00 6.000E+00 -symfunction_short Cu 2 Cu 5.000E-01 5.500E+00 6.000E+00 - -######################################################################### -# Narrow angular symmetry function set, for elements ['S', 'Cu'] -######################################################################### -# Radial parameters were generated using the following settings: -# rule = gastegger2018 -# mode = shift -# r_cutoff = 6.0 -# nb_param_pairs = 9 -# r_lower = 1.5 -# r_upper = 6.0 -# Sets of values for parameters: -# r_shift_grid = [1.5 2.0625 2.625 3.1875 3.75 4.3125 4.875 5.4375 6. ] -# eta_grid = [1.5802 1.5802 1.5802 1.5802 1.5802 1.5802 1.5802 1.5802 1.5802] -# lambdas = [-1. 1.] -# zetas = [1. 6.] - -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 S S 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 S S 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 - -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 - -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 -symfunction_short S 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 - -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 S S 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 S S 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 S S 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 - -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 S Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 S Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 - -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 1.500E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.062E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 2.625E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.188E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 3.750E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.312E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 4.875E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 5.438E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 1.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 -1 6.000E+00 6.000E+00 6.000E+00 -symfunction_short Cu 3 Cu Cu 1.580E+00 1 6.000E+00 6.000E+00 6.000E+00 - -######################################################################### -# Wide angular symmetry function set, for elements ['S', 'Cu'] -######################################################################### -# Radial parameters were generated using the following settings: -# rule = gastegger2018 -# mode = center -# r_cutoff = 6.0 -# nb_param_pairs = 3 -# r_lower = 1.5 -# r_upper = 6.0 -# Sets of values for parameters: -# r_shift_grid = [0. 0. 0.] -# eta_grid = [0.2222 0.0356 0.0139] -# lambdas = [-1. 1.] -# zetas = [1. 6.] - -symfunction_short S 9 S S 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S S 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 - -symfunction_short S 9 S Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 S Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 - -symfunction_short S 9 Cu Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short S 9 Cu Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 - -symfunction_short Cu 9 S S 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S S 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 - -symfunction_short Cu 9 S Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 S Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 - -symfunction_short Cu 9 Cu Cu 2.222E-01 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 2.222E-01 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 2.222E-01 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 2.222E-01 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 3.556E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 3.556E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 3.556E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 3.556E-02 1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 1.389E-02 -1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 1.389E-02 1 1.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 1.389E-02 -1 6.000E+00 6.000E+00 0.000E+00 -symfunction_short Cu 9 Cu Cu 1.389E-02 1 6.000E+00 6.000E+00 0.000E+00 - -######################################################################### -# Weighted radial symmetry function set, for elements ['S', 'Cu'] -######################################################################### -# Radial parameters were generated using the following settings: -# rule = imbalzano2018 -# mode = center -# r_cutoff = 5.0 -# nb_param_pairs = 5 -# Sets of values for parameters: -# r_shift_grid = [0. 0. 0. 0. 0.] -# eta_grid = [0.04 0.08 0.16 0.32 0.64] - -symfunction_short S 12 4.000E-02 0.000E+00 5.000E+00 -symfunction_short S 12 8.000E-02 0.000E+00 5.000E+00 -symfunction_short S 12 1.600E-01 0.000E+00 5.000E+00 -symfunction_short S 12 3.200E-01 0.000E+00 5.000E+00 -symfunction_short S 12 6.400E-01 0.000E+00 5.000E+00 - -symfunction_short Cu 12 4.000E-02 0.000E+00 5.000E+00 -symfunction_short Cu 12 8.000E-02 0.000E+00 5.000E+00 -symfunction_short Cu 12 1.600E-01 0.000E+00 5.000E+00 -symfunction_short Cu 12 3.200E-01 0.000E+00 5.000E+00 -symfunction_short Cu 12 6.400E-01 0.000E+00 5.000E+00 - -######################################################################### -# Weighted angular symmetry function set, for elements ['S', 'Cu'] -######################################################################### -# Radial parameters were generated using the following settings: -# rule = gastegger2018 -# mode = shift -# r_cutoff = 6.0 -# nb_param_pairs = 3 -# r_lower = 1.5 -# r_upper = 6.0 -# Sets of values for parameters: -# r_shift_grid = [1.5 3.75 6. ] -# eta_grid = [0.0988 0.0988 0.0988] -# lambdas = [-1. 1.] -# zetas = [1. 6.] - -symfunction_short S 13 9.877E-02 1.500E+00 -1 1.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 1.500E+00 1 1.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 1.500E+00 -1 6.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 1.500E+00 1 6.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 3.750E+00 -1 1.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 3.750E+00 1 1.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 3.750E+00 -1 6.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 3.750E+00 1 6.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 6.000E+00 -1 1.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 6.000E+00 1 1.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 6.000E+00 -1 6.000E+00 6.000E+00 -symfunction_short S 13 9.877E-02 6.000E+00 1 6.000E+00 6.000E+00 - -symfunction_short Cu 13 9.877E-02 1.500E+00 -1 1.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 1.500E+00 1 1.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 1.500E+00 -1 6.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 1.500E+00 1 6.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 3.750E+00 -1 1.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 3.750E+00 1 1.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 3.750E+00 -1 6.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 3.750E+00 1 6.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 6.000E+00 -1 1.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 6.000E+00 1 1.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 6.000E+00 -1 6.000E+00 6.000E+00 -symfunction_short Cu 13 9.877E-02 6.000E+00 1 6.000E+00 6.000E+00 - diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_outputs.py index 5c8ccae01..dc016b7aa 100644 --- a/tools/python/symfunc_paramgen/tests/test_outputs.py +++ b/tools/python/symfunc_paramgen/tests/test_outputs.py @@ -40,77 +40,8 @@ def test_element_combinations(symfunc_type, target_combinations): assert myGen.element_combinations == target_combinations -def isnotcomment(line): - if line[0] == '#': - return False - return True - - -def test_output(tmpdir): - '''To detect changes in parameter generation and writing, compared to older versions. - - ''' - elems = ['S', 'Cu'] - - outfile_path = os.path.join(tmpdir, 'outfile.txt') - - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - myGen.symfunc_type = 'radial' - myGen.generate_radial_params(rule='imbalzano2018', mode='shift', - nb_param_pairs=5) - myGen.write_settings_overview(outfile_path) - myGen.write_parameter_strings(outfile_path) - - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - myGen.symfunc_type = 'radial' - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - nb_param_pairs=5, r_lower=1.5, r_upper=5.5) - myGen.write_settings_overview(outfile_path) - myGen.write_parameter_strings(outfile_path) - - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - myGen.symfunc_type = 'angular_narrow' - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - nb_param_pairs=9, r_lower=1.5) - myGen.zetas = [1.0, 6.0] - myGen.write_settings_overview(outfile_path) - myGen.write_parameter_strings(outfile_path) - - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - myGen.symfunc_type = 'angular_wide' - myGen.generate_radial_params(rule='gastegger2018', mode='center', - nb_param_pairs=3, r_lower=1.5) - myGen.zetas = [1.0, 6.0] - myGen.write_settings_overview(outfile_path) - myGen.write_parameter_strings(outfile_path) - - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=5.) - myGen.symfunc_type = 'weighted_radial' - myGen.generate_radial_params(rule='imbalzano2018', mode='center', - nb_param_pairs=5) - myGen.write_settings_overview(outfile_path) - myGen.write_parameter_strings(outfile_path) - - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - myGen.symfunc_type = 'weighted_angular' - myGen.generate_radial_params(rule='gastegger2018', mode='shift', - nb_param_pairs=3, r_lower=1.5) - myGen.zetas = [1.0, 6.0] - myGen.write_settings_overview(outfile_path) - myGen.write_parameter_strings(outfile_path) - - # ignore comment lines, so the test does not immediately fail when only - # the parameter information is changed (which I would like to keep just - # for keeping track of the settings used in the reference output file, but - # is otherwise not essential) - with open(outfile_path) as f_out, open('reference_outputs.txt') as f_reference: - f_reference = filter(isnotcomment, f_reference) - f_out = filter(isnotcomment, f_out) - assert all(x == y for x, y in zip(f_out, f_reference)) - - def test_setter_symfunc_type(): - """Test if error when trying to set invalid symmetry function type + """Test if error when trying to set invalid symmetry function type. """ elems = ['S', 'Cu'] myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) diff --git a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py new file mode 100644 index 000000000..cb4e08834 --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py @@ -0,0 +1,66 @@ +import sys +sys.path.append('../src') + +import numpy as np +import pytest +import os +import SymFuncParamGenerator as sfpg + + +def isnotcomment(line): + """Filter lines according to whether they start in '#'. + """ + if line[0] == '#': + return False + return True + + +def test_write_parameter_strings(tmpdir): + '''Test parameter strings are the same as in reference file, for toy inputs. + ''' + elems = ['S', 'Cu'] + + outfile_path = os.path.join(tmpdir, 'outfile.txt') + reference_path = 'reference-output_write_parameter_strings.txt' + + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + + myGen.set_custom_radial_params([1,2], [4,5]) + + ## radial + myGen.symfunc_type = 'radial' + myGen.write_settings_overview(outfile_path) + myGen.write_parameter_strings(outfile_path) + + ## weighted_radial + myGen.symfunc_type = 'weighted_radial' + myGen.write_settings_overview(outfile_path) + myGen.write_parameter_strings(outfile_path) + + ## angular narrow + myGen.symfunc_type = 'angular_narrow' + myGen.zetas = [5.5, 7.5] + myGen.write_settings_overview(outfile_path) + myGen.write_parameter_strings(outfile_path) + + ## angular_wide + myGen.symfunc_type = 'angular_wide' + myGen.zetas = [5.5, 7.5] + myGen.write_settings_overview(outfile_path) + myGen.write_parameter_strings(outfile_path) + + ## weighted_angular + myGen.symfunc_type = 'weighted_angular' + myGen.zetas = [5.5, 7.5] + myGen.write_settings_overview(outfile_path) + myGen.write_parameter_strings(outfile_path) + + # ignore comment lines, so the test does not immediately fail when only + # the parameter information is changed (which I would like to keep just + # for keeping track of the settings used in the reference output file, but + # is otherwise not essential) + with open(outfile_path) as f_out, open(reference_path) as f_reference: + f_reference = filter(isnotcomment, f_reference) + f_out = filter(isnotcomment, f_out) + assert all(x == y for x, y in zip(f_out, f_reference)) \ No newline at end of file From 928297a27634e3f6ba089d1d9e2bf519d78b0df6 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 8 May 2019 12:42:52 +0200 Subject: [PATCH 40/60] Add dedicated test for settings write method. --- ...ference-output_write_settings_overview.txt | 137 ++++++++++++++++++ .../tests/test_write_settings_overview.py | 73 ++++++++++ 2 files changed, 210 insertions(+) create mode 100644 tools/python/symfunc_paramgen/tests/reference-output_write_settings_overview.txt create mode 100644 tools/python/symfunc_paramgen/tests/test_write_settings_overview.py diff --git a/tools/python/symfunc_paramgen/tests/reference-output_write_settings_overview.txt b/tools/python/symfunc_paramgen/tests/reference-output_write_settings_overview.txt new file mode 100644 index 000000000..5ea20e31b --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/reference-output_write_settings_overview.txt @@ -0,0 +1,137 @@ +######################################################################### +# Radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] + +######################################################################### +# Weighted radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] + +######################################################################### +# Narrow angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +######################################################################### +# Wide angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +######################################################################### +# Weighted angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# A custom set of values was used for the radial parameters r_shift and eta. +# Thus, there are no settings on radial parameter generation available for display. +# Sets of values for parameters: +# r_shift_grid = [1 2] +# eta_grid = [4 5] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +######################################################################### +# Radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# The following settings were used for generating sets +# of values for the radial parameters r_shift and eta: +# rule = gastegger2018 +# mode = center +# nb_param_pairs = 2 +# r_lower = 1.5 +# r_upper = 9.0 +# Sets of values for parameters: +# r_shift_grid = [0. 0.] +# eta_grid = [0.2222 0.0062] + +######################################################################### +# Weighted radial symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# The following settings were used for generating sets +# of values for the radial parameters r_shift and eta: +# rule = gastegger2018 +# mode = center +# nb_param_pairs = 2 +# r_lower = 1.5 +# r_upper = 9.0 +# Sets of values for parameters: +# r_shift_grid = [0. 0.] +# eta_grid = [0.2222 0.0062] + +######################################################################### +# Narrow angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# The following settings were used for generating sets +# of values for the radial parameters r_shift and eta: +# rule = gastegger2018 +# mode = center +# nb_param_pairs = 2 +# r_lower = 1.5 +# r_upper = 9.0 +# Sets of values for parameters: +# r_shift_grid = [0. 0.] +# eta_grid = [0.2222 0.0062] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +######################################################################### +# Wide angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# The following settings were used for generating sets +# of values for the radial parameters r_shift and eta: +# rule = gastegger2018 +# mode = center +# nb_param_pairs = 2 +# r_lower = 1.5 +# r_upper = 9.0 +# Sets of values for parameters: +# r_shift_grid = [0. 0.] +# eta_grid = [0.2222 0.0062] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + +######################################################################### +# Weighted angular symmetry function set, for elements ['S', 'Cu'] +######################################################################### +# r_cutoff = 11.22 +# The following settings were used for generating sets +# of values for the radial parameters r_shift and eta: +# rule = gastegger2018 +# mode = center +# nb_param_pairs = 2 +# r_lower = 1.5 +# r_upper = 9.0 +# Sets of values for parameters: +# r_shift_grid = [0. 0.] +# eta_grid = [0.2222 0.0062] +# lambdas = [-1. 1.] +# zetas = [5.5 7.5] + diff --git a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py new file mode 100644 index 000000000..96dbb8860 --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py @@ -0,0 +1,73 @@ +import sys +sys.path.append('../src') + +import numpy as np +import pytest +import os +import SymFuncParamGenerator as sfpg +import filecmp + + +def test_write_settings_overview(tmpdir): + ########### general settings ########### + outfile_path = os.path.join(tmpdir, 'outfile.txt') + reference_path = 'reference-output_write_settings_overview.txt' + + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + + ########### using custom radial parameters ########### + myGen.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) + + ## radial + myGen.symfunc_type = 'radial' + myGen.write_settings_overview(outfile_path) + + ## weighted_radial + myGen.symfunc_type = 'weighted_radial' + myGen.write_settings_overview(outfile_path) + + myGen.zetas = [5.5, 7.5] + + ## angular narrow + myGen.symfunc_type = 'angular_narrow' + myGen.write_settings_overview(outfile_path) + + ## angular_wide + myGen.symfunc_type = 'angular_wide' + myGen.write_settings_overview(outfile_path) + + ## weighted_angular + myGen.symfunc_type = 'weighted_angular' + myGen.write_settings_overview(outfile_path) + + ########### using the method for radial parameter generation ########### + myGen.generate_radial_params(rule='gastegger2018', mode='center', + nb_param_pairs=2, r_lower=1.5, r_upper=9.) + + ## radial + myGen.symfunc_type = 'radial' + myGen.write_settings_overview(outfile_path) + + ## weighted_radial + myGen.symfunc_type = 'weighted_radial' + myGen.write_settings_overview(outfile_path) + + myGen.zetas = [5.5, 7.5] + + ## angular narrow + myGen.symfunc_type = 'angular_narrow' + myGen.write_settings_overview(outfile_path) + + ## angular_wide + myGen.symfunc_type = 'angular_wide' + myGen.write_settings_overview(outfile_path) + + ## weighted_angular + myGen.symfunc_type = 'weighted_angular' + myGen.write_settings_overview(outfile_path) + + ########### test equality with target output ########### + assert filecmp.cmp(outfile_path, reference_path) + + From 245e3d7771aa73a66450c9e000ac626a8cd29c8c Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 8 May 2019 15:21:47 +0200 Subject: [PATCH 41/60] Reword some error messages; extend documentation. --- .../src/SymFuncParamGenerator.py | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 6541457cd..41b629557 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -127,7 +127,7 @@ def zetas(self): @zetas.setter def zetas(self, values): - # TODO: possibly add checks on values for zeta + # TODO: possibly add checks on values for zeta -> but how? self._zetas = np.array(values) @property @@ -405,10 +405,11 @@ def check_writing_prerequisites(self, calling_method_name=None): ---------- calling_method_name : string, optional The name of another method that calls this method. - If this parameter is given, a modified error message is printed - by this method, mentioning the method from which it was called. - This should make it clearer to the user in which part - of their own code to look for an error. + If this parameter is given, a modified error message is printed, + mentioning the method from which this error-raising method + was called. + This should make it clearer to a user in which part + of their code to look for an error. Raises ------ @@ -429,8 +430,11 @@ def check_writing_prerequisites(self, calling_method_name=None): raise ValueError('Values for r_shift and/or eta not set.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: if self.zetas is None: - raise ValueError(f'Values for zeta not set (required for symmetry' - f' function type {self.symfunc_type}).') + raise ValueError( + f'Values for zeta not set (required for symmetry' + f' function type {self.symfunc_type}).\n' + f' If you are seeing this error despite having previously set zetas, make sure\n' + f' they have not been cleared since by setting a non-angular symmetry function type.') else: if self._r_shift_grid is None or self._eta_grid is None: raise ValueError(f'Values for r_shift and/or eta not set. ' @@ -438,10 +442,12 @@ def check_writing_prerequisites(self, calling_method_name=None): f' that values for r_shift and eta have been set before.') if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: if self.zetas is None: - raise ValueError(f'Values for zeta not set. ' - f'Calling method {calling_method_name} requires' - f' zetas to have been set before, when using' - f' symmetry function type {self.symfunc_type}.') + raise ValueError( + f'Values for zeta not set.\n ' + f'Calling {calling_method_name}, while using symmetry function type {self.symfunc_type},\n' + f' requires zetas to have been set before.\n ' + f'If you are seeing this error despite having previously set zetas, make sure\n' + f' they have not been cleared since by setting a non-angular symmetry function type.') def write_settings_overview(self, file=None): """Write settings used in generating the currently stored set of symmetry function parameters. @@ -548,9 +554,33 @@ def write_parameter_strings(self, file=None): """Write symmetry function parameter sets, formatted as n2p2 requires. Each line in the output corresponds to one symmetry function. + Output is formatted in blocks separated by blank lines, each block - corresponding to one element combination. - Within each block, the other parameters are iterated over. + corresponding to one element combination. The different blocks differ + from each other only in the element combinations and are otherwise + the same. + + Within each block, all combinations of the other parameters + r_shift, eta, lambda, zeta (the latter two only for angular + symmetry function types), are iterated over. + Note, however, that the value pairs for r_shift and eta are not + all the possible combinations of elements in r_shift_grid and eta_grid, + but only the combinations of the i-th entries of r_shift_grid with + the i-th entries of eta_grid. + + Schematic example: When r_shift_grid = [1, 2], eta_grid = [3, 4], + zetas = [5, 6], lambdas = [-1, 1] (the latter not being intended to be + set by the user, anyway), within each block of the output, the + method iterates over the following combinations of + (r_shift, eta, zeta, lambda): + [(1, 3, 5, -1), + (1, 3, 5, 1), + (1, 3, 6, -1), + (1, 3, 6, 1), + (2, 4, 5, -1), + (2, 4, 5, 1), + (2, 4, 6, -1), + (2, 4, 6, 1)] Parameters ---------- From e0902f9b98ac671dedc0f0df007fb0ce6231089d Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 8 May 2019 15:28:22 +0200 Subject: [PATCH 42/60] Rename file test_outputs.py to test_misc.py. --- .../symfunc_paramgen/tests/{test_outputs.py => test_misc.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/python/symfunc_paramgen/tests/{test_outputs.py => test_misc.py} (100%) diff --git a/tools/python/symfunc_paramgen/tests/test_outputs.py b/tools/python/symfunc_paramgen/tests/test_misc.py similarity index 100% rename from tools/python/symfunc_paramgen/tests/test_outputs.py rename to tools/python/symfunc_paramgen/tests/test_misc.py From 374986f6b9b134ddc6eb876f144ea6cef132a446 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Thu, 9 May 2019 10:39:08 +0200 Subject: [PATCH 43/60] First quick build of sphinx documentation. --- tools/python/symfunc_paramgen/doc/Makefile | 20 + .../doc/_build/doctrees/environment.pickle | Bin 0 -> 46358 bytes .../doc/_build/doctrees/index.doctree | Bin 0 -> 106623 bytes .../doc/_build/html/.buildinfo | 4 + .../html/_modules/SymFuncParamGenerator.html | 717 ++ .../doc/_build/html/_modules/index.html | 76 + .../doc/_build/html/_sources/index.rst.txt | 23 + .../doc/_build/html/_static/alabaster.css | 701 ++ .../doc/_build/html/_static/basic.css | 748 ++ .../doc/_build/html/_static/custom.css | 1 + .../doc/_build/html/_static/doctools.js | 314 + .../html/_static/documentation_options.js | 10 + .../doc/_build/html/_static/file.png | Bin 0 -> 286 bytes .../doc/_build/html/_static/jquery-3.2.1.js | 10253 ++++++++++++++++ .../doc/_build/html/_static/jquery.js | 4 + .../doc/_build/html/_static/language_data.js | 297 + .../doc/_build/html/_static/minus.png | Bin 0 -> 90 bytes .../doc/_build/html/_static/plus.png | Bin 0 -> 90 bytes .../doc/_build/html/_static/pygments.css | 69 + .../doc/_build/html/_static/searchtools.js | 505 + .../_build/html/_static/underscore-1.3.1.js | 999 ++ .../doc/_build/html/_static/underscore.js | 31 + .../doc/_build/html/genindex.html | 175 + .../doc/_build/html/index.html | 491 + .../doc/_build/html/objects.inv | Bin 0 -> 454 bytes .../doc/_build/html/py-modindex.html | 98 + .../doc/_build/html/search.html | 91 + .../doc/_build/html/searchindex.js | 1 + tools/python/symfunc_paramgen/doc/conf.py | 175 + tools/python/symfunc_paramgen/doc/index.rst | 23 + tools/python/symfunc_paramgen/doc/make.bat | 36 + 31 files changed, 15862 insertions(+) create mode 100644 tools/python/symfunc_paramgen/doc/Makefile create mode 100644 tools/python/symfunc_paramgen/doc/_build/doctrees/environment.pickle create mode 100644 tools/python/symfunc_paramgen/doc/_build/doctrees/index.doctree create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/.buildinfo create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_modules/SymFuncParamGenerator.html create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_sources/index.rst.txt create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/file.png create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/jquery.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/language_data.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/minus.png create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/plus.png create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/pygments.css create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/searchtools.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/underscore-1.3.1.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/underscore.js create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/genindex.html create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/index.html create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/objects.inv create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/search.html create mode 100644 tools/python/symfunc_paramgen/doc/_build/html/searchindex.js create mode 100644 tools/python/symfunc_paramgen/doc/conf.py create mode 100644 tools/python/symfunc_paramgen/doc/index.rst create mode 100644 tools/python/symfunc_paramgen/doc/make.bat diff --git a/tools/python/symfunc_paramgen/doc/Makefile b/tools/python/symfunc_paramgen/doc/Makefile new file mode 100644 index 000000000..2770436b2 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = symfunc_paramgen +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/doctrees/environment.pickle b/tools/python/symfunc_paramgen/doc/_build/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..7953d2caef7b0c4f0d8f7518e17ab67fa0528ce9 GIT binary patch literal 46358 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 + + + + + SymFuncParamGenerator — symfunc_paramgen 1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for SymFuncParamGenerator

+# -*- coding: utf-8 -*-
+
+import numpy as np
+import sys
+import inspect
+import itertools
+import warnings
+
+
+
[docs]class SymFuncParamGenerator: + """Tools for generation, storage, and writing in the format required by n2p2, of symmetry function parameter sets. + + Parameters + ---------- + elements : list of string + The chemical elements present in the system. + r_cutoff : float + Cutoff radius, at which symmetry functions go to zero. + Must be greater than zero. + + Attributes + ---------- + symfunc_type_numbers : dict + Dictionary mapping strings specifying the symmetry function type to the + numbers used internally by n2p2 to distinguish symmetry function types. + lambdas : numpy.ndarray + Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. + radial_paramgen_settings : dict or None + Stores settings that were used in generating the symmetry function parameters r_shift and eta + using the class method provided for that purpose. + None, if no radial parameters have been generated yet, or if custom ones + (without using the method for generating radial parameters) were set. + _r_shift_grid : numpy.ndarray or None + The set of values for the symmetry function parameter r_shift that was generated. + _eta_grid : numpy.ndarray or None + The set of values for the symmetry function parameter eta that was generated. + elements + element_combinations + r_cutoff + symfunc_type + zetas + """ + + symfunc_type_numbers = dict(radial=2, + angular_narrow=3, + angular_wide=9, + weighted_radial=12, + weighted_angular=13) + lambdas = np.array([-1.0, 1.0]) + + def __init__(self, elements, r_cutoff: float): + self._elements = elements + if not r_cutoff > 0: + raise ValueError('Invalid cutoff radius given. ' + 'Must be greater than zero.') + else: + self._r_cutoff = r_cutoff + + self._element_combinations = None + self._symfunc_type = None + self._zetas = None + + self._r_shift_grid = None + self._eta_grid = None + self.radial_paramgen_settings = None + + @property + def elements(self): + """The chemical elements present in the system (list of string, read-only). + """ + return self._elements + + @property + def element_combinations(self): + """Combinations of elements (list of tuple of string, read-only). + + This is computed and set automatically by the setter for symfunc_type. + """ + return self._element_combinations + + @property + def symfunc_type(self): + """Type of symmetry function for which parameters are to be generated (`str`). + + When the setter for this is called it also checks the validity of + the input, builds the necessary element combinations for the given + symmetry function type, and stores it to member variable. + + If the given symmetry function type is a radial one, + the setter also clears any preexisting zetas + (i.e., sets the member variable zetas to None). + + Raises + ------ + ValueError + If invalid symmetry function type is given. + """ + return self._symfunc_type + + @symfunc_type.setter + def symfunc_type(self, value): + if value not in self.symfunc_type_numbers.keys(): + raise ValueError('Invalid symmetry function type. Must be one of {}'.format( + list(self.symfunc_type_numbers.keys()))) + else: + self._symfunc_type = value + # once symmetry function type has been set and found to be valid, + # build and store the element combinations + self._element_combinations = self.find_element_combinations() + # Clear any previous zeta values, if the given symfunc type is a radial one + if value in ['radial', 'weighted_radial']: + # set the member variable explicitly (with underscore) instead of + # calling setter, because the setter would put None into an array + self._zetas = None + + @property + def r_cutoff(self): + '''Cutoff radius where symmetry functions go to zero (float, read-only). + ''' + return self._r_cutoff + + @property + def zetas(self): + """Set of values for the parameter zeta of angular symmetry functions (`numpy.ndarray`). + """ + return self._zetas + + @zetas.setter + def zetas(self, values): + # TODO: possibly add checks on values for zeta -> but how? + self._zetas = np.array(values) + + @property + def r_shift_grid(self): + return self._r_shift_grid + + @property + def eta_grid(self): + return self._eta_grid + +
[docs] def check_symfunc_type(self, calling_method_name=None): + """Check if a symmetry function type has been set. + + Parameters + ---------- + calling_method_name : string, optional + The name of another method that calls this method. + If this parameter is given, a modified error message is printed + by this method, mentioning the method from which it was called. + This should make it clearer to the user in which part + of their own code to look for an error. + + Raises + ------ + TypeError + If the symmetry function type has not been set (i.e., it is None). + + Returns + ------- + None + """ + if self.symfunc_type is None: + if calling_method_name is None: + raise ValueError('Symmetry function type not set.') + else: + raise ValueError(f'Symmetry function type not set. ' + f'Calling method {calling_method_name} requires' + f' that symmetry function type have been set before.')
+ +
[docs] def generate_radial_params(self, rule, mode, nb_param_pairs: int, + r_lower=None, r_upper=None): + """Generate a set of values for r_shift and eta. + + Such a set of (r_shift, eta)-values is required for any + symmetry function type. + Its generation is independent of the symmetry function type + and the angular symmetry function parameters zeta and lambda. + + Rules for parameter generation are implemented based on [1]_ and [2]_. + + The generated values are stored as arrays in the member variables _r_shift_grid and _eta_grid. + The entries are to be understood pairwise, i.e., the i-th entry of _r_shift_grid + and the i-th entry of _eta_grid belong to one symmetry function. + Besides the set of values for r_shift and eta, the settings that + were used for generating it are also stored, in the dictionary radial_paramgen_settings. + + Parameters + ---------- + rule : {'gastegger2018', 'imbalzano2018'} + If rule=='gastegger2018' use the parameter generation rules presented in [1]_. + If rule=='imbalzano2018' use the parameter generation rules presented in [2]_. + mode : {'center', 'shift'} + Selects which parameter generation procedure to use, on top of the rule argument, + since there are again two different varieties presented in each of the two papers. + 'center' sets r_shift to zero for all symmetry functions, varying only eta. + 'shift' creates parameter sets where r_shift varies. + The exact implementation details differ depending on + the rule parameter and are described in the papers. + nb_param_pairs : int + Number of (r_shift, eta)-pairs to be generated. + r_lower : float + lowest value in the radial grid from which r_shift and eta values + are computed. + required if rule=='gastegger2018'. + ignored if rule=='imbalzano2018'. + r_upper : float, optional + Largest value in the radial grid from which r_shift and eta + values are computed. + Optional if rule=='gastegger2018, defaults to cutoff radius if not + given. + Ignored if rule=='imbalzano2018'. + + Raises + ------ + ValueError + If nb_param_pairs is not two or greater. + TypeError + If parameter r_lower is not given, when using rule 'gastegger2018'. + ValueError + If illegal relation between r_lower, r_upper, r_cutoff. + ValueError + If invalid argument for parameters rule or mode. + + Notes + ----- + [1] https://doi.org/10.1063/1.5019667 + [2] https://doi.org/10.1063/1.5024611 + + The parameter nb_param_pairs invariably specifies the number of + (r_shift, eta)-pairs ultimately generated, not the number of + intervals between points in a grid of r_shift values, or the + number of points in some auxiliary grid. + This constitutes a slight modification of the nomenclature in [2]_, + for the sake of consistent behavior across all options for rule and + mode. + + While the parameter generation by this method does not itself + depend on symmetry function type, be aware of the exact mathematical + expressions for the different symmetry function types and how the + parameters r_shift and eta appear slightly differently in each of them. + + All this method does is implement the procedures described in the two + papers for generating values of the symmetry function parameters + r_shift and eta. As far as this module is concerned, these can then + be used (with the above caveat) in combination with any symmetry + function type. However, this does not imply that their use with all + the different types of symmetry functions is actually discussed in + the papers or was necessarily intended by the authors. + + Returns + ------- + None + """ + if not nb_param_pairs >= 2: + raise ValueError('nb_param_pairs must be two or greater.') + + # store those infos on radial parameter generation settings that are + # independent of the rule argument + self.radial_paramgen_settings = dict(rule=rule, + mode=mode, + nb_param_pairs=nb_param_pairs) + + r_cutoff = self.r_cutoff + + if rule == 'gastegger2018': + if r_lower is None: + raise TypeError('Argument r_lower is required for rule "gastegger2018"') + if r_upper is None: + # by default, set largest value of radial grid to cutoff radius + r_upper = r_cutoff + + # store those settings that are unique to this rule + self.radial_paramgen_settings.update({'r_lower': r_lower, 'r_upper': r_upper}) + + # create auxiliary grid + grid = np.linspace(r_lower, r_upper, nb_param_pairs) + + if mode == 'center': + # r_lower = 0 is not allowed in center mode, + # because it causes division by zero + if not 0 < r_lower < r_upper <= r_cutoff: + raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 < r_lower < r_upper <= r_cutoff.') + r_shift_grid = np.zeros(nb_param_pairs) + eta_grid = 1.0 / (2.0 * grid ** 2) + elif mode == 'shift': + # on the other hand, in shift mode, r_lower = 0 is possible + if not 0 <= r_lower < r_upper <= r_cutoff: + raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 <= r_lower < r_upper <= r_cutoff.') + r_shift_grid = grid + # compute the equidistant grid spacing + dr = (r_upper - r_lower) / (nb_param_pairs - 1) + eta_grid = np.full(nb_param_pairs, 1.0 / (2.0 * dr * dr)) + else: + raise ValueError('invalid argument for "mode"') + + elif rule == 'imbalzano2018': + if r_lower is not None: + this_method_name = inspect.currentframe().f_code.co_name + warnings.warn(f'The argument r_lower to method' + f' {this_method_name} will be ignored,' + f' since it is unused when calling the method' + f' with rule="imbalzano2018".') + if r_upper is not None: + this_method_name = inspect.currentframe().f_code.co_name + warnings.warn(f'The argument r_upper to method' + f' {this_method_name} will be ignored,' + f' since it is unused when calling the method' + f' with rule="imbalzano2018".') + + if mode == 'center': + nb_intervals = nb_param_pairs - 1 + gridpoint_indices = np.array(range(0, nb_intervals + 1)) + eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) / r_cutoff) ** 2 + r_shift_grid = np.zeros_like(eta_grid) + elif mode == 'shift': + # create extended auxiliary grid of r_shift values, + # that contains nb_param_pairs + 1 values + nb_intervals_extended = nb_param_pairs + gridpoint_indices_extended = np.array(range(0, nb_intervals_extended + 1)) + rs_grid_extended = r_cutoff / nb_intervals_extended ** ( + gridpoint_indices_extended / nb_intervals_extended) + # from pairs of neighboring r_shift values, compute eta values. + # doing this for the nb_param_pairs + 1 values in the auxiliary + # grid ultimately gives nb_param_pairs different values for eta. + eta_grid = np.zeros(nb_param_pairs) + for idx in range(len(rs_grid_extended) - 1): + eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 + eta_grid[idx] = eta_current + # create final grid of r_shift values by excluding the first entry + # (for which r_shift coincides with the cutoff radius) from the extended grid + r_shift_grid = rs_grid_extended[1:] + # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift + # (not necessary, but makes the output consistent with the other options) + r_shift_grid = np.flip(r_shift_grid) + eta_grid = np.flip(eta_grid) + else: + raise ValueError('invalid argument for "mode"') + else: + raise ValueError('invalid argument for "rule"') + + # store the generated parameter sets + self._r_shift_grid = r_shift_grid + self._eta_grid = eta_grid
+ +
[docs] def set_custom_radial_params(self, r_shift_values, eta_values): + """Set custom r_shift and eta, bypassing the class's generation method. + + The parameters r_shift_values and eta_values must have the same + length. + Ttheir entries are to be understood pairwise, i.e., + the i-th entry of r_shift_values and the i-th entry of eta_values + belong together, describing one symmetry function. + + Parameters + ---------- + r_shift_values : sequence of float or 1D-array + Set of values for the symmetry function parameter r_shift. + eta_values : sequence of float or 1D-array + Set of values for the symmetry function parameter eta. + + Raises + ------ + TypeError + If r_shift_values and eta_values do not have equal length. + ValueError + If r_shift_values or eta_values contain non-positive entries. + + Notes + ----- + Setting r_shift and eta manually via this method instead of using the + method generate_radial_params somewhat defeats the purpose of the + class as a generator of symmetry function parameter values. However, + it might still be useful, in case one wants to use custom values for + r_shift and eta, for which the generation is not implemented as a + class method, while still benefiting from the parameter writing + functionality of the class. + + Returns + ------- + None + """ + if len(r_shift_values) != len(eta_values): + raise TypeError('r_shift_values and eta_values must have same length.') + if min(r_shift_values) <= 0: + raise ValueError('r_shift_values must all be greater than zero.') + if min(eta_values) <= 0: + raise ValueError('eta_values must all be greater than zero.') + # (re)set radial_paramgen_settings to None, indicating that custom + # values for (r_shift, eta) are used, rather than ones generated by + # class method. + self.radial_paramgen_settings = None + # set the values + self._r_shift_grid = np.array(r_shift_values) + self._eta_grid = np.array(eta_values)
+ +
[docs] def check_writing_prerequisites(self, calling_method_name=None): + """Check if all data required for writing symmetry function sets are present. + + This comprises checking if the following have been set: + -) symmetry function type + -) values for r_shift and eta + -) values for zeta, if the symmetry function type is an angular one + + Parameters + ---------- + calling_method_name : string, optional + The name of another method that calls this method. + If this parameter is given, a modified error message is printed, + mentioning the method from which this error-raising method + was called. + This should make it clearer to a user in which part + of their code to look for an error. + + Raises + ------ + TypeError + If values for r_shift or eta are not set. + TypeError + If an angular symmetry function type has been set, but no values + for zeta were set. + + Returns + ------- + None + """ + self.check_symfunc_type(calling_method_name=calling_method_name) + + if calling_method_name is None: + if self._r_shift_grid is None or self._eta_grid is None: + raise ValueError('Values for r_shift and/or eta not set.') + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.zetas is None: + raise ValueError( + f'Values for zeta not set (required for symmetry' + f' function type {self.symfunc_type}).\n' + f' If you are seeing this error despite having previously set zetas, make sure\n' + f' they have not been cleared since by setting a non-angular symmetry function type.') + else: + if self._r_shift_grid is None or self._eta_grid is None: + raise ValueError(f'Values for r_shift and/or eta not set. ' + f'Calling method {calling_method_name} requires' + f' that values for r_shift and eta have been set before.') + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.zetas is None: + raise ValueError( + f'Values for zeta not set.\n ' + f'Calling {calling_method_name}, while using symmetry function type {self.symfunc_type},\n' + f' requires zetas to have been set before.\n ' + f'If you are seeing this error despite having previously set zetas, make sure\n' + f' they have not been cleared since by setting a non-angular symmetry function type.')
+ +
[docs] def write_settings_overview(self, file=None): + """Write settings used in generating the currently stored set of symmetry function parameters. + + Parameters + ---------- + file : path-like, optional + The file to write the settings information to, using append mode. + If not specified, write to sys.stdout instead. + + Returns + ------- + None + """ + this_method_name = inspect.currentframe().f_code.co_name + self.check_writing_prerequisites(calling_method_name=this_method_name) + + type_descriptions = dict(radial='Radial', + angular_narrow='Narrow angular', + angular_wide='Wide angular', + weighted_radial='Weighted radial', + weighted_angular='Weighted angular') + + # depending on presence of file parameter, either direct output + # to stdout, or open the specified file, in append mode + handle = open(file, 'a') if file is not None else sys.stdout + + handle.write('#########################################################################\n') + handle.write( + f'# {type_descriptions[self.symfunc_type]} symmetry function set, ' + f'for elements {self.elements}\n') + handle.write('#########################################################################\n') + + handle.write(f'# r_cutoff = {self.r_cutoff}\n') + + # depending on whether radial parameters were generated using the method + # or custom-set (indicated by presence or absence of radial parameter + # generation settings), write the settings used or not + if self.radial_paramgen_settings is not None: + handle.write('# The following settings were used for generating sets\n') + handle.write('# of values for the radial parameters r_shift and eta:\n') + for key, value in self.radial_paramgen_settings.items(): + handle.write(f'# {key:14s} = {value}\n') + else: + handle.write('# A custom set of values was used for the radial parameters r_shift and eta.\n') + handle.write('# Thus, there are no settings on radial parameter generation available for display.\n') + + handle.write('# Sets of values for parameters:\n') + # set numpy print precision to lower number of decimal places for the following outputs + np.set_printoptions(precision=4) + handle.write(f'# r_shift_grid = {self._r_shift_grid}\n') + handle.write(f'# eta_grid = {self._eta_grid}\n') + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + handle.write(f'# lambdas = {self.lambdas}\n') + handle.write(f'# zetas = {self.zetas}\n') + # reset numpy print precision to default + np.set_printoptions(precision=8) + handle.write('\n') + + # close the file again (unless writing to sys.stdout, + # which should not be closed) + if handle is not sys.stdout: + handle.close()
+ +
[docs] def find_element_combinations(self): + """Create combinations of elements, depending on symmetry function type and the elements in the system. + + For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, + including of an element with itself. + For angular symmetry functions (narrow or wide), the combinations consist of all possible elements as the + central atom, and then again for each central element all possible unordered pairs of neighbor elements. + For weighted symmetry functions (radial or angular), the combinations run only over all possible + central elements, with neighbors not taken into account at this stage. + + Returns + ------- + combinations : list of tuple of string + Each tuple in the list represents one element combination. + Length of the individual tuples can be 1, 2 or 3, depending on symmetry function type. + Zero-th entry of tuples is always the type of the central atom, 1st and 2nd entry are neighbor atom types + (radial sf: one neighbor, angular sf: two neighbors, weighted sf: no neighbors) + """ + this_method_name = inspect.currentframe().f_code.co_name + self.check_symfunc_type(calling_method_name=this_method_name) + + combinations = [] + + if self.symfunc_type == 'radial': + for elem_central in self.elements: + for elem_neighbor in self.elements: + combinations.append((elem_central, elem_neighbor)) + elif self.symfunc_type in ['angular_narrow', 'angular_wide']: + for elem_central in self.elements: + for pair_of_neighbors in itertools.combinations_with_replacement(self.elements, 2): + comb = (elem_central,) + pair_of_neighbors + combinations.append(comb) + elif self.symfunc_type in ['weighted_radial', 'weighted_angular']: + for elem_central in self.elements: + combinations.append((elem_central,)) + + return combinations
+ +
[docs] def write_parameter_strings(self, file=None): + """Write symmetry function parameter sets, formatted as n2p2 requires. + + Each line in the output corresponds to one symmetry function. + + Output is formatted in blocks separated by blank lines, each block + corresponding to one element combination. The different blocks differ + from each other only in the element combinations and are otherwise + the same. + + Within each block, all combinations of the other parameters + r_shift, eta, lambda, zeta (the latter two only for angular + symmetry function types), are iterated over. + Note, however, that the value pairs for r_shift and eta are not + all the possible combinations of elements in r_shift_grid and eta_grid, + but only the combinations of the i-th entries of r_shift_grid with + the i-th entries of eta_grid. + + Schematic example: When r_shift_grid = [1, 2], eta_grid = [3, 4], + zetas = [5, 6], lambdas = [-1, 1] (the latter not being intended to be + set by the user, anyway), within each block of the output, the + method iterates over the following combinations of + (r_shift, eta, zeta, lambda): + [(1, 3, 5, -1), + (1, 3, 5, 1), + (1, 3, 6, -1), + (1, 3, 6, 1), + (2, 4, 5, -1), + (2, 4, 5, 1), + (2, 4, 6, -1), + (2, 4, 6, 1)] + + Parameters + ---------- + file : path-like, optional + The file to write the parameter strings to, using append mode. + If not specified, write to sys.stdout instead. + + Returns + ------- + None + """ + this_method_name = inspect.currentframe().f_code.co_name + self.check_writing_prerequisites(calling_method_name=this_method_name) + + # depending on presence of file parameter, either direct output + # to stdout, or open the specified file, in append mode + handle = open(file, 'a') if file is not None else sys.stdout + + r_cutoff = self.r_cutoff + sf_number = self.symfunc_type_numbers[self.symfunc_type] + + if self.symfunc_type == 'radial': + for comb in self.element_combinations: + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): + handle.write( + f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') + handle.write('\n') + + elif self.symfunc_type in ['angular_narrow', 'angular_wide']: + for comb in self.element_combinations: + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): + for zeta in self.zetas: + for lambd in self.lambdas: + handle.write( + f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {comb[2]:2s} {eta:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} {rs:9.3E}\n') + handle.write('\n') + + elif self.symfunc_type == 'weighted_radial': + for comb in self.element_combinations: + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): + handle.write( + f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') + handle.write('\n') + + elif self.symfunc_type == 'weighted_angular': + for comb in self.element_combinations: + for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): + for zeta in self.zetas: + for lambd in self.lambdas: + handle.write( + f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} \n') + handle.write('\n') + + # close the file again (unless writing to sys.stdout, + # which should not be closed) + if handle is not sys.stdout: + handle.close()
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html b/tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html new file mode 100644 index 000000000..2a45a21ed --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html @@ -0,0 +1,76 @@ + + + + + + + Overview: module code — symfunc_paramgen 1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

All modules for which code is available

+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_sources/index.rst.txt b/tools/python/symfunc_paramgen/doc/_build/html/_sources/index.rst.txt new file mode 100644 index 000000000..62407096f --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_sources/index.rst.txt @@ -0,0 +1,23 @@ +.. symfunc_paramgen documentation master file, created by + sphinx-quickstart on Wed May 8 15:37:02 2019. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to symfunc_paramgen's documentation! +============================================ + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +.. automodule:: SymFuncParamGenerator + :members: diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css b/tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css new file mode 100644 index 000000000..0eddaeb07 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css @@ -0,0 +1,701 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css b/tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css new file mode 100644 index 000000000..53acd096a --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css @@ -0,0 +1,748 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > p:first-child, +td > p:first-child { + margin-top: 0px; +} + +th > p:last-child, +td > p:last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist td { + vertical-align: top; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +li > p:first-child { + margin-top: 0px; +} + +li > p:last-child { + margin-bottom: 0px; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: flex; + flex-wrap: wrap; +} + +dl.field-list > dt { + flex-basis: 20%; + font-weight: bold; + word-break: break-word; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + flex-basis: 70%; + padding-left: 1em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > p:first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0.5em; + content: ":"; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css b/tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css new file mode 100644 index 000000000..2a924f1d6 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js b/tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js new file mode 100644 index 000000000..b33f87fcb --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js @@ -0,0 +1,314 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js b/tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js new file mode 100644 index 000000000..ad3a3d995 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js @@ -0,0 +1,10 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '1.0', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/file.png b/tools/python/symfunc_paramgen/doc/_build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js b/tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js new file mode 100644 index 000000000..d2d8ca479 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js @@ -0,0 +1,10253 @@ +/*! + * jQuery JavaScript Library v3.2.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2017-03-20T18:59Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.2.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Simple selector that can be filtered directly, removing non-Elements + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + // Complex selector, compare the two sets, removing non-Elements + qualifier = jQuery.filter( qualifier, elements ); + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( jQuery.isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + jQuery.isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ jQuery.camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( jQuery.camelCase ); + } else { + key = jQuery.camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: jQuery.isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( ">tbody", elem )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rmargin = ( /^margin/ ); + +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + div.style.cssText = + "box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; + div.innerHTML = ""; + documentElement.appendChild( container ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = divStyle.marginLeft === "2px"; + boxSizingReliableVal = divStyle.width === "4px"; + + // Support: Android 4.0 - 4.3 only + // Some styles come back with percentage values, even though they shouldn't + div.style.marginRight = "50%"; + pixelMarginRightVal = divStyle.marginRight === "4px"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + "padding:0;margin-top:1px;position:absolute"; + container.appendChild( div ); + + jQuery.extend( support, { + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelMarginRight: function() { + computeStyleTests(); + return pixelMarginRightVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i, + val = 0; + + // If we already have the right measurement, avoid augmentation + if ( extra === ( isBorderBox ? "border" : "content" ) ) { + i = 4; + + // Otherwise initialize for horizontal or vertical properties + } else { + i = name === "width" ? 1 : 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // At this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + + // At this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // At this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with computed style + var valueIsBorderBox, + styles = getStyles( elem ), + val = curCSS( elem, name, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test( val ) ) { + return val; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && + ( support.boxSizingReliable() || val === elem.style[ name ] ); + + // Fall back to offsetWidth/Height when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + if ( val === "auto" ) { + val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + "float": "cssFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + } ) : + getWidthOrHeight( elem, name, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = extra && getStyles( elem ), + subtract = extra && augmentWidthOrHeight( + elem, + name, + extra, + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + styles + ); + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ name ] = value; + value = jQuery.css( elem, name ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( !rmargin.test( prefix ) ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = jQuery.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 13 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( jQuery.isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( jQuery.isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( jQuery.isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = jQuery.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( jQuery.isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + if ( typeof value === "string" && value ) { + classes = value.match( rnothtmlwhite ) || []; + + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value; + + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnothtmlwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, isFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup contextmenu" ).split( " " ), + function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; +} ); + +jQuery.fn.extend( { + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +} ); + + + + +support.focusin = "onfocusin" in window; + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = jQuery.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = jQuery.isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( jQuery.isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 13 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available, append data to url + if ( s.data ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( jQuery.isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/index.html b/tools/python/symfunc_paramgen/doc/_build/html/index.html new file mode 100644 index 000000000..fdf8f4961 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/index.html @@ -0,0 +1,491 @@ + + + + + + + Welcome to symfunc_paramgen’s documentation! — symfunc_paramgen 1.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Welcome to symfunc_paramgen’s documentation!¶

+
+
+
+
+

Indices and tables¶

+ +
+
+class SymFuncParamGenerator.SymFuncParamGenerator(elements, r_cutoff: float)[source]¶
+

Tools for generation, storage, and writing in the format required by n2p2, of symmetry function parameter sets.

+
+
Parameters
+
+
elementslist of string

The chemical elements present in the system.

+
+
r_cutofffloat

Cutoff radius, at which symmetry functions go to zero. +Must be greater than zero.

+
+
+
+
Attributes
+
+
symfunc_type_numbersdict

Dictionary mapping strings specifying the symmetry function type to the +numbers used internally by n2p2 to distinguish symmetry function types.

+
+
lambdasnumpy.ndarray

Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1].

+
+
radial_paramgen_settingsdict or None

Stores settings that were used in generating the symmetry function parameters r_shift and eta +using the class method provided for that purpose. +None, if no radial parameters have been generated yet, or if custom ones +(without using the method for generating radial parameters) were set.

+
+
_r_shift_gridnumpy.ndarray or None

The set of values for the symmetry function parameter r_shift that was generated.

+
+
_eta_gridnumpy.ndarray or None

The set of values for the symmetry function parameter eta that was generated.

+
+
elements

The chemical elements present in the system (list of string, read-only).

+
+
element_combinations

Combinations of elements (list of tuple of string, read-only).

+
+
r_cutoff

Cutoff radius where symmetry functions go to zero (float, read-only).

+
+
symfunc_type

Type of symmetry function for which parameters are to be generated (str).

+
+
zetas

Set of values for the parameter zeta of angular symmetry functions (numpy.ndarray).

+
+
+
+
+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + +

check_symfunc_type(self[, calling_method_name])

Check if a symmetry function type has been set.

check_writing_prerequisites(self[, …])

Check if all data required for writing symmetry function sets are present.

find_element_combinations(self)

Create combinations of elements, depending on symmetry function type and the elements in the system.

generate_radial_params(self, rule, mode, …)

Generate a set of values for r_shift and eta.

set_custom_radial_params(self, …)

Set custom r_shift and eta, bypassing the class’s generation method.

write_parameter_strings(self[, file])

Write symmetry function parameter sets, formatted as n2p2 requires.

write_settings_overview(self[, file])

Write settings used in generating the currently stored set of symmetry function parameters.

+
+
+check_symfunc_type(self, calling_method_name=None)[source]¶
+

Check if a symmetry function type has been set.

+
+
Parameters
+
+
calling_method_namestring, optional

The name of another method that calls this method. +If this parameter is given, a modified error message is printed +by this method, mentioning the method from which it was called. +This should make it clearer to the user in which part +of their own code to look for an error.

+
+
+
+
Returns
+
+
None
+
+
+
Raises
+
+
TypeError

If the symmetry function type has not been set (i.e., it is None).

+
+
+
+
+
+ +
+
+check_writing_prerequisites(self, calling_method_name=None)[source]¶
+

Check if all data required for writing symmetry function sets are present.

+

This comprises checking if the following have been set: +-) symmetry function type +-) values for r_shift and eta +-) values for zeta, if the symmetry function type is an angular one

+
+
Parameters
+
+
calling_method_namestring, optional

The name of another method that calls this method. +If this parameter is given, a modified error message is printed, +mentioning the method from which this error-raising method +was called. +This should make it clearer to a user in which part +of their code to look for an error.

+
+
+
+
Returns
+
+
None
+
+
+
Raises
+
+
TypeError

If values for r_shift or eta are not set.

+
+
TypeError

If an angular symmetry function type has been set, but no values +for zeta were set.

+
+
+
+
+
+ +
+
+element_combinations¶
+

Combinations of elements (list of tuple of string, read-only).

+

This is computed and set automatically by the setter for symfunc_type.

+
+ +
+
+elements¶
+

The chemical elements present in the system (list of string, read-only).

+
+ +
+
+find_element_combinations(self)[source]¶
+

Create combinations of elements, depending on symmetry function type and the elements in the system.

+

For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, +including of an element with itself. +For angular symmetry functions (narrow or wide), the combinations consist of all possible elements as the +central atom, and then again for each central element all possible unordered pairs of neighbor elements. +For weighted symmetry functions (radial or angular), the combinations run only over all possible +central elements, with neighbors not taken into account at this stage.

+
+
Returns
+
+
combinationslist of tuple of string

Each tuple in the list represents one element combination. +Length of the individual tuples can be 1, 2 or 3, depending on symmetry function type. +Zero-th entry of tuples is always the type of the central atom, 1st and 2nd entry are neighbor atom types +(radial sf: one neighbor, angular sf: two neighbors, weighted sf: no neighbors)

+
+
+
+
+
+ +
+
+generate_radial_params(self, rule, mode, nb_param_pairs: int, r_lower=None, r_upper=None)[source]¶
+

Generate a set of values for r_shift and eta.

+

Such a set of (r_shift, eta)-values is required for any +symmetry function type. +Its generation is independent of the symmetry function type +and the angular symmetry function parameters zeta and lambda.

+

Rules for parameter generation are implemented based on [1]_ and [2]_.

+

The generated values are stored as arrays in the member variables _r_shift_grid and _eta_grid. +The entries are to be understood pairwise, i.e., the i-th entry of _r_shift_grid +and the i-th entry of _eta_grid belong to one symmetry function. +Besides the set of values for r_shift and eta, the settings that +were used for generating it are also stored, in the dictionary radial_paramgen_settings.

+
+
Parameters
+
+
rule{‘gastegger2018’, ‘imbalzano2018’}

If rule==’gastegger2018’ use the parameter generation rules presented in [1]_. +If rule==’imbalzano2018’ use the parameter generation rules presented in [2]_.

+
+
mode{‘center’, ‘shift’}

Selects which parameter generation procedure to use, on top of the rule argument, +since there are again two different varieties presented in each of the two papers. +‘center’ sets r_shift to zero for all symmetry functions, varying only eta. +‘shift’ creates parameter sets where r_shift varies. +The exact implementation details differ depending on +the rule parameter and are described in the papers.

+
+
nb_param_pairsint

Number of (r_shift, eta)-pairs to be generated.

+
+
r_lowerfloat

lowest value in the radial grid from which r_shift and eta values +are computed. +required if rule==’gastegger2018’. +ignored if rule==’imbalzano2018’.

+
+
r_upperfloat, optional

Largest value in the radial grid from which r_shift and eta +values are computed. +Optional if rule==’gastegger2018, defaults to cutoff radius if not +given. +Ignored if rule==’imbalzano2018’.

+
+
+
+
Returns
+
+
None
+
+
+
Raises
+
+
ValueError

If nb_param_pairs is not two or greater.

+
+
TypeError

If parameter r_lower is not given, when using rule ‘gastegger2018’.

+
+
ValueError

If illegal relation between r_lower, r_upper, r_cutoff.

+
+
ValueError

If invalid argument for parameters rule or mode.

+
+
+
+
+

Notes

+

[1] https://doi.org/10.1063/1.5019667 +[2] https://doi.org/10.1063/1.5024611

+

The parameter nb_param_pairs invariably specifies the number of +(r_shift, eta)-pairs ultimately generated, not the number of +intervals between points in a grid of r_shift values, or the +number of points in some auxiliary grid. +This constitutes a slight modification of the nomenclature in [2]_, +for the sake of consistent behavior across all options for rule and +mode.

+

While the parameter generation by this method does not itself +depend on symmetry function type, be aware of the exact mathematical +expressions for the different symmetry function types and how the +parameters r_shift and eta appear slightly differently in each of them.

+

All this method does is implement the procedures described in the two +papers for generating values of the symmetry function parameters +r_shift and eta. As far as this module is concerned, these can then +be used (with the above caveat) in combination with any symmetry +function type. However, this does not imply that their use with all +the different types of symmetry functions is actually discussed in +the papers or was necessarily intended by the authors.

+
+ +
+
+r_cutoff¶
+

Cutoff radius where symmetry functions go to zero (float, read-only).

+
+ +
+
+set_custom_radial_params(self, r_shift_values, eta_values)[source]¶
+

Set custom r_shift and eta, bypassing the class’s generation method.

+

The parameters r_shift_values and eta_values must have the same +length. +Ttheir entries are to be understood pairwise, i.e., +the i-th entry of r_shift_values and the i-th entry of eta_values +belong together, describing one symmetry function.

+
+
Parameters
+
+
r_shift_valuessequence of float or 1D-array

Set of values for the symmetry function parameter r_shift.

+
+
eta_valuessequence of float or 1D-array

Set of values for the symmetry function parameter eta.

+
+
+
+
Returns
+
+
None
+
+
+
Raises
+
+
TypeError

If r_shift_values and eta_values do not have equal length.

+
+
ValueError

If r_shift_values or eta_values contain non-positive entries.

+
+
+
+
+

Notes

+

Setting r_shift and eta manually via this method instead of using the +method generate_radial_params somewhat defeats the purpose of the +class as a generator of symmetry function parameter values. However, +it might still be useful, in case one wants to use custom values for +r_shift and eta, for which the generation is not implemented as a +class method, while still benefiting from the parameter writing +functionality of the class.

+
+ +
+
+symfunc_type¶
+

Type of symmetry function for which parameters are to be generated (str).

+

When the setter for this is called it also checks the validity of +the input, builds the necessary element combinations for the given +symmetry function type, and stores it to member variable.

+

If the given symmetry function type is a radial one, +the setter also clears any preexisting zetas +(i.e., sets the member variable zetas to None).

+
+
Raises
+
+
ValueError

If invalid symmetry function type is given.

+
+
+
+
+
+ +
+
+write_parameter_strings(self, file=None)[source]¶
+

Write symmetry function parameter sets, formatted as n2p2 requires.

+

Each line in the output corresponds to one symmetry function.

+

Output is formatted in blocks separated by blank lines, each block +corresponding to one element combination. The different blocks differ +from each other only in the element combinations and are otherwise +the same.

+

Within each block, all combinations of the other parameters +r_shift, eta, lambda, zeta (the latter two only for angular +symmetry function types), are iterated over. +Note, however, that the value pairs for r_shift and eta are not +all the possible combinations of elements in r_shift_grid and eta_grid, +but only the combinations of the i-th entries of r_shift_grid with +the i-th entries of eta_grid.

+

Schematic example: When r_shift_grid = [1, 2], eta_grid = [3, 4], +zetas = [5, 6], lambdas = [-1, 1] (the latter not being intended to be +set by the user, anyway), within each block of the output, the +method iterates over the following combinations of +(r_shift, eta, zeta, lambda): +[(1, 3, 5, -1),

+
+

(1, 3, 5, 1), +(1, 3, 6, -1), +(1, 3, 6, 1), +(2, 4, 5, -1), +(2, 4, 5, 1), +(2, 4, 6, -1), +(2, 4, 6, 1)]

+
+
+
Parameters
+
+
filepath-like, optional

The file to write the parameter strings to, using append mode. +If not specified, write to sys.stdout instead.

+
+
+
+
Returns
+
+
None
+
+
+
+
+ +
+
+write_settings_overview(self, file=None)[source]¶
+

Write settings used in generating the currently stored set of symmetry function parameters.

+
+
Parameters
+
+
filepath-like, optional

The file to write the settings information to, using append mode. +If not specified, write to sys.stdout instead.

+
+
+
+
Returns
+
+
None
+
+
+
+
+ +
+
+zetas¶
+

Set of values for the parameter zeta of angular symmetry functions (numpy.ndarray).

+
+ +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/objects.inv b/tools/python/symfunc_paramgen/doc/_build/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..72078f7a77ffc408ee593b1bb4f1cb35f1a1d9c4 GIT binary patch literal 454 zcmV;%0XhC7AX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk&d2MEO zZew3?VRB(@XJu{*BOq2~a&u{KZaN?_E-(rsAXI2&AaZ4GVQFq;WpW^IW*~HEX>%ZE zX>4U6X>%ZBZ*6dLWpi_7WFU2OX>MmAdTeQ8E(&tK%XR)F7JdYK+!9t?gX?h;oLChFwL(Z{H=4&czs56eCUX<5d=OrkTUdBO&a-ja z7}rJ(cFmM+@v<7o=*#S@uUK6*r|MSCIhxcW1hzhg{gJYg1LPAAlj%~7(==j{2^w5m zg1q;Nl9sEvV zUkd*U62Gl=+N8z90<{}0w$Q9zvx9fZV|TMzeWkTd&PhiZkI-q&!N{@0ODsc6oR7En wz*0q=k72ojiz@wvCz_5^eF$Xgef~ys`vBqP@Vz4Ya&nX7528o)34;<5vsRYPbN~PV literal 0 HcmV?d00001 diff --git a/tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html b/tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html new file mode 100644 index 000000000..e0bf356df --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html @@ -0,0 +1,98 @@ + + + + + + + Python Module Index — symfunc_paramgen 1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Python Module Index

+ +
+ s +
+ + + + + + + +
 
+ s
+ SymFuncParamGenerator +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/search.html b/tools/python/symfunc_paramgen/doc/_build/html/search.html new file mode 100644 index 000000000..75a588a98 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/search.html @@ -0,0 +1,91 @@ + + + + + + + Search — symfunc_paramgen 1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/searchindex.js b/tools/python/symfunc_paramgen/doc/_build/html/searchindex.js new file mode 100644 index 000000000..d767437b6 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["index"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst"],objects:{"":{SymFuncParamGenerator:[0,0,0,"-"]},"SymFuncParamGenerator.SymFuncParamGenerator":{check_symfunc_type:[0,2,1,""],check_writing_prerequisites:[0,2,1,""],element_combinations:[0,3,1,""],elements:[0,3,1,""],find_element_combinations:[0,2,1,""],generate_radial_params:[0,2,1,""],r_cutoff:[0,3,1,""],set_custom_radial_params:[0,2,1,""],symfunc_type:[0,3,1,""],write_parameter_strings:[0,2,1,""],write_settings_overview:[0,2,1,""],zetas:[0,3,1,""]},SymFuncParamGenerator:{SymFuncParamGenerator:[0,1,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute"},terms:{"1st":0,"2nd":0,"case":0,"class":0,"default":0,"float":0,"function":0,"int":0,"return":0,"while":0,For:0,Its:0,Such:0,The:0,_eta_grid:0,_r_shift_grid:0,abov:0,account:0,across:0,actual:0,again:0,all:0,also:0,alwai:0,angular:0,ani:0,anoth:0,anywai:0,appear:0,append:0,argument:0,arrai:0,atom:0,attribut:0,author:0,automat:0,auxiliari:0,awar:0,base:0,been:0,behavior:0,being:0,belong:0,benefit:0,besid:0,between:0,blank:0,block:0,build:0,bypass:0,call:0,calling_method_nam:0,can:0,caveat:0,center:0,central:0,check:0,check_symfunc_typ:0,check_writing_prerequisit:0,chemic:0,clear:0,clearer:0,code:0,combin:0,compris:0,comput:0,concern:0,consist:0,constitut:0,contain:0,correspond:0,creat:0,current:0,custom:0,cutoff:0,data:0,defeat:0,depend:0,describ:0,detail:0,dict:0,dictionari:0,differ:0,discuss:0,distinguish:0,doe:0,doi:0,each:0,element:0,element_combin:0,entri:0,equal:0,error:0,eta:0,eta_grid:0,eta_valu:0,exact:0,exampl:0,express:0,far:0,file:0,find_element_combin:0,fix:0,follow:0,format:0,from:0,gastegger2018:0,gener:0,generate_radial_param:0,given:0,greater:0,grid:0,has:0,have:0,how:0,howev:0,http:0,ignor:0,illeg:0,imbalzano2018:0,implement:0,impli:0,includ:0,independ:0,index:0,individu:0,inform:0,input:0,instead:0,intend:0,intern:0,interv:0,invalid:0,invari:0,iter:0,itself:0,lambda:0,largest:0,latter:0,length:0,like:0,line:0,list:0,look:0,lowest:0,make:0,manual:0,map:0,mathemat:0,member:0,mention:0,messag:0,method:0,might:0,mode:0,modif:0,modifi:0,modul:0,must:0,n2p2:0,name:0,narrow:0,nb_param_pair:0,ndarrai:0,necessari:0,necessarili:0,neighbor:0,nomenclatur:0,non:0,none:0,note:0,number:0,numpi:0,one:0,ones:0,onli:0,option:0,order:0,org:0,other:0,otherwis:0,output:0,over:0,own:0,page:0,pair:0,pairwis:0,paper:0,paramet:0,part:0,path:0,point:0,posit:0,possibl:0,preexist:0,present:0,print:0,procedur:0,provid:0,purpos:0,r_cutoff:0,r_lower:0,r_shift:0,r_shift_grid:0,r_shift_valu:0,r_upper:0,radial:0,radial_paramgen_set:0,radiu:0,rais:0,read:0,relat:0,repres:0,requir:0,rule:0,run:0,sake:0,same:0,schemat:0,search:0,select:0,self:0,separ:0,sequenc:0,set:0,set_custom_radial_param:0,setter:0,shift:0,should:0,sinc:0,slight:0,slightli:0,some:0,somewhat:0,sourc:0,specifi:0,stage:0,stdout:0,still:0,storag:0,store:0,str:0,string:0,symfunc_typ:0,symfunc_type_numb:0,symfuncparamgener:0,symmetri:0,sys:0,system:0,taken:0,than:0,them:0,thi:0,togeth:0,tool:0,top:0,ttheir:0,tupl:0,two:0,type:0,typeerror:0,ultim:0,understood:0,unord:0,use:0,used:0,useful:0,user:0,using:0,valid:0,valu:0,valueerror:0,vari:0,variabl:0,varieti:0,via:0,want:0,weight:0,were:0,when:0,where:0,which:0,wide:0,within:0,without:0,write:0,write_parameter_str:0,write_settings_overview:0,yet:0,zero:0,zeta:0},titles:["Welcome to symfunc_paramgen\u2019s documentation!"],titleterms:{document:0,indic:0,symfunc_paramgen:0,tabl:0,welcom:0}}) \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/conf.py b/tools/python/symfunc_paramgen/doc/conf.py new file mode 100644 index 000000000..3e87eb10d --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/conf.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# symfunc_paramgen documentation build configuration file, created by +# sphinx-quickstart on Wed May 8 15:37:02 2019. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. + +import os +import sys +sys.path.insert(0, os.path.abspath('../src/')) +sys.setrecursionlimit(1500) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'numpydoc'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'symfunc_paramgen' +copyright = '2019, Florian Buchner' +author = 'Florian Buchner' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +html_sidebars = { + '**': [ + 'relations.html', # needs 'show_related': True theme option to display + 'searchbox.html', + ] +} + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'symfunc_paramgendoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'symfunc_paramgen.tex', 'symfunc\\_paramgen Documentation', + 'Florian Buchner', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'symfunc_paramgen', 'symfunc_paramgen Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'symfunc_paramgen', 'symfunc_paramgen Documentation', + author, 'symfunc_paramgen', 'One line description of project.', + 'Miscellaneous'), +] + + + diff --git a/tools/python/symfunc_paramgen/doc/index.rst b/tools/python/symfunc_paramgen/doc/index.rst new file mode 100644 index 000000000..62407096f --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/index.rst @@ -0,0 +1,23 @@ +.. symfunc_paramgen documentation master file, created by + sphinx-quickstart on Wed May 8 15:37:02 2019. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to symfunc_paramgen's documentation! +============================================ + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +.. automodule:: SymFuncParamGenerator + :members: diff --git a/tools/python/symfunc_paramgen/doc/make.bat b/tools/python/symfunc_paramgen/doc/make.bat new file mode 100644 index 000000000..98281032d --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build +set SPHINXPROJ=symfunc_paramgen + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd From 7d1a7e477f5d9f8fb5955cee33e7fb04d4565dac Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sat, 11 May 2019 20:54:40 +0200 Subject: [PATCH 44/60] Rewrite in-line ifs -> tests report correct coverage. --- .../doc/_build/doctrees/environment.pickle | Bin 46358 -> 0 bytes .../doc/_build/doctrees/index.doctree | Bin 106623 -> 0 bytes .../doc/_build/html/.buildinfo | 4 - .../html/_modules/SymFuncParamGenerator.html | 717 -- .../doc/_build/html/_modules/index.html | 76 - .../doc/_build/html/_static/alabaster.css | 701 -- .../doc/_build/html/_static/basic.css | 748 -- .../doc/_build/html/_static/custom.css | 1 - .../doc/_build/html/_static/doctools.js | 314 - .../html/_static/documentation_options.js | 10 - .../doc/_build/html/_static/file.png | Bin 286 -> 0 bytes .../doc/_build/html/_static/jquery-3.2.1.js | 10253 ---------------- .../doc/_build/html/_static/jquery.js | 4 - .../doc/_build/html/_static/language_data.js | 297 - .../doc/_build/html/_static/minus.png | Bin 90 -> 0 bytes .../doc/_build/html/_static/plus.png | Bin 90 -> 0 bytes .../doc/_build/html/_static/pygments.css | 69 - .../doc/_build/html/_static/searchtools.js | 505 - .../_build/html/_static/underscore-1.3.1.js | 999 -- .../doc/_build/html/_static/underscore.js | 31 - .../doc/_build/html/genindex.html | 175 - .../doc/_build/html/index.html | 491 - .../doc/_build/html/objects.inv | Bin 454 -> 0 bytes .../doc/_build/html/py-modindex.html | 98 - .../doc/_build/html/search.html | 91 - .../doc/_build/html/searchindex.js | 1 - .../doc/apigen/SymFuncParamGenerator.rst | 7 + .../symfunc_paramgen/doc/apigen/modules.rst | 11 + .../doc/code_structure.rst.bak | 7 + tools/python/symfunc_paramgen/doc/conf.py | 30 +- tools/python/symfunc_paramgen/doc/index.rst | 12 +- .../_sources/index.rst.txt => index.rst.bak} | 11 +- .../src/SymFuncParamGenerator.py | 81 +- ...ference-output_write_parameter_strings.txt | 12 +- .../tests/stdout-comparison-file.txt | 2 + .../tests/test_write_parameter_strings.py | 71 +- .../tests/test_write_settings_overview.py | 68 +- 37 files changed, 245 insertions(+), 15652 deletions(-) delete mode 100644 tools/python/symfunc_paramgen/doc/_build/doctrees/environment.pickle delete mode 100644 tools/python/symfunc_paramgen/doc/_build/doctrees/index.doctree delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/.buildinfo delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_modules/SymFuncParamGenerator.html delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/file.png delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/jquery.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/language_data.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/minus.png delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/plus.png delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/pygments.css delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/searchtools.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/underscore-1.3.1.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/_static/underscore.js delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/genindex.html delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/index.html delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/objects.inv delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/search.html delete mode 100644 tools/python/symfunc_paramgen/doc/_build/html/searchindex.js create mode 100644 tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst create mode 100644 tools/python/symfunc_paramgen/doc/apigen/modules.rst create mode 100644 tools/python/symfunc_paramgen/doc/code_structure.rst.bak rename tools/python/symfunc_paramgen/doc/{_build/html/_sources/index.rst.txt => index.rst.bak} (83%) create mode 100644 tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt diff --git a/tools/python/symfunc_paramgen/doc/_build/doctrees/environment.pickle b/tools/python/symfunc_paramgen/doc/_build/doctrees/environment.pickle deleted file mode 100644 index 7953d2caef7b0c4f0d8f7518e17ab67fa0528ce9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46358 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 - - - - - SymFuncParamGenerator — symfunc_paramgen 1.0 documentation - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Source code for SymFuncParamGenerator

-# -*- coding: utf-8 -*-
-
-import numpy as np
-import sys
-import inspect
-import itertools
-import warnings
-
-
-
[docs]class SymFuncParamGenerator: - """Tools for generation, storage, and writing in the format required by n2p2, of symmetry function parameter sets. - - Parameters - ---------- - elements : list of string - The chemical elements present in the system. - r_cutoff : float - Cutoff radius, at which symmetry functions go to zero. - Must be greater than zero. - - Attributes - ---------- - symfunc_type_numbers : dict - Dictionary mapping strings specifying the symmetry function type to the - numbers used internally by n2p2 to distinguish symmetry function types. - lambdas : numpy.ndarray - Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. - radial_paramgen_settings : dict or None - Stores settings that were used in generating the symmetry function parameters r_shift and eta - using the class method provided for that purpose. - None, if no radial parameters have been generated yet, or if custom ones - (without using the method for generating radial parameters) were set. - _r_shift_grid : numpy.ndarray or None - The set of values for the symmetry function parameter r_shift that was generated. - _eta_grid : numpy.ndarray or None - The set of values for the symmetry function parameter eta that was generated. - elements - element_combinations - r_cutoff - symfunc_type - zetas - """ - - symfunc_type_numbers = dict(radial=2, - angular_narrow=3, - angular_wide=9, - weighted_radial=12, - weighted_angular=13) - lambdas = np.array([-1.0, 1.0]) - - def __init__(self, elements, r_cutoff: float): - self._elements = elements - if not r_cutoff > 0: - raise ValueError('Invalid cutoff radius given. ' - 'Must be greater than zero.') - else: - self._r_cutoff = r_cutoff - - self._element_combinations = None - self._symfunc_type = None - self._zetas = None - - self._r_shift_grid = None - self._eta_grid = None - self.radial_paramgen_settings = None - - @property - def elements(self): - """The chemical elements present in the system (list of string, read-only). - """ - return self._elements - - @property - def element_combinations(self): - """Combinations of elements (list of tuple of string, read-only). - - This is computed and set automatically by the setter for symfunc_type. - """ - return self._element_combinations - - @property - def symfunc_type(self): - """Type of symmetry function for which parameters are to be generated (`str`). - - When the setter for this is called it also checks the validity of - the input, builds the necessary element combinations for the given - symmetry function type, and stores it to member variable. - - If the given symmetry function type is a radial one, - the setter also clears any preexisting zetas - (i.e., sets the member variable zetas to None). - - Raises - ------ - ValueError - If invalid symmetry function type is given. - """ - return self._symfunc_type - - @symfunc_type.setter - def symfunc_type(self, value): - if value not in self.symfunc_type_numbers.keys(): - raise ValueError('Invalid symmetry function type. Must be one of {}'.format( - list(self.symfunc_type_numbers.keys()))) - else: - self._symfunc_type = value - # once symmetry function type has been set and found to be valid, - # build and store the element combinations - self._element_combinations = self.find_element_combinations() - # Clear any previous zeta values, if the given symfunc type is a radial one - if value in ['radial', 'weighted_radial']: - # set the member variable explicitly (with underscore) instead of - # calling setter, because the setter would put None into an array - self._zetas = None - - @property - def r_cutoff(self): - '''Cutoff radius where symmetry functions go to zero (float, read-only). - ''' - return self._r_cutoff - - @property - def zetas(self): - """Set of values for the parameter zeta of angular symmetry functions (`numpy.ndarray`). - """ - return self._zetas - - @zetas.setter - def zetas(self, values): - # TODO: possibly add checks on values for zeta -> but how? - self._zetas = np.array(values) - - @property - def r_shift_grid(self): - return self._r_shift_grid - - @property - def eta_grid(self): - return self._eta_grid - -
[docs] def check_symfunc_type(self, calling_method_name=None): - """Check if a symmetry function type has been set. - - Parameters - ---------- - calling_method_name : string, optional - The name of another method that calls this method. - If this parameter is given, a modified error message is printed - by this method, mentioning the method from which it was called. - This should make it clearer to the user in which part - of their own code to look for an error. - - Raises - ------ - TypeError - If the symmetry function type has not been set (i.e., it is None). - - Returns - ------- - None - """ - if self.symfunc_type is None: - if calling_method_name is None: - raise ValueError('Symmetry function type not set.') - else: - raise ValueError(f'Symmetry function type not set. ' - f'Calling method {calling_method_name} requires' - f' that symmetry function type have been set before.')
- -
[docs] def generate_radial_params(self, rule, mode, nb_param_pairs: int, - r_lower=None, r_upper=None): - """Generate a set of values for r_shift and eta. - - Such a set of (r_shift, eta)-values is required for any - symmetry function type. - Its generation is independent of the symmetry function type - and the angular symmetry function parameters zeta and lambda. - - Rules for parameter generation are implemented based on [1]_ and [2]_. - - The generated values are stored as arrays in the member variables _r_shift_grid and _eta_grid. - The entries are to be understood pairwise, i.e., the i-th entry of _r_shift_grid - and the i-th entry of _eta_grid belong to one symmetry function. - Besides the set of values for r_shift and eta, the settings that - were used for generating it are also stored, in the dictionary radial_paramgen_settings. - - Parameters - ---------- - rule : {'gastegger2018', 'imbalzano2018'} - If rule=='gastegger2018' use the parameter generation rules presented in [1]_. - If rule=='imbalzano2018' use the parameter generation rules presented in [2]_. - mode : {'center', 'shift'} - Selects which parameter generation procedure to use, on top of the rule argument, - since there are again two different varieties presented in each of the two papers. - 'center' sets r_shift to zero for all symmetry functions, varying only eta. - 'shift' creates parameter sets where r_shift varies. - The exact implementation details differ depending on - the rule parameter and are described in the papers. - nb_param_pairs : int - Number of (r_shift, eta)-pairs to be generated. - r_lower : float - lowest value in the radial grid from which r_shift and eta values - are computed. - required if rule=='gastegger2018'. - ignored if rule=='imbalzano2018'. - r_upper : float, optional - Largest value in the radial grid from which r_shift and eta - values are computed. - Optional if rule=='gastegger2018, defaults to cutoff radius if not - given. - Ignored if rule=='imbalzano2018'. - - Raises - ------ - ValueError - If nb_param_pairs is not two or greater. - TypeError - If parameter r_lower is not given, when using rule 'gastegger2018'. - ValueError - If illegal relation between r_lower, r_upper, r_cutoff. - ValueError - If invalid argument for parameters rule or mode. - - Notes - ----- - [1] https://doi.org/10.1063/1.5019667 - [2] https://doi.org/10.1063/1.5024611 - - The parameter nb_param_pairs invariably specifies the number of - (r_shift, eta)-pairs ultimately generated, not the number of - intervals between points in a grid of r_shift values, or the - number of points in some auxiliary grid. - This constitutes a slight modification of the nomenclature in [2]_, - for the sake of consistent behavior across all options for rule and - mode. - - While the parameter generation by this method does not itself - depend on symmetry function type, be aware of the exact mathematical - expressions for the different symmetry function types and how the - parameters r_shift and eta appear slightly differently in each of them. - - All this method does is implement the procedures described in the two - papers for generating values of the symmetry function parameters - r_shift and eta. As far as this module is concerned, these can then - be used (with the above caveat) in combination with any symmetry - function type. However, this does not imply that their use with all - the different types of symmetry functions is actually discussed in - the papers or was necessarily intended by the authors. - - Returns - ------- - None - """ - if not nb_param_pairs >= 2: - raise ValueError('nb_param_pairs must be two or greater.') - - # store those infos on radial parameter generation settings that are - # independent of the rule argument - self.radial_paramgen_settings = dict(rule=rule, - mode=mode, - nb_param_pairs=nb_param_pairs) - - r_cutoff = self.r_cutoff - - if rule == 'gastegger2018': - if r_lower is None: - raise TypeError('Argument r_lower is required for rule "gastegger2018"') - if r_upper is None: - # by default, set largest value of radial grid to cutoff radius - r_upper = r_cutoff - - # store those settings that are unique to this rule - self.radial_paramgen_settings.update({'r_lower': r_lower, 'r_upper': r_upper}) - - # create auxiliary grid - grid = np.linspace(r_lower, r_upper, nb_param_pairs) - - if mode == 'center': - # r_lower = 0 is not allowed in center mode, - # because it causes division by zero - if not 0 < r_lower < r_upper <= r_cutoff: - raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 < r_lower < r_upper <= r_cutoff.') - r_shift_grid = np.zeros(nb_param_pairs) - eta_grid = 1.0 / (2.0 * grid ** 2) - elif mode == 'shift': - # on the other hand, in shift mode, r_lower = 0 is possible - if not 0 <= r_lower < r_upper <= r_cutoff: - raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 <= r_lower < r_upper <= r_cutoff.') - r_shift_grid = grid - # compute the equidistant grid spacing - dr = (r_upper - r_lower) / (nb_param_pairs - 1) - eta_grid = np.full(nb_param_pairs, 1.0 / (2.0 * dr * dr)) - else: - raise ValueError('invalid argument for "mode"') - - elif rule == 'imbalzano2018': - if r_lower is not None: - this_method_name = inspect.currentframe().f_code.co_name - warnings.warn(f'The argument r_lower to method' - f' {this_method_name} will be ignored,' - f' since it is unused when calling the method' - f' with rule="imbalzano2018".') - if r_upper is not None: - this_method_name = inspect.currentframe().f_code.co_name - warnings.warn(f'The argument r_upper to method' - f' {this_method_name} will be ignored,' - f' since it is unused when calling the method' - f' with rule="imbalzano2018".') - - if mode == 'center': - nb_intervals = nb_param_pairs - 1 - gridpoint_indices = np.array(range(0, nb_intervals + 1)) - eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) / r_cutoff) ** 2 - r_shift_grid = np.zeros_like(eta_grid) - elif mode == 'shift': - # create extended auxiliary grid of r_shift values, - # that contains nb_param_pairs + 1 values - nb_intervals_extended = nb_param_pairs - gridpoint_indices_extended = np.array(range(0, nb_intervals_extended + 1)) - rs_grid_extended = r_cutoff / nb_intervals_extended ** ( - gridpoint_indices_extended / nb_intervals_extended) - # from pairs of neighboring r_shift values, compute eta values. - # doing this for the nb_param_pairs + 1 values in the auxiliary - # grid ultimately gives nb_param_pairs different values for eta. - eta_grid = np.zeros(nb_param_pairs) - for idx in range(len(rs_grid_extended) - 1): - eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 - eta_grid[idx] = eta_current - # create final grid of r_shift values by excluding the first entry - # (for which r_shift coincides with the cutoff radius) from the extended grid - r_shift_grid = rs_grid_extended[1:] - # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift - # (not necessary, but makes the output consistent with the other options) - r_shift_grid = np.flip(r_shift_grid) - eta_grid = np.flip(eta_grid) - else: - raise ValueError('invalid argument for "mode"') - else: - raise ValueError('invalid argument for "rule"') - - # store the generated parameter sets - self._r_shift_grid = r_shift_grid - self._eta_grid = eta_grid
- -
[docs] def set_custom_radial_params(self, r_shift_values, eta_values): - """Set custom r_shift and eta, bypassing the class's generation method. - - The parameters r_shift_values and eta_values must have the same - length. - Ttheir entries are to be understood pairwise, i.e., - the i-th entry of r_shift_values and the i-th entry of eta_values - belong together, describing one symmetry function. - - Parameters - ---------- - r_shift_values : sequence of float or 1D-array - Set of values for the symmetry function parameter r_shift. - eta_values : sequence of float or 1D-array - Set of values for the symmetry function parameter eta. - - Raises - ------ - TypeError - If r_shift_values and eta_values do not have equal length. - ValueError - If r_shift_values or eta_values contain non-positive entries. - - Notes - ----- - Setting r_shift and eta manually via this method instead of using the - method generate_radial_params somewhat defeats the purpose of the - class as a generator of symmetry function parameter values. However, - it might still be useful, in case one wants to use custom values for - r_shift and eta, for which the generation is not implemented as a - class method, while still benefiting from the parameter writing - functionality of the class. - - Returns - ------- - None - """ - if len(r_shift_values) != len(eta_values): - raise TypeError('r_shift_values and eta_values must have same length.') - if min(r_shift_values) <= 0: - raise ValueError('r_shift_values must all be greater than zero.') - if min(eta_values) <= 0: - raise ValueError('eta_values must all be greater than zero.') - # (re)set radial_paramgen_settings to None, indicating that custom - # values for (r_shift, eta) are used, rather than ones generated by - # class method. - self.radial_paramgen_settings = None - # set the values - self._r_shift_grid = np.array(r_shift_values) - self._eta_grid = np.array(eta_values)
- -
[docs] def check_writing_prerequisites(self, calling_method_name=None): - """Check if all data required for writing symmetry function sets are present. - - This comprises checking if the following have been set: - -) symmetry function type - -) values for r_shift and eta - -) values for zeta, if the symmetry function type is an angular one - - Parameters - ---------- - calling_method_name : string, optional - The name of another method that calls this method. - If this parameter is given, a modified error message is printed, - mentioning the method from which this error-raising method - was called. - This should make it clearer to a user in which part - of their code to look for an error. - - Raises - ------ - TypeError - If values for r_shift or eta are not set. - TypeError - If an angular symmetry function type has been set, but no values - for zeta were set. - - Returns - ------- - None - """ - self.check_symfunc_type(calling_method_name=calling_method_name) - - if calling_method_name is None: - if self._r_shift_grid is None or self._eta_grid is None: - raise ValueError('Values for r_shift and/or eta not set.') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - if self.zetas is None: - raise ValueError( - f'Values for zeta not set (required for symmetry' - f' function type {self.symfunc_type}).\n' - f' If you are seeing this error despite having previously set zetas, make sure\n' - f' they have not been cleared since by setting a non-angular symmetry function type.') - else: - if self._r_shift_grid is None or self._eta_grid is None: - raise ValueError(f'Values for r_shift and/or eta not set. ' - f'Calling method {calling_method_name} requires' - f' that values for r_shift and eta have been set before.') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - if self.zetas is None: - raise ValueError( - f'Values for zeta not set.\n ' - f'Calling {calling_method_name}, while using symmetry function type {self.symfunc_type},\n' - f' requires zetas to have been set before.\n ' - f'If you are seeing this error despite having previously set zetas, make sure\n' - f' they have not been cleared since by setting a non-angular symmetry function type.')
- -
[docs] def write_settings_overview(self, file=None): - """Write settings used in generating the currently stored set of symmetry function parameters. - - Parameters - ---------- - file : path-like, optional - The file to write the settings information to, using append mode. - If not specified, write to sys.stdout instead. - - Returns - ------- - None - """ - this_method_name = inspect.currentframe().f_code.co_name - self.check_writing_prerequisites(calling_method_name=this_method_name) - - type_descriptions = dict(radial='Radial', - angular_narrow='Narrow angular', - angular_wide='Wide angular', - weighted_radial='Weighted radial', - weighted_angular='Weighted angular') - - # depending on presence of file parameter, either direct output - # to stdout, or open the specified file, in append mode - handle = open(file, 'a') if file is not None else sys.stdout - - handle.write('#########################################################################\n') - handle.write( - f'# {type_descriptions[self.symfunc_type]} symmetry function set, ' - f'for elements {self.elements}\n') - handle.write('#########################################################################\n') - - handle.write(f'# r_cutoff = {self.r_cutoff}\n') - - # depending on whether radial parameters were generated using the method - # or custom-set (indicated by presence or absence of radial parameter - # generation settings), write the settings used or not - if self.radial_paramgen_settings is not None: - handle.write('# The following settings were used for generating sets\n') - handle.write('# of values for the radial parameters r_shift and eta:\n') - for key, value in self.radial_paramgen_settings.items(): - handle.write(f'# {key:14s} = {value}\n') - else: - handle.write('# A custom set of values was used for the radial parameters r_shift and eta.\n') - handle.write('# Thus, there are no settings on radial parameter generation available for display.\n') - - handle.write('# Sets of values for parameters:\n') - # set numpy print precision to lower number of decimal places for the following outputs - np.set_printoptions(precision=4) - handle.write(f'# r_shift_grid = {self._r_shift_grid}\n') - handle.write(f'# eta_grid = {self._eta_grid}\n') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - handle.write(f'# lambdas = {self.lambdas}\n') - handle.write(f'# zetas = {self.zetas}\n') - # reset numpy print precision to default - np.set_printoptions(precision=8) - handle.write('\n') - - # close the file again (unless writing to sys.stdout, - # which should not be closed) - if handle is not sys.stdout: - handle.close()
- -
[docs] def find_element_combinations(self): - """Create combinations of elements, depending on symmetry function type and the elements in the system. - - For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, - including of an element with itself. - For angular symmetry functions (narrow or wide), the combinations consist of all possible elements as the - central atom, and then again for each central element all possible unordered pairs of neighbor elements. - For weighted symmetry functions (radial or angular), the combinations run only over all possible - central elements, with neighbors not taken into account at this stage. - - Returns - ------- - combinations : list of tuple of string - Each tuple in the list represents one element combination. - Length of the individual tuples can be 1, 2 or 3, depending on symmetry function type. - Zero-th entry of tuples is always the type of the central atom, 1st and 2nd entry are neighbor atom types - (radial sf: one neighbor, angular sf: two neighbors, weighted sf: no neighbors) - """ - this_method_name = inspect.currentframe().f_code.co_name - self.check_symfunc_type(calling_method_name=this_method_name) - - combinations = [] - - if self.symfunc_type == 'radial': - for elem_central in self.elements: - for elem_neighbor in self.elements: - combinations.append((elem_central, elem_neighbor)) - elif self.symfunc_type in ['angular_narrow', 'angular_wide']: - for elem_central in self.elements: - for pair_of_neighbors in itertools.combinations_with_replacement(self.elements, 2): - comb = (elem_central,) + pair_of_neighbors - combinations.append(comb) - elif self.symfunc_type in ['weighted_radial', 'weighted_angular']: - for elem_central in self.elements: - combinations.append((elem_central,)) - - return combinations
- -
[docs] def write_parameter_strings(self, file=None): - """Write symmetry function parameter sets, formatted as n2p2 requires. - - Each line in the output corresponds to one symmetry function. - - Output is formatted in blocks separated by blank lines, each block - corresponding to one element combination. The different blocks differ - from each other only in the element combinations and are otherwise - the same. - - Within each block, all combinations of the other parameters - r_shift, eta, lambda, zeta (the latter two only for angular - symmetry function types), are iterated over. - Note, however, that the value pairs for r_shift and eta are not - all the possible combinations of elements in r_shift_grid and eta_grid, - but only the combinations of the i-th entries of r_shift_grid with - the i-th entries of eta_grid. - - Schematic example: When r_shift_grid = [1, 2], eta_grid = [3, 4], - zetas = [5, 6], lambdas = [-1, 1] (the latter not being intended to be - set by the user, anyway), within each block of the output, the - method iterates over the following combinations of - (r_shift, eta, zeta, lambda): - [(1, 3, 5, -1), - (1, 3, 5, 1), - (1, 3, 6, -1), - (1, 3, 6, 1), - (2, 4, 5, -1), - (2, 4, 5, 1), - (2, 4, 6, -1), - (2, 4, 6, 1)] - - Parameters - ---------- - file : path-like, optional - The file to write the parameter strings to, using append mode. - If not specified, write to sys.stdout instead. - - Returns - ------- - None - """ - this_method_name = inspect.currentframe().f_code.co_name - self.check_writing_prerequisites(calling_method_name=this_method_name) - - # depending on presence of file parameter, either direct output - # to stdout, or open the specified file, in append mode - handle = open(file, 'a') if file is not None else sys.stdout - - r_cutoff = self.r_cutoff - sf_number = self.symfunc_type_numbers[self.symfunc_type] - - if self.symfunc_type == 'radial': - for comb in self.element_combinations: - for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): - handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') - handle.write('\n') - - elif self.symfunc_type in ['angular_narrow', 'angular_wide']: - for comb in self.element_combinations: - for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): - for zeta in self.zetas: - for lambd in self.lambdas: - handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {comb[2]:2s} {eta:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} {rs:9.3E}\n') - handle.write('\n') - - elif self.symfunc_type == 'weighted_radial': - for comb in self.element_combinations: - for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): - handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') - handle.write('\n') - - elif self.symfunc_type == 'weighted_angular': - for comb in self.element_combinations: - for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): - for zeta in self.zetas: - for lambd in self.lambdas: - handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} \n') - handle.write('\n') - - # close the file again (unless writing to sys.stdout, - # which should not be closed) - if handle is not sys.stdout: - handle.close()
-
- -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html b/tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html deleted file mode 100644 index 2a45a21ed..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/_modules/index.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - Overview: module code — symfunc_paramgen 1.0 documentation - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

All modules for which code is available

- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css b/tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css deleted file mode 100644 index 0eddaeb07..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/_static/alabaster.css +++ /dev/null @@ -1,701 +0,0 @@ -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Georgia, serif; - font-size: 17px; - background-color: #fff; - color: #000; - margin: 0; - padding: 0; -} - - -div.document { - width: 940px; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; - font-size: 14px; - line-height: 1.5; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #fff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -div.body > .section { - text-align: left; -} - -div.footer { - width: 940px; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -p.caption { - font-family: inherit; - font-size: inherit; -} - - -div.relations { - display: none; -} - - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0; - margin: -10px 0 0 0px; - text-align: center; -} - -div.sphinxsidebarwrapper h1.logo { - margin-top: -10px; - text-align: center; - margin-bottom: 5px; - text-align: left; -} - -div.sphinxsidebarwrapper h1.logo-name { - margin-top: 0px; -} - -div.sphinxsidebarwrapper p.blurb { - margin-top: 0; - font-style: normal; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Georgia, serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar ul li.toctree-l1 > a { - font-size: 120%; -} - -div.sphinxsidebar ul li.toctree-l2 > a { - font-size: 110%; -} - -div.sphinxsidebar input { - border: 1px solid #CCC; - font-family: Georgia, serif; - font-size: 1em; -} - -div.sphinxsidebar hr { - border: none; - height: 1px; - color: #AAA; - background: #AAA; - - text-align: left; - margin-left: 0; - width: 50%; -} - -div.sphinxsidebar .badge { - border-bottom: none; -} - -div.sphinxsidebar .badge:hover { - border-bottom: none; -} - -/* To address an issue with donation coming after search */ -div.sphinxsidebar h3.donation { - margin-top: 10px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: Georgia, serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #DDD; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #EAEAEA; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - margin: 20px 0px; - padding: 10px 30px; - background-color: #EEE; - border: 1px solid #CCC; -} - -div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fafafa; -} - -div.admonition p.admonition-title { - font-family: Georgia, serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: #fff; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.warning { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.danger { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.error { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.caution { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.attention { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.important { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.note { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.tip { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.hint { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.seealso { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.topic { - background-color: #EEE; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt, code { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -.hll { - background-color: #FFC; - margin: 0 -12px; - padding: 0 12px; - display: block; -} - -img.screenshot { -} - -tt.descname, tt.descclassname, code.descname, code.descclassname { - font-size: 0.95em; -} - -tt.descname, code.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #EEE; - background: #FDFDFD; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.field-list p { - margin-bottom: 0.8em; -} - -/* Cloned from - * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 - */ -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -table.footnote td.label { - width: .1px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - /* Matches the 30px from the narrow-screen "li > ul" selector below */ - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #EEE; - padding: 7px 30px; - margin: 15px 0px; - line-height: 1.3em; -} - -div.viewcode-block:target { - background: #ffd; -} - -dl pre, blockquote pre, li pre { - margin-left: 0; - padding-left: 30px; -} - -tt, code { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, code.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fff; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -/* Don't put an underline on images */ -a.image-reference, a.image-reference:hover { - border-bottom: none; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt, a:hover code { - background: #EEE; -} - - -@media screen and (max-width: 870px) { - - div.sphinxsidebar { - display: none; - } - - div.document { - width: 100%; - - } - - div.documentwrapper { - margin-left: 0; - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - } - - div.bodywrapper { - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - margin-left: 0; - } - - ul { - margin-left: 0; - } - - li > ul { - /* Matches the 30px from the "ul, ol" selector above */ - margin-left: 30px; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .bodywrapper { - margin: 0; - } - - .footer { - width: auto; - } - - .github { - display: none; - } - - - -} - - - -@media screen and (max-width: 875px) { - - body { - margin: 0; - padding: 20px 30px; - } - - div.documentwrapper { - float: none; - background: #fff; - } - - div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: #FFF; - } - - div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; - } - - div.sphinxsidebar a { - color: #AAA; - } - - div.sphinxsidebar p.logo { - display: none; - } - - div.document { - width: 100%; - margin: 0; - } - - div.footer { - display: none; - } - - div.bodywrapper { - margin: 0; - } - - div.body { - min-height: 0; - padding: 0; - } - - .rtd_doc_footer { - display: none; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .footer { - width: auto; - } - - .github { - display: none; - } -} - - -/* misc. */ - -.revsys-inline { - display: none!important; -} - -/* Make nested-list/multi-paragraph items look better in Releases changelog - * pages. Without this, docutils' magical list fuckery causes inconsistent - * formatting between different release sub-lists. - */ -div#changelog > div.section > ul > li > p:only-child { - margin-bottom: 0; -} - -/* Hide fugly table cell borders in ..bibliography:: directive output */ -table.docutils.citation, table.docutils.citation td, table.docutils.citation th { - border: none; - /* Below needed in some edge cases; if not applied, bottom shadows appear */ - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - - -/* relbar */ - -.related { - line-height: 30px; - width: 100%; - font-size: 0.9rem; -} - -.related.top { - border-bottom: 1px solid #EEE; - margin-bottom: 20px; -} - -.related.bottom { - border-top: 1px solid #EEE; -} - -.related ul { - padding: 0; - margin: 0; - list-style: none; -} - -.related li { - display: inline; -} - -nav#rellinks { - float: right; -} - -nav#rellinks li+li:before { - content: "|"; -} - -nav#breadcrumbs li+li:before { - content: "\00BB"; -} - -/* Hide certain items when printing */ -@media print { - div.related { - display: none; - } -} \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css b/tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css deleted file mode 100644 index 53acd096a..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/_static/basic.css +++ /dev/null @@ -1,748 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px 7px 0 7px; - background-color: #ffe; - width: 40%; - float: right; -} - -p.sidebar-title { - font-weight: bold; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px 7px 0 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -div.admonition dl { - margin-bottom: 0; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > p:first-child, -td > p:first-child { - margin-top: 0px; -} - -th > p:last-child, -td > p:last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist td { - vertical-align: top; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -li > p:first-child { - margin-top: 0px; -} - -li > p:last-child { - margin-bottom: 0px; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: flex; - flex-wrap: wrap; -} - -dl.field-list > dt { - flex-basis: 20%; - font-weight: bold; - word-break: break-word; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - flex-basis: 70%; - padding-left: 1em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > p:first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0.5em; - content: ":"; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -td.linenos pre { - padding: 5px 0px; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -div.code-block-caption { - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -div.code-block-caption + div > div.highlight > pre { - margin-top: 0; -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - padding: 1em 1em 0; -} - -div.literal-block-wrapper div.highlight { - margin: 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: relative; - left: 0px; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css b/tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css deleted file mode 100644 index 2a924f1d6..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/_static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* This file intentionally left blank. */ diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js b/tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js deleted file mode 100644 index b33f87fcb..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/_static/doctools.js +++ /dev/null @@ -1,314 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keyup(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box or textarea - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js b/tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js deleted file mode 100644 index ad3a3d995..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/_static/documentation_options.js +++ /dev/null @@ -1,10 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '1.0', - LANGUAGE: 'None', - COLLAPSE_INDEX: false, - FILE_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false -}; \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/file.png b/tools/python/symfunc_paramgen/doc/_build/html/_static/file.png deleted file mode 100644 index a858a410e4faa62ce324d814e4b816fff83a6fb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js b/tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js deleted file mode 100644 index d2d8ca479..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/_static/jquery-3.2.1.js +++ /dev/null @@ -1,10253 +0,0 @@ -/*! - * jQuery JavaScript Library v3.2.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2017-03-20T18:59Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - - - - function DOMEval( code, doc ) { - doc = doc || document; - - var script = doc.createElement( "script" ); - - script.text = code; - doc.head.appendChild( script ).parentNode.removeChild( script ); - } -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.2.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - - // parseFloat NaNs numeric-cast false positives ("") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - !isNaN( obj - parseFloat( obj ) ); - }, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 13 - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.3 - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-08-08 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - disabledAncestor = addCombinator( - function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( el ) { - el.className = "i"; - return !el.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID filter and find - if ( support.getById ) { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( el ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( el ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Simple selector that can be filtered directly, removing non-Elements - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - // Complex selector, compare the two sets, removing non-Elements - qualifier = jQuery.filter( qualifier, elements ); - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; - } ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( jQuery.isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ jQuery.camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ jQuery.camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( jQuery.camelCase ); - } else { - key = jQuery.camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - jQuery.contains( elem.ownerDocument, elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - do { - - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; - - // Adjust and apply - initialInUnit = initialInUnit / scale; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); - -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); - - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // Support: IE <=9 only - option: [ 1, "" ], - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); -var documentElement = document.documentElement; - - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 only -// See #13393 for more info -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: jQuery.isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - - // Support: IE <=10 - 11, Edge 12 - 13 - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( ">tbody", elem )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); - events = pdataOld.events; - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( isFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rmargin = ( /^margin/ ); - -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - div.style.cssText = - "box-sizing:border-box;" + - "position:relative;display:block;" + - "margin:auto;border:1px;padding:1px;" + - "top:1%;width:50%"; - div.innerHTML = ""; - documentElement.appendChild( container ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = divStyle.marginLeft === "2px"; - boxSizingReliableVal = divStyle.width === "4px"; - - // Support: Android 4.0 - 4.3 only - // Some styles come back with percentage values, even though they shouldn't - div.style.marginRight = "50%"; - pixelMarginRightVal = divStyle.marginRight === "4px"; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + - "padding:0;margin-top:1px;position:absolute"; - container.appendChild( div ); - - jQuery.extend( support, { - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelMarginRight: function() { - computeStyleTests(); - return pixelMarginRightVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property -function vendorPropName( name ) { - - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. -function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; - } - return ret; -} - -function setPositiveNumber( elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i, - val = 0; - - // If we already have the right measurement, avoid augmentation - if ( extra === ( isBorderBox ? "border" : "content" ) ) { - i = 4; - - // Otherwise initialize for horizontal or vertical properties - } else { - i = name === "width" ? 1 : 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // At this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - - // At this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // At this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with computed style - var valueIsBorderBox, - styles = getStyles( elem ), - val = curCSS( elem, name, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test( val ) ) { - return val; - } - - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && - ( support.boxSizingReliable() || val === elem.style[ name ] ); - - // Fall back to offsetWidth/Height when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - if ( val === "auto" ) { - val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; - } - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - - // Use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - "float": "cssFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - } ) : - getWidthOrHeight( elem, name, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = extra && getStyles( elem ), - subtract = extra && augmentWidthOrHeight( - elem, - name, - extra, - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - styles - ); - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ name ] = value; - value = jQuery.css( elem, name ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = jQuery.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 13 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( jQuery.isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - jQuery.proxy( result.stop, result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = jQuery.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value; - - if ( typeof stateVal === "boolean" && type === "string" ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( jQuery.isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( type === "string" ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = value.match( rnothtmlwhite ) || []; - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, isFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup contextmenu" ).split( " " ), - function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; -} ); - -jQuery.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - - - - -support.focusin = "onfocusin" in window; - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = jQuery.now(); - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = jQuery.isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( jQuery.isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match == null ? null : match; - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 13 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available, append data to url - if ( s.data ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - - -jQuery._evalUrl = function( url ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - "throws": true - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/index.html b/tools/python/symfunc_paramgen/doc/_build/html/index.html deleted file mode 100644 index fdf8f4961..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/index.html +++ /dev/null @@ -1,491 +0,0 @@ - - - - - - - Welcome to symfunc_paramgen’s documentation! — symfunc_paramgen 1.0 documentation - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Welcome to symfunc_paramgen’s documentation!¶

-
-
-
-
-

Indices and tables¶

- -
-
-class SymFuncParamGenerator.SymFuncParamGenerator(elements, r_cutoff: float)[source]¶
-

Tools for generation, storage, and writing in the format required by n2p2, of symmetry function parameter sets.

-
-
Parameters
-
-
elementslist of string

The chemical elements present in the system.

-
-
r_cutofffloat

Cutoff radius, at which symmetry functions go to zero. -Must be greater than zero.

-
-
-
-
Attributes
-
-
symfunc_type_numbersdict

Dictionary mapping strings specifying the symmetry function type to the -numbers used internally by n2p2 to distinguish symmetry function types.

-
-
lambdasnumpy.ndarray

Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1].

-
-
radial_paramgen_settingsdict or None

Stores settings that were used in generating the symmetry function parameters r_shift and eta -using the class method provided for that purpose. -None, if no radial parameters have been generated yet, or if custom ones -(without using the method for generating radial parameters) were set.

-
-
_r_shift_gridnumpy.ndarray or None

The set of values for the symmetry function parameter r_shift that was generated.

-
-
_eta_gridnumpy.ndarray or None

The set of values for the symmetry function parameter eta that was generated.

-
-
elements

The chemical elements present in the system (list of string, read-only).

-
-
element_combinations

Combinations of elements (list of tuple of string, read-only).

-
-
r_cutoff

Cutoff radius where symmetry functions go to zero (float, read-only).

-
-
symfunc_type

Type of symmetry function for which parameters are to be generated (str).

-
-
zetas

Set of values for the parameter zeta of angular symmetry functions (numpy.ndarray).

-
-
-
-
-

Methods

- ---- - - - - - - - - - - - - - - - - - - - - - - - -

check_symfunc_type(self[, calling_method_name])

Check if a symmetry function type has been set.

check_writing_prerequisites(self[, …])

Check if all data required for writing symmetry function sets are present.

find_element_combinations(self)

Create combinations of elements, depending on symmetry function type and the elements in the system.

generate_radial_params(self, rule, mode, …)

Generate a set of values for r_shift and eta.

set_custom_radial_params(self, …)

Set custom r_shift and eta, bypassing the class’s generation method.

write_parameter_strings(self[, file])

Write symmetry function parameter sets, formatted as n2p2 requires.

write_settings_overview(self[, file])

Write settings used in generating the currently stored set of symmetry function parameters.

-
-
-check_symfunc_type(self, calling_method_name=None)[source]¶
-

Check if a symmetry function type has been set.

-
-
Parameters
-
-
calling_method_namestring, optional

The name of another method that calls this method. -If this parameter is given, a modified error message is printed -by this method, mentioning the method from which it was called. -This should make it clearer to the user in which part -of their own code to look for an error.

-
-
-
-
Returns
-
-
None
-
-
-
Raises
-
-
TypeError

If the symmetry function type has not been set (i.e., it is None).

-
-
-
-
-
- -
-
-check_writing_prerequisites(self, calling_method_name=None)[source]¶
-

Check if all data required for writing symmetry function sets are present.

-

This comprises checking if the following have been set: --) symmetry function type --) values for r_shift and eta --) values for zeta, if the symmetry function type is an angular one

-
-
Parameters
-
-
calling_method_namestring, optional

The name of another method that calls this method. -If this parameter is given, a modified error message is printed, -mentioning the method from which this error-raising method -was called. -This should make it clearer to a user in which part -of their code to look for an error.

-
-
-
-
Returns
-
-
None
-
-
-
Raises
-
-
TypeError

If values for r_shift or eta are not set.

-
-
TypeError

If an angular symmetry function type has been set, but no values -for zeta were set.

-
-
-
-
-
- -
-
-element_combinations¶
-

Combinations of elements (list of tuple of string, read-only).

-

This is computed and set automatically by the setter for symfunc_type.

-
- -
-
-elements¶
-

The chemical elements present in the system (list of string, read-only).

-
- -
-
-find_element_combinations(self)[source]¶
-

Create combinations of elements, depending on symmetry function type and the elements in the system.

-

For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, -including of an element with itself. -For angular symmetry functions (narrow or wide), the combinations consist of all possible elements as the -central atom, and then again for each central element all possible unordered pairs of neighbor elements. -For weighted symmetry functions (radial or angular), the combinations run only over all possible -central elements, with neighbors not taken into account at this stage.

-
-
Returns
-
-
combinationslist of tuple of string

Each tuple in the list represents one element combination. -Length of the individual tuples can be 1, 2 or 3, depending on symmetry function type. -Zero-th entry of tuples is always the type of the central atom, 1st and 2nd entry are neighbor atom types -(radial sf: one neighbor, angular sf: two neighbors, weighted sf: no neighbors)

-
-
-
-
-
- -
-
-generate_radial_params(self, rule, mode, nb_param_pairs: int, r_lower=None, r_upper=None)[source]¶
-

Generate a set of values for r_shift and eta.

-

Such a set of (r_shift, eta)-values is required for any -symmetry function type. -Its generation is independent of the symmetry function type -and the angular symmetry function parameters zeta and lambda.

-

Rules for parameter generation are implemented based on [1]_ and [2]_.

-

The generated values are stored as arrays in the member variables _r_shift_grid and _eta_grid. -The entries are to be understood pairwise, i.e., the i-th entry of _r_shift_grid -and the i-th entry of _eta_grid belong to one symmetry function. -Besides the set of values for r_shift and eta, the settings that -were used for generating it are also stored, in the dictionary radial_paramgen_settings.

-
-
Parameters
-
-
rule{‘gastegger2018’, ‘imbalzano2018’}

If rule==’gastegger2018’ use the parameter generation rules presented in [1]_. -If rule==’imbalzano2018’ use the parameter generation rules presented in [2]_.

-
-
mode{‘center’, ‘shift’}

Selects which parameter generation procedure to use, on top of the rule argument, -since there are again two different varieties presented in each of the two papers. -‘center’ sets r_shift to zero for all symmetry functions, varying only eta. -‘shift’ creates parameter sets where r_shift varies. -The exact implementation details differ depending on -the rule parameter and are described in the papers.

-
-
nb_param_pairsint

Number of (r_shift, eta)-pairs to be generated.

-
-
r_lowerfloat

lowest value in the radial grid from which r_shift and eta values -are computed. -required if rule==’gastegger2018’. -ignored if rule==’imbalzano2018’.

-
-
r_upperfloat, optional

Largest value in the radial grid from which r_shift and eta -values are computed. -Optional if rule==’gastegger2018, defaults to cutoff radius if not -given. -Ignored if rule==’imbalzano2018’.

-
-
-
-
Returns
-
-
None
-
-
-
Raises
-
-
ValueError

If nb_param_pairs is not two or greater.

-
-
TypeError

If parameter r_lower is not given, when using rule ‘gastegger2018’.

-
-
ValueError

If illegal relation between r_lower, r_upper, r_cutoff.

-
-
ValueError

If invalid argument for parameters rule or mode.

-
-
-
-
-

Notes

-

[1] https://doi.org/10.1063/1.5019667 -[2] https://doi.org/10.1063/1.5024611

-

The parameter nb_param_pairs invariably specifies the number of -(r_shift, eta)-pairs ultimately generated, not the number of -intervals between points in a grid of r_shift values, or the -number of points in some auxiliary grid. -This constitutes a slight modification of the nomenclature in [2]_, -for the sake of consistent behavior across all options for rule and -mode.

-

While the parameter generation by this method does not itself -depend on symmetry function type, be aware of the exact mathematical -expressions for the different symmetry function types and how the -parameters r_shift and eta appear slightly differently in each of them.

-

All this method does is implement the procedures described in the two -papers for generating values of the symmetry function parameters -r_shift and eta. As far as this module is concerned, these can then -be used (with the above caveat) in combination with any symmetry -function type. However, this does not imply that their use with all -the different types of symmetry functions is actually discussed in -the papers or was necessarily intended by the authors.

-
- -
-
-r_cutoff¶
-

Cutoff radius where symmetry functions go to zero (float, read-only).

-
- -
-
-set_custom_radial_params(self, r_shift_values, eta_values)[source]¶
-

Set custom r_shift and eta, bypassing the class’s generation method.

-

The parameters r_shift_values and eta_values must have the same -length. -Ttheir entries are to be understood pairwise, i.e., -the i-th entry of r_shift_values and the i-th entry of eta_values -belong together, describing one symmetry function.

-
-
Parameters
-
-
r_shift_valuessequence of float or 1D-array

Set of values for the symmetry function parameter r_shift.

-
-
eta_valuessequence of float or 1D-array

Set of values for the symmetry function parameter eta.

-
-
-
-
Returns
-
-
None
-
-
-
Raises
-
-
TypeError

If r_shift_values and eta_values do not have equal length.

-
-
ValueError

If r_shift_values or eta_values contain non-positive entries.

-
-
-
-
-

Notes

-

Setting r_shift and eta manually via this method instead of using the -method generate_radial_params somewhat defeats the purpose of the -class as a generator of symmetry function parameter values. However, -it might still be useful, in case one wants to use custom values for -r_shift and eta, for which the generation is not implemented as a -class method, while still benefiting from the parameter writing -functionality of the class.

-
- -
-
-symfunc_type¶
-

Type of symmetry function for which parameters are to be generated (str).

-

When the setter for this is called it also checks the validity of -the input, builds the necessary element combinations for the given -symmetry function type, and stores it to member variable.

-

If the given symmetry function type is a radial one, -the setter also clears any preexisting zetas -(i.e., sets the member variable zetas to None).

-
-
Raises
-
-
ValueError

If invalid symmetry function type is given.

-
-
-
-
-
- -
-
-write_parameter_strings(self, file=None)[source]¶
-

Write symmetry function parameter sets, formatted as n2p2 requires.

-

Each line in the output corresponds to one symmetry function.

-

Output is formatted in blocks separated by blank lines, each block -corresponding to one element combination. The different blocks differ -from each other only in the element combinations and are otherwise -the same.

-

Within each block, all combinations of the other parameters -r_shift, eta, lambda, zeta (the latter two only for angular -symmetry function types), are iterated over. -Note, however, that the value pairs for r_shift and eta are not -all the possible combinations of elements in r_shift_grid and eta_grid, -but only the combinations of the i-th entries of r_shift_grid with -the i-th entries of eta_grid.

-

Schematic example: When r_shift_grid = [1, 2], eta_grid = [3, 4], -zetas = [5, 6], lambdas = [-1, 1] (the latter not being intended to be -set by the user, anyway), within each block of the output, the -method iterates over the following combinations of -(r_shift, eta, zeta, lambda): -[(1, 3, 5, -1),

-
-

(1, 3, 5, 1), -(1, 3, 6, -1), -(1, 3, 6, 1), -(2, 4, 5, -1), -(2, 4, 5, 1), -(2, 4, 6, -1), -(2, 4, 6, 1)]

-
-
-
Parameters
-
-
filepath-like, optional

The file to write the parameter strings to, using append mode. -If not specified, write to sys.stdout instead.

-
-
-
-
Returns
-
-
None
-
-
-
-
- -
-
-write_settings_overview(self, file=None)[source]¶
-

Write settings used in generating the currently stored set of symmetry function parameters.

-
-
Parameters
-
-
filepath-like, optional

The file to write the settings information to, using append mode. -If not specified, write to sys.stdout instead.

-
-
-
-
Returns
-
-
None
-
-
-
-
- -
-
-zetas¶
-

Set of values for the parameter zeta of angular symmetry functions (numpy.ndarray).

-
- -
- -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/objects.inv b/tools/python/symfunc_paramgen/doc/_build/html/objects.inv deleted file mode 100644 index 72078f7a77ffc408ee593b1bb4f1cb35f1a1d9c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 454 zcmV;%0XhC7AX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk&d2MEO zZew3?VRB(@XJu{*BOq2~a&u{KZaN?_E-(rsAXI2&AaZ4GVQFq;WpW^IW*~HEX>%ZE zX>4U6X>%ZBZ*6dLWpi_7WFU2OX>MmAdTeQ8E(&tK%XR)F7JdYK+!9t?gX?h;oLChFwL(Z{H=4&czs56eCUX<5d=OrkTUdBO&a-ja z7}rJ(cFmM+@v<7o=*#S@uUK6*r|MSCIhxcW1hzhg{gJYg1LPAAlj%~7(==j{2^w5m zg1q;Nl9sEvV zUkd*U62Gl=+N8z90<{}0w$Q9zvx9fZV|TMzeWkTd&PhiZkI-q&!N{@0ODsc6oR7En wz*0q=k72ojiz@wvCz_5^eF$Xgef~ys`vBqP@Vz4Ya&nX7528o)34;<5vsRYPbN~PV diff --git a/tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html b/tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html deleted file mode 100644 index e0bf356df..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/py-modindex.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - Python Module Index — symfunc_paramgen 1.0 documentation - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- - -

Python Module Index

- -
- s -
- - - - - - - -
 
- s
- SymFuncParamGenerator -
- - -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/search.html b/tools/python/symfunc_paramgen/doc/_build/html/search.html deleted file mode 100644 index 75a588a98..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/search.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - Search — symfunc_paramgen 1.0 documentation - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Search

-
- -

- Please activate JavaScript to enable the search - functionality. -

-
-

- From here you can search these documents. Enter your search - words into the box below and click "search". Note that the search - function will automatically search for all of the words. Pages - containing fewer words won't appear in the result list. -

-
- - - -
- -
- -
- -
- -
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/_build/html/searchindex.js b/tools/python/symfunc_paramgen/doc/_build/html/searchindex.js deleted file mode 100644 index d767437b6..000000000 --- a/tools/python/symfunc_paramgen/doc/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["index"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst"],objects:{"":{SymFuncParamGenerator:[0,0,0,"-"]},"SymFuncParamGenerator.SymFuncParamGenerator":{check_symfunc_type:[0,2,1,""],check_writing_prerequisites:[0,2,1,""],element_combinations:[0,3,1,""],elements:[0,3,1,""],find_element_combinations:[0,2,1,""],generate_radial_params:[0,2,1,""],r_cutoff:[0,3,1,""],set_custom_radial_params:[0,2,1,""],symfunc_type:[0,3,1,""],write_parameter_strings:[0,2,1,""],write_settings_overview:[0,2,1,""],zetas:[0,3,1,""]},SymFuncParamGenerator:{SymFuncParamGenerator:[0,1,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute"},terms:{"1st":0,"2nd":0,"case":0,"class":0,"default":0,"float":0,"function":0,"int":0,"return":0,"while":0,For:0,Its:0,Such:0,The:0,_eta_grid:0,_r_shift_grid:0,abov:0,account:0,across:0,actual:0,again:0,all:0,also:0,alwai:0,angular:0,ani:0,anoth:0,anywai:0,appear:0,append:0,argument:0,arrai:0,atom:0,attribut:0,author:0,automat:0,auxiliari:0,awar:0,base:0,been:0,behavior:0,being:0,belong:0,benefit:0,besid:0,between:0,blank:0,block:0,build:0,bypass:0,call:0,calling_method_nam:0,can:0,caveat:0,center:0,central:0,check:0,check_symfunc_typ:0,check_writing_prerequisit:0,chemic:0,clear:0,clearer:0,code:0,combin:0,compris:0,comput:0,concern:0,consist:0,constitut:0,contain:0,correspond:0,creat:0,current:0,custom:0,cutoff:0,data:0,defeat:0,depend:0,describ:0,detail:0,dict:0,dictionari:0,differ:0,discuss:0,distinguish:0,doe:0,doi:0,each:0,element:0,element_combin:0,entri:0,equal:0,error:0,eta:0,eta_grid:0,eta_valu:0,exact:0,exampl:0,express:0,far:0,file:0,find_element_combin:0,fix:0,follow:0,format:0,from:0,gastegger2018:0,gener:0,generate_radial_param:0,given:0,greater:0,grid:0,has:0,have:0,how:0,howev:0,http:0,ignor:0,illeg:0,imbalzano2018:0,implement:0,impli:0,includ:0,independ:0,index:0,individu:0,inform:0,input:0,instead:0,intend:0,intern:0,interv:0,invalid:0,invari:0,iter:0,itself:0,lambda:0,largest:0,latter:0,length:0,like:0,line:0,list:0,look:0,lowest:0,make:0,manual:0,map:0,mathemat:0,member:0,mention:0,messag:0,method:0,might:0,mode:0,modif:0,modifi:0,modul:0,must:0,n2p2:0,name:0,narrow:0,nb_param_pair:0,ndarrai:0,necessari:0,necessarili:0,neighbor:0,nomenclatur:0,non:0,none:0,note:0,number:0,numpi:0,one:0,ones:0,onli:0,option:0,order:0,org:0,other:0,otherwis:0,output:0,over:0,own:0,page:0,pair:0,pairwis:0,paper:0,paramet:0,part:0,path:0,point:0,posit:0,possibl:0,preexist:0,present:0,print:0,procedur:0,provid:0,purpos:0,r_cutoff:0,r_lower:0,r_shift:0,r_shift_grid:0,r_shift_valu:0,r_upper:0,radial:0,radial_paramgen_set:0,radiu:0,rais:0,read:0,relat:0,repres:0,requir:0,rule:0,run:0,sake:0,same:0,schemat:0,search:0,select:0,self:0,separ:0,sequenc:0,set:0,set_custom_radial_param:0,setter:0,shift:0,should:0,sinc:0,slight:0,slightli:0,some:0,somewhat:0,sourc:0,specifi:0,stage:0,stdout:0,still:0,storag:0,store:0,str:0,string:0,symfunc_typ:0,symfunc_type_numb:0,symfuncparamgener:0,symmetri:0,sys:0,system:0,taken:0,than:0,them:0,thi:0,togeth:0,tool:0,top:0,ttheir:0,tupl:0,two:0,type:0,typeerror:0,ultim:0,understood:0,unord:0,use:0,used:0,useful:0,user:0,using:0,valid:0,valu:0,valueerror:0,vari:0,variabl:0,varieti:0,via:0,want:0,weight:0,were:0,when:0,where:0,which:0,wide:0,within:0,without:0,write:0,write_parameter_str:0,write_settings_overview:0,yet:0,zero:0,zeta:0},titles:["Welcome to symfunc_paramgen\u2019s documentation!"],titleterms:{document:0,indic:0,symfunc_paramgen:0,tabl:0,welcom:0}}) \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst b/tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst new file mode 100644 index 000000000..96126ba03 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst @@ -0,0 +1,7 @@ +SymFuncParamGenerator module +============================ + +.. automodule:: SymFuncParamGenerator + :members: + :undoc-members: + :show-inheritance: diff --git a/tools/python/symfunc_paramgen/doc/apigen/modules.rst b/tools/python/symfunc_paramgen/doc/apigen/modules.rst new file mode 100644 index 000000000..fd8366931 --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/apigen/modules.rst @@ -0,0 +1,11 @@ +src +=== + +.. toctree:: + :maxdepth: 4 + + SymFuncParamGenerator + generate-acsf-angular_narrow + generate-acsf-angular_wide + generate-acsf-radial + my_local_tests diff --git a/tools/python/symfunc_paramgen/doc/code_structure.rst.bak b/tools/python/symfunc_paramgen/doc/code_structure.rst.bak new file mode 100644 index 000000000..29586a33d --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/code_structure.rst.bak @@ -0,0 +1,7 @@ +Class SymFuncParamGenerator +--------------------------- + +.. currentmodule:: SymFuncParamGenerator + +.. autoclass:: SymFuncParamGenerator + diff --git a/tools/python/symfunc_paramgen/doc/conf.py b/tools/python/symfunc_paramgen/doc/conf.py index 3e87eb10d..6b7fee253 100644 --- a/tools/python/symfunc_paramgen/doc/conf.py +++ b/tools/python/symfunc_paramgen/doc/conf.py @@ -33,11 +33,28 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', - 'numpydoc'] + 'sphinx.ext.doctest', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'sphinx.ext.autosummary', + # 'numpydoc'] + 'sphinx.ext.napoleon'] + +# TODO: remove if no longer needed with napoleon +# numpydoc_show_class_members = False + +# Napoleon settings +napoleon_google_docstring = False +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -89,7 +106,8 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +# html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/tools/python/symfunc_paramgen/doc/index.rst b/tools/python/symfunc_paramgen/doc/index.rst index 62407096f..d3b432293 100644 --- a/tools/python/symfunc_paramgen/doc/index.rst +++ b/tools/python/symfunc_paramgen/doc/index.rst @@ -11,6 +11,16 @@ Welcome to symfunc_paramgen's documentation! :caption: Contents: +Code documentation +================== + +.. + This used to be autosummary instead of toctree + +.. toctree:: + :maxdepth: 2 + + apigen/SymFuncParamGenerator Indices and tables ================== @@ -19,5 +29,3 @@ Indices and tables * :ref:`modindex` * :ref:`search` -.. automodule:: SymFuncParamGenerator - :members: diff --git a/tools/python/symfunc_paramgen/doc/_build/html/_sources/index.rst.txt b/tools/python/symfunc_paramgen/doc/index.rst.bak similarity index 83% rename from tools/python/symfunc_paramgen/doc/_build/html/_sources/index.rst.txt rename to tools/python/symfunc_paramgen/doc/index.rst.bak index 62407096f..d92263382 100644 --- a/tools/python/symfunc_paramgen/doc/_build/html/_sources/index.rst.txt +++ b/tools/python/symfunc_paramgen/doc/index.rst.bak @@ -12,6 +12,15 @@ Welcome to symfunc_paramgen's documentation! +Code documentation +================== + +.. toctree:: + :maxdepth: 2 + + code_structure + + Indices and tables ================== @@ -19,5 +28,3 @@ Indices and tables * :ref:`modindex` * :ref:`search` -.. automodule:: SymFuncParamGenerator - :members: diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py index 41b629557..3bfb8a2c8 100644 --- a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py +++ b/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py @@ -150,14 +150,14 @@ def check_symfunc_type(self, calling_method_name=None): This should make it clearer to the user in which part of their own code to look for an error. - Raises - ------ - TypeError - If the symmetry function type has not been set (i.e., it is None). - Returns ------- None + + Raises + ------ + ValueError + If the symmetry function type has not been set (i.e., it is None). """ if self.symfunc_type is None: if calling_method_name is None: @@ -206,10 +206,14 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, r_upper : float, optional Largest value in the radial grid from which r_shift and eta values are computed. - Optional if rule=='gastegger2018, defaults to cutoff radius if not + Optional if rule=='gastegger2018', defaults to cutoff radius if not given. Ignored if rule=='imbalzano2018'. + Returns + ------- + None + Raises ------ ValueError @@ -223,9 +227,6 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, Notes ----- - [1] https://doi.org/10.1063/1.5019667 - [2] https://doi.org/10.1063/1.5024611 - The parameter nb_param_pairs invariably specifies the number of (r_shift, eta)-pairs ultimately generated, not the number of intervals between points in a grid of r_shift values, or the @@ -247,9 +248,10 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, the different types of symmetry functions is actually discussed in the papers or was necessarily intended by the authors. - Returns - ------- - None + References + ---------- + .. [1] https://doi.org/10.1063/1.5019667 + .. [2] https://doi.org/10.1063/1.5024611 """ if not nb_param_pairs >= 2: raise ValueError('nb_param_pairs must be two or greater.') @@ -358,6 +360,10 @@ def set_custom_radial_params(self, r_shift_values, eta_values): eta_values : sequence of float or 1D-array Set of values for the symmetry function parameter eta. + Returns + ------- + None + Raises ------ TypeError @@ -374,10 +380,6 @@ class as a generator of symmetry function parameter values. However, r_shift and eta, for which the generation is not implemented as a class method, while still benefiting from the parameter writing functionality of the class. - - Returns - ------- - None """ if len(r_shift_values) != len(eta_values): raise TypeError('r_shift_values and eta_values must have same length.') @@ -396,10 +398,10 @@ class method, while still benefiting from the parameter writing def check_writing_prerequisites(self, calling_method_name=None): """Check if all data required for writing symmetry function sets are present. - This comprises checking if the following have been set: - -) symmetry function type - -) values for r_shift and eta - -) values for zeta, if the symmetry function type is an angular one + | This comprises checking if the following have been set: + | - symmetry function type + | - values for r_shift and eta + | - values for zeta, if the symmetry function type is an angular one Parameters ---------- @@ -411,17 +413,17 @@ def check_writing_prerequisites(self, calling_method_name=None): This should make it clearer to a user in which part of their code to look for an error. + Returns + ------- + None + Raises ------ - TypeError + ValueError If values for r_shift or eta are not set. - TypeError + ValueError If an angular symmetry function type has been set, but no values for zeta were set. - - Returns - ------- - None """ self.check_symfunc_type(calling_method_name=calling_method_name) @@ -473,7 +475,10 @@ def write_settings_overview(self, file=None): # depending on presence of file parameter, either direct output # to stdout, or open the specified file, in append mode - handle = open(file, 'a') if file is not None else sys.stdout + if file is None: + handle = sys.stdout + else: + handle = open(file, 'a') handle.write('#########################################################################\n') handle.write( @@ -573,14 +578,15 @@ def write_parameter_strings(self, file=None): set by the user, anyway), within each block of the output, the method iterates over the following combinations of (r_shift, eta, zeta, lambda): - [(1, 3, 5, -1), - (1, 3, 5, 1), - (1, 3, 6, -1), - (1, 3, 6, 1), - (2, 4, 5, -1), - (2, 4, 5, 1), - (2, 4, 6, -1), - (2, 4, 6, 1)] + + | (1, 3, 5, -1) + | (1, 3, 5, 1) + | (1, 3, 6, -1) + | (1, 3, 6, 1) + | (2, 4, 5, -1) + | (2, 4, 5, 1) + | (2, 4, 6, -1) + | (2, 4, 6, 1) Parameters ---------- @@ -597,7 +603,10 @@ def write_parameter_strings(self, file=None): # depending on presence of file parameter, either direct output # to stdout, or open the specified file, in append mode - handle = open(file, 'a') if file is not None else sys.stdout + if file is None: + handle = sys.stdout + else: + handle = open(file, 'a') r_cutoff = self.r_cutoff sf_number = self.symfunc_type_numbers[self.symfunc_type] diff --git a/tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt b/tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt index 6dfce6b68..6ca29419e 100644 --- a/tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt +++ b/tools/python/symfunc_paramgen/tests/reference-output_write_parameter_strings.txt @@ -1,3 +1,10 @@ +# -------------------------------------------------------------------------------------- +# | Comment lines in this file (lines starting with '#') are not relevant to the tests | +# | and are ignored by them. | +# | They are only a reminder of what settings to use in the tests to recreate the | +# | reference output contained in this file. | +# -------------------------------------------------------------------------------------- +# ######################################################################### # Radial symmetry function set, for elements ['S', 'Cu'] ######################################################################### @@ -7,7 +14,6 @@ # Sets of values for parameters: # r_shift_grid = [1 2] # eta_grid = [4 5] - symfunction_short S 2 S 4.000E+00 1.000E+00 1.122E+01 symfunction_short S 2 S 5.000E+00 2.000E+00 1.122E+01 @@ -29,7 +35,6 @@ symfunction_short Cu 2 Cu 5.000E+00 2.000E+00 1.122E+01 # Sets of values for parameters: # r_shift_grid = [1 2] # eta_grid = [4 5] - symfunction_short S 12 4.000E+00 1.000E+00 1.122E+01 symfunction_short S 12 5.000E+00 2.000E+00 1.122E+01 @@ -47,7 +52,6 @@ symfunction_short Cu 12 5.000E+00 2.000E+00 1.122E+01 # eta_grid = [4 5] # lambdas = [-1. 1.] # zetas = [5.5 7.5] - symfunction_short S 3 S S 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 symfunction_short S 3 S S 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 symfunction_short S 3 S S 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 @@ -113,7 +117,6 @@ symfunction_short Cu 3 Cu Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 # eta_grid = [4 5] # lambdas = [-1. 1.] # zetas = [5.5 7.5] - symfunction_short S 9 S S 4.000E+00 -1 5.500E+00 1.122E+01 1.000E+00 symfunction_short S 9 S S 4.000E+00 1 5.500E+00 1.122E+01 1.000E+00 symfunction_short S 9 S S 4.000E+00 -1 7.500E+00 1.122E+01 1.000E+00 @@ -179,7 +182,6 @@ symfunction_short Cu 9 Cu Cu 5.000E+00 1 7.500E+00 1.122E+01 2.000E+00 # eta_grid = [4 5] # lambdas = [-1. 1.] # zetas = [5.5 7.5] - symfunction_short S 13 4.000E+00 1.000E+00 -1 5.500E+00 1.122E+01 symfunction_short S 13 4.000E+00 1.000E+00 1 5.500E+00 1.122E+01 symfunction_short S 13 4.000E+00 1.000E+00 -1 7.500E+00 1.122E+01 diff --git a/tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt b/tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt new file mode 100644 index 000000000..4b38891b8 --- /dev/null +++ b/tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt @@ -0,0 +1,2 @@ +An interesting message on the first line. +Another interesting message on the second line. diff --git a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py index cb4e08834..b1210a345 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py +++ b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py @@ -4,6 +4,7 @@ import numpy as np import pytest import os +import sys import SymFuncParamGenerator as sfpg @@ -15,11 +16,9 @@ def isnotcomment(line): return True -def test_write_parameter_strings(tmpdir): - '''Test parameter strings are the same as in reference file, for toy inputs. +def test_write_parameter_strings_file(tmpdir): + '''Test parameter strings written to file match reference file, for toy inputs. ''' - elems = ['S', 'Cu'] - outfile_path = os.path.join(tmpdir, 'outfile.txt') reference_path = 'reference-output_write_parameter_strings.txt' @@ -30,37 +29,79 @@ def test_write_parameter_strings(tmpdir): ## radial myGen.symfunc_type = 'radial' - myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) ## weighted_radial myGen.symfunc_type = 'weighted_radial' - myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) ## angular narrow myGen.symfunc_type = 'angular_narrow' myGen.zetas = [5.5, 7.5] - myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) ## angular_wide myGen.symfunc_type = 'angular_wide' myGen.zetas = [5.5, 7.5] - myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) ## weighted_angular myGen.symfunc_type = 'weighted_angular' myGen.zetas = [5.5, 7.5] - myGen.write_settings_overview(outfile_path) myGen.write_parameter_strings(outfile_path) - # ignore comment lines, so the test does not immediately fail when only - # the parameter information is changed (which I would like to keep just - # for keeping track of the settings used in the reference output file, but - # is otherwise not essential) + # Ignore comment lines in the reference output file (lines starting + # with '#'). These lines are included in the reference output file as a + # reminder of what settings to use in the tests to recreate the reference + # output, but they are otherwise not essential for the test. with open(outfile_path) as f_out, open(reference_path) as f_reference: f_reference = filter(isnotcomment, f_reference) - f_out = filter(isnotcomment, f_out) - assert all(x == y for x, y in zip(f_out, f_reference)) \ No newline at end of file + assert all(x == y for x, y in zip(f_out, f_reference)) + + +def test_write_parameter_strings_stdout(capsys): + '''Test parameter strings written to stdout match reference file, for toy inputs. + ''' + reference_path = 'reference-output_write_parameter_strings.txt' + + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + + myGen.set_custom_radial_params([1,2], [4,5]) + + ## radial + myGen.symfunc_type = 'radial' + myGen.write_parameter_strings() + + ## weighted_radial + myGen.symfunc_type = 'weighted_radial' + myGen.write_parameter_strings() + + ## angular narrow + myGen.symfunc_type = 'angular_narrow' + myGen.zetas = [5.5, 7.5] + myGen.write_parameter_strings() + + ## angular_wide + myGen.symfunc_type = 'angular_wide' + myGen.zetas = [5.5, 7.5] + myGen.write_parameter_strings() + + ## weighted_angular + myGen.symfunc_type = 'weighted_angular' + myGen.zetas = [5.5, 7.5] + myGen.write_parameter_strings() + + # capture the output written to stdout by parameter string writing method + captured = capsys.readouterr() + + # compare what was written to stdout with the reference output file + reference_data = [] + with open(reference_path, 'r') as f_reference: + for line in f_reference: + # ignore comment lines in reference output file + if not line[0] == '#': + reference_data.append(line) + assert ''.join(reference_data) == captured.out + + diff --git a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py index 96dbb8860..98f5aba8e 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py +++ b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py @@ -8,7 +8,7 @@ import filecmp -def test_write_settings_overview(tmpdir): +def test_write_settings_overview_file(tmpdir): ########### general settings ########### outfile_path = os.path.join(tmpdir, 'outfile.txt') reference_path = 'reference-output_write_settings_overview.txt' @@ -71,3 +71,69 @@ def test_write_settings_overview(tmpdir): assert filecmp.cmp(outfile_path, reference_path) +def test_write_settings_overview_stdout(capsys): + ########### general settings ########### + reference_path = 'reference-output_write_settings_overview.txt' + + elems = ['S', 'Cu'] + myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + + ########### using custom radial parameters ########### + myGen.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) + + ## radial + myGen.symfunc_type = 'radial' + myGen.write_settings_overview() + + ## weighted_radial + myGen.symfunc_type = 'weighted_radial' + myGen.write_settings_overview() + + myGen.zetas = [5.5, 7.5] + + ## angular narrow + myGen.symfunc_type = 'angular_narrow' + myGen.write_settings_overview() + + ## angular_wide + myGen.symfunc_type = 'angular_wide' + myGen.write_settings_overview() + + ## weighted_angular + myGen.symfunc_type = 'weighted_angular' + myGen.write_settings_overview() + + ########### using the method for radial parameter generation ########### + myGen.generate_radial_params(rule='gastegger2018', mode='center', + nb_param_pairs=2, r_lower=1.5, r_upper=9.) + + ## radial + myGen.symfunc_type = 'radial' + myGen.write_settings_overview() + + ## weighted_radial + myGen.symfunc_type = 'weighted_radial' + myGen.write_settings_overview() + + myGen.zetas = [5.5, 7.5] + + ## angular narrow + myGen.symfunc_type = 'angular_narrow' + myGen.write_settings_overview() + + ## angular_wide + myGen.symfunc_type = 'angular_wide' + myGen.write_settings_overview() + + ## weighted_angular + myGen.symfunc_type = 'weighted_angular' + myGen.write_settings_overview() + + # capture the output written to stdout by settings writing method + captured = capsys.readouterr() + + ########### test equality with target output ########### + with open(reference_path, 'r') as f_reference: + assert captured.out == f_reference.read() + + From 66f215420a7e4ec34dc25a8e90595d9df728ba32 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sat, 11 May 2019 22:26:02 +0200 Subject: [PATCH 45/60] Rewrite various tests using pytest fixtures. --- .../tests/test_generate_radial_params.py | 97 ++++++++------- .../symfunc_paramgen/tests/test_misc.py | 65 +++++----- .../tests/test_write_parameter_strings.py | 72 ++++++------ .../tests/test_write_settings_overview.py | 111 +++++++++--------- 4 files changed, 171 insertions(+), 174 deletions(-) diff --git a/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py index 0f33ad031..2320ce0c4 100644 --- a/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py +++ b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py @@ -7,33 +7,37 @@ import SymFuncParamGenerator as sfpg +@pytest.fixture +def basic_generator(): + elems = ['S', 'Cu'] + return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + + @pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ ('bad_argument', 'center', 5, 1.5), ('bad_argument', 'shift', 5, 1.5), ('gastegger2018', 'bad_argument', 5, 1.5), ('imbalzano2018', 'bad_argument', 5, None) ]) -def test_errors_rule_mode(rule, mode, nb_param_pairs, r_lower): +def test_errors_rule_mode(basic_generator, + rule, mode, nb_param_pairs, r_lower): """Test for ValueError when invalid arguments for rule or method. """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): - myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs, r_lower=r_lower) + basic_generator.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) @pytest.mark.parametrize("rule,mode,nb_param_pairs", [ ('gastegger2018', 'center', 5), ('gastegger2018', 'shift', 5) ]) -def test_errors_rlower(rule, mode, nb_param_pairs): +def test_errors_rlower(basic_generator, + rule, mode, nb_param_pairs): """Test for TypeError when omitting r_lower argument in rule 'gastegger2018' """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(TypeError): - myGen.generate_radial_params(rule=rule, mode=mode, + basic_generator.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs) @@ -43,14 +47,13 @@ def test_errors_rlower(rule, mode, nb_param_pairs): ('imbalzano2018', 'center', 1, None), ('imbalzano2018', 'shift', 1, None) ]) -def test_errors_nb_param_pairs(rule, mode, nb_param_pairs, r_lower): +def test_errors_nb_param_pairs(basic_generator, + rule, mode, nb_param_pairs, r_lower): """Test for ValueError when nb_param_pairs less than two. """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): - myGen.generate_radial_params(rule=rule, mode=mode, - nb_param_pairs=nb_param_pairs, r_lower=r_lower) + basic_generator.generate_radial_params(rule=rule, mode=mode, + nb_param_pairs=nb_param_pairs, r_lower=r_lower) @pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower,r_upper", [ @@ -65,13 +68,12 @@ def test_errors_nb_param_pairs(rule, mode, nb_param_pairs, r_lower): ('gastegger2018', 'shift', 2, 7, None), ('gastegger2018', 'shift', 2, 1., 7.) ]) -def test_errors_numerical_order(rule, mode, nb_param_pairs, r_lower, r_upper): +def test_errors_numerical_order(basic_generator, + rule, mode, nb_param_pairs, r_lower, r_upper): """Test for ValueError when illegal relation between r_lower, r_upper, r_cutoff in rule 'gastegger2018' """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) with pytest.raises(ValueError): - myGen.generate_radial_params(rule=rule, mode=mode, + basic_generator.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs, r_lower=r_lower, r_upper=r_upper) @@ -89,37 +91,35 @@ def test_errors_numerical_order(rule, mode, nb_param_pairs, r_lower, r_upper): [1, 3.5, 6], [1/(2*2.5**2)]*3) ]) -def test_parameter_generation_gastegger2018(rule, mode, nb_param_pairs, r_lower, r_upper, - target_r_shift, target_eta): +def test_parameter_generation_gastegger2018(basic_generator, + rule, mode, nb_param_pairs, r_lower, r_upper, + target_r_shift, target_eta): """Test if generated r_shift and eta values match target values. """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - # when passing r_upper if r_upper is not None: - myGen.generate_radial_params(rule=rule, mode=mode, + basic_generator.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs, r_lower=r_lower, r_upper=r_upper) # when not passing r_upper, using default value of r_cutoff else: - myGen.generate_radial_params(rule=rule, mode=mode, + basic_generator.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs, r_lower=r_lower) # test if generated parameter sets match target values - assert np.allclose(myGen.r_shift_grid, np.array(target_r_shift)) - assert np.allclose(myGen.eta_grid, np.array(target_eta)) + assert np.allclose(basic_generator.r_shift_grid, np.array(target_r_shift)) + assert np.allclose(basic_generator.eta_grid, np.array(target_eta)) # test if settings have been correctly stored - assert myGen.radial_paramgen_settings['rule'] == rule - assert myGen.radial_paramgen_settings['mode'] == mode - assert myGen.radial_paramgen_settings['nb_param_pairs'] == nb_param_pairs - assert myGen.radial_paramgen_settings['r_lower'] == r_lower + assert basic_generator.radial_paramgen_settings['rule'] == rule + assert basic_generator.radial_paramgen_settings['mode'] == mode + assert basic_generator.radial_paramgen_settings['nb_param_pairs'] == nb_param_pairs + assert basic_generator.radial_paramgen_settings['r_lower'] == r_lower if r_upper is not None: - assert myGen.radial_paramgen_settings['r_upper'] == r_upper + assert basic_generator.radial_paramgen_settings['r_upper'] == r_upper else: - assert myGen.radial_paramgen_settings['r_upper'] == myGen.r_cutoff + assert basic_generator.radial_paramgen_settings['r_upper'] == basic_generator.r_cutoff @pytest.mark.parametrize("rule,mode,nb_param_pairs,target_r_shift,target_eta", [ @@ -130,43 +130,38 @@ def test_parameter_generation_gastegger2018(rule, mode, nb_param_pairs, r_lower, [1.5, 2.1213203, 3.0, 4.2426407], [2.5904121, 1.2952060, 0.6476030, 0.3238015]) ]) -def test_parameter_generation_imbalzano2018(rule, mode, nb_param_pairs, - target_r_shift, target_eta): +def test_parameter_generation_imbalzano2018(basic_generator, + rule, mode, nb_param_pairs, + target_r_shift, target_eta): """Test if generated r_shift and eta values match target values. """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - - myGen.generate_radial_params(rule=rule, mode=mode, + basic_generator.generate_radial_params(rule=rule, mode=mode, nb_param_pairs=nb_param_pairs) # test if generated parameter sets match target values - assert np.allclose(myGen.r_shift_grid, np.array(target_r_shift)) - assert np.allclose(myGen.eta_grid, np.array(target_eta)) + assert np.allclose(basic_generator.r_shift_grid, np.array(target_r_shift)) + assert np.allclose(basic_generator.eta_grid, np.array(target_eta)) # test if settings have been correctly stored - assert myGen.radial_paramgen_settings['rule'] == rule - assert myGen.radial_paramgen_settings['mode'] == mode - assert myGen.radial_paramgen_settings['nb_param_pairs'] == nb_param_pairs + assert basic_generator.radial_paramgen_settings['rule'] == rule + assert basic_generator.radial_paramgen_settings['mode'] == mode + assert basic_generator.radial_paramgen_settings['nb_param_pairs'] == nb_param_pairs @pytest.mark.parametrize("mode", ['center', 'shift']) -def test_warning_unused_args(mode): +def test_warning_unused_args(basic_generator, mode): """Test if warning when passing r_lower or r_upper while using rule 'imbalzano2018' """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - with pytest.warns(UserWarning): - myGen.generate_radial_params(rule='imbalzano2018', mode=mode, + basic_generator.generate_radial_params(rule='imbalzano2018', mode=mode, nb_param_pairs=3, r_lower=1) with pytest.warns(UserWarning): - myGen.generate_radial_params(rule='imbalzano2018', mode=mode, + basic_generator.generate_radial_params(rule='imbalzano2018', mode=mode, nb_param_pairs=3, r_upper=5) with pytest.warns(UserWarning): - myGen.generate_radial_params(rule='imbalzano2018', mode=mode, + basic_generator.generate_radial_params(rule='imbalzano2018', mode=mode, nb_param_pairs=3, r_lower=1, r_upper=5) diff --git a/tools/python/symfunc_paramgen/tests/test_misc.py b/tools/python/symfunc_paramgen/tests/test_misc.py index dc016b7aa..cf75c99d3 100644 --- a/tools/python/symfunc_paramgen/tests/test_misc.py +++ b/tools/python/symfunc_paramgen/tests/test_misc.py @@ -7,6 +7,12 @@ import SymFuncParamGenerator as sfpg +@pytest.fixture +def basic_generator(): + elems = ['S', 'Cu'] + return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + + @pytest.mark.parametrize("symfunc_type,target_combinations", [ ('radial', [('H', 'H'), ('H', 'C'), ('H', 'O'), @@ -40,15 +46,6 @@ def test_element_combinations(symfunc_type, target_combinations): assert myGen.element_combinations == target_combinations -def test_setter_symfunc_type(): - """Test if error when trying to set invalid symmetry function type. - """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - with pytest.raises(ValueError): - myGen.symfunc_type = 'illegal_type' - - def test_rcutoff(): elems = ['S', 'Cu'] # test for errors when cutoff radius not greater than zero @@ -64,6 +61,13 @@ def test_rcutoff(): myGen.r_cutoff = 10 +def test_setter_symfunc_type(basic_generator): + """Test if error when trying to set invalid symmetry function type. + """ + with pytest.raises(ValueError): + basic_generator.symfunc_type = 'illegal_type' + + @pytest.mark.parametrize("symfunc_type,r_shift_grid,eta_grid,zetas", [ (None, np.array([1,2,3]), np.array([4,5,6]), None), ('radial', None, np.array([4,5,6]), None), @@ -80,57 +84,52 @@ def test_rcutoff(): ('weighted_angular', np.array([1,2,3]), None, np.array([1,4,9])), ('weighted_angular', np.array([1,2,3]), np.array([4,5,6]), None) ]) -def test_check_writing_prerequisites(symfunc_type, r_shift_grid, eta_grid, zetas): +def test_check_writing_prerequisites(basic_generator, + symfunc_type, r_shift_grid, eta_grid, zetas): """Test if error when writing parameters or settings while data are missing. """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - if symfunc_type is not None: - myGen.symfunc_type = symfunc_type + basic_generator.symfunc_type = symfunc_type if r_shift_grid is not None: - myGen._r_shift_grid = r_shift_grid + basic_generator._r_shift_grid = r_shift_grid if eta_grid is not None: - myGen._eta_grid = eta_grid + basic_generator._eta_grid = eta_grid if zetas is not None: - myGen.zetas = zetas + basic_generator.zetas = zetas # test the completeness checker on its own (without argument) with pytest.raises(ValueError): - myGen.check_writing_prerequisites() + basic_generator.check_writing_prerequisites() # test the methods that call the completeness checker (which call it with argument) with pytest.raises(ValueError): - myGen.write_settings_overview() + basic_generator.write_settings_overview() with pytest.raises(ValueError): - myGen.write_parameter_strings() + basic_generator.write_parameter_strings() -def test_set_custom_radial_params(): +def test_set_custom_radial_params(basic_generator): """Test if set_custom_radial_params correctly raises exceptions and sets values. """ - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) - # test for exception when unequal length with pytest.raises(TypeError): - myGen.set_custom_radial_params([1.1, 2.2, 3.3], [4.4, 5.5]) + basic_generator.set_custom_radial_params([1.1, 2.2, 3.3], [4.4, 5.5]) # test for exception when non-positive value in values for r_shift with pytest.raises(ValueError): - myGen.set_custom_radial_params([0, 2.2, 3.3], [1.1, 2.2, 3.3]) + basic_generator.set_custom_radial_params([0, 2.2, 3.3], [1.1, 2.2, 3.3]) # test for exception when non-positive value in values for eta with pytest.raises(ValueError): - myGen.set_custom_radial_params([1.1, 2.2, 3.3], [0, 2.2, 3.3]) + basic_generator.set_custom_radial_params([1.1, 2.2, 3.3], [0, 2.2, 3.3]) # test if setting custom r_shift and eta values works correctly - myGen.set_custom_radial_params([1.1, 2.2, 3.3], [3.3, 2.2, 1.1]) - assert np.array_equal(myGen.r_shift_grid, np.array([1.1, 2.2, 3.3])) - assert np.array_equal(myGen.eta_grid, np.array([3.3, 2.2, 1.1])) + basic_generator.set_custom_radial_params([1.1, 2.2, 3.3], [3.3, 2.2, 1.1]) + assert np.array_equal(basic_generator.r_shift_grid, np.array([1.1, 2.2, 3.3])) + assert np.array_equal(basic_generator.eta_grid, np.array([3.3, 2.2, 1.1])) # test if the dict containing radial parameter generation settings is # correctly reset to None, when setting custom radial parameters - myGen.generate_radial_params(rule='imbalzano2018', mode='center', nb_param_pairs=3) - myGen.set_custom_radial_params([1.1, 2.2, 3.3], [3.3, 2.2, 1.1]) - assert myGen.radial_paramgen_settings is None + basic_generator.generate_radial_params(rule='imbalzano2018', mode='center', nb_param_pairs=3) + basic_generator.set_custom_radial_params([1.1, 2.2, 3.3], [3.3, 2.2, 1.1]) + assert basic_generator.radial_paramgen_settings is None diff --git a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py index b1210a345..2d2d5e4ca 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py +++ b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py @@ -8,6 +8,12 @@ import SymFuncParamGenerator as sfpg +@pytest.fixture +def basic_generator(): + elems = ['S', 'Cu'] + return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + + def isnotcomment(line): """Filter lines according to whether they start in '#'. """ @@ -16,39 +22,36 @@ def isnotcomment(line): return True -def test_write_parameter_strings_file(tmpdir): +def test_write_parameter_strings_file(basic_generator, tmpdir): '''Test parameter strings written to file match reference file, for toy inputs. ''' outfile_path = os.path.join(tmpdir, 'outfile.txt') reference_path = 'reference-output_write_parameter_strings.txt' - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) - - myGen.set_custom_radial_params([1,2], [4,5]) + basic_generator.set_custom_radial_params([1,2], [4,5]) ## radial - myGen.symfunc_type = 'radial' - myGen.write_parameter_strings(outfile_path) + basic_generator.symfunc_type = 'radial' + basic_generator.write_parameter_strings(outfile_path) ## weighted_radial - myGen.symfunc_type = 'weighted_radial' - myGen.write_parameter_strings(outfile_path) + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_parameter_strings(outfile_path) ## angular narrow - myGen.symfunc_type = 'angular_narrow' - myGen.zetas = [5.5, 7.5] - myGen.write_parameter_strings(outfile_path) + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings(outfile_path) ## angular_wide - myGen.symfunc_type = 'angular_wide' - myGen.zetas = [5.5, 7.5] - myGen.write_parameter_strings(outfile_path) + basic_generator.symfunc_type = 'angular_wide' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings(outfile_path) ## weighted_angular - myGen.symfunc_type = 'weighted_angular' - myGen.zetas = [5.5, 7.5] - myGen.write_parameter_strings(outfile_path) + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings(outfile_path) # Ignore comment lines in the reference output file (lines starting # with '#'). These lines are included in the reference output file as a @@ -59,38 +62,35 @@ def test_write_parameter_strings_file(tmpdir): assert all(x == y for x, y in zip(f_out, f_reference)) -def test_write_parameter_strings_stdout(capsys): +def test_write_parameter_strings_stdout(basic_generator, capsys): '''Test parameter strings written to stdout match reference file, for toy inputs. ''' reference_path = 'reference-output_write_parameter_strings.txt' - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) - - myGen.set_custom_radial_params([1,2], [4,5]) + basic_generator.set_custom_radial_params([1,2], [4,5]) ## radial - myGen.symfunc_type = 'radial' - myGen.write_parameter_strings() + basic_generator.symfunc_type = 'radial' + basic_generator.write_parameter_strings() ## weighted_radial - myGen.symfunc_type = 'weighted_radial' - myGen.write_parameter_strings() + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_parameter_strings() ## angular narrow - myGen.symfunc_type = 'angular_narrow' - myGen.zetas = [5.5, 7.5] - myGen.write_parameter_strings() + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings() ## angular_wide - myGen.symfunc_type = 'angular_wide' - myGen.zetas = [5.5, 7.5] - myGen.write_parameter_strings() + basic_generator.symfunc_type = 'angular_wide' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings() ## weighted_angular - myGen.symfunc_type = 'weighted_angular' - myGen.zetas = [5.5, 7.5] - myGen.write_parameter_strings() + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings() # capture the output written to stdout by parameter string writing method captured = capsys.readouterr() diff --git a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py index 98f5aba8e..eb7a50880 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py +++ b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py @@ -8,126 +8,129 @@ import filecmp -def test_write_settings_overview_file(tmpdir): +@pytest.fixture +def basic_generator(): + elems = ['S', 'Cu'] + return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + + +def test_write_settings_overview_file(basic_generator, tmpdir): ########### general settings ########### outfile_path = os.path.join(tmpdir, 'outfile.txt') reference_path = 'reference-output_write_settings_overview.txt' elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + basic_generator = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) ########### using custom radial parameters ########### - myGen.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) + basic_generator.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) ## radial - myGen.symfunc_type = 'radial' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'radial' + basic_generator.write_settings_overview(outfile_path) ## weighted_radial - myGen.symfunc_type = 'weighted_radial' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_settings_overview(outfile_path) - myGen.zetas = [5.5, 7.5] + basic_generator.zetas = [5.5, 7.5] ## angular narrow - myGen.symfunc_type = 'angular_narrow' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.write_settings_overview(outfile_path) ## angular_wide - myGen.symfunc_type = 'angular_wide' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'angular_wide' + basic_generator.write_settings_overview(outfile_path) ## weighted_angular - myGen.symfunc_type = 'weighted_angular' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.write_settings_overview(outfile_path) ########### using the method for radial parameter generation ########### - myGen.generate_radial_params(rule='gastegger2018', mode='center', + basic_generator.generate_radial_params(rule='gastegger2018', mode='center', nb_param_pairs=2, r_lower=1.5, r_upper=9.) ## radial - myGen.symfunc_type = 'radial' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'radial' + basic_generator.write_settings_overview(outfile_path) ## weighted_radial - myGen.symfunc_type = 'weighted_radial' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_settings_overview(outfile_path) - myGen.zetas = [5.5, 7.5] + basic_generator.zetas = [5.5, 7.5] ## angular narrow - myGen.symfunc_type = 'angular_narrow' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.write_settings_overview(outfile_path) ## angular_wide - myGen.symfunc_type = 'angular_wide' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'angular_wide' + basic_generator.write_settings_overview(outfile_path) ## weighted_angular - myGen.symfunc_type = 'weighted_angular' - myGen.write_settings_overview(outfile_path) + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.write_settings_overview(outfile_path) ########### test equality with target output ########### assert filecmp.cmp(outfile_path, reference_path) -def test_write_settings_overview_stdout(capsys): +def test_write_settings_overview_stdout(basic_generator, capsys): ########### general settings ########### reference_path = 'reference-output_write_settings_overview.txt' - elems = ['S', 'Cu'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) - ########### using custom radial parameters ########### - myGen.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) + basic_generator.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) ## radial - myGen.symfunc_type = 'radial' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'radial' + basic_generator.write_settings_overview() ## weighted_radial - myGen.symfunc_type = 'weighted_radial' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_settings_overview() - myGen.zetas = [5.5, 7.5] + basic_generator.zetas = [5.5, 7.5] ## angular narrow - myGen.symfunc_type = 'angular_narrow' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.write_settings_overview() ## angular_wide - myGen.symfunc_type = 'angular_wide' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'angular_wide' + basic_generator.write_settings_overview() ## weighted_angular - myGen.symfunc_type = 'weighted_angular' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.write_settings_overview() ########### using the method for radial parameter generation ########### - myGen.generate_radial_params(rule='gastegger2018', mode='center', + basic_generator.generate_radial_params(rule='gastegger2018', mode='center', nb_param_pairs=2, r_lower=1.5, r_upper=9.) ## radial - myGen.symfunc_type = 'radial' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'radial' + basic_generator.write_settings_overview() ## weighted_radial - myGen.symfunc_type = 'weighted_radial' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_settings_overview() - myGen.zetas = [5.5, 7.5] + basic_generator.zetas = [5.5, 7.5] ## angular narrow - myGen.symfunc_type = 'angular_narrow' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.write_settings_overview() ## angular_wide - myGen.symfunc_type = 'angular_wide' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'angular_wide' + basic_generator.write_settings_overview() ## weighted_angular - myGen.symfunc_type = 'weighted_angular' - myGen.write_settings_overview() + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.write_settings_overview() # capture the output written to stdout by settings writing method captured = capsys.readouterr() From 439e1d9a14c7c7fc7c9d97982eb16f7aa968edcd Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 12 May 2019 12:47:19 +0200 Subject: [PATCH 46/60] Rename main module file to meet PEP-8 conventions. --- .../src/{SymFuncParamGenerator.py => sfparamgen.py} | 0 .../tests/test_generate_radial_params.py | 4 ++-- tools/python/symfunc_paramgen/tests/test_misc.py | 12 ++++++------ .../tests/test_write_parameter_strings.py | 4 ++-- .../tests/test_write_settings_overview.py | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) rename tools/python/symfunc_paramgen/src/{SymFuncParamGenerator.py => sfparamgen.py} (100%) diff --git a/tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py b/tools/python/symfunc_paramgen/src/sfparamgen.py similarity index 100% rename from tools/python/symfunc_paramgen/src/SymFuncParamGenerator.py rename to tools/python/symfunc_paramgen/src/sfparamgen.py diff --git a/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py index 2320ce0c4..e3cdaf865 100644 --- a/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py +++ b/tools/python/symfunc_paramgen/tests/test_generate_radial_params.py @@ -4,13 +4,13 @@ import numpy as np import pytest import os -import SymFuncParamGenerator as sfpg +from sfparamgen import SymFuncParamGenerator @pytest.fixture def basic_generator(): elems = ['S', 'Cu'] - return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + return SymFuncParamGenerator(elements=elems, r_cutoff=6.) @pytest.mark.parametrize("rule,mode,nb_param_pairs,r_lower", [ diff --git a/tools/python/symfunc_paramgen/tests/test_misc.py b/tools/python/symfunc_paramgen/tests/test_misc.py index cf75c99d3..1d740af27 100644 --- a/tools/python/symfunc_paramgen/tests/test_misc.py +++ b/tools/python/symfunc_paramgen/tests/test_misc.py @@ -4,13 +4,13 @@ import numpy as np import pytest import os -import SymFuncParamGenerator as sfpg +from sfparamgen import SymFuncParamGenerator @pytest.fixture def basic_generator(): elems = ['S', 'Cu'] - return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + return SymFuncParamGenerator(elements=elems, r_cutoff=6.) @pytest.mark.parametrize("symfunc_type,target_combinations", [ @@ -41,7 +41,7 @@ def test_element_combinations(symfunc_type, target_combinations): """Test if element combinations are correctly constructed. """ elems = ['H', 'C', 'O'] - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6.) + myGen = SymFuncParamGenerator(elements=elems, r_cutoff=6.) myGen.symfunc_type = symfunc_type assert myGen.element_combinations == target_combinations @@ -50,11 +50,11 @@ def test_rcutoff(): elems = ['S', 'Cu'] # test for errors when cutoff radius not greater than zero with pytest.raises(ValueError): - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=0) + myGen = SymFuncParamGenerator(elements=elems, r_cutoff=0) with pytest.raises(ValueError): - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=-5) + myGen = SymFuncParamGenerator(elements=elems, r_cutoff=-5) # test if initializing and retrieving r_cutoff works as expected - myGen = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=6) + myGen = SymFuncParamGenerator(elements=elems, r_cutoff=6) assert myGen.r_cutoff == 6 # test for AttributeError when trying to change r_cutoff afterwards with pytest.raises(AttributeError): diff --git a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py index 2d2d5e4ca..385488770 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py +++ b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py @@ -5,13 +5,13 @@ import pytest import os import sys -import SymFuncParamGenerator as sfpg +from sfparamgen import SymFuncParamGenerator @pytest.fixture def basic_generator(): elems = ['S', 'Cu'] - return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + return SymFuncParamGenerator(elements=elems, r_cutoff=11.22) def isnotcomment(line): diff --git a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py index eb7a50880..01385773a 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py +++ b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py @@ -4,14 +4,14 @@ import numpy as np import pytest import os -import SymFuncParamGenerator as sfpg +from sfparamgen import SymFuncParamGenerator import filecmp @pytest.fixture def basic_generator(): elems = ['S', 'Cu'] - return sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + return SymFuncParamGenerator(elements=elems, r_cutoff=11.22) def test_write_settings_overview_file(basic_generator, tmpdir): @@ -20,7 +20,7 @@ def test_write_settings_overview_file(basic_generator, tmpdir): reference_path = 'reference-output_write_settings_overview.txt' elems = ['S', 'Cu'] - basic_generator = sfpg.SymFuncParamGenerator(elements=elems, r_cutoff=11.22) + basic_generator = SymFuncParamGenerator(elements=elems, r_cutoff=11.22) ########### using custom radial parameters ########### basic_generator.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) From cc1d22f736474f89f9e25e868a198d9dc84bfbcd Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 3 Jul 2019 13:08:46 +0200 Subject: [PATCH 47/60] Begin work on example. --- .../example-checkpoint.ipynb | 180 ++++++++++++++++++ .../symfunc_paramgen/examples/example.ipynb | 180 ++++++++++++++++++ 2 files changed, 360 insertions(+) create mode 100644 tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb create mode 100644 tools/python/symfunc_paramgen/examples/example.ipynb diff --git a/tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb b/tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb new file mode 100644 index 000000000..ea8e95c61 --- /dev/null +++ b/tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example usage of Symmetry Function Parameter Generator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Importing the tool" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append('../src')\n", + "from sfparamgen import SymFuncParamGenerator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic usage overview" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using this tool typically consists of the following steps:\n", + "\n", + "1. Creating an object of the symmetry function parameter generator class.\n", + "2. Filling this object with the necessary settings and symmetry function parameters, using the class methods provided.\n", + "3. Printing the symmetry function parameters, in the format that n2p2 requires.\n", + "\n", + "Steps 2. and 3. will most likely be repeated several times, with different settings, to create different symmetry function parameter sets." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Creating an object of the symmetry function parameter generator class" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To start generating symmetry function parameter sets, we first need to instantiate the symmetry function parameter generator class.\n", + "\n", + "The elements in the system, and the cutoff radius are required as arguments to the constructor. These are considered parameters describing the system, rather than symmetry function settings, and as such are not intended for later change. To generate symmetry function parameters for different elements and/or for different cutoff radiuses, a new instance of the class should be created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator = SymFuncParamGenerator(elements=['S', 'Cu'], r_cutoff = 6.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Supplying the object with settings and generating the radial symmetry function parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far, we have a 'bare' symmetry function parameter generator object. We need to pass it the desired settings and tell it to generate actual symmetry function parameters. The different settings/method calls necessary to do this, are independent of each other and can be made in any order." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The symmetry function type needs to be specified. In this example, we will be setting the symmetry function type to 'radial':" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.symfunc_type = 'radial'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.generate_radial_params(rule='imbalzano2018', mode='shift', nb_param_pairs=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this, everything is ready. We can, to check for correctness, or for future reference, display all current settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.write_settings_overview()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Printing the symmetry function parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The object now contains a set of symmetry function parameters. We can now print these, in the format that n2p2 requires.\n", + "\n", + "By default, they are written to stdout, and you can proceed with them to your liking (pipe to a parameter file for n2p2, copy, ...)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.write_parameter_strings()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tools/python/symfunc_paramgen/examples/example.ipynb b/tools/python/symfunc_paramgen/examples/example.ipynb new file mode 100644 index 000000000..ea8e95c61 --- /dev/null +++ b/tools/python/symfunc_paramgen/examples/example.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example usage of Symmetry Function Parameter Generator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Importing the tool" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append('../src')\n", + "from sfparamgen import SymFuncParamGenerator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic usage overview" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using this tool typically consists of the following steps:\n", + "\n", + "1. Creating an object of the symmetry function parameter generator class.\n", + "2. Filling this object with the necessary settings and symmetry function parameters, using the class methods provided.\n", + "3. Printing the symmetry function parameters, in the format that n2p2 requires.\n", + "\n", + "Steps 2. and 3. will most likely be repeated several times, with different settings, to create different symmetry function parameter sets." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Creating an object of the symmetry function parameter generator class" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To start generating symmetry function parameter sets, we first need to instantiate the symmetry function parameter generator class.\n", + "\n", + "The elements in the system, and the cutoff radius are required as arguments to the constructor. These are considered parameters describing the system, rather than symmetry function settings, and as such are not intended for later change. To generate symmetry function parameters for different elements and/or for different cutoff radiuses, a new instance of the class should be created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator = SymFuncParamGenerator(elements=['S', 'Cu'], r_cutoff = 6.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Supplying the object with settings and generating the radial symmetry function parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far, we have a 'bare' symmetry function parameter generator object. We need to pass it the desired settings and tell it to generate actual symmetry function parameters. The different settings/method calls necessary to do this, are independent of each other and can be made in any order." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The symmetry function type needs to be specified. In this example, we will be setting the symmetry function type to 'radial':" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.symfunc_type = 'radial'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.generate_radial_params(rule='imbalzano2018', mode='shift', nb_param_pairs=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this, everything is ready. We can, to check for correctness, or for future reference, display all current settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.write_settings_overview()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Printing the symmetry function parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The object now contains a set of symmetry function parameters. We can now print these, in the format that n2p2 requires.\n", + "\n", + "By default, they are written to stdout, and you can proceed with them to your liking (pipe to a parameter file for n2p2, copy, ...)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.write_parameter_strings()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From c2c511dbcc9ef7186a1e81c46ce342a77c8b1d81 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Wed, 3 Jul 2019 16:35:41 +0200 Subject: [PATCH 48/60] Continue working on example. --- .../example-checkpoint.ipynb | 180 -------------- .../symfunc_paramgen/examples/example.ipynb | 229 +++++++++++++++++- .../python/symfunc_paramgen/src/sfparamgen.py | 2 +- 3 files changed, 222 insertions(+), 189 deletions(-) delete mode 100644 tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb diff --git a/tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb b/tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb deleted file mode 100644 index ea8e95c61..000000000 --- a/tools/python/symfunc_paramgen/examples/.ipynb_checkpoints/example-checkpoint.ipynb +++ /dev/null @@ -1,180 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Example usage of Symmetry Function Parameter Generator" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Importing the tool" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "sys.path.append('../src')\n", - "from sfparamgen import SymFuncParamGenerator" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Basic usage overview" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using this tool typically consists of the following steps:\n", - "\n", - "1. Creating an object of the symmetry function parameter generator class.\n", - "2. Filling this object with the necessary settings and symmetry function parameters, using the class methods provided.\n", - "3. Printing the symmetry function parameters, in the format that n2p2 requires.\n", - "\n", - "Steps 2. and 3. will most likely be repeated several times, with different settings, to create different symmetry function parameter sets." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1. Creating an object of the symmetry function parameter generator class" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To start generating symmetry function parameter sets, we first need to instantiate the symmetry function parameter generator class.\n", - "\n", - "The elements in the system, and the cutoff radius are required as arguments to the constructor. These are considered parameters describing the system, rather than symmetry function settings, and as such are not intended for later change. To generate symmetry function parameters for different elements and/or for different cutoff radiuses, a new instance of the class should be created." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "myGenerator = SymFuncParamGenerator(elements=['S', 'Cu'], r_cutoff = 6.)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2. Supplying the object with settings and generating the radial symmetry function parameters" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So far, we have a 'bare' symmetry function parameter generator object. We need to pass it the desired settings and tell it to generate actual symmetry function parameters. The different settings/method calls necessary to do this, are independent of each other and can be made in any order." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The symmetry function type needs to be specified. In this example, we will be setting the symmetry function type to 'radial':" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "myGenerator.symfunc_type = 'radial'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "myGenerator.generate_radial_params(rule='imbalzano2018', mode='shift', nb_param_pairs=5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With this, everything is ready. We can, to check for correctness, or for future reference, display all current settings." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "myGenerator.write_settings_overview()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. Printing the symmetry function parameters" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The object now contains a set of symmetry function parameters. We can now print these, in the format that n2p2 requires.\n", - "\n", - "By default, they are written to stdout, and you can proceed with them to your liking (pipe to a parameter file for n2p2, copy, ...)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "myGenerator.write_parameter_strings()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/tools/python/symfunc_paramgen/examples/example.ipynb b/tools/python/symfunc_paramgen/examples/example.ipynb index ea8e95c61..3f569ce7f 100644 --- a/tools/python/symfunc_paramgen/examples/example.ipynb +++ b/tools/python/symfunc_paramgen/examples/example.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Example usage of Symmetry Function Parameter Generator" + "# Usage of Symmetry Function Parameter Generator" ] }, { @@ -21,7 +21,15 @@ "outputs": [], "source": [ "import sys\n", - "sys.path.append('../src')\n", + "sys.path.append('../src')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "from sfparamgen import SymFuncParamGenerator" ] }, @@ -40,7 +48,7 @@ "\n", "1. Creating an object of the symmetry function parameter generator class.\n", "2. Filling this object with the necessary settings and symmetry function parameters, using the class methods provided.\n", - "3. Printing the symmetry function parameters, in the format that n2p2 requires.\n", + "3. Writing the symmetry function parameters, in a format usable by n2p2.\n", "\n", "Steps 2. and 3. will most likely be repeated several times, with different settings, to create different symmetry function parameter sets." ] @@ -56,7 +64,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To start generating symmetry function parameter sets, we first need to instantiate the symmetry function parameter generator class.\n", + "We first need to instantiate the symmetry function parameter generator class.\n", "\n", "The elements in the system, and the cutoff radius are required as arguments to the constructor. These are considered parameters describing the system, rather than symmetry function settings, and as such are not intended for later change. To generate symmetry function parameters for different elements and/or for different cutoff radiuses, a new instance of the class should be created." ] @@ -81,7 +89,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "So far, we have a 'bare' symmetry function parameter generator object. We need to pass it the desired settings and tell it to generate actual symmetry function parameters. The different settings/method calls necessary to do this, are independent of each other and can be made in any order." + "So far, we have a 'bare' symmetry function parameter generator object. We need to pass it the desired settings and tell it to generate actual symmetry function parameters. The different settings/method calls necessary for this are independent of each other and can be made in any order." ] }, { @@ -103,7 +111,13 @@ { "cell_type": "markdown", "metadata": {}, - "source": [] + "source": [ + "Importantly, we also need to generate a set of values for what we will call the 'radial parameters', r_shift and eta. We call them 'radial parameters' because they govern the sampling of radial space, but they are in fact required by any type of symmetry function, not only those of type 'radial'.\n", + "\n", + "The symmetry function parameter generator class provides a method for generating these parameters based on algorithms proposed in the literature. This method is in fact the central functionality of this tool.\n", + "\n", + "The method takes a few parameters. For explanation of these parameters and literature references, we refer to the documentation." + ] }, { "cell_type": "code", @@ -134,7 +148,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 3. Printing the symmetry function parameters" + "### 3. Writing the symmetry function parameters" ] }, { @@ -143,7 +157,119 @@ "source": [ "The object now contains a set of symmetry function parameters. We can now print these, in the format that n2p2 requires.\n", "\n", - "By default, they are written to stdout, and you can proceed with them to your liking (pipe to a parameter file for n2p2, copy, ...)." + "(By default, they are written to stdout. See further down for how to write them to a file.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.write_parameter_strings()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Repeating 2. and 3. with different settings" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Typically, you will want to create multiple symmetry function parameter sets, using different settings and symmetry function types. To do so, simply repeat steps 2. and 3. from above, with different settings.
\n", + "NB: Previously stored parameters are overwritten when setting new ones!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this next example, let us now use one of the angular symmetry function types:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.symfunc_type = 'angular_narrow'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since we are now using an angular symmetry function type, we need to specify the additional parameter zetas, which was not needed in the example with a radial type from above:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.zetas = [1.0, 6.0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the sake of example, let us also generate new radial parameters, with different settings (although we could keep those from before):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.generate_radial_params(rule='gastegger2018', mode='center', nb_param_pairs=3, r_lower=1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now again print an overview of all settings used, as well as the final ready-for-use parameter strings:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.write_settings_overview()\n", + "myGenerator.write_parameter_strings()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Examples on usage of additional features" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Writing to a file" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above examples, the settings overview and the parameter strings were written to stdout, which is the default behavior. You can, however, also write them to a file by passing the file path as an optional argument.\n", + "\n", + "If the file does not exist, it is created by the methods. If it exists already, the methods append to it." ] }, { @@ -152,8 +278,95 @@ "metadata": {}, "outputs": [], "source": [ + "import os\n", + "\n", + "try:\n", + " myGenerator.write_settings_overview(file='outfile.txt')\n", + " myGenerator.write_parameter_strings(file='outfile.txt')\n", + "finally:\n", + " # to remove clutter in this example, we remove the file again\n", + " os.remove('outfile.txt')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Accessing the element combinations" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Describing the environment of an atom in a multi-element system requires distinct symmetry functions corresponding to all possible central-atom-neighbor combinations.\n", + "\n", + "When outputting the symmetry function parameters the normal way, using the class' writing method, these element combinations are already taken care of. However, if needed, you can also access the combinations on their own via the dedicated member variable, as shown below.\n", + "\n", + "The element combinations are dependendent on the symmetry function type, and as such are (re-)calculated and stored each time the symmetry function type is set." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.symfunc_type = 'radial'\n", + "print('radial:')\n", + "print(myGenerator.element_combinations)\n", + "\n", + "myGenerator.symfunc_type = 'angular_wide'\n", + "print('angular_wide:')\n", + "print(myGenerator.element_combinations)\n", + "\n", + "myGenerator.symfunc_type = 'angular_narrow'\n", + "print('angular_narrow:')\n", + "print(myGenerator.element_combinations)\n", + "\n", + "myGenerator.symfunc_type = 'weighted_angular'\n", + "print('weighted_angular:')\n", + "print(myGenerator.element_combinations)\n", + "\n", + "myGenerator.symfunc_type = 'weighted_radial'\n", + "print('weighted_radial:')\n", + "print(myGenerator.element_combinations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Setting custom radial parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instead of using the method for generating the 'radial parameters' r_shift and eta according to the schemes taken from the literature, there is also the possibility to set custom values for these parameters.\n", + "\n", + "This is actually kind of bypassing the class' core functionality. But this way, you can still make use of the class' storage and writing functionalities, while using radial parameters of your own." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.set_custom_radial_params(r_shift_values=[1.1, 2.2, 3.3, 4.4], eta_values=[4.1, 3.2, 2.3, 1.4])\n", + "\n", + "myGenerator.write_settings_overview()\n", "myGenerator.write_parameter_strings()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/tools/python/symfunc_paramgen/src/sfparamgen.py b/tools/python/symfunc_paramgen/src/sfparamgen.py index 3bfb8a2c8..3d7d2599c 100644 --- a/tools/python/symfunc_paramgen/src/sfparamgen.py +++ b/tools/python/symfunc_paramgen/src/sfparamgen.py @@ -172,7 +172,7 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, """Generate a set of values for r_shift and eta. Such a set of (r_shift, eta)-values is required for any - symmetry function type. + symmetry function type (not only those called 'radial'). Its generation is independent of the symmetry function type and the angular symmetry function parameters zeta and lambda. From 7ff519492b4807e78459cb0f5f51e08c760291c6 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 5 Jul 2019 15:56:28 +0200 Subject: [PATCH 49/60] Rework documentation. --- .../doc/apigen/SymFuncParamGenerator.rst | 7 ---- .../symfunc_paramgen/doc/apigen/modules.rst | 11 ------- .../symfunc_paramgen/doc/code_structure.rst | 8 +++++ .../doc/code_structure.rst.bak | 7 ---- tools/python/symfunc_paramgen/doc/conf.py | 32 +++++++++---------- tools/python/symfunc_paramgen/doc/index.rst | 7 ++-- .../python/symfunc_paramgen/doc/index.rst.bak | 30 ----------------- .../python/symfunc_paramgen/src/sfparamgen.py | 22 ++++++++----- 8 files changed, 41 insertions(+), 83 deletions(-) delete mode 100644 tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst delete mode 100644 tools/python/symfunc_paramgen/doc/apigen/modules.rst create mode 100644 tools/python/symfunc_paramgen/doc/code_structure.rst delete mode 100644 tools/python/symfunc_paramgen/doc/code_structure.rst.bak delete mode 100644 tools/python/symfunc_paramgen/doc/index.rst.bak diff --git a/tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst b/tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst deleted file mode 100644 index 96126ba03..000000000 --- a/tools/python/symfunc_paramgen/doc/apigen/SymFuncParamGenerator.rst +++ /dev/null @@ -1,7 +0,0 @@ -SymFuncParamGenerator module -============================ - -.. automodule:: SymFuncParamGenerator - :members: - :undoc-members: - :show-inheritance: diff --git a/tools/python/symfunc_paramgen/doc/apigen/modules.rst b/tools/python/symfunc_paramgen/doc/apigen/modules.rst deleted file mode 100644 index fd8366931..000000000 --- a/tools/python/symfunc_paramgen/doc/apigen/modules.rst +++ /dev/null @@ -1,11 +0,0 @@ -src -=== - -.. toctree:: - :maxdepth: 4 - - SymFuncParamGenerator - generate-acsf-angular_narrow - generate-acsf-angular_wide - generate-acsf-radial - my_local_tests diff --git a/tools/python/symfunc_paramgen/doc/code_structure.rst b/tools/python/symfunc_paramgen/doc/code_structure.rst new file mode 100644 index 000000000..c75e442ad --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/code_structure.rst @@ -0,0 +1,8 @@ +module sfparamgen +--------------------------- + +.. currentmodule:: sfparamgen + +.. autoclass:: SymFuncParamGenerator + :members: + :undoc-members: \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/doc/code_structure.rst.bak b/tools/python/symfunc_paramgen/doc/code_structure.rst.bak deleted file mode 100644 index 29586a33d..000000000 --- a/tools/python/symfunc_paramgen/doc/code_structure.rst.bak +++ /dev/null @@ -1,7 +0,0 @@ -Class SymFuncParamGenerator ---------------------------- - -.. currentmodule:: SymFuncParamGenerator - -.. autoclass:: SymFuncParamGenerator - diff --git a/tools/python/symfunc_paramgen/doc/conf.py b/tools/python/symfunc_paramgen/doc/conf.py index 6b7fee253..0b15dc7d2 100644 --- a/tools/python/symfunc_paramgen/doc/conf.py +++ b/tools/python/symfunc_paramgen/doc/conf.py @@ -38,23 +38,23 @@ 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.autosummary', - # 'numpydoc'] - 'sphinx.ext.napoleon'] + 'numpydoc'] + # 'sphinx.ext.napoleon'] # TODO: remove if no longer needed with napoleon # numpydoc_show_class_members = False -# Napoleon settings -napoleon_google_docstring = False -napoleon_numpy_docstring = True -napoleon_include_private_with_doc = False -napoleon_include_special_with_doc = True -napoleon_use_admonition_for_examples = False -napoleon_use_admonition_for_notes = False -napoleon_use_admonition_for_references = False -napoleon_use_ivar = False -napoleon_use_param = True -napoleon_use_rtype = False +# # Napoleon settings +# napoleon_google_docstring = False +# napoleon_numpy_docstring = True +# napoleon_include_private_with_doc = False +# napoleon_include_special_with_doc = True +# napoleon_use_admonition_for_examples = False +# napoleon_use_admonition_for_notes = False +# napoleon_use_admonition_for_references = False +# napoleon_use_ivar = False +# napoleon_use_param = True +# napoleon_use_rtype = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -106,14 +106,14 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -# html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' +html_theme = 'alabaster' +# html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = {'show_related': True} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/tools/python/symfunc_paramgen/doc/index.rst b/tools/python/symfunc_paramgen/doc/index.rst index d3b432293..d92263382 100644 --- a/tools/python/symfunc_paramgen/doc/index.rst +++ b/tools/python/symfunc_paramgen/doc/index.rst @@ -11,16 +11,15 @@ Welcome to symfunc_paramgen's documentation! :caption: Contents: + Code documentation ================== -.. - This used to be autosummary instead of toctree - .. toctree:: :maxdepth: 2 - apigen/SymFuncParamGenerator + code_structure + Indices and tables ================== diff --git a/tools/python/symfunc_paramgen/doc/index.rst.bak b/tools/python/symfunc_paramgen/doc/index.rst.bak deleted file mode 100644 index d92263382..000000000 --- a/tools/python/symfunc_paramgen/doc/index.rst.bak +++ /dev/null @@ -1,30 +0,0 @@ -.. symfunc_paramgen documentation master file, created by - sphinx-quickstart on Wed May 8 15:37:02 2019. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to symfunc_paramgen's documentation! -============================================ - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - - -Code documentation -================== - -.. toctree:: - :maxdepth: 2 - - code_structure - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/tools/python/symfunc_paramgen/src/sfparamgen.py b/tools/python/symfunc_paramgen/src/sfparamgen.py index 3d7d2599c..b079ea6ae 100644 --- a/tools/python/symfunc_paramgen/src/sfparamgen.py +++ b/tools/python/symfunc_paramgen/src/sfparamgen.py @@ -30,10 +30,8 @@ class SymFuncParamGenerator: using the class method provided for that purpose. None, if no radial parameters have been generated yet, or if custom ones (without using the method for generating radial parameters) were set. - _r_shift_grid : numpy.ndarray or None - The set of values for the symmetry function parameter r_shift that was generated. - _eta_grid : numpy.ndarray or None - The set of values for the symmetry function parameter eta that was generated. + r_shift_grid + eta_grid elements element_combinations r_cutoff @@ -82,13 +80,17 @@ def element_combinations(self): def symfunc_type(self): """Type of symmetry function for which parameters are to be generated (`str`). - When the setter for this is called it also checks the validity of - the input, builds the necessary element combinations for the given - symmetry function type, and stores it to member variable. + When the setter for this is called it checks the validity of the given + symmetry function type. A symmetry function type is valid if it is in + the keys of the dict :py:attr:`~symfunc_type_numbers`, + and invalid otherwise. + + The setter also builds the necessary element combinations for the given + symmetry function type, and stores it to :py:attr:`~element_combinations`. If the given symmetry function type is a radial one, the setter also clears any preexisting zetas - (i.e., sets the member variable zetas to None). + (i.e., sets :py:attr:`~zetas` to None). Raises ------ @@ -132,10 +134,14 @@ def zetas(self, values): @property def r_shift_grid(self): + """Set of values for the symmetry function parameter r_shift (`numpy.ndarray` or None). + """ return self._r_shift_grid @property def eta_grid(self): + """Set of values for the symmetry function parameter eta (`numpy.ndarray` or None). + """ return self._eta_grid def check_symfunc_type(self, calling_method_name=None): From ddcbea9171d00dcb59c948e858f82a1adfad1bd7 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Fri, 5 Jul 2019 16:52:14 +0200 Subject: [PATCH 50/60] Some inter-documentation linking, some rewording. --- .../symfunc_paramgen/doc/code_structure.rst | 2 + .../python/symfunc_paramgen/src/sfparamgen.py | 39 ++++++++++--------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/tools/python/symfunc_paramgen/doc/code_structure.rst b/tools/python/symfunc_paramgen/doc/code_structure.rst index c75e442ad..5816cfcf6 100644 --- a/tools/python/symfunc_paramgen/doc/code_structure.rst +++ b/tools/python/symfunc_paramgen/doc/code_structure.rst @@ -3,6 +3,8 @@ module sfparamgen .. currentmodule:: sfparamgen +class SymFuncParamGenerator +=========================== .. autoclass:: SymFuncParamGenerator :members: :undoc-members: \ No newline at end of file diff --git a/tools/python/symfunc_paramgen/src/sfparamgen.py b/tools/python/symfunc_paramgen/src/sfparamgen.py index b079ea6ae..7d97f951a 100644 --- a/tools/python/symfunc_paramgen/src/sfparamgen.py +++ b/tools/python/symfunc_paramgen/src/sfparamgen.py @@ -72,7 +72,8 @@ def elements(self): def element_combinations(self): """Combinations of elements (list of tuple of string, read-only). - This is computed and set automatically by the setter for symfunc_type. + This is (re)computed and set automatically each time + :py:attr:`~symfunc_type` is set. """ return self._element_combinations @@ -112,7 +113,7 @@ def symfunc_type(self, value): # Clear any previous zeta values, if the given symfunc type is a radial one if value in ['radial', 'weighted_radial']: # set the member variable explicitly (with underscore) instead of - # calling setter, because the setter would put None into an array + # calling setter, because the setter would make an array out of the None self._zetas = None @property @@ -184,11 +185,12 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, Rules for parameter generation are implemented based on [1]_ and [2]_. - The generated values are stored as arrays in the member variables _r_shift_grid and _eta_grid. - The entries are to be understood pairwise, i.e., the i-th entry of _r_shift_grid - and the i-th entry of _eta_grid belong to one symmetry function. - Besides the set of values for r_shift and eta, the settings that - were used for generating it are also stored, in the dictionary radial_paramgen_settings. + The generated values are stored as arrays to :py:attr:`~r_shift_grid` + and :py:attr:`~eta_grid`. The entries are to be understood pairwise, + i.e., the i-th entry of :py:attr:`~r_shift_grid` and the i-th entry of + :py:attr:`~eta_grid` belong to one symmetry function. + Besides the values, the settings they were generated with are also stored, + to :py:attr:`~radial_paramgen_settings`. Parameters ---------- @@ -355,7 +357,7 @@ def set_custom_radial_params(self, r_shift_values, eta_values): The parameters r_shift_values and eta_values must have the same length. - Ttheir entries are to be understood pairwise, i.e., + Their entries are to be understood pairwise, i.e., the i-th entry of r_shift_values and the i-th entry of eta_values belong together, describing one symmetry function. @@ -380,13 +382,14 @@ def set_custom_radial_params(self, r_shift_values, eta_values): Notes ----- Setting r_shift and eta manually via this method instead of using the - method generate_radial_params somewhat defeats the purpose of the - class as a generator of symmetry function parameter values. However, - it might still be useful, in case one wants to use custom values for - r_shift and eta, for which the generation is not implemented as a - class method, while still benefiting from the parameter writing - functionality of the class. + method :py:attr:`~generate_radial_params` somewhat defeats the + purpose of the class as a generator of symmetry function parameter + values. However, it might still be useful, in case one wants to use + custom values for r_shift and eta, for which the generation is not + implemented as a class method, while still benefiting from the + parameter writing functionality of the class. """ + if len(r_shift_values) != len(eta_values): raise TypeError('r_shift_values and eta_values must have same length.') if min(r_shift_values) <= 0: @@ -405,9 +408,9 @@ def check_writing_prerequisites(self, calling_method_name=None): """Check if all data required for writing symmetry function sets are present. | This comprises checking if the following have been set: - | - symmetry function type - | - values for r_shift and eta - | - values for zeta, if the symmetry function type is an angular one + | - :py:attr:`~symfunc_type` + | - :py:attr:`~r_shift_grid` and :py:attr:`~eta_grid` + | - :py:attr:`~zetas`, if the symmetry function type is an angular one Parameters ---------- @@ -458,7 +461,7 @@ def check_writing_prerequisites(self, calling_method_name=None): f' they have not been cleared since by setting a non-angular symmetry function type.') def write_settings_overview(self, file=None): - """Write settings used in generating the currently stored set of symmetry function parameters. + """Write the settings the currently stored set of symmetry function parameters was generated with. Parameters ---------- From 0ab43d979429ba719539fcf9c683cded88098219 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 8 Jul 2019 12:31:39 +0200 Subject: [PATCH 51/60] Add brief verbal description at beginning of doc. --- tools/python/symfunc_paramgen/doc/_static/readme.txt | 1 + tools/python/symfunc_paramgen/doc/index.rst | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tools/python/symfunc_paramgen/doc/_static/readme.txt diff --git a/tools/python/symfunc_paramgen/doc/_static/readme.txt b/tools/python/symfunc_paramgen/doc/_static/readme.txt new file mode 100644 index 000000000..b64c312ca --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/_static/readme.txt @@ -0,0 +1 @@ +Any static files might go here. diff --git a/tools/python/symfunc_paramgen/doc/index.rst b/tools/python/symfunc_paramgen/doc/index.rst index d92263382..80ebed08d 100644 --- a/tools/python/symfunc_paramgen/doc/index.rst +++ b/tools/python/symfunc_paramgen/doc/index.rst @@ -10,6 +10,9 @@ Welcome to symfunc_paramgen's documentation! :maxdepth: 2 :caption: Contents: +This tool generates sets of symmetry function parameters, according to rules proposed in the literature ([1]_, [2]_), and outputs +them in the format required by n2p2. + Code documentation @@ -28,3 +31,9 @@ Indices and tables * :ref:`modindex` * :ref:`search` + +.. rubric:: References + +.. [1] https://doi.org/10.1063/1.5019667 +.. [2] https://doi.org/10.1063/1.5024611 + From 4e853c845420dacfe935dfd6ac5d092badea4f11 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 8 Jul 2019 13:41:12 +0200 Subject: [PATCH 52/60] Add README.md for docs. --- tools/python/symfunc_paramgen/doc/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tools/python/symfunc_paramgen/doc/README.md diff --git a/tools/python/symfunc_paramgen/doc/README.md b/tools/python/symfunc_paramgen/doc/README.md new file mode 100644 index 000000000..083f2284d --- /dev/null +++ b/tools/python/symfunc_paramgen/doc/README.md @@ -0,0 +1,14 @@ +#### Building the documentation + +run + + make html + +to generate the documentation using sphinx. +This tool uses numpydoc-style docstrings. + +*Requires*: + +* Sphinx +* Sphinx alabaster theme (while the rtd theme might look nicer in principle, there seemed to be rendering issues when using it) +* numpydoc From cb6568777ca321d1688e8cdae598c22f9c329245 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 8 Jul 2019 17:14:38 +0200 Subject: [PATCH 53/60] Make small addition to example and fix typo. --- .../symfunc_paramgen/examples/example.ipynb | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/tools/python/symfunc_paramgen/examples/example.ipynb b/tools/python/symfunc_paramgen/examples/example.ipynb index 3f569ce7f..86a094a6e 100644 --- a/tools/python/symfunc_paramgen/examples/example.ipynb +++ b/tools/python/symfunc_paramgen/examples/example.ipynb @@ -292,7 +292,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Accessing the element combinations" + "### Retrieving the element combinations on their own within Python" ] }, { @@ -303,7 +303,7 @@ "\n", "When outputting the symmetry function parameters the normal way, using the class' writing method, these element combinations are already taken care of. However, if needed, you can also access the combinations on their own via the dedicated member variable, as shown below.\n", "\n", - "The element combinations are dependendent on the symmetry function type, and as such are (re-)calculated and stored each time the symmetry function type is set." + "The element combinations are dependent on the symmetry function type, and as such are (re-)calculated and stored each time the symmetry function type is set." ] }, { @@ -333,6 +333,32 @@ "print(myGenerator.element_combinations)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Retrieving the radial parameters on their own within Python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Having generated sets of values for the 'radial parameters' r_shift and eta, you can retrieve them from within Python by accessing their member variables like so:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "myGenerator.generate_radial_params(rule='imbalzano2018', mode='shift', nb_param_pairs=5)\n", + "print(myGenerator.r_shift_grid)\n", + "print(myGenerator.eta_grid)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -344,7 +370,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Instead of using the method for generating the 'radial parameters' r_shift and eta according to the schemes taken from the literature, there is also the possibility to set custom values for these parameters.\n", + "Instead of using the method for generating the 'radial parameters' r_shift and eta according to the schemes proposed in the literature, there is also the possibility to set custom values for these parameters.\n", "\n", "This is actually kind of bypassing the class' core functionality. But this way, you can still make use of the class' storage and writing functionalities, while using radial parameters of your own." ] @@ -385,7 +411,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.1" } }, "nbformat": 4, From 62143b7a4bd670f91e01c544cc383f0933c18be6 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Tue, 9 Jul 2019 11:42:23 +0200 Subject: [PATCH 54/60] Delete unused 'stdout-comparison-file.txt' in docs. --- tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt diff --git a/tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt b/tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt deleted file mode 100644 index 4b38891b8..000000000 --- a/tools/python/symfunc_paramgen/tests/stdout-comparison-file.txt +++ /dev/null @@ -1,2 +0,0 @@ -An interesting message on the first line. -Another interesting message on the second line. From 2ea8ad2db500b0031885185490f5873f4989b316 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Tue, 9 Jul 2019 17:06:17 +0200 Subject: [PATCH 55/60] Mention name of target parameter file 'input.nn'. --- tools/python/symfunc_paramgen/examples/example.ipynb | 4 ++-- tools/python/symfunc_paramgen/src/sfparamgen.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/python/symfunc_paramgen/examples/example.ipynb b/tools/python/symfunc_paramgen/examples/example.ipynb index 86a094a6e..bb42a8669 100644 --- a/tools/python/symfunc_paramgen/examples/example.ipynb +++ b/tools/python/symfunc_paramgen/examples/example.ipynb @@ -155,7 +155,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The object now contains a set of symmetry function parameters. We can now print these, in the format that n2p2 requires.\n", + "The object now contains a set of symmetry function parameters. We can now print these, in the format that the parameter file 'input.nn' used by n2p2 requires.\n", "\n", "(By default, they are written to stdout. See further down for how to write them to a file.)" ] @@ -411,7 +411,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.1" + "version": "3.7.3" } }, "nbformat": 4, diff --git a/tools/python/symfunc_paramgen/src/sfparamgen.py b/tools/python/symfunc_paramgen/src/sfparamgen.py index 7d97f951a..3fc487634 100644 --- a/tools/python/symfunc_paramgen/src/sfparamgen.py +++ b/tools/python/symfunc_paramgen/src/sfparamgen.py @@ -377,7 +377,9 @@ def set_custom_radial_params(self, r_shift_values, eta_values): TypeError If r_shift_values and eta_values do not have equal length. ValueError - If r_shift_values or eta_values contain non-positive entries. + If there are negative entries in r_shift_values. + ValueError + If there are non-positive entries in eta_values. Notes ----- @@ -392,8 +394,8 @@ def set_custom_radial_params(self, r_shift_values, eta_values): if len(r_shift_values) != len(eta_values): raise TypeError('r_shift_values and eta_values must have same length.') - if min(r_shift_values) <= 0: - raise ValueError('r_shift_values must all be greater than zero.') + if min(r_shift_values) < 0: + raise ValueError('r_shift_values must all be non-negative.') if min(eta_values) <= 0: raise ValueError('eta_values must all be greater than zero.') # (re)set radial_paramgen_settings to None, indicating that custom @@ -567,6 +569,9 @@ def find_element_combinations(self): def write_parameter_strings(self, file=None): """Write symmetry function parameter sets, formatted as n2p2 requires. + The output format is that required by the parameter file 'input.nn' + used by n2p2. The output is intended to be pasted/appended to that file. + Each line in the output corresponds to one symmetry function. Output is formatted in blocks separated by blank lines, each block From 9b977306a060a8db3d8b9fa8504cb213b9ed777e Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 22 Jul 2019 11:34:31 +0200 Subject: [PATCH 56/60] Bugfix in write_settings_overview. When printing long arrays, EVERY line of multiline output is now made into comment. --- tools/python/symfunc_paramgen/src/sfparamgen.py | 17 +++++++++++++---- .../python/symfunc_paramgen/tests/test_misc.py | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/sfparamgen.py b/tools/python/symfunc_paramgen/src/sfparamgen.py index 3fc487634..44aefa80f 100644 --- a/tools/python/symfunc_paramgen/src/sfparamgen.py +++ b/tools/python/symfunc_paramgen/src/sfparamgen.py @@ -514,11 +514,20 @@ def write_settings_overview(self, file=None): handle.write('# Sets of values for parameters:\n') # set numpy print precision to lower number of decimal places for the following outputs np.set_printoptions(precision=4) - handle.write(f'# r_shift_grid = {self._r_shift_grid}\n') - handle.write(f'# eta_grid = {self._eta_grid}\n') + + # printing numpy arrays causes linebreaks if they contain many entries. + # -> need to make sure that every single line in the output + # is prepended by "# " to make it into a comment. + outstring_r_shift = f'r_shift_grid = {self._r_shift_grid}' + handle.write('# ' + outstring_r_shift.replace("\n", "\n# ") + '\n') + outstring_eta = f'eta_grid = {self._eta_grid}' + handle.write('# ' + outstring_eta.replace("\n", "\n# ") + '\n') + if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: - handle.write(f'# lambdas = {self.lambdas}\n') - handle.write(f'# zetas = {self.zetas}\n') + outstring_lambdas = f'lambdas = {self.lambdas}' + handle.write('# ' + outstring_lambdas.replace("\n", "\n# ") + '\n') + outstring_zetas = f'zetas = {self.zetas}' + handle.write('# ' + outstring_zetas.replace("\n", "\n# ") + '\n') # reset numpy print precision to default np.set_printoptions(precision=8) handle.write('\n') diff --git a/tools/python/symfunc_paramgen/tests/test_misc.py b/tools/python/symfunc_paramgen/tests/test_misc.py index 1d740af27..f0406c730 100644 --- a/tools/python/symfunc_paramgen/tests/test_misc.py +++ b/tools/python/symfunc_paramgen/tests/test_misc.py @@ -113,9 +113,9 @@ def test_set_custom_radial_params(basic_generator): # test for exception when unequal length with pytest.raises(TypeError): basic_generator.set_custom_radial_params([1.1, 2.2, 3.3], [4.4, 5.5]) - # test for exception when non-positive value in values for r_shift + # test for exception when negative value in values for r_shift with pytest.raises(ValueError): - basic_generator.set_custom_radial_params([0, 2.2, 3.3], [1.1, 2.2, 3.3]) + basic_generator.set_custom_radial_params([-0.1, 2.2, 3.3], [1.1, 2.2, 3.3]) # test for exception when non-positive value in values for eta with pytest.raises(ValueError): basic_generator.set_custom_radial_params([1.1, 2.2, 3.3], [0, 2.2, 3.3]) From 59d5258139f5fee40d10ce6ad0769a2226466c6e Mon Sep 17 00:00:00 2001 From: Andreas Singraber Date: Fri, 4 Oct 2019 12:08:32 +0200 Subject: [PATCH 57/60] PEP8 formatting for sfparamgen.py --- .../python/symfunc_paramgen/src/sfparamgen.py | 237 +++++++++++------- 1 file changed, 150 insertions(+), 87 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/sfparamgen.py b/tools/python/symfunc_paramgen/src/sfparamgen.py index 44aefa80f..ba3d5fc25 100644 --- a/tools/python/symfunc_paramgen/src/sfparamgen.py +++ b/tools/python/symfunc_paramgen/src/sfparamgen.py @@ -8,7 +8,8 @@ class SymFuncParamGenerator: - """Tools for generation, storage, and writing in the format required by n2p2, of symmetry function parameter sets. + """Tools for generation, storage, and writing in the format required by + n2p2, of symmetry function parameter sets. Parameters ---------- @@ -24,12 +25,14 @@ class SymFuncParamGenerator: Dictionary mapping strings specifying the symmetry function type to the numbers used internally by n2p2 to distinguish symmetry function types. lambdas : numpy.ndarray - Set of values for the parameter lambda of angular symmetry functions. Fixed to [-1, 1]. + Set of values for the parameter lambda of angular symmetry functions. + Fixed to [-1, 1]. radial_paramgen_settings : dict or None - Stores settings that were used in generating the symmetry function parameters r_shift and eta - using the class method provided for that purpose. - None, if no radial parameters have been generated yet, or if custom ones - (without using the method for generating radial parameters) were set. + Stores settings that were used in generating the symmetry function + parameters r_shift and eta using the class method provided for that + purpose. None, if no radial parameters have been generated yet, or if + custom ones (without using the method for generating radial parameters) + were set. r_shift_grid eta_grid elements @@ -40,10 +43,10 @@ class SymFuncParamGenerator: """ symfunc_type_numbers = dict(radial=2, - angular_narrow=3, - angular_wide=9, - weighted_radial=12, - weighted_angular=13) + angular_narrow=3, + angular_wide=9, + weighted_radial=12, + weighted_angular=13) lambdas = np.array([-1.0, 1.0]) def __init__(self, elements, r_cutoff: float): @@ -79,7 +82,8 @@ def element_combinations(self): @property def symfunc_type(self): - """Type of symmetry function for which parameters are to be generated (`str`). + """Type of symmetry function for which parameters are to be generated + (`str`). When the setter for this is called it checks the validity of the given symmetry function type. A symmetry function type is valid if it is in @@ -87,7 +91,8 @@ def symfunc_type(self): and invalid otherwise. The setter also builds the necessary element combinations for the given - symmetry function type, and stores it to :py:attr:`~element_combinations`. + symmetry function type, and stores it to + :py:attr:`~element_combinations`. If the given symmetry function type is a radial one, the setter also clears any preexisting zetas @@ -103,17 +108,20 @@ def symfunc_type(self): @symfunc_type.setter def symfunc_type(self, value): if value not in self.symfunc_type_numbers.keys(): - raise ValueError('Invalid symmetry function type. Must be one of {}'.format( - list(self.symfunc_type_numbers.keys()))) + raise ValueError('Invalid symmetry function type. Must be one of ' + '{}'.format( + list(self.symfunc_type_numbers.keys()))) else: self._symfunc_type = value # once symmetry function type has been set and found to be valid, # build and store the element combinations self._element_combinations = self.find_element_combinations() - # Clear any previous zeta values, if the given symfunc type is a radial one + # Clear any previous zeta values, if the given symfunc type is a + # radial one if value in ['radial', 'weighted_radial']: # set the member variable explicitly (with underscore) instead of - # calling setter, because the setter would make an array out of the None + # calling setter, because the setter would make an array out of + # the None self._zetas = None @property @@ -124,7 +132,8 @@ def r_cutoff(self): @property def zetas(self): - """Set of values for the parameter zeta of angular symmetry functions (`numpy.ndarray`). + """Set of values for the parameter zeta of angular symmetry functions + (`numpy.ndarray`). """ return self._zetas @@ -135,13 +144,15 @@ def zetas(self, values): @property def r_shift_grid(self): - """Set of values for the symmetry function parameter r_shift (`numpy.ndarray` or None). + """Set of values for the symmetry function parameter r_shift + (`numpy.ndarray` or None). """ return self._r_shift_grid @property def eta_grid(self): - """Set of values for the symmetry function parameter eta (`numpy.ndarray` or None). + """Set of values for the symmetry function parameter eta + (`numpy.ndarray` or None). """ return self._eta_grid @@ -171,8 +182,9 @@ def check_symfunc_type(self, calling_method_name=None): raise ValueError('Symmetry function type not set.') else: raise ValueError(f'Symmetry function type not set. ' - f'Calling method {calling_method_name} requires' - f' that symmetry function type have been set before.') + f'Calling method {calling_method_name} ' + f'requires that symmetry function type have ' + f'been set before.') def generate_radial_params(self, rule, mode, nb_param_pairs: int, r_lower=None, r_upper=None): @@ -189,21 +201,23 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, and :py:attr:`~eta_grid`. The entries are to be understood pairwise, i.e., the i-th entry of :py:attr:`~r_shift_grid` and the i-th entry of :py:attr:`~eta_grid` belong to one symmetry function. - Besides the values, the settings they were generated with are also stored, - to :py:attr:`~radial_paramgen_settings`. + Besides the values, the settings they were generated with are also + stored, to :py:attr:`~radial_paramgen_settings`. Parameters ---------- rule : {'gastegger2018', 'imbalzano2018'} - If rule=='gastegger2018' use the parameter generation rules presented in [1]_. - If rule=='imbalzano2018' use the parameter generation rules presented in [2]_. + If rule=='gastegger2018' use the parameter generation rules + presented in [1]_. If rule=='imbalzano2018' use the parameter + generation rules presented in [2]_. mode : {'center', 'shift'} - Selects which parameter generation procedure to use, on top of the rule argument, - since there are again two different varieties presented in each of the two papers. - 'center' sets r_shift to zero for all symmetry functions, varying only eta. - 'shift' creates parameter sets where r_shift varies. - The exact implementation details differ depending on - the rule parameter and are described in the papers. + Selects which parameter generation procedure to use, on top of the + rule argument, since there are again two different varieties + presented in each of the two papers. 'center' sets r_shift to zero + for all symmetry functions, varying only eta. 'shift' creates + parameter sets where r_shift varies. The exact implementation + details differ depending on the rule parameter and are described in + the papers. nb_param_pairs : int Number of (r_shift, eta)-pairs to be generated. r_lower : float @@ -274,13 +288,15 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, if rule == 'gastegger2018': if r_lower is None: - raise TypeError('Argument r_lower is required for rule "gastegger2018"') + raise TypeError('Argument r_lower is required for ' + 'rule "gastegger2018"') if r_upper is None: # by default, set largest value of radial grid to cutoff radius r_upper = r_cutoff # store those settings that are unique to this rule - self.radial_paramgen_settings.update({'r_lower': r_lower, 'r_upper': r_upper}) + self.radial_paramgen_settings.update({'r_lower': r_lower, + 'r_upper': r_upper}) # create auxiliary grid grid = np.linspace(r_lower, r_upper, nb_param_pairs) @@ -289,13 +305,17 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, # r_lower = 0 is not allowed in center mode, # because it causes division by zero if not 0 < r_lower < r_upper <= r_cutoff: - raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 < r_lower < r_upper <= r_cutoff.') + raise ValueError(f'Invalid argument(s): rule = {rule:s}, ' + f'mode = {mode:s} requires that 0 < ' + f'r_lower < r_upper <= r_cutoff.') r_shift_grid = np.zeros(nb_param_pairs) eta_grid = 1.0 / (2.0 * grid ** 2) elif mode == 'shift': # on the other hand, in shift mode, r_lower = 0 is possible if not 0 <= r_lower < r_upper <= r_cutoff: - raise ValueError(f'Invalid argument(s): rule = {rule:s}, mode = {mode:s} requires that 0 <= r_lower < r_upper <= r_cutoff.') + raise ValueError(f'Invalid argument(s): rule = {rule:s}, ' + f'mode = {mode:s} requires that 0 <= ' + f'r_lower < r_upper <= r_cutoff.') r_shift_grid = grid # compute the equidistant grid spacing dr = (r_upper - r_lower) / (nb_param_pairs - 1) @@ -320,27 +340,33 @@ def generate_radial_params(self, rule, mode, nb_param_pairs: int, if mode == 'center': nb_intervals = nb_param_pairs - 1 gridpoint_indices = np.array(range(0, nb_intervals + 1)) - eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) / r_cutoff) ** 2 + eta_grid = (nb_intervals ** (gridpoint_indices / nb_intervals) + / r_cutoff) ** 2 r_shift_grid = np.zeros_like(eta_grid) elif mode == 'shift': # create extended auxiliary grid of r_shift values, # that contains nb_param_pairs + 1 values nb_intervals_extended = nb_param_pairs - gridpoint_indices_extended = np.array(range(0, nb_intervals_extended + 1)) + gridpoint_indices_extended = np.array( + range(0, nb_intervals_extended + 1)) rs_grid_extended = r_cutoff / nb_intervals_extended ** ( - gridpoint_indices_extended / nb_intervals_extended) + gridpoint_indices_extended / nb_intervals_extended) # from pairs of neighboring r_shift values, compute eta values. # doing this for the nb_param_pairs + 1 values in the auxiliary - # grid ultimately gives nb_param_pairs different values for eta. + # grid ultimately gives nb_param_pairs different values for + # eta. eta_grid = np.zeros(nb_param_pairs) for idx in range(len(rs_grid_extended) - 1): - eta_current = 1 / (rs_grid_extended[idx] - rs_grid_extended[idx + 1]) ** 2 + eta_current = 1 / (rs_grid_extended[idx] + - rs_grid_extended[idx + 1]) ** 2 eta_grid[idx] = eta_current - # create final grid of r_shift values by excluding the first entry - # (for which r_shift coincides with the cutoff radius) from the extended grid + # create final grid of r_shift values by excluding the first + # entry (for which r_shift coincides with the cutoff radius) + # from the extended grid r_shift_grid = rs_grid_extended[1:] - # reverse the order of r_shift and eta values so they are sorted in order of ascending r_shift - # (not necessary, but makes the output consistent with the other options) + # reverse the order of r_shift and eta values so they are + # sorted in order of ascending r_shift (not necessary, but + # makes the output consistent with the other options) r_shift_grid = np.flip(r_shift_grid) eta_grid = np.flip(eta_grid) else: @@ -393,7 +419,8 @@ def set_custom_radial_params(self, r_shift_values, eta_values): """ if len(r_shift_values) != len(eta_values): - raise TypeError('r_shift_values and eta_values must have same length.') + raise TypeError('r_shift_values and eta_values must ' + 'have same length.') if min(r_shift_values) < 0: raise ValueError('r_shift_values must all be non-negative.') if min(eta_values) <= 0: @@ -407,7 +434,8 @@ def set_custom_radial_params(self, r_shift_values, eta_values): self._eta_grid = np.array(eta_values) def check_writing_prerequisites(self, calling_method_name=None): - """Check if all data required for writing symmetry function sets are present. + """Check if all data required for writing symmetry function sets are + present. | This comprises checking if the following have been set: | - :py:attr:`~symfunc_type` @@ -441,29 +469,40 @@ def check_writing_prerequisites(self, calling_method_name=None): if calling_method_name is None: if self._r_shift_grid is None or self._eta_grid is None: raise ValueError('Values for r_shift and/or eta not set.') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.symfunc_type in ['angular_narrow', + 'angular_wide', + 'weighted_angular']: if self.zetas is None: raise ValueError( f'Values for zeta not set (required for symmetry' f' function type {self.symfunc_type}).\n' - f' If you are seeing this error despite having previously set zetas, make sure\n' - f' they have not been cleared since by setting a non-angular symmetry function type.') + f' If you are seeing this error despite having ' + f'previously set zetas, make sure\n' + f' they have not been cleared since by setting a ' + f'non-angular symmetry function type.') else: if self._r_shift_grid is None or self._eta_grid is None: raise ValueError(f'Values for r_shift and/or eta not set. ' - f'Calling method {calling_method_name} requires' - f' that values for r_shift and eta have been set before.') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + f'Calling method {calling_method_name} ' + f'requires that values for r_shift and eta ' + f'have been set before.') + if self.symfunc_type in ['angular_narrow', + 'angular_wide', + 'weighted_angular']: if self.zetas is None: raise ValueError( f'Values for zeta not set.\n ' - f'Calling {calling_method_name}, while using symmetry function type {self.symfunc_type},\n' + f'Calling {calling_method_name}, while using symmetry ' + f'function type {self.symfunc_type},\n' f' requires zetas to have been set before.\n ' - f'If you are seeing this error despite having previously set zetas, make sure\n' - f' they have not been cleared since by setting a non-angular symmetry function type.') + f'If you are seeing this error despite having ' + f'previously set zetas, make sure\n' + f' they have not been cleared since by setting a ' + f'non-angular symmetry function type.') def write_settings_overview(self, file=None): - """Write the settings the currently stored set of symmetry function parameters was generated with. + """Write the settings the currently stored set of symmetry function + parameters was generated with. Parameters ---------- @@ -491,28 +530,35 @@ def write_settings_overview(self, file=None): else: handle = open(file, 'a') - handle.write('#########################################################################\n') + handle.write('########################################################' + '#################\n') handle.write( f'# {type_descriptions[self.symfunc_type]} symmetry function set, ' f'for elements {self.elements}\n') - handle.write('#########################################################################\n') + handle.write('########################################################' + '#################\n') handle.write(f'# r_cutoff = {self.r_cutoff}\n') - # depending on whether radial parameters were generated using the method - # or custom-set (indicated by presence or absence of radial parameter - # generation settings), write the settings used or not + # depending on whether radial parameters were generated using the + # method or custom-set (indicated by presence or absence of radial + # parameter generation settings), write the settings used or not if self.radial_paramgen_settings is not None: - handle.write('# The following settings were used for generating sets\n') - handle.write('# of values for the radial parameters r_shift and eta:\n') + handle.write('# The following settings were used for generating ' + 'sets\n') + handle.write('# of values for the radial parameters r_shift and ' + 'eta:\n') for key, value in self.radial_paramgen_settings.items(): handle.write(f'# {key:14s} = {value}\n') else: - handle.write('# A custom set of values was used for the radial parameters r_shift and eta.\n') - handle.write('# Thus, there are no settings on radial parameter generation available for display.\n') + handle.write('# A custom set of values was used for the radial ' + 'parameters r_shift and eta.\n') + handle.write('# Thus, there are no settings on radial parameter ' + 'generation available for display.\n') handle.write('# Sets of values for parameters:\n') - # set numpy print precision to lower number of decimal places for the following outputs + # set numpy print precision to lower number of decimal places for the + # following outputs np.set_printoptions(precision=4) # printing numpy arrays causes linebreaks if they contain many entries. @@ -523,7 +569,9 @@ def write_settings_overview(self, file=None): outstring_eta = f'eta_grid = {self._eta_grid}' handle.write('# ' + outstring_eta.replace("\n", "\n# ") + '\n') - if self.symfunc_type in ['angular_narrow', 'angular_wide', 'weighted_angular']: + if self.symfunc_type in ['angular_narrow', + 'angular_wide', + 'weighted_angular']: outstring_lambdas = f'lambdas = {self.lambdas}' handle.write('# ' + outstring_lambdas.replace("\n", "\n# ") + '\n') outstring_zetas = f'zetas = {self.zetas}' @@ -538,22 +586,28 @@ def write_settings_overview(self, file=None): handle.close() def find_element_combinations(self): - """Create combinations of elements, depending on symmetry function type and the elements in the system. - - For radial symmetry functions, the combinations are all possible ordered pairs of elements in the system, - including of an element with itself. - For angular symmetry functions (narrow or wide), the combinations consist of all possible elements as the - central atom, and then again for each central element all possible unordered pairs of neighbor elements. - For weighted symmetry functions (radial or angular), the combinations run only over all possible - central elements, with neighbors not taken into account at this stage. + """Create combinations of elements, depending on symmetry function type + and the elements in the system. + + For radial symmetry functions, the combinations are all possible + ordered pairs of elements in the system, including of an element with + itself. + For angular symmetry functions (narrow or wide), the combinations + consist of all possible elements as the central atom, and then again + for each central element all possible unordered pairs of neighbor + elements. + For weighted symmetry functions (radial or angular), the combinations + run only over all possible central elements, with neighbors not taken + into account at this stage. Returns ------- combinations : list of tuple of string - Each tuple in the list represents one element combination. - Length of the individual tuples can be 1, 2 or 3, depending on symmetry function type. - Zero-th entry of tuples is always the type of the central atom, 1st and 2nd entry are neighbor atom types - (radial sf: one neighbor, angular sf: two neighbors, weighted sf: no neighbors) + Each tuple in the list represents one element combination. Length + of the individual tuples can be 1, 2 or 3, depending on symmetry + function type. Zero-th entry of tuples is always the type of the + central atom, 1st and 2nd entry are neighbor atom types (radial sf: + one neighbor, angular sf: two neighbors, weighted sf: no neighbors) """ this_method_name = inspect.currentframe().f_code.co_name self.check_symfunc_type(calling_method_name=this_method_name) @@ -566,7 +620,9 @@ def find_element_combinations(self): combinations.append((elem_central, elem_neighbor)) elif self.symfunc_type in ['angular_narrow', 'angular_wide']: for elem_central in self.elements: - for pair_of_neighbors in itertools.combinations_with_replacement(self.elements, 2): + for pair_of_neighbors in \ + itertools.combinations_with_replacement(self.elements, + 2): comb = (elem_central,) + pair_of_neighbors combinations.append(comb) elif self.symfunc_type in ['weighted_radial', 'weighted_angular']: @@ -579,7 +635,8 @@ def write_parameter_strings(self, file=None): """Write symmetry function parameter sets, formatted as n2p2 requires. The output format is that required by the parameter file 'input.nn' - used by n2p2. The output is intended to be pasted/appended to that file. + used by n2p2. The output is intended to be pasted/appended to that + file. Each line in the output corresponds to one symmetry function. @@ -602,8 +659,7 @@ def write_parameter_strings(self, file=None): method iterates over the following combinations of (r_shift, eta, zeta, lambda): - | (1, 3, 5, -1) - | (1, 3, 5, 1) + | (1, 3, 5, -1) | (1, 3, 5, 1) | (1, 3, 6, -1) | (1, 3, 6, 1) | (2, 4, 5, -1) @@ -638,7 +694,8 @@ def write_parameter_strings(self, file=None): for comb in self.element_combinations: for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') + f'symfunction_short {comb[0]:2s} {sf_number} ' + f'{comb[1]:2s} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') handle.write('\n') elif self.symfunc_type in ['angular_narrow', 'angular_wide']: @@ -647,14 +704,18 @@ def write_parameter_strings(self, file=None): for zeta in self.zetas: for lambd in self.lambdas: handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {comb[1]:2s} {comb[2]:2s} {eta:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} {rs:9.3E}\n') + f'symfunction_short {comb[0]:2s} {sf_number} ' + f'{comb[1]:2s} {comb[2]:2s} {eta:9.3E} ' + f'{lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} ' + f'{rs:9.3E}\n') handle.write('\n') elif self.symfunc_type == 'weighted_radial': for comb in self.element_combinations: for (eta, rs) in zip(self._eta_grid, self._r_shift_grid): handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') + f'symfunction_short {comb[0]:2s} {sf_number} ' + f'{eta:9.3E} {rs:9.3E} {r_cutoff:9.3E}\n') handle.write('\n') elif self.symfunc_type == 'weighted_angular': @@ -663,7 +724,9 @@ def write_parameter_strings(self, file=None): for zeta in self.zetas: for lambd in self.lambdas: handle.write( - f'symfunction_short {comb[0]:2s} {sf_number} {eta:9.3E} {rs:9.3E} {lambd:2.0f} {zeta:9.3E} {r_cutoff:9.3E} \n') + f'symfunction_short {comb[0]:2s} {sf_number} ' + f'{eta:9.3E} {rs:9.3E} {lambd:2.0f} ' + f'{zeta:9.3E} {r_cutoff:9.3E} \n') handle.write('\n') # close the file again (unless writing to sys.stdout, From c3293b24f7029976cbbc4555eeecd67e0b7ec8b7 Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 22 Dec 2019 21:29:03 +0100 Subject: [PATCH 58/60] Very minor refactor of tests for write methods. --- .../tests/test_write_parameter_strings.py | 14 +++++++------- .../tests/test_write_settings_overview.py | 18 +++++++----------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py index 385488770..cd11b34a6 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py +++ b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py @@ -8,6 +8,9 @@ from sfparamgen import SymFuncParamGenerator +REFERENCE_PATH = 'reference-output_write_parameter_strings.txt' + + @pytest.fixture def basic_generator(): elems = ['S', 'Cu'] @@ -23,10 +26,9 @@ def isnotcomment(line): def test_write_parameter_strings_file(basic_generator, tmpdir): - '''Test parameter strings written to file match reference file, for toy inputs. + '''Test parameter strings written to file match reference, for toy inputs. ''' outfile_path = os.path.join(tmpdir, 'outfile.txt') - reference_path = 'reference-output_write_parameter_strings.txt' basic_generator.set_custom_radial_params([1,2], [4,5]) @@ -57,16 +59,14 @@ def test_write_parameter_strings_file(basic_generator, tmpdir): # with '#'). These lines are included in the reference output file as a # reminder of what settings to use in the tests to recreate the reference # output, but they are otherwise not essential for the test. - with open(outfile_path) as f_out, open(reference_path) as f_reference: + with open(outfile_path) as f_out, open(REFERENCE_PATH) as f_reference: f_reference = filter(isnotcomment, f_reference) assert all(x == y for x, y in zip(f_out, f_reference)) def test_write_parameter_strings_stdout(basic_generator, capsys): - '''Test parameter strings written to stdout match reference file, for toy inputs. + '''Test parameter strings written to stdout match reference, for toy inputs. ''' - reference_path = 'reference-output_write_parameter_strings.txt' - basic_generator.set_custom_radial_params([1,2], [4,5]) ## radial @@ -97,7 +97,7 @@ def test_write_parameter_strings_stdout(basic_generator, capsys): # compare what was written to stdout with the reference output file reference_data = [] - with open(reference_path, 'r') as f_reference: + with open(REFERENCE_PATH, 'r') as f_reference: for line in f_reference: # ignore comment lines in reference output file if not line[0] == '#': diff --git a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py index 01385773a..e27952acd 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py +++ b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py @@ -8,6 +8,9 @@ import filecmp +REFERENCE_PATH = 'reference-output_write_settings_overview.txt' + + @pytest.fixture def basic_generator(): elems = ['S', 'Cu'] @@ -15,15 +18,11 @@ def basic_generator(): def test_write_settings_overview_file(basic_generator, tmpdir): - ########### general settings ########### outfile_path = os.path.join(tmpdir, 'outfile.txt') - reference_path = 'reference-output_write_settings_overview.txt' - - elems = ['S', 'Cu'] - basic_generator = SymFuncParamGenerator(elements=elems, r_cutoff=11.22) ########### using custom radial parameters ########### - basic_generator.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) + basic_generator.set_custom_radial_params(r_shift_values=[1,2], + eta_values=[4,5]) ## radial basic_generator.symfunc_type = 'radial' @@ -74,13 +73,10 @@ def test_write_settings_overview_file(basic_generator, tmpdir): basic_generator.write_settings_overview(outfile_path) ########### test equality with target output ########### - assert filecmp.cmp(outfile_path, reference_path) + assert filecmp.cmp(outfile_path, REFERENCE_PATH) def test_write_settings_overview_stdout(basic_generator, capsys): - ########### general settings ########### - reference_path = 'reference-output_write_settings_overview.txt' - ########### using custom radial parameters ########### basic_generator.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) @@ -136,7 +132,7 @@ def test_write_settings_overview_stdout(basic_generator, capsys): captured = capsys.readouterr() ########### test equality with target output ########### - with open(reference_path, 'r') as f_reference: + with open(REFERENCE_PATH, 'r') as f_reference: assert captured.out == f_reference.read() From 9171cb323c5cb5704d47f0eefbae680a7713593f Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Sun, 22 Dec 2019 22:46:57 +0100 Subject: [PATCH 59/60] Change write method args from paths to file objects. --- .../python/symfunc_paramgen/src/sfparamgen.py | 44 +++------ .../tests/test_write_parameter_strings.py | 45 ++++----- .../tests/test_write_settings_overview.py | 98 ++++++++++--------- 3 files changed, 89 insertions(+), 98 deletions(-) diff --git a/tools/python/symfunc_paramgen/src/sfparamgen.py b/tools/python/symfunc_paramgen/src/sfparamgen.py index ba3d5fc25..222326812 100644 --- a/tools/python/symfunc_paramgen/src/sfparamgen.py +++ b/tools/python/symfunc_paramgen/src/sfparamgen.py @@ -5,6 +5,7 @@ import inspect import itertools import warnings +from typing import Optional, TextIO class SymFuncParamGenerator: @@ -500,15 +501,15 @@ def check_writing_prerequisites(self, calling_method_name=None): f' they have not been cleared since by setting a ' f'non-angular symmetry function type.') - def write_settings_overview(self, file=None): + def write_settings_overview(self, fileobj: Optional[TextIO]=None): """Write the settings the currently stored set of symmetry function parameters was generated with. Parameters ---------- - file : path-like, optional - The file to write the settings information to, using append mode. - If not specified, write to sys.stdout instead. + fileobj : `typing.TextIO`, optional + file object to write the settings information to. + If not given, write to sys.stdout instead. Returns ------- @@ -523,12 +524,10 @@ def write_settings_overview(self, file=None): weighted_radial='Weighted radial', weighted_angular='Weighted angular') - # depending on presence of file parameter, either direct output - # to stdout, or open the specified file, in append mode - if file is None: + if fileobj is None: handle = sys.stdout else: - handle = open(file, 'a') + handle = fileobj handle.write('########################################################' '#################\n') @@ -580,11 +579,6 @@ def write_settings_overview(self, file=None): np.set_printoptions(precision=8) handle.write('\n') - # close the file again (unless writing to sys.stdout, - # which should not be closed) - if handle is not sys.stdout: - handle.close() - def find_element_combinations(self): """Create combinations of elements, depending on symmetry function type and the elements in the system. @@ -631,11 +625,11 @@ def find_element_combinations(self): return combinations - def write_parameter_strings(self, file=None): + def write_parameter_strings(self, fileobj: Optional[TextIO]=None): """Write symmetry function parameter sets, formatted as n2p2 requires. The output format is that required by the parameter file 'input.nn' - used by n2p2. The output is intended to be pasted/appended to that + used by n2p2. The output is intended to be pasted/written to that file. Each line in the output corresponds to one symmetry function. @@ -659,7 +653,8 @@ def write_parameter_strings(self, file=None): method iterates over the following combinations of (r_shift, eta, zeta, lambda): - | (1, 3, 5, -1) | (1, 3, 5, 1) + | (1, 3, 5, -1) + | (1, 3, 5, 1) | (1, 3, 6, -1) | (1, 3, 6, 1) | (2, 4, 5, -1) @@ -669,9 +664,9 @@ def write_parameter_strings(self, file=None): Parameters ---------- - file : path-like, optional - The file to write the parameter strings to, using append mode. - If not specified, write to sys.stdout instead. + fileobj : `typing.TextIO`, optional + file object to write the parameter strings to. + If not given, write to sys.stdout instead. Returns ------- @@ -680,12 +675,10 @@ def write_parameter_strings(self, file=None): this_method_name = inspect.currentframe().f_code.co_name self.check_writing_prerequisites(calling_method_name=this_method_name) - # depending on presence of file parameter, either direct output - # to stdout, or open the specified file, in append mode - if file is None: + if fileobj is None: handle = sys.stdout else: - handle = open(file, 'a') + handle = fileobj r_cutoff = self.r_cutoff sf_number = self.symfunc_type_numbers[self.symfunc_type] @@ -728,8 +721,3 @@ def write_parameter_strings(self, file=None): f'{eta:9.3E} {rs:9.3E} {lambd:2.0f} ' f'{zeta:9.3E} {r_cutoff:9.3E} \n') handle.write('\n') - - # close the file again (unless writing to sys.stdout, - # which should not be closed) - if handle is not sys.stdout: - handle.close() diff --git a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py index cd11b34a6..757bb4c73 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py +++ b/tools/python/symfunc_paramgen/tests/test_write_parameter_strings.py @@ -32,28 +32,29 @@ def test_write_parameter_strings_file(basic_generator, tmpdir): basic_generator.set_custom_radial_params([1,2], [4,5]) - ## radial - basic_generator.symfunc_type = 'radial' - basic_generator.write_parameter_strings(outfile_path) - - ## weighted_radial - basic_generator.symfunc_type = 'weighted_radial' - basic_generator.write_parameter_strings(outfile_path) - - ## angular narrow - basic_generator.symfunc_type = 'angular_narrow' - basic_generator.zetas = [5.5, 7.5] - basic_generator.write_parameter_strings(outfile_path) - - ## angular_wide - basic_generator.symfunc_type = 'angular_wide' - basic_generator.zetas = [5.5, 7.5] - basic_generator.write_parameter_strings(outfile_path) - - ## weighted_angular - basic_generator.symfunc_type = 'weighted_angular' - basic_generator.zetas = [5.5, 7.5] - basic_generator.write_parameter_strings(outfile_path) + with open(outfile_path, 'w') as outfile_obj: + ## radial + basic_generator.symfunc_type = 'radial' + basic_generator.write_parameter_strings(outfile_obj) + + ## weighted_radial + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_parameter_strings(outfile_obj) + + ## angular narrow + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings(outfile_obj) + + ## angular_wide + basic_generator.symfunc_type = 'angular_wide' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings(outfile_obj) + + ## weighted_angular + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.zetas = [5.5, 7.5] + basic_generator.write_parameter_strings(outfile_obj) # Ignore comment lines in the reference output file (lines starting # with '#'). These lines are included in the reference output file as a diff --git a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py index e27952acd..1682afdf9 100644 --- a/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py +++ b/tools/python/symfunc_paramgen/tests/test_write_settings_overview.py @@ -24,53 +24,54 @@ def test_write_settings_overview_file(basic_generator, tmpdir): basic_generator.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) - ## radial - basic_generator.symfunc_type = 'radial' - basic_generator.write_settings_overview(outfile_path) - - ## weighted_radial - basic_generator.symfunc_type = 'weighted_radial' - basic_generator.write_settings_overview(outfile_path) - - basic_generator.zetas = [5.5, 7.5] - - ## angular narrow - basic_generator.symfunc_type = 'angular_narrow' - basic_generator.write_settings_overview(outfile_path) - - ## angular_wide - basic_generator.symfunc_type = 'angular_wide' - basic_generator.write_settings_overview(outfile_path) - - ## weighted_angular - basic_generator.symfunc_type = 'weighted_angular' - basic_generator.write_settings_overview(outfile_path) - - ########### using the method for radial parameter generation ########### - basic_generator.generate_radial_params(rule='gastegger2018', mode='center', - nb_param_pairs=2, r_lower=1.5, r_upper=9.) - - ## radial - basic_generator.symfunc_type = 'radial' - basic_generator.write_settings_overview(outfile_path) - - ## weighted_radial - basic_generator.symfunc_type = 'weighted_radial' - basic_generator.write_settings_overview(outfile_path) - - basic_generator.zetas = [5.5, 7.5] - - ## angular narrow - basic_generator.symfunc_type = 'angular_narrow' - basic_generator.write_settings_overview(outfile_path) - - ## angular_wide - basic_generator.symfunc_type = 'angular_wide' - basic_generator.write_settings_overview(outfile_path) - - ## weighted_angular - basic_generator.symfunc_type = 'weighted_angular' - basic_generator.write_settings_overview(outfile_path) + with open(outfile_path, 'w') as outfile_obj: + ## radial + basic_generator.symfunc_type = 'radial' + basic_generator.write_settings_overview(outfile_obj) + + ## weighted_radial + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_settings_overview(outfile_obj) + + basic_generator.zetas = [5.5, 7.5] + + ## angular narrow + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.write_settings_overview(outfile_obj) + + ## angular_wide + basic_generator.symfunc_type = 'angular_wide' + basic_generator.write_settings_overview(outfile_obj) + + ## weighted_angular + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.write_settings_overview(outfile_obj) + + ########### using the method for radial parameter generation ########### + basic_generator.generate_radial_params(rule='gastegger2018', mode='center', + nb_param_pairs=2, r_lower=1.5, r_upper=9.) + + ## radial + basic_generator.symfunc_type = 'radial' + basic_generator.write_settings_overview(outfile_obj) + + ## weighted_radial + basic_generator.symfunc_type = 'weighted_radial' + basic_generator.write_settings_overview(outfile_obj) + + basic_generator.zetas = [5.5, 7.5] + + ## angular narrow + basic_generator.symfunc_type = 'angular_narrow' + basic_generator.write_settings_overview(outfile_obj) + + ## angular_wide + basic_generator.symfunc_type = 'angular_wide' + basic_generator.write_settings_overview(outfile_obj) + + ## weighted_angular + basic_generator.symfunc_type = 'weighted_angular' + basic_generator.write_settings_overview(outfile_obj) ########### test equality with target output ########### assert filecmp.cmp(outfile_path, REFERENCE_PATH) @@ -78,7 +79,8 @@ def test_write_settings_overview_file(basic_generator, tmpdir): def test_write_settings_overview_stdout(basic_generator, capsys): ########### using custom radial parameters ########### - basic_generator.set_custom_radial_params(r_shift_values=[1,2], eta_values=[4,5]) + basic_generator.set_custom_radial_params(r_shift_values=[1,2], + eta_values=[4,5]) ## radial basic_generator.symfunc_type = 'radial' From 6189fa0dd199c2b2e664192d46c2ace6cabd7b8c Mon Sep 17 00:00:00 2001 From: Florian Buchner Date: Mon, 23 Dec 2019 21:28:17 +0100 Subject: [PATCH 60/60] Adapt example to reflect changed write methods. --- .../symfunc_paramgen/examples/example.ipynb | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/tools/python/symfunc_paramgen/examples/example.ipynb b/tools/python/symfunc_paramgen/examples/example.ipynb index bb42a8669..96b0f93f6 100644 --- a/tools/python/symfunc_paramgen/examples/example.ipynb +++ b/tools/python/symfunc_paramgen/examples/example.ipynb @@ -46,7 +46,7 @@ "source": [ "Using this tool typically consists of the following steps:\n", "\n", - "1. Creating an object of the symmetry function parameter generator class.\n", + "1. Creating an object of the SymFuncParamGenerator class.\n", "2. Filling this object with the necessary settings and symmetry function parameters, using the class methods provided.\n", "3. Writing the symmetry function parameters, in a format usable by n2p2.\n", "\n", @@ -64,9 +64,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We first need to instantiate the symmetry function parameter generator class.\n", + "We first need to instantiate the SymFuncParamGenerator class.\n", "\n", - "The elements in the system, and the cutoff radius are required as arguments to the constructor. These are considered parameters describing the system, rather than symmetry function settings, and as such are not intended for later change. To generate symmetry function parameters for different elements and/or for different cutoff radiuses, a new instance of the class should be created." + "The elements in the system, and the cutoff radius are required as arguments to the constructor. These are considered system parameters, rather than symmetry function settings, and as such are not intended for later change. To generate symmetry function parameters for different elements and/or for different cutoff radiuses, a new instance of the class should be created." ] }, { @@ -96,7 +96,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The symmetry function type needs to be specified. In this example, we will be setting the symmetry function type to 'radial':" + "The symmetry function type needs to be specified. In this example, we will be setting it to 'radial':" ] }, { @@ -267,9 +267,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the above examples, the settings overview and the parameter strings were written to stdout, which is the default behavior. You can, however, also write them to a file by passing the file path as an optional argument.\n", - "\n", - "If the file does not exist, it is created by the methods. If it exists already, the methods append to it." + "In the above examples, the settings overview and the parameter strings were written to stdout, which is the default behavior. You can, however, also write them to a file by passing a file object as an optional argument." ] }, { @@ -278,14 +276,9 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", - "\n", - "try:\n", - " myGenerator.write_settings_overview(file='outfile.txt')\n", - " myGenerator.write_parameter_strings(file='outfile.txt')\n", - "finally:\n", - " # to remove clutter in this example, we remove the file again\n", - " os.remove('outfile.txt')" + "with open('example-outfile.txt', 'w') as f:\n", + " myGenerator.write_settings_overview(fileobj=f)\n", + " myGenerator.write_parameter_strings(fileobj=f)" ] }, { @@ -411,7 +404,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.7.1" } }, "nbformat": 4,