// MAUS WARNING: THIS IS LEGACY CODE. //BTSolenoid.cc //Solenoid modelling for the G4MICE BeamTools package #include using namespace std; #include "CLHEP/Vector/ThreeVector.h" #include "CLHEP/Vector/LorentzVector.h" #include "CLHEP/Units/PhysicalConstants.h" #include "src/legacy/Interface/STLUtils.hh" #include "BTSolenoid.hh" using CLHEP::m; using CLHEP::tesla; int BTSolenoid::StaticNumberOfRCoords=0, BTSolenoid::StaticNumberOfZCoords=0, BTSolenoid::StaticNumberOfSheets=0; double BTSolenoid::StaticZExtentFactor=0, BTSolenoid::StaticRExtentFactor=0; std::vector BTSolenoid::StaticFieldMaps = std::vector(); const double BTSolenoid::mySheetTolerance = 1e-3*CLHEP::mm; BTSolenoid::BTSolenoid() { SetToDefaults(); double myBbMin[3]={-rMax, -rMax, zMin}, myBbMax[3]={rMax, rMax, zMax}; BTField::bbMin = std::vector(myBbMin, myBbMin+3); BTField::bbMax = std::vector(myBbMax, myBbMax+3); } BTSolenoid::BTSolenoid(const BTSolenoid& rhs) : mySheets(rhs.mySheets), myNumberOfRCoords(rhs.myNumberOfRCoords), myNumberOfZCoords(rhs.myNumberOfZCoords), myMap(rhs.myMap), zMin(rhs.zMin), zMax(rhs.zMax), rMin(rhs.rMin), rMax(rhs.rMax), myNumberOfSheets(rhs.myNumberOfSheets), isAnalytic(rhs.isAnalytic) { } // Simple Constructor BTSolenoid::BTSolenoid(double length, double thickness, double innerRadius, double currentDensity, bool analytic, double tolerance, std::string fileName, std::string interpolation) : myNumberOfRCoords(0), myNumberOfZCoords(0), zMin(0), zMax(0), rMin(0), rMax(0), interpolation("LinearCubic"), isAnalytic(analytic) { if(!isAnalytic) { SetToDefaults(); myNumberOfRCoords = StaticNumberOfRCoords; myNumberOfZCoords = StaticNumberOfZCoords; BuildSheets(length,thickness,innerRadius,currentDensity, tolerance, fileName, interpolation); } else { SetToDefaults(); BuildSheets(length,thickness,innerRadius,currentDensity); } } // Constructor, assuming the user has written the complete solenoid // onto a file. BTSolenoid::BTSolenoid(char const *fileName, std::string interpolationAlgorithm): interpolation(interpolationAlgorithm), isAnalytic(false) { ReadFieldMap(fileName, interpolation); } // Destructor BTSolenoid::~BTSolenoid() { } void BTSolenoid::SetToDefaults() { SetNumberOfRCoords(StaticNumberOfRCoords); SetNumberOfZCoords(StaticNumberOfZCoords); SetZExtentFactor(StaticZExtentFactor); SetRExtentFactor(StaticRExtentFactor); SetNumberOfSheets(StaticNumberOfSheets); SetIsAnalytic(false); } // Method called from the Detector constructor user class to write a solenoidal // map once it has been created, so that next time the code can directly // read a binary file and avoid the time consuming task of constructing // the map. void BTSolenoid::WriteFieldMap(const char *fileName) { if(!isAnalytic) { //Set the sheet information... myMap->SetSheetInformation(GetSheetInformation()); //Use the MagFieldMap class to write the map if(GetFieldMap(fileName)==NULL) { myMap->WriteG4MiceBinaryMapV1((std::string)fileName); StaticFieldMaps.push_back(myMap); } else { delete myMap; myMap = GetFieldMap(fileName); } } else std::cerr << "Cannot write analytic field maps. Target file name was " << fileName << std::endl; } void BTSolenoid::ReadFieldMap(const char *fileName, std::string interpolationAlgorithm) { std::string theFileType = "g4micebinary"; std::string theFileName = fileName; interpolation = interpolationAlgorithm; if(GetFieldMap(fileName)!=NULL) myMap = GetFieldMap(fileName); else { myMap = new MagFieldMap(theFileName, theFileType, interpolation); StaticFieldMaps.push_back(myMap); } int id, type; double thickness, radius, current, length, x, y, z; std::vector sheet = myMap->GetSheetInformation(); mySheets = std::vector(); for(unsigned int i=0; izMinf(); zMax = myMap->zMaxf(); rMin = myMap->rMinf(); rMax = myMap->rMaxf(); double myBbMin[3]={-rMax, -rMax, zMin}, myBbMax[3]={rMax, rMax, zMax}; BTField::bbMin = std::vector(myBbMin, myBbMin+3); BTField::bbMax = std::vector(myBbMax, myBbMax+3); } std::vector BTSolenoid::GetSheetInformation() { std::vector sheetInformation; for(unsigned int i=0; i mySheets[i].rad() - mySheetTolerance) PointCylCoords[0] = mySheets[i].rad() - mySheetTolerance; mySheets[i].GetFieldValue(PointCylCoords, BfieldCylCoords); if(PointCylCoords[0]>0) //if r=0, Br=0 for symmetry reasons { Bfield[0]+=BfieldCylCoords[0]*Point[0]/PointCylCoords[0]; //Bx += Br*x/r Bfield[1]+=BfieldCylCoords[0]*Point[1]/PointCylCoords[0]; //By += Br*y/r } Bfield[2]+=BfieldCylCoords[2]; } } //return is rMax, zMax; assume zMin=-zMax; assume rMin = 0 std::vector BTSolenoid::FindGridEdge(double absoluteTolerance) { std::vector edge(2,0); std::vector myR(1,0); std::vector myZ(1,0); double field[6] = {0,0,0,0,0,0}; double dZ = 0.1*(zMax-zMin)/(double)(myNumberOfZCoords-1); double dR = 0.1*(rMax-rMin)/(double)(myNumberOfRCoords-1); double bTotZ = 1; double bTotR = 1; while(bTotZ>absoluteTolerance || bTotR>absoluteTolerance) { bTotZ = -1; for(unsigned int i=0; i absoluteTolerance) myZ.push_back(myZ.back()+dZ); bTotR = -1; for(unsigned int i=0; i absoluteTolerance) myR.push_back(myR.back()+dR); } edge[0] = myR.back(); edge[1] = myZ.back(); return edge; } TwoDGrid* BTSolenoid::BuildGrid1(double absoluteTolerance) { int rOrder = 2; if(interpolation == "BiCubic") rOrder = 4; int zOrder = 4; if(interpolation == "BiLinear") zOrder = 2; std::vector edge = FindGridEdge(absoluteTolerance); std::vector rGrid(2,0); std::vector zGrid(2,0); rGrid[1] = edge[0]; zGrid[1] = edge[1]; bool finished = false; double rInner = mySheets[0].rad()*0.95; double rOuter = mySheets.back().rad()*1.05; double zOuter = mySheets[0].len()/2.*1.05; while(!finished) { std::vector rChanged(rGrid.size(), false); std::vector zChanged(zGrid.size(), false); finished = true; for(int i=rGrid.size()-2; i>=0; i--) { for(int j=zGrid.size()-2; j>=0; j--) { if(rGrid[i]rOuter || zGrid[j]>zOuter ) { std::vector rError = DerivativeError(0, rOrder, zGrid[j], rGrid[i], rGrid[i+1]-rGrid[i]); std::vector zError = DerivativeError(2, zOrder, zGrid[j], rGrid[i], zGrid[j+1]-zGrid[j]); if(rError[0]>absoluteTolerance && !rChanged[i]) { rGrid.insert(rGrid.begin()+i+1, (rGrid[i+1]+rGrid[i])/2.); rChanged[i] = true; finished = false; } if(zError[0]>absoluteTolerance && !zChanged[j]) { zGrid.insert(zGrid.begin()+j+1, (zGrid[j+1]+zGrid[j])/2.); zChanged[j] = true; finished = false; } } } } } std::vector newZ(zGrid.size()*2-1, 0); for(unsigned int i=0; i myR(1,0); std::vector myZ(1,0); //dynamically calculate grid size such that field error < tolerance and //estimate error ~ d^nB/du^n * du^n where n is the order //relative error is absolute error/B //linear interpolation along r means r order is 2 //cubic interpolation along z means z order is 4 int rOrder = 2; if(interpolation == "BiCubic") rOrder = 4; int zOrder = 4; if(interpolation == "BiLinear") zOrder = 2; double dZ = 0.1*(zMax-zMin)/(double)(myNumberOfZCoords-1); double dR = 0.1*(rMax-rMin)/(double)(myNumberOfRCoords-1); double bTotZ = 1e6*tesla; double bTotR = 1e6*tesla; double dMin = 1; double dMax = 1e5; //enforce stability std::vector edge = FindGridEdge(absoluteTolerance); while( myR.back() error = DerivativeError(2, zOrder, myR[0], myZ.back(), dZ); while(error[0]>absoluteTolerance && absoluteTolerance>0 && dZ>dMin) { error = DerivativeError(2, zOrder, myR[0], myZ.back(), dZ); dZ/=2; for(unsigned int i=0; i0) && bTotZ>absoluteTolerance && dZabsoluteTolerance && absoluteTolerance>0 && dR>dMin) { error = DerivativeError(0, rOrder, myR.back(), myZ[0], dR); dR/=2; for(unsigned int i=0; i0) && bTotR>absoluteTolerance && dR < dMax) { error = DerivativeError(0, rOrder, myR.back(), myZ[0], dR); dR*=2; for(unsigned int i=0; i0) grid = BuildGrid1(tolerance); else grid = BuildGrid(); myNumberOfRCoords = grid->xSize(); myNumberOfZCoords = grid->ySize(); // number of nodes in the map grid rMin = grid->x(1); rMax = grid->x(grid->xSize()); zMin = grid->y(1); zMax = grid->y(grid->ySize()); double B0[6]= {0,0,0,0,0,0}; double ** myBr = new double*[grid->xSize()]; double ** myBz = new double*[grid->xSize()]; for(int i=0; iySize()]; myBz[i] = new double[grid->ySize()]; } for(int i=0; ixSize(); i++) for(int j=0; jySize(); j++) { myBr[i][j] = 0; myBz[i][j] = 0; double point[4] = {grid->x(i+1),0,grid->y(j+1),0}; for(unsigned int k=0; kSetSheetInformation(GetSheetInformation()); for(int i=0; i(myBbMin, myBbMin+3); BTField::bbMax = std::vector(myBbMax, myBbMax+3); } std::vector BTSolenoid::Largest(std::vector v1, std::vector v2) { std::vector vout(v1.size(), 0); for(unsigned int i=0; i v2[i]) vout[i] = v1[i]; else vout[i] = v2[i]; return vout; } //calculate b at various points across the grid; get f(r,z) and apply polynomial fit; calculate derivative; return abs value std::vector BTSolenoid::DerivativeError (int axis, int order, double z0, double r0, double dAxis) const { std::vector errors(2,0); double point[4] = {0,0,0,0}; double field[6] = {0,0,0,0,0,0}; double bMean = 0; std::vector fieldZ(order+1,0); std::vector fieldR(order+1,0); for(int i=0; i<=order; i++) { point[0] = r0; point[2] = z0; point[axis] += dAxis*i/double(order); GetAnalyticFieldValue(point, field); fieldR[i] = field[0]; fieldZ[i] = field[2]; bMean += sqrt(fieldR[i]*fieldR[i] + fieldZ[i]*fieldZ[i])/double(order+1); } while(fieldZ.size() > 1) { for(unsigned int i=0; i fabs(fieldR[0])) errors[0] = fabs(fieldZ[0]); else errors[0] = fabs(fieldR[0]); errors[1] = errors[0]/bMean; // std::cout << axis << " " << order << " " << z0 << " " << r0 << " " << dAxis << " * " << errors[0] << std::endl; return errors; } void BTSolenoid::BuildSheets(double length, double thickness, double innerRadius, double currentDensity, double tolerance=-1, std::string fileName, std::string interpolationAlgorithm) { interpolation = interpolationAlgorithm; int nSheets = myNumberOfSheets; BTSheet aSheet(Hep3Vector(0,0,0), 0, 0, 0, 0, 0, 0); double sheetRadius, sheetCurrent, sheetSeparation; sheetSeparation = thickness/(double)(nSheets); sheetCurrent = currentDensity * thickness/(double)nSheets; for(int i=0; i(myBbMin, myBbMin+3); BTField::bbMax = std::vector(myBbMax, myBbMax+3); } void BTSolenoid::Print(std::ostream & out) const { double length, currentDensity, radialSeparation, innerRadius, thickness; length = mySheets[0].len(); radialSeparation = mySheets[1].rad() - mySheets[0].rad(); thickness = radialSeparation*(double)mySheets.size(); innerRadius = mySheets[0].rad() - radialSeparation/2.; currentDensity=mySheets[0].cur()*(double)mySheets.size()/thickness; Hep3Vector position = GetGlobalPosition(); out << "Solenoid Length: " << length << " Inner Radius: " << innerRadius << " Thickness: " << thickness << " Current Density: " << currentDensity << " "; BTField::Print(out); } void BTSolenoid::SetStaticVariables(int NumberOfRCoords, int NumberOfZCoords, int NumberOfSheets, double ZExtentFactor, double RExtentFactor) { StaticNumberOfRCoords = NumberOfRCoords; StaticNumberOfZCoords = NumberOfZCoords; StaticNumberOfSheets = NumberOfSheets; StaticZExtentFactor = ZExtentFactor; StaticRExtentFactor = RExtentFactor; } MagFieldMap* BTSolenoid::GetFieldMap(std::string fileName) { fileName = STLUtils::ReplaceVariables(fileName); for(unsigned int i=0; iGetFileName()==fileName) return StaticFieldMaps[i]; } return NULL; } CLHEP::HepLorentzVector BTSolenoid::GetVectorPotential(CLHEP::HepLorentzVector Point) const { CLHEP::HepLorentzVector A(0,0,0,0); //Ax = sum^{oo}_{n=0} [ -y 1/(2*(-4)^n)n!(n+1)! d^{2n}B/dz^{2n} ] //Ay = sum^{oo}_{n=0} [ x 1/(2*(-4)^n)n!(n+1)! d^{2n}B/dz^{2n} ] //where B = B_z(r=0, z) double f = 0; double x = Point.x(); double y = Point.y(); double z = Point.z(); double Bfield[6] = {0,0,0,0,0,0}; double Pos[4] = {0,0,z,0}; double r2 = 0; //DISABLED GetFieldValue(Pos,Bfield); f = Bfield[2]/2. - 1/16.*r2*Getd2Bdz2(z); A.setX( -y*f ); A.setY( x*f ); return A; } void BTSolenoid::ClearStaticMaps() { for(int i=0; i<(int)StaticFieldMaps.size(); i++) delete StaticFieldMaps[i]; StaticFieldMaps.clear(); } int BTSolenoid::WriteIcoolSheets(std::ostream & out, Hep3Vector point, int firstSheetNumber) const { Hep3Vector centrePos = GetGlobalPosition() - point; for(int i=0; i Solenoids) { std::ofstream fout(filename.c_str()); int numberOfSheets=0; if(!fout) { MAUS::Squeak::mout(MAUS::Squeak::warning) << "Could not open file " << filename << " for icool output" << std::endl; return; } for(unsigned int i=0; iGetNumberOfSheets(); fout << "Sheets_from_G4MICE\n" << numberOfSheets << "\n" << 1 << "\n"; int firstSheet = 0; for(unsigned int i=0; iWriteIcoolSheets(fout, point, firstSheet); if(!fout) MAUS::Squeak::mout(MAUS::Squeak::warning) << "There was an error while writing " << filename << " for icool output" << std::endl; fout.close(); }