optimize.py 6.36 KB
Newer Older
1
"""
2
3
Created on 12/15/16 10:08 AM
@author: Numan Laanait
4
5
6
7
8
9
10
"""

from warnings import warn
import numpy as np
import sys
import multiprocessing as mp
from .guess_methods import GuessMethods
11
12
from .fit_methods import Fit_Methods
import scipy
13

14
def targetFuncGuess(args, **kwargs):
15
16
17
18
19
20
    """
    Needed to create mappable function for multiprocessing
    :param args:
    :param kwargs:
    :return:
    """
Chris Smith's avatar
Chris Smith committed
21
22
    opt = args[-1]
    func = opt._guessFunc()
23
24
25
    results = func(args[0])
    return results

26
27
28
29
30
31
32
def targetFuncFit(args, **kwargs):
    """
    Needed to create mappable function for multiprocessing
    :param args:
    :param kwargs:
    :return:
    """
Chris Smith's avatar
Chris Smith committed
33
34
    opt = args[-1]
    solver, solver_options, func = opt._initiateSolverAndObjFunc()
35
36
37
    results = solver(func, args[1], args=[args[0]])
    return results

38
39
40
41
42
class Optimize(object):
    """
    In charge of all optimization and computation and is used within the Model Class.
    """

43
    def __init__(self, data=np.array([]), guess=np.array([]), parallel=True):
44
45
46
47
48
49
        """

        :param data:
        """
        if isinstance(data, np.ndarray):
            self.data = data
50
51
        if isinstance(guess, np.ndarray):
            self.guess = guess
52
        else:
53
            warn('Error: data and guess must be numpy.ndarray. Exiting...')
54
55
56
57
58
59
60
61
62
63
            sys.exit()
        self._parallel = parallel


    def _guessFunc(self):
        gm = GuessMethods()
        if self.strategy in gm.methods:
            func = gm.__getattribute__(self.strategy)(**self.options)
            return func
        else:
64
            warn('Error: %s is not implemented in pycroscopy.analysis.GuessMethods to find guesses' % self.strategy)
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100



    def computeGuess(self, processors = 1, strategy='wavelet_peaks',
                     options={"peak_widths": np.array([10,200]),"peak_step":20}, **kwargs):
        """

        Parameters
        ----------
        data
        strategy: string
            Default is 'Wavelet_Peaks'.
            Can be one of ['wavelet_peaks', 'relative_maximum', 'gaussian_processes']. For updated list, run GuessMethods.methods
        options: dict
            Default: Options for wavelet_peaks{"peaks_widths": np.array([10,200]), "peak_step":20}.
            Dictionary of options passed to strategy. For more info see GuessMethods documentation.

        kwargs:
            processors: int
                number of processors to use. Default all processors on the system except for 1.

        Returns
        -------

        """
        self.strategy = strategy
        self.options = options
        gm = GuessMethods()
        if strategy in gm.methods:
            # func = gm.__getattribute__(strategy)(**options)
            results = list()
            if self._parallel:
                # start pool of workers
                print('Computing Jobs In parallel ... launching %i kernels...' % processors)
                pool = mp.Pool(processors)
                # Vectorize tasks
Chris Smith's avatar
Chris Smith committed
101
                tasks = [(vector, self) for vector in self.data]
102
103
                chunk = int(self.data.shape[0] / processors)
                # Map them across processors
104
                jobs = pool.imap(targetFuncGuess, tasks, chunksize=chunk)
105
106
107
108
109
110
                # get Results from different processes
                results = [j for j in jobs]
                print('Extracted Results...')
                # Finished reading the entire data set
                print('closing %i kernels...' % processors)
                pool.close()
111
112
                return results

113
114
            else:
                print("Computing Guesses In Serial ...")
Chris Smith's avatar
Chris Smith committed
115
                results = [targetFuncGuess((vector, self)) for vector in self.data]
116
117
118
                return results
        else:
            warn('Error: %s is not implemented in pycroscopy.analysis.GuessMethods to find guesses' % strategy)
119
120
121
122
123
124
125

    def _initiateSolverAndObjFunc(self):
        if self.solver_type in scipy.optimize.__dict__.keys():
            solver = scipy.optimize.__dict__[self.solver_type]
        if self.obj_func is None:
            fm = Fit_Methods()
            func = fm.__getattribute__(self.obj_func_name)(self.obj_func_xvals)
126
        return solver, self.solver_options, func
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

    def computeFit(self, processors = 1, solver_type='least_squares', solver_options={},
                   obj_func={'class':'Fit_Methods','obj_func':'SHO','xvals':np.array([])}):
        """

        Parameters
        ----------
        data
        solver_type : string
            Optimization solver to use (minimize,least_sq, etc...). For additional info see scipy.optimize
        solver_options: dict()
            Default: dict()
            Dictionary of options passed to solver. For additional info see scipy.optimize
        obj_func: dict()
            Default is 'SHO'.
            Can be one of ['wavelet_peaks', 'relative_maximum', 'gaussian_processes']. For updated list, run GuessMethods.methods

        Returns
        -------

        """
        self.solver_type = solver_type
        self.solver_options = solver_options
        if self.solver_type not in scipy.optimize.__dict__.keys():
            warn('Solver %s does not exist!. For additional info see scipy.optimize' % (solver_type))
            sys.exit()
        if obj_func['class'] is None:
            self.obj_func = obj_func['obj_func']
        else:
            self.obj_func_xvals = obj_func['xvals']
            self.obj_func = None
            self.obj_func_name = obj_func['obj_func']
            self.obj_func_class = obj_func['class']

        if self._parallel:
            # start pool of workers
            print('Computing Jobs In parallel ... launching %i kernels...' % processors)
            pool = mp.Pool(processors)
            # Vectorize tasks
Chris Smith's avatar
Chris Smith committed
166
            tasks = [(vector, guess, self) for vector, guess in zip(self.data, self.guess)]
167
168
169
170
171
172
173
174
175
176
177
178
            chunk = int(self.data.shape[0] / processors)
            # Map them across processors
            jobs = pool.imap(targetFuncFit, tasks, chunksize=chunk)
            # get Results from different processes
            results = [j for j in jobs]
            # Finished reading the entire data set
            print('closing %i kernels...' % processors)
            pool.close()
            return results

        else:
            print("Computing Fits In Serial ...")
Chris Smith's avatar
Chris Smith committed
179
            tasks = [(vector, guess, self) for vector, guess in zip(self.data, self.guess)]
180
            results = [targetFuncFit(task) for task in tasks]
181
            return results