Article

# The Diffraction Grating Calculator

, 30 Oct 2010
 Rate this:
An MFC Windows program related to Concave Diffraction Gratings using VTK libraries.

## Introduction

This is a short introduction to a Physics related piece of software: the Grating Calculator program.

The Grating Calculator program is free software available on SourceForge under the GPL GNU License Version 3.0. The article presents the Physics problem that is solved by the software as well as the use under MFC of the VTK (Visualisation Tool Kit) Libraries as used by the program for 3D graphical representation of physical results. The VTK libs are a 3D rendering engine used in Scientific Visualisation built over the OpenGL graphics base libraries. The version used for the VTK libs is the 5.4.2 VTK Home. The program also makes use of the Charting Control of Cedric Moonen: Charting Control ver. 3.0, available on the CodeProject.

The problem addressed by the program is the following: concave specular (i.e., reflective) diffraction grating is used in research to obtain focal properties in conjunction with a diffractive element. The light reflected by such gratings is focused in addition to being spectrally dispersed. This makes possible to have a single element as the complete optical instrument that diffracts and focuses the light onto a plane or curved surface for recording. For instance, the curved Rowland gratings are the simplest optical elements that combine spectral diffraction with focusing properties. Gratings mounted in the so called Rowland mount (i.e., set-up) have the property to focus spectrally dispersed light in a circle whose diameter is the size of the radius of the concave grating. If the light source is on such a circle (called Rowland circle), then the light is focused onto the same circle after diffraction.

More recently, physicists have started using the so-called Flat Field Spectrometers. Such spectrometers use concave reflective gratings whose line density is not strictly periodical. The grooves on such gratings are ruled with a periodicity that changes from end to end in an aperiodical way. The ruling of such gratings is controlled numerically to adhere to such a prescribed pattern in a very precise way. Such aperiodicity superimposed on the main periodical ruling gives as a result the fact that such gratings are capable of focusing spectrally dispersed light onto surfaces approximately flat, i.e., plain. This is useful as most of the recording sensors nowadays available have flat surfaces (for instance, Charged Coupled Devices - CCDs - as opposed to pellicular films).

The program presented is capable of solving the ray-tracing equations for a general grating, giving the focus position for each dispersed light wavelength in the range sought. The grating is characterised in terms of the aperiodical ruling, and may go from the simple Rowland mount (no aperiodicity) to the most modern flat field ones (controlled aperiodical ruling). The program already recognizes in the set-up parameters two kinds of aperiodically ruled gratings as used in the modern research for soft x-ray spectrometers. The parameters are derived from the works of refs. [1,2,3], where the notion of current day grazing incidence flat field spectrometer is introduced (see also ref. [5]).

Disclaimer: The present article has a thick physical description of the problem solved by the program, and the only code presented is about the use of the VTK 3D libraries in displaying scientific data.

## Physics Background

This section illustrates the physical problem solved by the program in physical terms.

Flat field spectrometers in the soft x-ray domain are a well established technology for spectroscopic studies. Concave and plane varied line-space (VLS) gratings providing enhanced spectral image focusing properties are used for synchrotron radiation instrumentation [1], plasma diagnosis [2], and space astrophysics [3]. In the design of a concave grating and in the analysis of its spectral image focusing properties, an analytical method that uses the light path function is usually adopted [4].

If point P is a generic point on the grating with local coordinates u, w, l on its surface (with u as a function of w, l), and A and B are, respectively, a point source and a nominal focal point of a spectrum of wavelength lambda diffracted in the mth order by the grating; then the light path function is defined as:

`F = AP + BP + n*m*lambda`

where n is the number of grooves at P counted from a reference point O on the grating (which we can assume is the centre of the grating blank).

The grating set-up for computations

According to Fermat's principle, for point B in the figure to be a stigmatic image of A at the wavelength lambda, it is required that the following differential conditions be satisfied simultaneously:

`dF/dw = 0, dF/dl = 0.`

With reference again to the figure, we introduce a polar coordinate system and express the distances as:

