// BLEngeFunction.hh /* This source file is part of G4beamline, http://g4beamline.muonsinc.com Copyright (C) 2003,2004,2005,2006 by Tom Roberts, all rights reserved. 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. http://www.gnu.org/copyleft/gpl.html */ #ifndef BLENGEFUNCTION_HH #define BLENGEFUNCTION_HH #include /** enum BLEngeType specifies the default parameters of BLEngeFunction. **/ enum BLEngeType { ENGE_BLOCK, ENGE_BEND, ENGE_QUAD, ENGE_OTHER }; /** class EngeFunction implements the Enge function for fringe fields. * * z is the distance from the nominal edge, with z=0 being the edge. * it should be divided by the aperture diameter or full width/height. * z<0 is inside, z>0 is outside. * * See the COSY reference manual (pp 32-35) for suggested values of * a1-a6, or use the ENGE_BEND or ENGE_QUAD types (which come from there). * http://cosy.pa.msu.edu/cosymanu/index.html * * Mathematica was used to compute the derivatives. **/ class BLEngeFunction { BLEngeType type; double a1,a2,a3,a4,a5,a6; public: /// default constructor. BLEngeFunction() { type=ENGE_BLOCK; set(0,0,0,0,0,0); } /// constructor for common magnet types. BLEngeFunction(BLEngeType t) { switch(t) { case ENGE_BLOCK: case ENGE_OTHER: set(0,0,0,0,0,0); break; case ENGE_BEND: set(0.478959,1.911289,-1.185953,1.630554,-1.082657,0.318111); break; case ENGE_QUAD: set(0.296471,4.533219,-2.270982,1.068627,-0.036391,0.022261); break; } type = t; } /// general constructor. BLEngeFunction(double _a1, double _a2, double _a3, double _a4, double _a5, double _a6) { set(_a1,_a2,_a3,_a4,_a5,_a6); } /// set the parameters. void set(double _a1, double _a2, double _a3, double _a4, double _a5, double _a6) { a1=_a1; a2=_a2; a3=_a3; a4=_a4; a5=_a5; a6=_a6; if(a1==0.0 && a2==0.0 && a3==0.0 && a4==0.0 && a5==0.0 && a6==0.0) type = ENGE_BLOCK; else type = ENGE_OTHER; } /// evaluate the Enge function at z. double operator()(double z) const { if(type == ENGE_BLOCK) return (z<=0.0 ? 1.0 : 0.0); if(z < -4.0) return 1.0; if(z > 4.0) return 0.0; return 1.0/(1.0+exp(a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))))); } /// evaluate the derivative of the Enge function at z. double prime(double z) const { if(type == ENGE_BLOCK) return 0.0; if(fabs(z) > 4.0) return 0.0; double exp1 = exp(a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6))))); return -exp1/(1.0+exp1)/(1.0+exp1)* (a2+z*(2.0*a3+z*(3.0*a4+z*(4.0*a5+z*5.0*a6)))); } double first(double z) { return prime(z); } /// evaluate the second derivative of the Enge function at z. double second(double z) const { if(type == ENGE_BLOCK) return 0.0; if(fabs(z) > 4.0) return 0.0; double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); double f2 = (a2+2*a3*z+3*a4*z*z+4*a5*z*z*z+5*a6*z*z*z*z); double f3 = (2*a3+6*a4*z+12*a5*z*z+20*a6*z*z*z); double exp1 = exp(f1); return exp1*((exp1-1.0)*f2*f2-(1.0+exp1)*f3)/ (1.0+exp1)/(1.0+exp1)/(1.0+exp1); } /// evaluate the third derivative of the Enge function at z. double third(double z) const { if(type == ENGE_BLOCK) return 0.0; if(fabs(z) > 4.0) return 0.0; double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); double f2 = a2+z*(2*a3+z*(3*a4+4*a5*z+5*a6*z*z)); double f3 = 2*(a3+z*(3*a4+2*z*(3*a5+5*a6*z))); double f4 = a4+2.0*z*(2.0*a5+5.0*a6*z); double exp1 = exp(f1); double onepexp1 = 1.0 + exp1; return -exp1*(6*exp1*exp1*f2*f2*f2-6*exp1*f2*(f2*f2+f3)*onepexp1 +(f2*f2*f2+3*f2*f3+6*f4)*onepexp1*onepexp1) /(onepexp1*onepexp1*onepexp1*onepexp1); } /// evaluate the fourth derivative of the Enge function at z. double fourth(double z) const { if(type == ENGE_BLOCK) return 0.0; if(fabs(z) > 4.0) return 0.0; double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); double f2 = a2+z*(2*a3+z*(3*a4+4*a5*z+5*a6*z*z)); double f3 = 2*(a3+z*(3*a4+2*z*(3*a5+5*a6*z))); double f4 = a4+2.0*z*(2.0*a5+5.0*a6*z); double f5 = a5 + 5*a6*z; double exp1 = exp(f1); double onepexp1 = 1.0 + exp1; return -exp1*(-24*exp1*exp1*exp1*f2*f2*f2*f2+onepexp1* (36*exp1*exp1*f2*f2*(f2*f2+f3)-2*exp1*(7*f2*f2*f2*f2 +18*f2*f2*f3+3*f3*f3+24*f2*f4)*onepexp1 +(f2*f2*f2*f2+6*f2*f2*f3+3*f3*f3+24*f2*f4+24*f5) *onepexp1*onepexp1)) /(onepexp1*onepexp1*onepexp1*onepexp1*onepexp1); } /// evaluate the fifth derivative of the Enge function at z. double fifth(double z) const { if(type == ENGE_BLOCK) return 0.0; if(fabs(z) > 4.0) return 0.0; double f1 = a1+z*(a2+z*(a3+z*(a4+z*(a5+z*a6)))); double f2 = a2+z*(2*a3+z*(3*a4+4*a5*z+5*a6*z*z)); double f3 = 2*(a3+z*(3*a4+2*z*(3*a5+5*a6*z))); double f4 = a4+2.0*z*(2.0*a5+5.0*a6*z); double f5 = a5 + 5*a6*z; double exp1 = exp(f1); double onepexp1 = 1.0 + exp1; return -exp1/(onepexp1*onepexp1*onepexp1*onepexp1*onepexp1*onepexp1) *(120*exp1*exp1*exp1*exp1*f2*f2*f2*f2*f2 -240*exp1*exp1*exp1*f2*f2*f2*(f2*f2+f3)*onepexp1 +onepexp1*onepexp1*(30*exp1*exp1*f2*(5*f2*f2*f2*f2 +12*f2*f2*f3+3*f3*f3+12*f2*f4)-10*exp1*(3*f2*f2*f2*f2*f2 +14*f2*f2*f2*f3+9*f2*f3*f3+36*f2*f2*f4+12*f3*f4+24*f2*f5) *onepexp1+(120*a6+f2*f2*f2*f2*f2+10*f2*f2*f2*f3+60*f2*f2*f4 +60*f3*f4+15*f2*(f3*f3+8*f5))*onepexp1*onepexp1)); } /// return the type of Enge function BLEngeType getType() const { return type; } }; #endif // BLENGEFUNCTION_HH