diff --git a/App/inc/DrawHelper.h b/App/inc/DrawHelper.h index 1795e26a28e0787f1d5b92dda722d55da7957dfc..9529331e9ab20f5fa63d7d15d6adb9dd13553989 100644 --- a/App/inc/DrawHelper.h +++ b/App/inc/DrawHelper.h @@ -18,6 +18,8 @@ class TCanvas; +class MultiLayer; +class TPad; //- ------------------------------------------------------------------- //! @class DrawHelper @@ -44,6 +46,9 @@ public: //! process double click in canvas to magnify given pad void ExecuteMagnifier(Int_t event, Int_t px, Int_t py, TObject *sel); + //! draw multilayer structure in TPad + void DrawMultilayer(const MultiLayer *sample); + private: /// prevents client from creating a copy of the singleton DrawHelper(); diff --git a/App/inc/TestFresnelCoeff.h b/App/inc/TestFresnelCoeff.h index 7882fd81bad546d09c9935e39e30112d61717667..78eb9e7408e36da6817c2ceb7ba9f86304aa1dc9 100644 --- a/App/inc/TestFresnelCoeff.h +++ b/App/inc/TestFresnelCoeff.h @@ -20,25 +20,23 @@ #include "OutputData.h" +//- ------------------------------------------------------------------- +//! @class TestFresnelCoeff +//! @brief Calculate Fresnel coefficients for several typical multilayer +//! samples and produce validation plots +//- ------------------------------------------------------------------- class TestFresnelCoeff : public IAlgorithm { public: TestFresnelCoeff(); -// class MyData { -// public: -// double alpha_i; -// OpticalFresnel::MultiLayerCoeff_t coeffs; -// }; -// typedef std::vector<MyData > MyDataSet_t; - void execute(); -// void Draw(const MultiLayer *sample, const MyDataSet_t &data); - void Draw(const MultiLayer *sample); -private: - OutputData<OpticalFresnel::MultiLayerCoeff_t > *m_coeffs; + void draw(); +private: + MultiLayer *m_sample; //!< pointer to multilayer sample + OutputData<OpticalFresnel::MultiLayerCoeff_t > *m_coeffs; //!< output data structure }; diff --git a/App/src/DrawHelper.cpp b/App/src/DrawHelper.cpp index b67c6dac627f190375831bb2334b4ae9c36cf84d..ffbfaba2b22dfb63317d7404e953016dec7df0f2 100644 --- a/App/src/DrawHelper.cpp +++ b/App/src/DrawHelper.cpp @@ -1,13 +1,22 @@ #include "DrawHelper.h" #include "Exceptions.h" +#include "MultiLayer.h" #include <iostream> +#include <vector> +#include <map> +#include <string> +#include <list> + #include "TROOT.h" #include "TCanvas.h" #include "TObject.h" #include "TStyle.h" #include "TKey.h" - +#include "TLine.h" +#include "TBox.h" +#include "TLatex.h" +#include "TH1F.h" DrawHelper *DrawHelper::m_instance = 0; bool DrawHelper::m_destroyed = false; @@ -70,7 +79,7 @@ void DrawHelper::onDeadReference() { /* ************************************************************************* */ -// assign function to handle mouse events inside canvas +// assign function to canvas to handle mouse events inside canvas /* ************************************************************************* */ void DrawHelper::SetMagnifier(TCanvas *canvas) { @@ -83,11 +92,9 @@ void DrawHelper::SetMagnifier(TCanvas *canvas) /* ************************************************************************* */ void DrawHelper::ExecuteMagnifier(int event, int px, int py, TObject *sel) { - TCanvas *c = (TCanvas *) gTQSender; - if(sel) { - // we do not need it for the moment - } + (void)sel; if ( (event == kButton1Double) ) { + TCanvas *c = (TCanvas *) gTQSender; char cname[256]; sprintf(cname,"%s_%d",c->GetTitle(),(int)time(0)); TPad *pad = c->Pick(px, py, 0); @@ -98,7 +105,6 @@ void DrawHelper::ExecuteMagnifier(int event, int px, int py, TObject *sel) pad_new->SetEditable(kTRUE); pad_new->Draw(); pad_new->Modified(); - //gVirtualX->SetCursor(gPad->GetId() , gVirtualX->CreateCursor(kWatch)); pad_new->Update(); c1->RaiseWindow(); } @@ -248,4 +254,93 @@ void DrawHelper::SaveReport() } +/* ************************************************************************* */ +// Draw multilayer structure in gPad +/* ************************************************************************* */ +void DrawHelper::DrawMultilayer(const MultiLayer *sample) +{ + size_t nlayers = sample->getNumberOfLayers(); + if(nlayers < 1) return; + + double z1 = sample->getLayerBottomZ(0); + double z2 = sample->getLayerBottomZ(nlayers-1); + + double size = std::abs(z2 - z1); // typical size of sample + double margin = size*0.02; // safety margin to avoid overlapping of layers + double fake_thickness = size*0.3; // thickness for layers without defined thickness (like ambience&substrate) + + // frame to draw + TH1F *h1 = gPad->DrawFrame(-size, -size*2., size, size*1.0); + h1->GetXaxis()->SetTitle("X, [nm]"); + h1->GetYaxis()->SetTitle("Y, [nm]"); + h1->GetYaxis()->SetTitleOffset(1.4); + + // drawing properties for interfaces, material and their names + TLine interface; + interface.SetLineWidth(3); + interface.SetLineStyle(3); + interface.SetLineColor(kRed); + TBox bulk; + bulk.SetFillStyle(1001); + TLatex tex; + tex.SetNDC(false); + tex.SetTextAlign(12); + tex.SetTextSize(0.04); + + // defining set of good colors + int a_colors[]={kOrange, kAzure+1, kViolet-9, kCyan+2, kViolet+6, kRed+1, kOrange-3, kBlue-9}; + std::list<int> good_colors(a_colors, a_colors+sizeof(a_colors)/sizeof(int)); + + // map of correspondance between material with given name and used color + // two colors are reserved for materials with name 'substrate' and 'ambience' + std::map<std::string, int> colors; + colors["substrate"] = kOrange-5; + colors["ambience"] = kCyan-10; + + // loop over layers and drawing + for(size_t i_layer = 0; i_layer<nlayers; i_layer++) { + const Layer *layer = sample->getLayer(i_layer); + double z = sample->getLayerBottomZ(i_layer); + double thickness = layer->getThickness(); + + //calculating size of box representing layer + double x1(0), x2(0), y1(0), y2(0); + x1 = -size*0.5; + x2 = size*0.5; + y1 = z; + y2 = z+thickness; + // but top and bottom layers need special treatment, since they thickness==0 + if(i_layer==0) { // ambience normally doesn't have thickness + y1=z; + y2=z+fake_thickness; + } + if(i_layer==nlayers-1) { // substrate normally doesn't have thickness and has wrong zbottom + y2=z; + y1=z-fake_thickness; + } + + // selecting colors for bulk material, materials with same name will have same color + int color = kBlack; + std::string matname = layer->getMaterial()->getName(); + std::map<std::string, int>::iterator pos = colors.find(matname); + if(pos != colors.end()) { + // existing material + color = pos->second; + }else{ + // new material + color = good_colors.front(); // taking color from list of good colors + good_colors.remove(color); // this color want be used anymore + colors[matname] = color; // saving correspondance of selected color and material + } + + bulk.SetFillColor(color); + bulk.DrawBox(x1,y1+margin,x2,y2-margin); + tex.DrawLatex(x2+margin, (y1+y2)/2., matname.c_str()); + if(sample->getLayerBottomInterface(i_layer)) interface.DrawLine(x1,y1,x2,y1); + } + + gPad->Update(); +} + + diff --git a/App/src/StandardSamples.cpp b/App/src/StandardSamples.cpp index 985f530b8d98f488ab106a8742ec4c80cdd8875d..b64d4cbd3a1ab7d4fd1a7f2d478b3c8bde7a1d2d 100644 --- a/App/src/StandardSamples.cpp +++ b/App/src/StandardSamples.cpp @@ -98,7 +98,7 @@ ISample *StandardSamples::SimpleMultilayer() // adding layers mySample->addLayer(lAmbience); - const unsigned nrepetitions = 1; + const unsigned nrepetitions = 2; for(unsigned i=0; i<nrepetitions; ++i) { mySample->addLayer(lAg1); mySample->addLayer(lCr1); diff --git a/App/src/TestFresnelCoeff.cpp b/App/src/TestFresnelCoeff.cpp index d10b4c95a241bed72424f92f267ec291ff8a1489..2f55d77ae0fb7a2bf841ee745f3ec9ff7289b367 100644 --- a/App/src/TestFresnelCoeff.cpp +++ b/App/src/TestFresnelCoeff.cpp @@ -4,6 +4,8 @@ #include "TGraph.h" #include "TH1F.h" #include "TApplication.h" +#include "TLatex.h" +#include "TLegend.h" #include "Layer.h" #include "MultiLayer.h" @@ -28,9 +30,10 @@ void TestFresnelCoeff::execute() { std::cout << "TestFresnelCoeff::execute() -> Info." << std::endl; - //size_t nsamples = SampleFactory::instance().getNumberOfSamples(); - for(int i_sample=0; i_sample<2; i_sample++){ - MultiLayer *mySample = dynamic_cast<MultiLayer *>(SampleFactory::instance().createStandard(i_sample)); + // loop over standard samples defined in SampleFactory and StandardSamples + size_t nsamples = SampleFactory::instance().getNumberOfSamples(); + for(size_t i_sample=0; i_sample<nsamples; i_sample++){ + m_sample = dynamic_cast<MultiLayer *>(SampleFactory::instance().createStandard(i_sample)); m_coeffs = new OutputData<OpticalFresnel::MultiLayerCoeff_t >; @@ -45,34 +48,41 @@ void TestFresnelCoeff::execute() kvector_t kvec = kvector_t::LambdaAlphaPhi(1.54*Units::angstrom, -alpha_i, 0.0); OpticalFresnel::MultiLayerCoeff_t coeffs; - OpticalFresnel::execute(*mySample, kvec, coeffs); + OpticalFresnel::execute(*m_sample, kvec, coeffs); m_coeffs->currentValue() = coeffs; ++index; } // alpha_i - Draw(mySample); + draw(); - delete mySample; + delete m_sample; delete m_coeffs; } // i_sample } -void TestFresnelCoeff::Draw(const MultiLayer *sample) +void TestFresnelCoeff::draw() { static int ncall = 0; - //size_t nlayers = data.front().coeffs.size(); - size_t nlayers = sample->getNumberOfLayers(); - // creation of graphics to plot R,T coefficients in layers as a function of alpha_i - std::vector<TGraph *> gr_absR; - std::vector<TGraph *> gr_absT; + size_t nlayers = m_sample->getNumberOfLayers(); + + // graphics for R,T coefficients in layers as a function of alpha_i + size_t ncoeffs = 2; + enum key_coeffs { kCoeffR, kCoeffT}; + const char *coeffs_title[]={" |R| "," |T| "}; + int coeffs_color[] = {kBlue, kRed}; + + std::vector<std::vector<TGraph *> > gr_coeff; // [nlayers][ncoeffs] + gr_coeff.resize(nlayers); for(size_t i_layer=0; i_layer<nlayers; i_layer++) { - gr_absR.push_back(new TGraph() ); - gr_absT.push_back(new TGraph() ); + gr_coeff[i_layer].resize(ncoeffs,0); + for(size_t i_coeff=0; i_coeff<ncoeffs; i_coeff++) { + gr_coeff[i_layer][i_coeff] = new TGraph(); + } } TGraph *gr_absSum = new TGraph(); // |R_top|+|T_bottom| @@ -88,15 +98,14 @@ void TestFresnelCoeff::Draw(const MultiLayer *sample) // Filling graphics for R,T as a function of alpha_i for(size_t i_layer=0; i_layer<nlayers; ++i_layer ) { - gr_absR[i_layer]->SetPoint(i_point, Units::rad2deg(alpha_i), std::abs(coeffs[i_layer].R) ); - gr_absT[i_layer]->SetPoint(i_point, Units::rad2deg(alpha_i), std::abs(coeffs[i_layer].T) ); - //std::cout << Units::rad2deg(alpha_i) << " l:" << i_layer << " R:" << std::abs(coeffs[i_layer].R) << "T:" << std::abs(coeffs[i_layer].T) << std::endl; + gr_coeff[i_layer][kCoeffR]->SetPoint(i_point, Units::rad2deg(alpha_i), std::abs(coeffs[i_layer].R) ); + gr_coeff[i_layer][kCoeffT]->SetPoint(i_point, Units::rad2deg(alpha_i), std::abs(coeffs[i_layer].T) ); } // Filling graphics for |R|+|T| as a function of alpha_i taking R from the top and T from the bottom layers int nlast = nlayers - 1; - complex_t nx = sample->getLayer(nlast)->getRefractiveIndex(); - complex_t n1 = sample->getLayer(0)->getRefractiveIndex(); + complex_t nx = m_sample->getLayer(nlast)->getRefractiveIndex(); + complex_t n1 = m_sample->getLayer(0)->getRefractiveIndex(); //std::complex<double> kk = (1./(n1*std::sin(theta_i)))*std::sqrt(std::pow(nx,2)-cos(theta_i)*cos(theta_i)*std::pow(n1,2)); complex_t kk = std::sqrt((complex_t(1,0) - cos(alpha_i)*cos(alpha_i)/nx/nx) ) / sin(alpha_i); double sum = std::norm(coeffs[0].R) + std::abs(kk)*std::norm(coeffs[nlast].T); @@ -113,42 +122,55 @@ void TestFresnelCoeff::Draw(const MultiLayer *sample) // create name of canvas different for each new call of this method std::ostringstream os; os << (ncall++) << std::endl; - std::string cname = std::string("c1_test_fresnel")+os.str(); - + std::string cname = std::string("c1_test_fresnel_sample")+os.str(); TCanvas *c1 = new TCanvas(cname.c_str(),"Fresnel Coefficients in Multilayer",1024,768); - //DrawHelper::instance().SetMagnifier(c1); - - int ndivy = sqrt(nlayers); - int ndivx = nlayers/ndivy + 1; - //c1->Divide(ndivx, ndivy); - c1->Divide(2,2); - - TH1F *h1ref = new TH1F("h1ref","h1ref",100,0.0,2.0); - h1ref->SetMinimum(0.01); - h1ref->SetMaximum(3.0); - h1ref->SetStats(0); - h1ref->SetTitle(""); + DrawHelper::instance().SetMagnifier(c1); + + // estimate subdivision of canvas (we need place for 'nlayers' and for one sample picture) + int ndiv(2); + if( nlayers+1 > 4 ) ndiv = int(sqrt(nlayers+1)+1); + c1->Divide(ndiv,ndiv); + for(size_t i_layer=0; i_layer<nlayers; i_layer++) { - c1->cd(i_layer+1); - //gPad->SetLogy(); - h1ref->Draw(); - - TGraph *gr = gr_absR[i_layer]; - gr->SetLineColor(kBlue); - gr->SetMarkerColor(kBlue); - gr->SetMarkerStyle(21); - gr->SetMarkerSize(0.2); - gr->Draw("pl same"); - - gr = gr_absT[i_layer]; - gr->SetMarkerStyle(21); - gr->SetMarkerSize(0.2); - gr->SetLineColor(kRed); - gr->SetMarkerColor(kRed); - gr->Draw("pl same"); - double xmin, ymin, xmax, ymax; - gr->ComputeRange(xmin, ymin, xmax, ymax); - std::cout << i_layer << " xmin:" << xmin << " ymin:" << ymin << " xmax:" << xmax << " ymax:" << ymax << std::endl; + c1->cd(i_layer+1); + + // calculating histogram limits common for all graphs on given pad + double xmin(0), ymin(0), xmax(0), ymax(0); + for(size_t i_coeff=0; i_coeff<ncoeffs; i_coeff++){ + double x1(0), y1(0), x2(0), y2(0); + gr_coeff[i_layer][kCoeffT]->ComputeRange(x1, y1, x2, y2); + if(x1 < xmin ) xmin= x1; + if(x2 > xmax ) xmax = x2; + if(y1 < ymin ) ymin = y1; + if(y2 > ymax ) ymax = y2; + } + TH1F h1ref("h1ref","h1ref",100, xmin, xmax); + h1ref.SetMinimum(ymin); + h1ref.SetMaximum(ymax*1.1); + h1ref.SetStats(0); + h1ref.SetTitle(""); + h1ref.GetXaxis()->SetTitle("angle, deg"); + h1ref.GetYaxis()->SetTitle("|R|, |T|"); + h1ref.DrawCopy(); + + TLegend *leg = new TLegend(0.725,0.7,0.89,0.88); + leg->SetTextSize(0.04); + leg->SetBorderSize(1); + leg->SetFillStyle(0); + std::ostringstream os; + os << " layer #" << i_layer; + leg->SetHeader(os.str().c_str()); + + for(size_t i_coeff=0; i_coeff<ncoeffs; i_coeff++) { + TGraph *gr = gr_coeff[i_layer][i_coeff]; + gr->SetLineColor( coeffs_color[i_coeff] ); + gr->SetMarkerColor( coeffs_color[i_coeff] ); + gr->SetMarkerStyle(21); + gr->SetMarkerSize(0.2); + gr->Draw("pl same"); + leg->AddEntry(gr, coeffs_title[i_coeff],"pl"); + } + leg->Draw(); } TGraph *gr = gr_absSum; gr->SetMarkerStyle(21); @@ -156,7 +178,16 @@ void TestFresnelCoeff::Draw(const MultiLayer *sample) gr->SetLineColor(kMagenta); gr->SetMarkerColor(kMagenta); gr->Draw("pl same"); - + TLegend *leg = new TLegend(0.625,0.6,0.89,0.69); + leg->SetTextSize(0.04); + leg->SetBorderSize(0); + leg->SetFillStyle(0); + leg->AddEntry(gr, "|R_top|+|T_bottom|","pl"); + leg->Draw(); + + // drawing sample geometry + c1->cd(nlayers+1); + DrawHelper::instance().DrawMultilayer(m_sample); }