to interpolation occurring in the frequency domain rather than the
spatial domain.
-\subsection{Filtered Backprojection}\index{Filtered backprojection}
+\subsection{Filtered Backprojection}\index{Filtered backprojection}\index{Symmetric multiprocessing}\index{SMP}
The technique is comprised of two sequential steps:
filtering projections followed by backprojecting the filtered projections. Though
these two steps are sequential, each view position can be processed independently.
\subsubsection{Parallel Computer Processing}\index{Parallel processing}
Since each view can be processed independently, filtered backprojection is amendable to
parallel processing. Indeed, this has been used in commercial scanners to speed reconstruction.
-This parallelism is exploited in the MPI versions of \ctsim\ where the
-data from all the views are spread about amongst all of the
-processors. This has been testing in a cluster of 16 computers with excellent
+This parallelism is exploited both in the \ctsim\ graphical shell and
+in the \helpref{LAM}{ctsimtextlam} version of \ctsimtext. \ctsim\ can distribute it's workload
+amongst multiple processors working in parallel.
+
+The graphical shell will automatically take advantage of multiple CPU's when
+running on a \emph{Symmetric Multiprocessing}
+computer. Dual-CPU computers are commonly available which provide a near doubling
+in reconstruction speeds. \ctsim, though, has no limits on the number of CPU's
+that can be used in parallel. The \emph{LAM} version
+of \ctsimtext\ is designed to work in a cluster of computers.
+This has been testing with a cluster of 16 computers in a
+\urlref{Beowulf-class}{http://www.beowulf.org} cluster with excellent
results.
\subsubsection{Filter projections}
new installations. With this option set, \ctsim\ will display
helpful tips when \ctsim\ is started.}
+\twocolitem{\textbf{Run background tasks}}{This option is initially turned off in
+new installations. With this option set, \ctsim\ execute lengthy calculations in the
+background. A background window will appear when processes are running in the background
+and will disappear when no background processes are executing. This background window shows
+the status and progress of all background processes.}
+
\end{twocollist}
\subsection{File - Open}
\end{enumerate}
-\section{Parallel Processing}\index{Parallel processing}
+\section{Parallel Processing}\label{ctsimtextlam}\index{Parallel processing}\index{MPI}\index{LAM}
\ctsimtext\ can distribute it's processing over a cluster. Specifically,
\ctsimtext\ supports the \urlref{LAM}{http://www.mpi.nd.edu/lam} version of
the MPI environment. On platforms with LAM installed, a parallel version of
** This is part of the CTSim program
** Copyright (c) 1983-2001 Kevin Rosenberg
**
-** $Id: backprojectors.h,v 1.22 2001/02/22 18:22:40 kevin Exp $
+** $Id: backprojectors.h,v 1.23 2001/02/23 02:06:01 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
~Backprojector ();
void BackprojectView (const double* const viewData, const double viewAngle);
+ void PostProcessing();
bool fail() const {return m_fail;}
const std::string& failMessage() const {return m_failMessage;}
virtual ~Backproject ();
- virtual void BackprojectView (const double* const viewData, const double viewAngle) {};
+ virtual void BackprojectView (const double* const viewData, const double viewAngle) = 0;
+ virtual void PostProcessing (); // call after backprojecting all views
protected:
void ScaleImageByRotIncrement ();
void Backproject::errorIndexOutsideDetector (int ix, int iy, double theta, double r, double phi, double L, int ni);
void Backproject::errorIndexOutsideDetector (int ix, int iy, double theta, double L, int ni);
-
const Projections& proj;
ImageFile& im;
int interpType;
double xInc, yInc; // size of cells
int m_interpFactor;
double m_dFocalLength;
+ bool m_bPostProcessingDone;
private:
Backproject (const Backproject& rhs);
BackprojectTable (const Projections& proj, ImageFile& im, int interpID, const int interpFactor);
virtual ~BackprojectTable ();
- void BackprojectView (const double* const t, const double view_angle);
+ virtual void BackprojectView (const double* const t, const double view_angle);
+ virtual void PostProcessing (); // call after backprojecting all views
protected:
Array2d<kfloat64> arrayR;
BackprojectDiff (const Projections& proj, ImageFile& im, int interpID, const int interpFactor);
~BackprojectDiff ();
- void BackprojectView (const double* const t, const double view_angle);
+ virtual void BackprojectView (const double* const t, const double view_angle);
+ virtual void PostProcessing (); // call after backprojecting all views
protected:
double start_r;
** This is part of the CTSim program
** Copyright (c) 1983-2001 Kevin Rosenberg
**
-** $Id: reconstruct.h,v 1.6 2001/02/20 04:48:45 kevin Exp $
+** $Id: reconstruct.h,v 1.7 2001/02/23 02:06:01 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
void reconstructAllViews ();
void reconstructView (int iStartView = 0, int iViewCount = -1, SGP* pSGP = NULL, bool bBackprojectView = true, double dGraphWidth = 1.);
+ void postProcessing ();
};
#endif
** This is part of the CTSim program
** Copyright (c) 1983-2001 Kevin Rosenberg
**
-** $Id: backprojectors.cpp,v 1.27 2001/02/22 18:22:40 kevin Exp $
+** $Id: backprojectors.cpp,v 1.28 2001/02/23 02:06:01 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
m_pBackprojectImplem->BackprojectView (viewData, viewAngle);
}
+void
+Backprojector::PostProcessing()
+{
+ if (m_pBackprojectImplem != NULL)
+ m_pBackprojectImplem->PostProcessing();
+}
+
Backprojector::~Backprojector ()
{
delete m_pBackprojectImplem;
// Pure virtual base class for all backprojectors.
Backproject::Backproject (const Projections& proj, ImageFile& im, int interpType, const int interpFactor)
-: proj(proj), im(im), interpType(interpType), m_interpFactor(interpFactor)
+: proj(proj), im(im), interpType(interpType), m_interpFactor(interpFactor), m_bPostProcessingDone(false)
{
detInc = proj.detInc();
nDet = proj.nDet();
Backproject::~Backproject ()
{}
+void
+Backproject::PostProcessing()
+{
+ m_bPostProcessingDone = true;
+}
+
void
Backproject::ScaleImageByRotIncrement ()
{
BackprojectTable::~BackprojectTable ()
{
- ScaleImageByRotIncrement();
+}
+
+void
+BackprojectTable::PostProcessing()
+{
+ if (! m_bPostProcessingDone) {
+ ScaleImageByRotIncrement();
+ m_bPostProcessingDone = true;
+ }
}
void
im.arrayDataClear();
}
-BackprojectDiff::~BackprojectDiff()
+BackprojectDiff::~BackprojectDiff ()
{
- ScaleImageByRotIncrement();
}
+void
+BackprojectDiff::PostProcessing()
+{
+ if (! m_bPostProcessingDone) {
+ ScaleImageByRotIncrement();
+ m_bPostProcessingDone = true;
+ }
+}
void
BackprojectDiff::BackprojectView (const double* const filteredProj, const double view_angle)
** This is part of the CTSim program
** Copyright (c) 1983-2001 Kevin Rosenberg
**
-** $Id: reconstruct.cpp,v 1.13 2001/02/20 04:48:45 kevin Exp $
+** $Id: reconstruct.cpp,v 1.14 2001/02/23 02:06:01 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
Reconstructor::reconstructAllViews ()
{
reconstructView (0, m_rProj.nView());
- delete m_pBackprojector; m_pBackprojector = NULL;
+ postProcessing();
+}
+
+void
+Reconstructor::postProcessing()
+{
+ m_pBackprojector->PostProcessing();
}
--------------------Configuration: ctsim - Win32 Debug--------------------
</h3>
<h3>Command Lines</h3>
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP84D.tmp" with contents
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP58.tmp" with contents
[
/nologo /G6 /MTd /W3 /Gm /Gi /GR /GX /Zi /Od /Gy /I "\wx2.2.5\include" /I "..\..\..\fftw-2.1.3\fftw" /I "\wx2.2.5\src\png" /I "\wx2.2.5\src\zlib" /I "..\..\include" /I "..\..\getopt" /I "..\..\..\fftw-2.1.3\rfftw" /D VERSION=\"3.0.0beta1\" /D "_DEBUG" /D "__WXMSW__" /D "HAVE_SGP" /D "HAVE_PNG" /D "HAVE_WXWINDOWS" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "HAVE_STRING_H" /D "HAVE_FFTW" /D "HAVE_RFFTW" /D "HAVE_GETOPT_H" /D "MSVC" /D "__WIN95__" /D "__WIN32__" /D WINVER=0x0400 /D "STRICT" /D CTSIMVERSION=\"3.0.4\" /FR"Debug/" /Fp"Debug/ctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
"C:\ctsim\src\backgroundmgr.cpp"
]
-Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP84D.tmp"
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP84E.tmp" with contents
+Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP58.tmp"
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP59.tmp" with contents
[
winmm.lib rpcrt4.lib ws2_32.lib ../libctsim/Debug/libctsim.lib libcmtd.lib ..\..\..\fftw-2.1.3\Win32\FFTW2st\Debug\FFTW2st.lib ..\..\..\fftw-2.1.3\Win32\RFFTW2st\Debug\RFFTW2st.lib wxd.lib xpmd.lib tiffd.lib zlibd.lib pngd.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib htmlhelp.lib /nologo /subsystem:windows /incremental:yes /pdb:"Debug/ctsim.pdb" /debug /machine:I386 /out:"Debug/ctsim.exe" /pdbtype:sept /libpath:"\wx2.2.5\lib"
+.\Debug\backgroundmgr.obj
.\Debug\ctsim.obj
.\Debug\dialogs.obj
.\Debug\dlgprojections.obj
.\Debug\dlgreconstruct.obj
.\Debug\docs.obj
.\Debug\graph3dview.obj
+.\Debug\threadrecon.obj
+.\Debug\tips.obj
.\Debug\views.obj
.\Debug\ctsim.res
-.\Debug\tips.obj
-.\Debug\threadrecon.obj
-.\Debug\backgroundmgr.obj
\ctsim\msvc\libctsim\Debug\libctsim.lib
"\fftw-2.1.3\Win32\FFTW2st\Debug\FFTW2st.lib"
"\fftw-2.1.3\Win32\RFFTW2st\Debug\RFFTW2st.lib"
\wx2.2.5\lib\zlibd.lib
\wx2.2.5\lib\tiffd.lib
]
-Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP84E.tmp"
+Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP59.tmp"
<h3>Output Window</h3>
Compiling...
backgroundmgr.cpp
** This is part of the CTSim program
** Copyright (C) 1983-2001 Kevin Rosenberg
**
-** $Id: backgroundmgr.cpp,v 1.2 2001/02/22 18:22:40 kevin Exp $
+** $Id: backgroundmgr.cpp,v 1.3 2001/02/23 02:06:02 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
END_EVENT_TABLE()
BackgroundManager::BackgroundManager ()
- : wxMiniFrame (theApp->getMainFrame(), -1, _T("Background Tasks"), wxPoint(0,0), wxSize(200, 100)) //, wxTHICK_FRAME)
+ : wxMiniFrame (theApp->getMainFrame(), -1, _T("Background Tasks"), wxPoint(0,0), wxSize(210, 50)) //, wxTHICK_FRAME)
{
m_iNumTasks = 0;
m_pCanvas = new BackgroundManagerCanvas (this);
theApp->setIconForFrame (this);
- Show(false);
+ m_sizeGauge.Set (50, 15);
+ m_sizeLabel.Set (140, 15);
+ m_sizeCell.Set (200, 25);
+ m_sizeBorder.Set (4, 4);
+
+ Show(false);
}
{
wxCriticalSectionLocker locker (m_criticalSection);
int iNumTasks = m_vecpBackgroundTasks.size();
- int iTaskHeight = 20;
- wxSize size (50, 10);
- wxPoint pos (4, 5 + iNumTasks * iTaskHeight);
+ std::vector<bool> vecPositionUsed (iNumTasks);
+ int i;
+ for (i = 0; i < iNumTasks; i++)
+ vecPositionUsed[i] = false;
+
+ for (i = 0; i < iNumTasks; i++) {
+ int iPosUsed = m_vecpPositions[i];
+ if (iPosUsed < iNumTasks)
+ vecPositionUsed[iPosUsed] = true;
+ }
+
+ int iFirstUnusedPos = iNumTasks; // default is just past current number of tasks
+ for (i = 0; i < iNumTasks; i++)
+ if (! vecPositionUsed[i]) {
+ iFirstUnusedPos = i;
+ break;
+ }
+
+ wxPoint posGauge (m_sizeBorder.x, m_sizeBorder.y + iFirstUnusedPos * m_sizeCell.y);
+ wxPoint posLabel (m_sizeBorder.x + m_sizeGauge.x, m_sizeBorder.y + iFirstUnusedPos * m_sizeCell.y);
+ wxGauge* pGauge = new wxGauge (m_pCanvas, -1, iNumUnits, posGauge, m_sizeGauge);
+ wxStaticText* pLabel = new wxStaticText (m_pCanvas, -1, pszTaskName, posLabel, m_sizeLabel);
- wxGauge* pGauge = new wxGauge (m_pCanvas, -1, iNumUnits, pos, size);
m_vecpBackgroundTasks.push_back (pTask);
m_vecpGauges.push_back (pGauge);
m_vecpNames.push_back (new std::string (pszTaskName));
+ m_vecpPositions.push_back (iFirstUnusedPos);
+ m_vecpLabels.push_back (pLabel);
m_iNumTasks++;
+ resizeWindow();
Show(true);
return (pGauge);
}
void
BackgroundManager::taskDone (BackgroundTask* pTask)
{
- wxCriticalSection doneSection;
- doneSection.Enter();
+ wxCriticalSectionLocker locker (m_criticalSection);
StringContainer::iterator iName = m_vecpNames.begin();
GaugeContainer::iterator iGauge = m_vecpGauges.begin();
+ PositionContainer::iterator iPosition = m_vecpPositions.begin();
+ LabelContainer::iterator iLabel = m_vecpLabels.begin();
for (TaskContainer::iterator iTask = m_vecpBackgroundTasks.begin(); iTask != m_vecpBackgroundTasks.end(); iTask++) {
if (*iTask == pTask) {
delete *iName;
delete *iGauge;
+ delete *iLabel;
m_vecpBackgroundTasks.erase (iTask);
m_vecpGauges.erase (iGauge);
m_vecpNames.erase (iName);
+ m_vecpPositions.erase (iPosition);
+ m_vecpLabels.erase (iLabel);
m_iNumTasks--;
break;
}
- iTask++;
+ iName++;
iGauge++;
+ iPosition++;
+ iLabel++;
}
- doneSection.Leave();
+ resizeWindow();
if (m_iNumTasks <= 0)
Show(false);
+ // delete pTask;
+}
+
+void
+BackgroundManager::resizeWindow()
+{
+ int iHighestPosition = -1;
+
+ for (int i = 0; i < m_vecpPositions.size(); i++)
+ if (iHighestPosition < m_vecpPositions[i])
+ iHighestPosition = m_vecpPositions[i];
+
+ wxSize sizeWindow (m_sizeCell.x, m_sizeCell.y * (iHighestPosition + 1));
+ SetClientSize (sizeWindow);
m_pCanvas->Refresh();
- // delete pTask;
}
+
bool
BackgroundManager::isCancelling (BackgroundTask* pTask)
{
** This is part of the CTSim program
** Copyright (C) 1983-2001 Kevin Rosenberg
**
-** $Id: backgroundmgr.h,v 1.2 2001/02/22 18:22:40 kevin Exp $
+** $Id: backgroundmgr.h,v 1.3 2001/02/23 02:06:02 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
typedef std::vector<BackgroundTask*> TaskContainer;
typedef std::vector<wxGauge*> GaugeContainer;
typedef std::vector<std::string*> StringContainer;
+ typedef std::vector<int> PositionContainer;
+ typedef std::vector<wxStaticText*> LabelContainer;
TaskContainer m_vecpBackgroundTasks;
GaugeContainer m_vecpGauges;
StringContainer m_vecpNames;
+ PositionContainer m_vecpPositions;
+ LabelContainer m_vecpLabels;
+ wxSize m_sizeGauge;
+ wxSize m_sizeLabel;
+ wxSize m_sizeCell;
+ wxSize m_sizeBorder;
- void OnCloseWindow(wxCloseEvent& event);
+ void resizeWindow();
public:
BackgroundManager ();
TaskContainer& getTasks() { return m_vecpBackgroundTasks;}
GaugeContainer& getGauges() { return m_vecpGauges;}
StringContainer& getNames() { return m_vecpNames;}
+ PositionContainer& getPositions() { return m_vecpPositions;}
+ LabelContainer& getLabels() { return m_vecpLabels;}
+ void OnCloseWindow(wxCloseEvent& event);
+
DECLARE_EVENT_TABLE()
};
** This is part of the CTSim program
** Copyright (C) 1983-2001 Kevin Rosenberg
**
-** $Id: threadrecon.cpp,v 1.3 2001/02/22 18:22:40 kevin Exp $
+** $Id: threadrecon.cpp,v 1.4 2001/02/23 02:06:02 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
m_pProjView->GetDocument()->addReconstructor (this);
if (! theApp->getUseBackgroundTasks())
m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), m_iTotalViews, m_pProjView->getFrame(), wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
- else
- m_pGauge = theApp->getBackgroundManager()->addTask (this, m_iTotalViews, m_pProjView->GetFrame()->GetTitle());
+ else {
+ std::string strLabel ("Reconstructing ");
+ strLabel += m_pProjView->GetFrame()->GetTitle();
+ m_pGauge = theApp->getBackgroundManager()->addTask (this, m_iTotalViews, strLabel.c_str());
+ }
m_iRunning = m_iNumThreads;
m_iViewsDone = 0;
eventProgress.SetInt (RTHREAD_UNIT_COMPLETE);
wxPostEvent (m_pSupervisor, eventProgress);
}
+ m_pReconstructor->postProcessing();
eventProgress.SetInt (m_iThread); // Send back thread# that has finished
wxPostEvent (m_pSupervisor, eventProgress);
** This is part of the CTSim program
** Copyright (C) 1983-2001 Kevin Rosenberg
**
-** $Id: threadrecon.h,v 1.3 2001/02/22 18:22:40 kevin Exp $
+** $Id: threadrecon.h,v 1.4 2001/02/23 02:06:02 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
#include <wx/progdlg.h>
#include "timer.h"
+// This thread creates a BackgroundTask event handler object
+// The thread is detached and terminates when BackgroundTask terminates
+class BackgroundTaskThread : public wxThread {
+private:
+
+public:
+ BackgroundTaskThread();
+
+ virtual wxThread::ExitCode Entry();
+
+ // called when the thread exits - whether it terminates normally or is stopped with Delete()
+ virtual void OnExit();
+};
+
class BackgroundTask : public wxEvtHandler {
private:
virtual wxThread::ExitCode Entry(); // thread execution starts here
- // called when the thread exits - whether it terminates normally or is
- // stopped with Delete() (but not when it is Kill()ed!)
- virtual void OnExit();
+ // called when the thread exits - whether it terminates normally or is stopped with Delete()
+ virtual void OnExit();
};
** This is part of the CTSim program
** Copyright (c) 1983-2001 Kevin Rosenberg
**
-** $Id: views.cpp,v 1.113 2001/02/22 15:00:20 kevin Exp $
+** $Id: views.cpp,v 1.114 2001/02/23 02:06:02 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
::wxUsleep(50);
}
}
+ pReconstructor->postProcessing();
delete pDlgReconstruct;
delete pReconstructor;
ImageFileDocument* pReconDoc = theApp->newImageDoc();
return;
}
}
+ pReconstructor->postProcessing();
delete pReconstructor;
ImageFileDocument* pReconDoc = theApp->newImageDoc();
if (! pReconDoc) {
** This is part of the CTSim program
** Copyright (C) 1983-2000 Kevin Rosenberg
**
-** $Id: pjrec.cpp,v 1.24 2001/02/16 00:28:42 kevin Exp $
+** $Id: pjrec.cpp,v 1.25 2001/02/23 02:06:02 kevin Exp $
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
{0, 0, 0, 0}
};
-static const char* g_szIdStr = "$Id: pjrec.cpp,v 1.24 2001/02/16 00:28:42 kevin Exp $";
+static const char* g_szIdStr = "$Id: pjrec.cpp,v 1.25 2001/02/23 02:06:02 kevin Exp $";
void
pjrec_usage (const char *program)
return (1);
}
reconstruct.reconstructAllViews();
-
+
if (bOptVerbose)
timerReconstruct.timerEndAndReport ("Time to reconstruct");