/*************************************************************************** PNL_PippardFitter.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2009-2021 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include "PNL_PippardFitter.h" #define GAMMA_MU 0.0851615503527 #define DEGREE2RAD 0.0174532925199 ClassImp(PNL_PippardFitterGlobal) //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- /** * */ PNL_PippardFitterGlobal::PNL_PippardFitterGlobal() { // read XML startup file char startup_path_name[128]; TSAXParser *saxParser = new TSAXParser(); PNL_StartupHandler *fStartupHandler = new PNL_StartupHandler(); strcpy(startup_path_name, fStartupHandler->GetStartupFilePath().Data()); saxParser->ConnectToHandler("PNL_StartupHandler", fStartupHandler); //Int_t status = saxParser->ParseFile(startup_path_name); // parsing the file as above seems to lead to problems in certain environments; // use the parseXmlFile function instead (see PUserFcnBase.cpp for the definition) Int_t status = parseXmlFile(saxParser, startup_path_name); // check for parse errors if (status) { // error std::cout << std::endl << ">> PNL_PippardFitterGlobal::PNL_PippardFitterGlobal: **WARNING** Reading/parsing nonlocal_startup.xml failed."; std::cout << std::endl; fValid = false; } // clean up if (saxParser) { delete saxParser; saxParser = 0; } // check if everything went fine with the startup handler if (!fStartupHandler->IsValid()) { std::cout << std::endl << ">> PNL_PippardFitterGlobal::PNL_PippardFitterGlobal **PANIC ERROR**"; std::cout << std::endl << ">> startup handler too unhappy. Will terminate unfriendly, sorry."; std::cout << std::endl; fValid = false; } fFourierPoints = fStartupHandler->GetFourierPoints(); // load all the TRIM.SP rge-files fRgeHandler = new PRgeHandler("./nonlocal_startup.xml"); if (!fRgeHandler->IsValid()) { std::cout << std::endl << ">> PNL_PippardFitterGlobal::PNL_PippardFitterGlobal **PANIC ERROR**"; std::cout << std::endl << ">> rge data handler too unhappy. Will terminate unfriendly, sorry."; std::cout << std::endl; fValid = false; } fPlanPresent = false; fFieldq = 0; fFieldB = 0; fShift = 0; f_nn = 4.0; f_dx = 0.02; } //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- /** * */ PNL_PippardFitterGlobal::~PNL_PippardFitterGlobal() { fPreviousParam.clear(); if (fPlanPresent) { fftw_destroy_plan(fPlan); } if (fFieldq) { fftw_free(fFieldq); fFieldq = 0; } if (fFieldB) { fftw_free(fFieldq); fFieldB = 0; } if (fRgeHandler) { delete fRgeHandler; fRgeHandler = 0; } if (fStartupHandler) { delete fStartupHandler; fStartupHandler = 0; } } //-------------------------------------------------------------------------- // CalculateField (public) //-------------------------------------------------------------------------- /** * */ void PNL_PippardFitterGlobal::CalculateField(const std::vector ¶m) const { // param: [0] energy, [1] temp, [2] thickness, [3] meanFreePath, [4] xi0, [5] lambdaL, [6] Bext, [7] phase, [8] dead-layer // check that param are new and hence a calculation is needed (except the energy and phase, which is not needed here) Bool_t newParams = false; if (fPreviousParam.size() == 0) { for (UInt_t i=0; i= 6)) // for energy, Bext, phase, and dead-layer, nothing to be done here continue; if (param[i] != fPreviousParam[i]) { newParams = true; break; } } } if (!newParams) return; // keep parameters for (UInt_t i=0; i fabs(norm)) { norm = fFieldB[i][1]; fShift = i; } } for (Int_t i=0; i f_dz*fFourierPoints/2.0) return 0.0; Int_t bin = (Int_t)(z/f_dz); result = fFieldB[bin+fShift][1]; return result; } //-------------------------------------------------------------------------- // DeltaBCS //-------------------------------------------------------------------------- /** * */ Double_t PNL_PippardFitterGlobal::DeltaBCS(const Double_t t) const { Double_t result = 0.0; // reduced temperature table Double_t tt[] = {1, 0.98, 0.96, 0.94, 0.92, 0.9, 0.88, 0.86, 0.84, 0.82, 0.8, 0.78, 0.76, 0.74, 0.72, 0.7, 0.68, 0.66, 0.64, 0.62, 0.6, 0.58, 0.56, 0.54, 0.52, 0.5, 0.48, 0.46, 0.44, 0.42, 0.4, 0.38, 0.36, 0.34, 0.32, 0.3, 0.28, 0.26, 0.24, 0.22, 0.2, 0.18, 0.16, 0.14}; // gap table from Muehlschlegel Double_t ee[] = {0, 0.2436, 0.3416, 0.4148, 0.4749, 0.5263, 0.5715, 0.6117, 0.648, 0.681, 0.711, 0.7386, 0.764, 0.7874, 0.8089, 0.8288, 0.8471, 0.864, 0.8796, 0.8939, 0.907, 0.919, 0.9299, 0.9399, 0.9488, 0.9569, 0.9641, 0.9704, 0.976, 0.9809, 0.985, 0.9885, 0.9915, 0.9938, 0.9957, 0.9971, 0.9982, 0.9989, 0.9994, 0.9997, 0.9999, 1, 1, 1, 1}; if (t>1.0) result = 0.0; else if (t<0.14) result = 1.0; else { // find correct bin for t UInt_t i=0; for (i=0; i Approximated xi_P(T). The main approximation is that (lamdaL(T)/lambdaL(0))^2 = 1/(1-t^2). This way * xi_P(T) is close the the BCS xi_BCS(T). */ Double_t PNL_PippardFitterGlobal::XiP_T(const Double_t xi0, const Double_t meanFreePath, Double_t t) const { if (t>0.96) t=0.96; Double_t J0T = DeltaBCS(t)/(1.0-pow(t,2.0)) * tanh(0.881925 * DeltaBCS(t) / t); return xi0*meanFreePath/(meanFreePath*J0T+xi0); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ClassImp(PNL_PippardFitter) //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- /** * */ PNL_PippardFitter::~PNL_PippardFitter() { if ((fPippardFitterGlobal != 0) && fInvokedGlobal) { delete fPippardFitterGlobal; fPippardFitterGlobal = 0; } } //-------------------------------------------------------------------------- // SetGlobalPart (public) //-------------------------------------------------------------------------- /** *

* * return: * * \param globalPart * \param idx */ void PNL_PippardFitter::SetGlobalPart(std::vector &globalPart, UInt_t idx) { fIdxGlobal = static_cast(idx); if ((Int_t)globalPart.size() <= fIdxGlobal) { fPippardFitterGlobal = new PNL_PippardFitterGlobal(); if (fPippardFitterGlobal == nullptr) { fValid = false; std::cerr << std::endl << ">> PNL_PippardFitter::SetGlobalPart(): **ERROR** Couldn't invoke global user function object, sorry ..." << std::endl; } else if (!fPippardFitterGlobal->IsValid()) { fValid = false; std::cerr << std::endl << ">> PNL_PippardFitter::SetGlobalPart(): **ERROR** initialization of global user function object failed, sorry ..." << std::endl; } else { fValid = true; fInvokedGlobal = true; globalPart.resize(fIdxGlobal+1); globalPart[fIdxGlobal] = dynamic_cast(fPippardFitterGlobal); } } else { fValid = true; fPippardFitterGlobal = (PNL_PippardFitterGlobal*)globalPart[fIdxGlobal]; } } //-------------------------------------------------------------------------- // GlobalPartIsValid (public) //-------------------------------------------------------------------------- /** *

* * return: */ Bool_t PNL_PippardFitter::GlobalPartIsValid() const { return (fValid && fPippardFitterGlobal->IsValid()); } //-------------------------------------------------------------------------- // operator() //-------------------------------------------------------------------------- /** * */ Double_t PNL_PippardFitter::operator()(Double_t t, const std::vector ¶m) const { // param: [0] energy, [1] temp, [2] thickness, [3] meanFreePath, [4] xi0, [5] lambdaL, [6] Bext, [7] phase, [8] dead-layer // optionally [9] nn, where nn is the exponent in lambda = lambda_L / sqrt(1-t^nn). Default is nn=4. assert((param.size() == 9) || (param.size() == 10)); if (param.size() == 10) // nn given, hence set it fPippardFitterGlobal->SetTempExponent(param[9]); // for negative time return polarization == 1 if (t <= 0.0) return 1.0; // calculate field if parameter have changed fPippardFitterGlobal->CalculateField(param); Int_t energyIndex = fPippardFitterGlobal->GetEnergyIndex(param[0]); if (energyIndex == -1) { // energy not found std::cerr << std::endl << ">> PNL_PippardFitter::operator() energy " << param[0] << " not found. Will terminate." << std::endl; assert(0); } // calcualte polarization Bool_t done = false; Double_t pol = 0.0, dPol = 0.0; Double_t z=0.0; Int_t terminate = 0; Double_t dz = 1.0; do { if (z < param[8]) { // z < dead-layer dPol = fPippardFitterGlobal->GetMuonStoppingDensity(energyIndex, z) * cos(GAMMA_MU * param[6] * t + param[7] * DEGREE2RAD); } else { dPol = fPippardFitterGlobal->GetMuonStoppingDensity(energyIndex, z) * cos(GAMMA_MU * param[6] * fPippardFitterGlobal->GetMagneticField(z-param[8]) * t + param[7] * DEGREE2RAD); } z += dz; pol += dPol; // change in polarization is very small hence start termination counting if (fabs(dPol) < 1.0e-9) { terminate++; } else { terminate = 0; } if (terminate > 10) // polarization died out hence one can stop done = true; } while (!done); return pol*dz; }