```AP = r<sup>2</sup> + u<sup>2</sup> + l<sup>2</sup> - 2*u*r*cos(alpha) - 2*w*r*sin(alpha)
BP = r'<sup>2</sup> + u<sup>2</sup> + l<sup>2</sup> - 2*u*r'*cos(beta) - 2*w*r'*sin(beta)```

where alpha is the angle of incidence, and beta of diffraction from the grating at O.

For a concave grating with a spherical substrate, a point P is defined by the equation:

`(u-R)<sup>2</sup> + w<sup>2</sup> + l<sup>2</sup> = R<sup>2</sup>`

where R is the radius of the grating. Expanding in a power series, we get:

`u = (w<sup>2</sup>+l<sup>2</sup>)/2R + (w<sup>2</sup>+l<sup>2</sup>)<sup>2</sup>/8R<sup>3</sup> + ...`

The groove number n on the varied line spaced grating (aperiodically ruled) is defined as:

`n = (rho)<sub>0</sub> * ( w + b<sub>2</sub>/R * w<sup>2</sup> + b<sub>3</sub>/R<sup>2</sup> * w<sup>3</sup> + b<sub>4</sub>/R<sup>3</sup> * w<sup>4</sup> + ... )`

where (rho)0 is the line density at the centre O of the grating (hence it is the periodical component of the line density), and b2, b3, and b4 are the controlling numerical parameters for the aperiodical part of the ruling of the grating.

Using the equations above, we can express the light path function as a power series of w and l, as follows:

```F = r + r' + w*F<sub>10</sub> + w<sup>2</sup>*F<sub>20</sub> + l<sup>2</sup>*F<sub>02</sub>
+ w<sup>3</sup>*F<sub>30</sub> + w*l<sup>2</sup>*F<sub>12</sub> + w<sup>4</sup>*F<sub>40</sub>
+ w<sup>2</sup>*l<sup>2</sup>*F<sub>22</sub> + l<sup>4</sup>*F<sub>04</sub> + O(w<sup>5</sup>).```

In this equation, every Fij term can be expressed as:

`F<sub>ij</sub> = C<sub>ij</sub> + m*lambda*rho<sub>0</sub>*M<sub>ij</sub>`

For a complete list of the coefficients Cij and Mij, see ref. [3].

When an aperiodically ruled grating is designed for an imaging spectrometer, the optical layout and the ruling parameters are chosen to minimise aberrations along both the spectral and spatial directions. Stigmatic imaging requires that Fij=0 to the highest possible order.

The condition F10=0 gives the grating equation:

`sin(alpha) + sin(beta) = m*lambda*rho<sub>0</sub>`

while the focal curve along the spectral dispersion direction is obtained from F20=0 to be used in conjunction with the grating equation:

```r' = r * R * cos<sup>2</sup>(beta) /
( r*(cos(alpha)+cos(beta)-2*m*lambda*rho<sub>0</sub>*b<sub>2</sub>) - R*cos<sup>2</sup>(alpha))```

This shows that only the linear ruling parameter b2 determines the position of the focal plane, given any optical layout. The two other ruling parameters b3, b4 are often chosen in order to minimise the coma and spherical aberration (F30=0, F40=0, respectively) in the spectral direction at a given wavelength of interest. Particular mountings can also be investigated in order to reduce the aberrations along the spatial direction [3].

To estimate the spectral focusing properties of these spectrometers, a ray-tracing code may be used instead of the equations for Fij=0.

The code determines the focus position by ray-tracing a large number of rays through the grating and following them until the smallest spread is found. For stigmatic imaging from a reflecting surface, the rays should converge to the focus after having travelled an equal amount of time from the source. This is true also for a grating if the optical path length introduced by its elements for constructive interference is taken into account. This is the core of the code: for each ray, the optical path length is corrected by an amount corresponding exactly at the diffraction introduced by the grating in the dispersed ray wavelength. For diffraction to the mth order, this amount corresponds to:

`m*lambda*(Number of ruled lines between the point P on grating and reference point O)`

I.e., exactly the term on the right of the optical light path function, as defined as:

`F = AP + BP + n*m*lambda`

As the image is not stigmatic, the smallest geometrical spread of the rays around the focus gives an estimate of the spectral resolution. This resolution that geometric optics predicts, of course, cannot exceed the wave optics limit. The code has been tested against the analytical formulae, and found in good agreement with it in predicting the location of the focus plane.

## VTK Rendering in the Code

The most interesting piece of software for CodeProject readers contained in the program is the class that is used to interface the program with the 3D rendering library VTK. Such a class is reproduced here with comments about all its members, describing the use of the VTK 3D graphics library. In an MFC application using VTK, we derive a `CView` type object from the class `CVTKView` that itself derives from `CView`. This allows seamless integration of the VTK rendering engine in an MFC view.

The header of the class follows:

```// CVTKView view

#if !defined( __VTK_VIEW__ )
#define __VTK_VIEW__

#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkProperty.h"
#include "vtkProperty2D.h"
#include "vtkPropCollection.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkTextProperty.h"

#include "vtkMFCWindow.h"
#include "vtkWin32OpenGLRenderWindow.h"

class CVTKView : public CView
{
DECLARE_DYNCREATE(CVTKView)
protected:
CVTKView();   // protected constructor used by dynamic creation
virtual ~CVTKView();

protected:
vtkRenderer*   pvtkRenderer;
vtkMFCWindow*  pvtkMFCWindow;
bool m_bInitCreate; // to check to avoid duplicating work on New/Open Documents
bool m_bInitUpdate; // to check to avoid duplicating work on New/Open Documents

public:
vtkRenderer*  GetRenderer()  { ASSERT(pvtkRenderer); return pvtkRenderer; }
vtkMFCWindow* GetMFCWindow() { ASSERT(pvtkMFCWindow); return pvtkMFCWindow; };
// Render the view
void Render();
// Override to avoid duplicating work OnCreate on New/Open Documents
// Call base class first !, use m_bInitCreate
virtual void OnViewCreate();
// Override to avoid duplicating work OnInitialUpdate on New/Open Documents
// Call base class first !, use m_bInitUpdate
virtual void OnViewInitUpdate();

public:
virtual void OnDraw(CDC* pDC);      // overridden to draw this view
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif
#endif

protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnSize(UINT nType, int cx, int cy);
virtual void OnInitialUpdate();
};

#endif // !defined( __VTK_VIEW__ )```

The body of the class follows:

```// VTKView.cpp : implementation file

#include "stdafx.h"
#include "VTKView.h"

// CVTKView

IMPLEMENT_DYNCREATE(CVTKView, CView)

CVTKView::CVTKView()
{
pvtkMFCWindow = NULL;
pvtkRenderer  = NULL;

m_bInitCreate = false;
m_bInitUpdate = false;
}

CVTKView::~CVTKView()
{
}

BEGIN_MESSAGE_MAP(CVTKView, CView)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_ERASEBKGND()
ON_WM_SIZE()
END_MESSAGE_MAP()

// CVTKView drawing

void CVTKView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
if (pvtkMFCWindow)
{
// VTK printing support
if (pDC->IsPrinting())
pvtkMFCWindow->DrawDC(pDC);
}
}

// CVTKView diagnostics

#ifdef _DEBUG
void CVTKView::AssertValid() const
{
CView::AssertValid();
}

#ifndef _WIN32_WCE
void CVTKView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif
#endif //_DEBUG

// CVTKView message handlers

int CVTKView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;

// call our virtual create view method
OnViewCreate();

m_bInitCreate = true;

return 0;
}

/*
* Override to avoid duplicating work OnCreate on New/Open Documents
* Call base class first !, use m_bInitCreate
*/
void CVTKView::OnViewCreate()
{
if ( !m_bInitCreate )
{
if (pvtkMFCWindow)
{
delete pvtkMFCWindow;
pvtkMFCWindow = NULL;
}
// Create the new hosted MFC window
pvtkMFCWindow = new vtkMFCWindow(this);
// Create the renderer and add it to window's view
pvtkRenderer  = vtkRenderer::New();
if (pvtkMFCWindow)
}
}

void CVTKView::OnDestroy()
{
CView::OnDestroy();

if (pvtkMFCWindow)
{
delete pvtkMFCWindow;
pvtkMFCWindow = NULL;
}
if (pvtkRenderer)
{
pvtkRenderer->Delete();
}
}

// Avoid possible flickering
BOOL CVTKView::OnEraseBkgnd(CDC* pDC)
{
// return CView::OnEraseBkgnd(pDC);
return TRUE;
}

void CVTKView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);

// resize our view
if (pvtkMFCWindow)
pvtkMFCWindow->MoveWindow(0, 0, cx, cy);
}

void CVTKView::OnInitialUpdate()
{
CView::OnInitialUpdate();

// Call our virtual method for initial update
OnViewInitUpdate();
Render();

m_bInitUpdate = true;
}

/*
* Override to avoid duplicating work OnInitialUpdate on New/Open Documents
* Call base class first !, use m_bInitUpdate
*/
void CVTKView::OnViewInitUpdate()
{
if ( !m_bInitUpdate )
{
// Add a default interactor to our view
vtkWin32OpenGLRenderWindow* pRenderWindow = NULL;
pRenderWindow = pvtkMFCWindow->GetRenderWindow();
if (pRenderWindow)
{
pRenderWindow->GetInteractor()->Initialize();
pRenderWindow->GetInteractor()->Start();
}
}
}

/*
* Render the view
*/
void CVTKView::Render()
{
if (!pvtkMFCWindow)
return;

vtkWin32OpenGLRenderWindow* pRenderWindow = NULL;
pRenderWindow = pvtkMFCWindow->GetRenderWindow();
if (pRenderWindow)
{
pvtkRenderer->Render();
pRenderWindow->Render();
}
}```

VTK works around the concept of a graphical pipeline. The data is processed, starting with source objects that are then filtered (i.e., processed) and finally mapped in an actor of the view.

`Source objects -> Filters -> Mappers -> Actors -> Insertion of actors in the Scene`

In the derived class from `CVTKView`, a single method is then used to add the graphical pipeline that displays our data in the VTK derived view:

