diff --git a/solcore/config_tools.py b/solcore/config_tools.py index f265ab2c..1aa4402e 100755 --- a/solcore/config_tools.py +++ b/solcore/config_tools.py @@ -7,8 +7,8 @@ import solcore import glob -home_folder = os.path.expanduser('~') -user_config = os.path.join(home_folder, '.solcore_config.txt') +home_folder: str = os.path.expanduser('~') +user_config: str = os.path.join(home_folder, '.solcore_config.txt') user_config_data = ConfigParser() user_config_data.read(user_config) @@ -16,7 +16,7 @@ default_config_data.read(solcore.default_config) -def reset_defaults(confirm=False): +def reset_defaults(confirm: bool = False) -> None: """ Resets the default Solcore configuration in the user home folder. :return: None @@ -39,7 +39,7 @@ def reset_defaults(confirm=False): print('Default Solcore configuration has been restored!') -def save_user_config(): +def save_user_config() -> None: """ Saves the current user configuration :return: None @@ -48,7 +48,7 @@ def save_user_config(): user_config_data.write(fp) -def remove_source(section, name): +def remove_source(section: str, name: str) -> None: """ General function to remove sources from the configuration files. It checks if the source exists and, if so, if it is a default Solcore source. In the later case, it disable the source by setting it to an empty string rather than removing it. @@ -72,7 +72,7 @@ def remove_source(section, name): print('{}:{} source removed!'.format(section, name)) -def add_source(section, name, location): +def add_source(section: str, name: str, location: str) -> None: """ General function to add sources to the configuration files. If the source already exists, its value will be replaced by the new one. @@ -86,7 +86,7 @@ def add_source(section, name, location): print('{}:{} source added!'.format(section, name)) -def restore_default_source(section, name): +def restore_default_source(section: str, name: str) -> None: """ Restores the default value of a source, assuming the source has a default value. :param section: The section of the source. @@ -104,7 +104,7 @@ def restore_default_source(section, name): print('Default Solcore value for {} source {} has been restored!'.format(section, name)) -def add_units_source(name, location): +def add_units_source(name: str, location: str) -> None: """ Adds a Units source to Solcore. :param name: The name of the source. @@ -114,7 +114,7 @@ def add_units_source(name, location): add_source('Units', name, location=location) -def add_parameters_source(name, location): +def add_parameters_source(name: str, location: str) -> None: """ Adds a Parameters source to Solcore. :param name: The name of the source. @@ -124,7 +124,7 @@ def add_parameters_source(name, location): add_source('Parameters', name, location=location) -def add_materials_source(name, location): +def add_materials_source(name: str, location: str) -> None: """ Adds a Materials source to Solcore. :param name: The name of the source. @@ -135,7 +135,7 @@ def add_materials_source(name, location): add_source('Materials', name, location=location) -def remove_units_source(name): +def remove_units_source(name: str) -> None: """ Removes a Units source from Solcore. :param name: The name of the source. @@ -144,7 +144,7 @@ def remove_units_source(name): remove_source('Units', name) -def remove_parameters_source(name): +def remove_parameters_source(name: str) -> None: """ Removes a Parameters source from Solcore. :param name: The name of the source. @@ -153,7 +153,7 @@ def remove_parameters_source(name): remove_source('Parameters', name) -def remove_materials_source(name): +def remove_materials_source(name: str) -> None: """ Removes a Materials source from Solcore. :param name: The name of the source. @@ -162,7 +162,7 @@ def remove_materials_source(name): remove_source('Materials', name) -def restore_default_units_source(name): +def restore_default_units_source(name: str) -> None: """ Restores the default value of a Units source from Solcore. :param name: The name of the source. @@ -171,7 +171,7 @@ def restore_default_units_source(name): restore_default_source('Units', name) -def restore_default_parameters_source(name): +def restore_default_parameters_source(name: str) -> None: """ Restores the default value of a Parameters source from Solcore. :param name: The name of the source. @@ -180,7 +180,7 @@ def restore_default_parameters_source(name): restore_default_source('Parameters', name) -def restore_default_materials_source(name): +def restore_default_materials_source(name: str) -> None: """ Restores the default value of a Materials source from Solcore. :param name: The name of the source. @@ -189,7 +189,7 @@ def restore_default_materials_source(name): restore_default_source('Materials', name) -def welcome_message(show): +def welcome_message(show: bool) -> None: """ Sets if the welcome message must be shown or not :param show: True/False for showing/hiding the welcome message @@ -198,7 +198,7 @@ def welcome_message(show): user_config_data['Configuration']['welcome_message'] = int(show) -def verbose_loading(show): +def verbose_loading(show: bool) -> None: """ Sets if the loading messages (besides the welcome message) must be shown or not :param show: True/False for showing/hiding the loading messages @@ -207,7 +207,7 @@ def verbose_loading(show): user_config_data['Configuration']['verbose_loading'] = int(show) -def set_location_of_spice(location): +def set_location_of_spice(location: str) -> None: """ Sets the location of the spice executable. It does not test if it works. :param location: The location of the spice executable. @@ -217,7 +217,7 @@ def set_location_of_spice(location): save_user_config() -def set_location_of_smarts(location): +def set_location_of_smarts(location: str) -> None: """ Sets the location of the SMARTS distribution (the root folder). It does not test if it works. :param location: The location of the SMARTS distribution. @@ -227,7 +227,7 @@ def set_location_of_smarts(location): save_user_config() -def get_current_config(): +def get_current_config() -> None: """ Prints the current Solcore configuration :return: None @@ -241,7 +241,7 @@ def get_current_config(): print() -def check_user_config(): +def check_user_config() -> None: """ Checks if there's a user configuration file, asking if it needs to be created. :return: None diff --git a/solcore/crystals.py b/solcore/crystals.py index 5e5dc80a..4e21bc6a 100755 --- a/solcore/crystals.py +++ b/solcore/crystals.py @@ -2,8 +2,9 @@ Calculates the k-points of the Brillouin zone in a given direction """ import numpy as np +from typing import List, Dict, Tuple -label_map = { +label_map: Dict[str, str] = { "Gamma": "$\Gamma$", "X": "X", "K": "K", @@ -12,7 +13,8 @@ "U": "U", } -def brillouin_critical_points(a): + +def brillouin_critical_points(a: float) -> Dict[str, np.ndarray]: return { "Gamma": np.array((0, 0, 0)), "X": np.pi / a * np.array((0, 2, 0)), @@ -23,7 +25,11 @@ def brillouin_critical_points(a): } -def traverse_brillouin(a, traverse_order=("L", "Gamma", "X", "W", "K", "Gamma"), steps=30): +def traverse_brillouin(a: float, + traverse_order: tuple = ("L", "Gamma", "X", + "W", "K", "Gamma"), + steps: int = 30) -> Tuple[np.ndarray, float, + List[Tuple[float, str]]]: critical_points = brillouin_critical_points(a) traverse_list = list(traverse_order) @@ -57,9 +63,11 @@ def traverse_brillouin(a, traverse_order=("L", "Gamma", "X", "W", "K", "Gamma"), return np.array(coords), graph_cords / scale, list(zip(xticks / scale, [label_map[s] for s in traverse_order])) -def kvector(a, t=0, p=np.pi, fraction=0.2, points=50, vin=None): +def kvector(a: float, t: float = 0, p: float = np.pi, + fraction: float = 0.2, points: int = 50, + vin: np.ndarray = None) -> np.ndarray: """ Calculates the k points in a direction given by the spheric angles theta (t) and phi (p). - + The fraction of the Brilluin zone calculated is given by "fraction" and the number of points by "points". If "vin" is given, the direction of interest is taken from this vector.""" diff --git a/solcore/interpolate.py b/solcore/interpolate.py index 90e86693..267c018b 100755 --- a/solcore/interpolate.py +++ b/solcore/interpolate.py @@ -1,6 +1,7 @@ # from scipy import interpolate as I import numpy as np from scipy.interpolate import make_interp_spline, splev +from typing import Union class interp1d(object): @@ -12,8 +13,9 @@ class interp1d(object): UnivariateSpline - a more recent wrapper of the FITPACK routines """ - def __init__(self, x, y, kind='linear', axis=-1, - copy=True, bounds_error=False, fill_value=np.nan): + def __init__(self, x: np.ndarray, y: np.ndarray, kind: str = 'linear', + axis: int = -1, copy: bool = True, bounds_error: bool = False, + fill_value: float = np.nan): """ Initialize a 1D linear interpolation class. Description @@ -118,7 +120,7 @@ def __init__(self, x, y, kind='linear', axis=-1, self.x = x self.y = oriented_y - def _call_linear(self, x_new): + def _call_linear(self, x_new: np.ndarray) -> np.ndarray: # 2. Find where in the orignal data, the values to interpolate # would be inserted. @@ -148,7 +150,7 @@ def _call_linear(self, x_new): return y_new - def _call_nearest(self, x_new): + def _call_nearest(self, x_new: np.ndarray) -> np.ndarray: """ Find nearest neighbour interpolated y_new = f(x_new).""" # 2. Find where in the averaged data the values to interpolate @@ -165,12 +167,12 @@ def _call_nearest(self, x_new): return y_new - def _call_spline(self, x_new): + def _call_spline(self, x_new: np.ndarray) -> np.ndarray: x_new = np.asarray(x_new) result = splev(x_new.ravel(), self._spline) return result.reshape(x_new.shape + result.shape[1:]) - def __call__(self, x_new): + def __call__(self, x_new: np.ndarray) -> np.ndarray: """Find interpolated y_new = f(x_new). Parameters @@ -223,7 +225,7 @@ def __call__(self, x_new): axes[self.axis:self.axis] = list(range(nx)) return y_new.transpose(axes) - def _check_bounds(self, x_new): + def _check_bounds(self, x_new: np.ndarray) -> np.ndarray: """Check the inputs for being in the bounds of the interpolated data. Parameters @@ -259,7 +261,8 @@ def _check_bounds(self, x_new): class BilinearInterpolation(object): """docstring for BilinearInterpolation""" - def __init__(self, x=None, y=None, z=None, fill_value=0.): + def __init__(self, x: Union[list, np.ndarray], y: Union[list, np.ndarray], + z: Union[list, np.ndarray], fill_value: float = 0.): super(BilinearInterpolation, self).__init__() self.x = np.array(x) self.y = np.array(y) @@ -278,7 +281,7 @@ def __init__(self, x=None, y=None, z=None, fill_value=0.): 1], "The number of columns in z (which is %s), must be the same as number of elements in y (which is %s)" % ( y_s[0], z_s[1]) - def __call__(self, xvalue, yvalue): + def __call__(self, xvalue: float, yvalue: float) -> np.ndarray: """The intepolated value of the surface.""" try: x_i = 0 @@ -362,7 +365,7 @@ def __call__(self, xvalue, yvalue): y = np.array([0., np.pi / 4, np.pi / 2]) # Some reflectivity values - # rads @ 400nm, rads @ 600nm, rads @ 601m, rads @ 1000nm + # rads @ 400nm, rads @ 600nm, rads @ 601m, rads @ 1000nm z = np.array([[0., 0., 0.], [1e-9, 1e-9, 1e-9], [1 - 1e-9, 1 - 1e-9, 1 - 1e-9], [1., 1., 1.]]) # print z.shape diff --git a/solcore/science_tracker.py b/solcore/science_tracker.py index c510c94d..4ef9e317 100755 --- a/solcore/science_tracker.py +++ b/solcore/science_tracker.py @@ -1,23 +1,23 @@ import inspect -bibliography = [] -bibliography_id = [] -science_tracking = [] -track_science_references = False -track_each_reference_call = False +bibliography: list = [] +bibliography_id: list = [] +science_tracking: list = [] +track_science_references: bool = False +track_each_reference_call: bool = False -def hexID(obj): +def hexID(obj: str) -> str: return "{}".format(id(obj)) -def science_reference(short_purpose, reference): +def science_reference(short_purpose: str, reference: str) -> None: """Marker acting as a reference for the origin of specific information - + Acts as a marker in code where particular alogrithms/data/... originates. General execution of code silently passes these markers, but remembers how and where they were called. Which markers were passed in a particular program run can be recalled with print_references(). - + Arguments: short_purpose: Identify the thing being referenced (string) reference: The reference itself, in any sensible format. @@ -49,7 +49,7 @@ def science_reference(short_purpose, reference): science_tracking.append((call_record, short_purpose, bibliography_id.index(identifier) + 1)) -def print_references(): +def print_references() -> None: """ recall the science_reference markers passed, print out the referenes.""" global bibliography, bibliography_id, science_tracking, track_each_reference_call @@ -64,7 +64,7 @@ def print_references(): print("[{}] - {}".format(i + 1, b)) -def track_science(track_each_call=False): +def track_science(track_each_call: bool = False): """configure science references -- determine whether or not each call separately or only the first for each reference.""" global track_science_references, track_each_reference_call @@ -73,11 +73,11 @@ def track_science(track_each_call=False): if __name__ == "__main__": - def myRandomFunctionA(): + def myRandomFunctionA() -> None: myRandomFunctionB(d=1) - def myRandomFunctionB(d): + def myRandomFunctionB(d) -> None: a = 1 science_reference("doing something smart", "My Awesome Book, by me.") diff --git a/solcore/singleton.py b/solcore/singleton.py index b720209f..5dcf5391 100755 --- a/solcore/singleton.py +++ b/solcore/singleton.py @@ -1,19 +1,21 @@ from solcore import verbose +from typing import Any, Dict, Callable class Singleton(type): # META! """ A metaclass that restricts children to one instance. Attempting to create a second instance simply returns the first instance. """ - _dufftown = {} # All the Singleton instances live here... + # All the Singleton instances live here... + _dufftown: Dict['Singleton', 'Singleton'] = {} - def __call__(cls, *args, **kwargs): + def __call__(cls, *args: Any, **kwargs: Any) -> 'Singleton': if cls not in cls._dufftown: # ... or if they don't yet, it's about time! # print("Instantiating cls", cls) cls._dufftown[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._dufftown[cls] - def breakout(method): + def breakout(method: 'Singleton') -> 'Singleton': """ Decorator for singleton methods that should be available in global scope """ method.break_me_out = None # or, you know, anything. @@ -25,11 +27,11 @@ class Redirect_to_singleton_method: standalone function. """ - def __init__(self, cls, function): + def __init__(self, cls: 'Singleton', function: Callable) -> None: self.singleton_class = cls # LABEL COME_BACK_HERE; here instead.;RETURN; self.function = function - def __call__(self, *args, **kwargs): + def __call__(self, *args: Any, **kwargs: Any) -> str: """ Call the singleton method and return the result """ return self.function(self.singleton_class(), *args, **kwargs) @@ -38,10 +40,10 @@ class breakoutFunctions: This is identical to the 'breakoutClass' function defined in 'source_managed_class', but has the option of making the function available not in the global scope but somewhere else. """ - def __init__(self, namespace): + def __init__(self, namespace: str) -> None: self.namespace_to_breakout_into = namespace - def __call__(self, cls): + def __call__(self, cls: 'Singleton') -> 'Singleton': """ And this is really the decorator for singletons which should make some of their methods available somewhere else """ @@ -82,15 +84,16 @@ class test: @Singleton.breakoutFunctions(moo) class ForeverAlone(metaclass=Singleton): @Singleton.breakout - def wait_you_havent_instantiated_anything(self): + def wait_you_havent_instantiated_anything(self) -> str: return "YES I DID YOU JUST MISSED IT: " + str(self) @Singleton.breakout - def a_global_instance_method_surely_not(self): + def a_global_instance_method_surely_not(self) -> str: return "YES SURELY." @Singleton.breakout - def rofl_this_will_never_work(self, end_symbol, end_number): + def rofl_this_will_never_work(self, end_symbol: str, + end_number: int) -> str: return "WHO'S LAUGHING NOW" + end_symbol * end_number @@ -102,7 +105,7 @@ def rofl_this_will_never_work(self, end_symbol, end_number): print("moo.a_global_instance_method_surely_not() -> ", b) print("moo.rofl_this_will_never_work('!', end_number=3) -> ", c) - # should output: + # should output: # wait_you_havent_instantiated_anything() -> YES I DID YOU JUST MISSED IT: <__main__.ForeverAlone object at 0x10c377b90> # a_global_instance_method_surely_not() -> YES SURELY. # rofl_this_will_never_work('!', end_number=3) -> WHO'S LAUGHING NOW!!! diff --git a/solcore/smooth.py b/solcore/smooth.py index 49c4b114..7672e4e2 100755 --- a/solcore/smooth.py +++ b/solcore/smooth.py @@ -1,35 +1,36 @@ import numpy as np -def smooth(x, window_len, window='hanning', blurmode="even"): +def smooth(x: np.ndarray, window_len: int, window: str = 'hanning', + blurmode: str = "even") -> np.ndarray: """smooth the data using a window with requested size. - + This method is based on the convolution of a scaled window with the signal. - The signal is prepared by introducing reflected copies of the signal + The signal is prepared by introducing reflected copies of the signal (with the window size) in both ends so that transient parts are minimized in the begining and end part of the output signal. - + input: - x: the input signal + x: the input signal window_len: the dimension of the smoothing window; should be an odd integer window: the type of window from 'flat', 'hanning', 'hamming', 'bartlett', 'blackman' flat window will produce a moving average smoothing. output: the smoothed signal - + example: t=linspace(-2,2,0.1) x=sin(t)+randn(len(t))*0.1 y=smooth(x) - - see also: - + + see also: + numpy.hanning, numpy.hamming, numpy.bartlett, numpy.blackman, numpy.convolve scipy.signal.lfilter - - TODO: the window parameter could be the window itself if an array instead of a string + + TODO: the window parameter could be the window itself if an array instead of a string """ if x.ndim != 1: