1 /*****************************************************************************
4 ** Name: threadrecon.cpp
5 ** Purpose: Threaded reconstruction class
6 ** Programmer: Kevin Rosenberg
7 ** Date Started: February 2001
9 ** This is part of the CTSim program
10 ** Copyright (C) 1983-2001 Kevin Rosenberg
12 ** $Id: threadrecon.cpp,v 1.7 2001/02/23 21:58:32 kevin Exp $
14 ** This program is free software; you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License (version 2) as
16 ** published by the Free Software Foundation.
18 ** This program is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ** GNU General Public License for more details.
23 ** You should have received a copy of the GNU General Public License
24 ** along with this program; if not, write to the Free Software
25 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 ******************************************************************************/
28 #include "wx/wxprec.h"
38 #include "threadrecon.h"
39 #include "backgroundmgr.h"
41 #if defined(HAVE_CONFIG_H)
46 IMPLEMENT_DYNAMIC_CLASS(ReconstructorSupervisor, BackgroundSupervisor)
47 BEGIN_EVENT_TABLE(ReconstructorSupervisor, BackgroundSupervisor)
48 EVT_MENU(MSG_BACKGROUND_SUPERVISOR_CANCEL, ReconstructorSupervisor::OnCancel)
49 EVT_MENU(MSG_WORKER_THREAD_FAIL, ReconstructorSupervisor::OnWorkerFail)
50 EVT_MENU(MSG_WORKER_THREAD_DONE, ReconstructorSupervisor::OnWorkerDone)
51 EVT_MENU(MSG_WORKER_THREAD_UNIT_TICK, ReconstructorSupervisor::OnWorkerUnitTick)
55 ReconstructorSupervisor::ReconstructorSupervisor (ProjectionFileView* pProjView,
56 int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod,
57 int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
58 const char* pszBackprojectName, const char* const pszLabel)
59 : m_pDialogProgress(NULL), m_bFail(false), m_iNumThreads(0), m_iImageNX(iImageNX),
60 m_iImageNY(iImageNY), m_strLabel(pszLabel), m_pTimer(NULL), m_bCancelled(false), m_bCancelling(false),
61 BackgroundSupervisor()
63 m_iNumThreads = theApp->getNumberCPU();
65 m_iTotalViews = pProjView->GetDocument()->getProjections().nView();
66 int iBaseViews = m_iTotalViews / m_iNumThreads;
67 int iExtraViews = m_iTotalViews % m_iNumThreads;
69 m_vecpChildImageFile.reserve (m_iNumThreads);
70 m_vecpThread.reserve (m_iNumThreads);
72 for (unsigned int iProc = 0; iProc < m_iNumThreads; iProc++) {
73 m_vecpChildImageFile[iProc] = new ImageFile (iImageNX, iImageNY);
75 int iStartView = iProc * iBaseViews;
76 int iNumViews = iBaseViews;
77 if (iProc < iExtraViews)
79 m_vecpThread[iProc] = new ReconstructorWorker (this, pProjView, m_vecpChildImageFile[iProc], iProc, iStartView, iNumViews,
80 pszFilterName, dFilterParam, pszFilterMethod, iZeropad, pszFilterGenerationName, pszInterpName, iInterpParam, pszBackprojectName);
81 if (m_vecpThread[iProc]->Create () != wxTHREAD_NO_ERROR) {
86 m_pProjView = pProjView;
87 m_pProjDoc = pProjView->GetDocument();
92 BackgroundSupervisor::cancelSupervisor (BackgroundSupervisor* pSupervisor)
94 wxCommandEvent cancelEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_CANCEL);
95 wxPostEvent (pSupervisor, cancelEvent);
100 ReconstructorSupervisor::start()
105 if (! theApp->getUseBackgroundTasks())
106 m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), m_iTotalViews, m_pProjView->getFrame(), wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
108 std::string strLabel ("Reconstructing ");
109 strLabel += m_pProjView->GetFrame()->GetTitle();
110 wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_ADD);
111 addTaskEvent.SetString (strLabel.c_str());
112 addTaskEvent.SetInt (m_iTotalViews);
113 addTaskEvent.SetClientData (this);
114 wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
115 wxPostEvent (m_pProjDoc, addTaskEvent);
118 m_iRunning = m_iNumThreads;
120 m_pTimer = new Timer;
122 // starting all threads
123 for (int i = 0; i < m_iNumThreads; i++)
124 m_vecpThread[i]->Run();
130 ReconstructorSupervisor::OnCancel(wxCommandEvent& event)
132 if (isDone() || m_bCancelled)
135 m_bCancelling = false;
140 ReconstructorSupervisor::cleanUp()
142 wxCriticalSection cleanSection;
143 cleanSection.Enter();
145 m_critsectThreadContainer.Enter();
146 for (int i = 0; i < m_iNumThreads; i++)
147 if (m_vecpThread[i] && m_vecpThread[i]->IsRunning()) {
148 m_vecpThread[i]->Pause();
149 m_vecpThread[i]->Delete();
152 for (i = 0; i < m_iNumThreads; i++) {
153 delete m_vecpChildImageFile[i];
154 m_vecpChildImageFile[i] = NULL;
156 m_critsectThreadContainer.Leave();
160 delete m_pDialogProgress;
162 m_pDialogProgress = NULL;
165 wxCommandEvent doneEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_REMOVE);
166 doneEvent.SetClientData (this);
167 wxPostEvent (theApp->getBackgroundManager(), doneEvent);
168 wxPostEvent (m_pProjDoc, doneEvent);
170 cleanSection.Leave();
174 ReconstructorSupervisor::onDone()
176 wxCriticalSection doneSection;
180 ImageFileDocument* pReconDoc = theApp->newImageDoc();
182 sys_error (ERR_SEVERE, "Unable to create image file");
187 ImageFile* pImageFile = getImageFile();
188 pReconDoc->setImageFile (pImageFile);
189 if (theApp->getAskDeleteNewDocs())
190 pReconDoc->Modify (true);
191 pReconDoc->UpdateAllViews (m_pProjView);
192 if (ImageFileView* rasterView = pReconDoc->getView()) {
193 rasterView->OnUpdate (rasterView, NULL);
194 rasterView->getFrame()->SetFocus();
195 rasterView->getFrame()->Show(true);
197 *theApp->getLog() << m_strLabel << "\n";
198 pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel());
199 pImageFile->labelAdd (m_strLabel.c_str(), m_pTimer->timerEnd());
206 ReconstructorSupervisor::OnWorkerUnitTick (wxCommandEvent& event)
211 if (theApp->getVerboseLogging())
212 *theApp->getLog() << "Views done: " << static_cast<int>(m_iViewsDone) <<"\n";
215 if (m_pDialogProgress)
216 m_bCancelling = ! m_pDialogProgress->Update (m_iViewsDone - 1);
218 wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_UNIT_TICK);
219 addTaskEvent.SetInt (m_iViewsDone - 1);
220 addTaskEvent.SetClientData (this);
221 wxPostEvent (theApp->getBackgroundManager(), addTaskEvent);
226 ReconstructorSupervisor::OnWorkerDone (wxCommandEvent& event)
229 wxASSERT (m_iRunning >= 0);
230 m_critsectThreadContainer.Enter();
231 m_vecpThread[event.GetInt()] = NULL;
232 m_critsectThreadContainer.Leave();
235 if (theApp->getVerboseLogging()) {
237 msg.Printf("Reconstructor Supervisor: Thread finished. Remaining threads: %d\n", m_iRunning);
238 wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
239 eventLog.SetString( msg );
240 wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
243 if (m_iRunning <= 0) {
250 ReconstructorSupervisor::OnWorkerFail (wxCommandEvent& event)
256 m_critsectThreadContainer.Enter();
257 m_vecpThread[event.GetInt()] = NULL;
258 m_critsectThreadContainer.Leave();
259 wxCommandEvent eventLog( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
260 eventLog.SetString( event.GetString() );
261 wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
269 ReconstructorSupervisor::getImageFile()
271 ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
272 pImageFile->arrayDataClear();
273 ImageFileArray pArray = pImageFile->getArray();
276 for (i = 0; i < m_iNumThreads; i++) {
277 ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
278 for (int ix = 0; ix < m_iImageNX; ix++)
279 for (int iy = 0; iy < m_iImageNY; iy++)
280 pArray[ix][iy] += pChildArray[ix][iy];
287 ReconstructorSupervisor::testDone()
289 return (m_iRunning <= 0 ? true : false);
293 ReconstructorSupervisor::~ReconstructorSupervisor()
298 ReconstructorWorker::ReconstructorWorker
299 (ReconstructorSupervisor* pSupervisor, ProjectionFileView* pProjView, ImageFile* pImageFile, int iThread, int iStartView, int iNumViews,
300 const char* pszFilterName, double dFilterParam, const char* pszFilterMethod,
301 int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
302 const char* pszBackprojectName)
303 : m_pSupervisor(pSupervisor), m_iStartView(iStartView), m_iNumViews(iNumViews), m_iThread(iThread),
304 m_pProjView(pProjView), m_pImageFile(pImageFile), m_strFilterName(pszFilterName), m_dFilterParam(dFilterParam), m_strFilterMethod(pszFilterMethod),
305 m_iZeropad(iZeropad), m_strFilterGenerationName(pszFilterGenerationName), m_strInterpName(pszInterpName),
306 m_iInterpParam(iInterpParam), m_strBackprojectName(pszBackprojectName),
307 wxThread(wxTHREAD_DETACHED)
312 ReconstructorWorker::Entry ()
314 Reconstructor* pReconstructor = new Reconstructor (m_pProjView->GetDocument()->getProjections(),
315 *m_pImageFile, m_strFilterName.c_str(), m_dFilterParam, m_strFilterMethod.c_str(), m_iZeropad,
316 m_strFilterGenerationName.c_str(), m_strInterpName.c_str(), m_iInterpParam, m_strBackprojectName.c_str(), Trace::TRACE_NONE);
317 if (pReconstructor->fail()) {
319 msg.Printf("Unable to make reconstructor: %s", pReconstructor->failMessage());
320 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_FAIL );
321 event.SetString( msg );
322 wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way
323 return reinterpret_cast<wxThread::ExitCode>(-1);
326 wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
328 for (int iView = 0; iView < m_iNumViews; iView++) {
332 msg.Printf("Received destroy message view #%d\n", iView);
333 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
334 event.SetString( msg );
335 wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way
337 delete pReconstructor;
338 return reinterpret_cast<wxThread::ExitCode>(-1);
340 pReconstructor->reconstructView (iView + m_iStartView, 1);
341 wxPostEvent (m_pSupervisor, eventProgress);
343 pReconstructor->postProcessing();
345 wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE);
346 eventProgress.SetInt (m_iThread); // Send back thread# that has finished
347 wxPostEvent (m_pSupervisor, eventDone);
349 delete pReconstructor;
350 return reinterpret_cast<wxThread::ExitCode>(0);
354 ReconstructorWorker::OnExit ()