```void CPlotFocalDensity::PlotData()
{
if ( !m_pFocalSpotObj )
return;

CWaitCursor wc;

int nX, nY; nX = nY = 0;
m_pFocalSpotObj->GetAttribute(FS_DENSITY_3D_NX)->Get_int(nX);
m_pFocalSpotObj->GetAttribute(FS_DENSITY_3D_NY)->Get_int(nY);

CAttribute_Generic *at, *atX, *atY;
at = atX = atY = NULL;
at  = m_pFocalSpotObj->GetAttribute(FS_DENSITY_3D);
atX = m_pFocalSpotObj->GetAttribute(FS_DENSITY_3D_X);
atY = m_pFocalSpotObj->GetAttribute(FS_DENSITY_3D_Y);

size_t Naux;
at->GetSize(Naux);

// Set-up VTK Source objects
vtkStructuredGrid* sgrid  = vtkStructuredGrid::New();
vtkFloatArray*     scalar = vtkFloatArray::New();
vtkPoints*         points = vtkPoints::New();

double x, y, z;
for (size_t j=0; j<Naux; j++)
{
atX->GetAt(x,j);
atY->GetAt(y,j);
points->InsertPoint(j,x,y,0.0);
at->GetAt(z,j);
scalar->InsertValue(j,z);
}

sgrid->SetDimensions(nX,nY,1);
sgrid->SetPoints(points);
sgrid->GetPointData()->SetScalars(scalar);

// Create a color lookup table
vtkLookupTable* lut = vtkLookupTable::New();
lut->SetNumberOfTableValues(256);
lut->SetHueRange(0.0,0.667);
lut->Build();

// Map the grid datasets
vtkDataSetMapper*  mapper = vtkDataSetMapper::New();
mapper->SetInput(sgrid);
mapper->SetLookupTable(lut);
double tmp[2];
sgrid->GetScalarRange(tmp);
mapper->SetScalarRange(tmp);

// Apply a contour filter to the data
vtkContourFilter* contourFilter = vtkContourFilter::New();
contourFilter->SetInput(sgrid);
contourFilter->GenerateValues(20,tmp);

// Map the contour field
vtkPolyDataMapper* contourMapper = vtkPolyDataMapper::New();
contourMapper->SetInput(contourFilter->GetOutput());
sgrid->GetScalarRange(tmp);
contourMapper->SetScalarRange(tmp);

// Add the actors in the scene
if ( carpet )
{
pvtkRenderer->RemoveActor(carpet);
Render();
}
carpet = vtkActor::New();
carpet->SetMapper(mapper);

if ( contour )
{
pvtkRenderer->RemoveActor(contour);
Render();
}
contour = vtkActor::New();
contour->SetMapper(contourMapper);

if ( scalarBar )
{
pvtkRenderer->RemoveActor(scalarBar);
Render();
}
scalarBar = vtkScalarBarActor::New();
scalarBar->SetLookupTable(lut);
scalarBar->SetTitle(_T("Focal Spot Density"));
scalarBar->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
scalarBar->GetPositionCoordinate()->SetValue(0.8,0.2);

// assign our actors to the renderer
pvtkRenderer->SetBackground(1.0,1.0,0.4);

// draw the resulting scene
pvtkRenderer->ResetCamera();
pvtkRenderer->GetActiveCamera()->Zoom(3.0);
pvtkRenderer->GetActiveCamera()->Elevation(45);
pvtkRenderer->GetActiveCamera()->Azimuth(30);
pvtkRenderer->GetActiveCamera()->Dolly(1.0);
pvtkRenderer->ResetCameraClippingRange();
Render();
}```

## Points of Interest

Example of using VTK 3D libraries under MFC Visual Studio 2008 SP1 built applications.

## Bibliography

• [1] T. Harada, T. Kita, M. Itou, H. Taira, and A. Mikuni, Nucl. Instrum. Methods A 246, 272 (1986). M. Itou, T. Harada, and T. Kita, Appl. Opt. 28, 146 (1989).
• [2] T. Kita, T. Harada, N. Nakano, and H. Kuroda, Appl. Opt. 22, 512 (1983). N. Nakano, H. Kuroda, T. Kita, and T. Harada, Appl. Opt. 23, 2386 (1984).
• [3] T. Harada, H. Sakuma, K. Takahashi, T. Watanabe, H. Hara, and T. Kita, Appl. Opt. 37, 6803 (1998).
• [4] T. Namioka, J. Opt. Soc. Am. 49, 446 (1959).
• [5] Instruments division, Hitachi Ltd, 882 Ichige, Hitachinaka-shi, Ibaragi 312âˆ’ 0033, Japan.

## History

• 27 October 2010 - First draft.

## Share

Software Developer (Senior)
Italy
Senior Software Developer in C/C++ and Oracle.
Ex-physicist holding a Ph.D. on x-ray lasers.

 First Prev Next
 Thanks for sharing `Randor` 29-Oct-10 14:59
 My vote of 2 Rick York 29-Oct-10 8:13
 Re: My vote of 2 federico.strati 30-Oct-10 22:57
 My vote of 5 sam.hill 27-Oct-10 17:10
 title JohnWallis42 27-Oct-10 11:47
 Re: title federico.strati 27-Oct-10 20:54
 Re: title JohnWallis42 27-Oct-10 21:57
 Re: title federico.strati 27-Oct-10 22:29
 Any screenshots available ? Maximilien 27-Oct-10 4:46
 Re: Any screenshots available ? federico.strati 27-Oct-10 5:07
 Re: Any screenshots available ? federico.strati 27-Oct-10 21:00
 Last Visit: 31-Dec-99 18:00     Last Update: 23-Aug-14 4:13 Refresh 1