File: fit_thread.py

package info (click to toggle)
python-bumps 0.7.11-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 10,264 kB
  • sloc: python: 22,226; ansic: 4,973; cpp: 4,849; xml: 493; makefile: 163; perl: 108; sh: 101
file content (194 lines) | stat: -rw-r--r-- 7,600 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

from copy import deepcopy
from threading import Thread
import os

import wx.lib.newevent

from .. import monitor
from ..fitters import FitDriver
from ..mapper import  MPMapper, SerialMapper
from ..util import redirect_console

from .convergence_view import ConvergenceMonitor
#==============================================================================

PROGRESS_DELAY = 5
IMPROVEMENT_DELAY = 5

(FitProgressEvent, EVT_FIT_PROGRESS) = wx.lib.newevent.NewEvent()
(FitCompleteEvent, EVT_FIT_COMPLETE) = wx.lib.newevent.NewEvent()

# NOTE: GUI monitors are running in a separate thread.  They should not
# touch the problem internals.
class GUIProgressMonitor(monitor.TimedUpdate):
    def __init__(self, win, problem, progress=None, improvement=None):
        monitor.TimedUpdate.__init__(self, progress=progress or PROGRESS_DELAY,
                                     improvement=improvement or IMPROVEMENT_DELAY)
        self.win = win
        self.problem = problem

    def show_progress(self, history):
        evt = FitProgressEvent(problem=self.problem,
                               message="progress",
                               step=history.step[0],
                               value=history.value[0],
                               point=history.point[0]+0) # avoid race
        wx.PostEvent(self.win, evt)

    def show_improvement(self, history):
        evt = FitProgressEvent(problem=self.problem,
                               message="improvement",
                               step=history.step[0],
                               value=history.value[0],
                               point=history.point[0]+0) # avoid race
        wx.PostEvent(self.win, evt)


class GUIMonitor(monitor.Monitor):
    """
    Generic GUI monitor.

    Sends a fit progress event messge, **monitor.progress() every n seconds.
    """
    def __init__(self, win, problem, message, monitor, rate=None):
        self.time = 0
        self.rate = rate or 10
        self.win = win
        self.problem = problem
        self.message = message
        self.monitor = monitor
    def config_history(self, history):
        self.monitor.config_history(history)
        history.requires(time=1)
    def __call__(self, history):
        self.monitor(history)
        if history.time[0] >= self.time+self.rate:
            evt = FitProgressEvent(problem=self.problem,
                                   message=self.message,
                                   **self.monitor.progress())
            wx.PostEvent(self.win, evt)
            self.time = history.time[0]
    def final(self):
        """
        Close out the monitor
        """
        evt = FitProgressEvent(problem=self.problem,
                               message=self.message,
                               **self.monitor.progress())
        wx.PostEvent(self.win, evt)

# Horrible hack: we put the DREAM state in the fitter object the first time
# back from the DREAM monitor; if our fitter object contains dream_state,
# then we will send the dream_update notifications periodically.
class DreamMonitor(monitor.Monitor):
    def __init__(self, win, problem, message, fitter, rate=None):
        self.time = 0
        self.rate = rate or 60
        self.win = win
        self.problem = problem
        self.fitter = fitter
        self.message = message
        self.uncertainty_state = None
    def config_history(self, history):
        history.requires(time=1)
    def __call__(self, history):
        try:
            self.uncertainty_state = history.uncertainty_state
            if history.time[0] >= self.time+self.rate:
                # Gack! holding on to state for final
                evt = FitProgressEvent(problem=self.problem,
                                       message="uncertainty_update",
                                       uncertainty_state = deepcopy(self.uncertainty_state))
                wx.PostEvent(self.win, evt)
                self.time = history.time[0]
        except AttributeError:
            self.uncertainty_state = None
            pass

    def final(self):
        """
        Close out the monitor
        """
        if self.uncertainty_state:
            evt = FitProgressEvent(problem=self.problem,
                                   message="uncertainty_final",
                                   uncertainty_state = deepcopy(self.uncertainty_state))
            wx.PostEvent(self.win, evt)

#==============================================================================

class FitThread(Thread):
    """Run the fit in a separate thread from the GUI thread."""
    def __init__(self, win, fitLock=None, abort_test=None, problem=None,
                 fitclass=None, options=None, mapper=None):
        # base class initialization
        #Process.__init__(self)

        Thread.__init__(self)
        self.win = win
        self.fitLock = fitLock
        self.abort_test = abort_test
        self.problem = problem
        self.fitclass = fitclass
        self.options = options
        self.mapper = mapper
        self.start() # Start it working.

    def run(self):
        # TODO: we have no interlocks on changes in problem state.  What
        # happens when the user changes the problem while a fit is being run?
        # May want to keep a history of changes to the problem definition,
        # along with a function to reverse them so we can handle undo.

        # NOTE: Problem must be the original problem (not a copy) when used
        # inside the GUI monitor otherwise AppPanel will not be able to
        # recognize that it is the same problem when updating views.
        monitors = [GUIProgressMonitor(self.win, self.problem),
                    GUIMonitor(self.win, self.problem,
                               message="convergence_update",
                               monitor=ConvergenceMonitor(),
                               rate=5),
                    DreamMonitor(self.win, self.problem,
                                 fitter = self.fitclass,
                                 message="uncertainty_update",
                                 rate=30),
                    ]
        try:
            # Only use parallel on windows if the problem can be pickled
            if os.name == "nt":
                try:
                    import cPickle as pickle
                except ImportError:
                    import pickle
                pickle.dumps(self.problem)
            mapper = MPMapper
        except Exception:
            mapper = SerialMapper

        # Be safe and keep a private copy of the problem while fitting
        #print "fitclass",self.fitclass
        problem = deepcopy(self.problem)
        #print "fitclass id",id(self.fitclass),self.fitclass,threading.current_thread()
        def abort_wrapper():
            with self.fitLock:
                return self.abort_test()
        driver = FitDriver(self.fitclass, problem=problem,
                           monitors=monitors, abort_test = abort_wrapper,
                           mapper = mapper.start_mapper(problem, []),
                           **self.options)

        x,fx = driver.fit()
        # Give final state message from monitors
        for M in monitors:
            if hasattr(M, 'final'): M.final()

        with redirect_console() as fid:
            driver.show()
            captured_output = fid.getvalue()

        evt = FitCompleteEvent(problem=self.problem,
                               point=x,
                               value=fx,
                               info=captured_output)
        wx.PostEvent(self.win, evt)