1 | #include "ParabolicSurface.h" |
---|
2 | #include "LensUtils.h" |
---|
3 | |
---|
4 | using std::swap; |
---|
5 | using namespace G4FresnelLens; |
---|
6 | |
---|
7 | //______________________________________________________________________________ |
---|
8 | ParabolicSurface::ParabolicSurface(double k, double z, double rhomax): |
---|
9 | ParametricSurface(z,rhomax), |
---|
10 | fK(k) |
---|
11 | { |
---|
12 | //kHalfTolerance=kTolerance; |
---|
13 | //kTolerance=2.*kHalfTolerance; |
---|
14 | Configure(); |
---|
15 | } |
---|
16 | |
---|
17 | //______________________________________________________________________________ |
---|
18 | ParabolicSurface::~ParabolicSurface(){ |
---|
19 | |
---|
20 | |
---|
21 | } |
---|
22 | |
---|
23 | //______________________________________________________________________________ |
---|
24 | void ParabolicSurface::Configure(){ |
---|
25 | fZ1=fZmin=PointOnSurf(0.); |
---|
26 | fZ2=fZmax=PointOnSurf(fR); |
---|
27 | if ( fZmin>fZmax ) swap(fZmin,fZmax); |
---|
28 | } |
---|
29 | |
---|
30 | //__________________________________________________________________________________ |
---|
31 | void ParabolicSurface::print(){ |
---|
32 | printf("paraboloid z=%g perp=%g k=%g min/max=%g/%g\n", fZpos, fR, fK, fZmin, fZmax); |
---|
33 | } |
---|
34 | |
---|
35 | //__________________________________________________________________________________ |
---|
36 | void ParabolicSurface::GuessParameters(int n, int tn, int* idx, double* rho, double* z, bool minimum){ |
---|
37 | if ( fK!=DBL_MAX ) return; |
---|
38 | int i1a=idx[1]; |
---|
39 | int i1b=i1a+1; |
---|
40 | int i1=(z[i1a]>z[i1b])^minimum?i1a:i1b; |
---|
41 | |
---|
42 | int i2a=idx[tn-1]; |
---|
43 | int i2b=i2a+1; |
---|
44 | int i2=(z[i2a]>z[i2b])^minimum?i2a:i2b; |
---|
45 | |
---|
46 | double dz=z[i2]-z[i1]; |
---|
47 | double dr2=rho[i2]*rho[i2]-rho[i1]*rho[i1]; |
---|
48 | fK=dr2?dz/dr2:0.; |
---|
49 | } |
---|
50 | |
---|
51 | //__________________________________________________________________________________ |
---|
52 | void ParabolicSurface::GuessParameters(const std::vector<SSurface*>& surfaces, bool minimum){ |
---|
53 | if ( fK!=DBL_MAX ) return; |
---|
54 | |
---|
55 | SSurface* s1=*(surfaces.begin()); |
---|
56 | SSurface* s2=*(surfaces.end()-1); |
---|
57 | double r1,r2,z1,z2; |
---|
58 | double za=s1->GetZ1(); |
---|
59 | double zb=s1->GetZ2(); |
---|
60 | if ( (za>zb)^minimum ){ |
---|
61 | z1=s1->GetZ1(); |
---|
62 | r1=s1->GetR1(); |
---|
63 | } |
---|
64 | else { |
---|
65 | z1=s1->GetZ2(); |
---|
66 | r1=s1->GetR2(); |
---|
67 | } |
---|
68 | |
---|
69 | za=s2->GetZ1(); |
---|
70 | zb=s2->GetZ2(); |
---|
71 | if ( (za>zb)^minimum ){ |
---|
72 | z2=s2->GetZ1(); |
---|
73 | r2=s2->GetR1(); |
---|
74 | } |
---|
75 | else { |
---|
76 | z2=s2->GetZ2(); |
---|
77 | r2=s2->GetR2(); |
---|
78 | } |
---|
79 | |
---|
80 | double dz=z2-z1; |
---|
81 | double dr2=r2*r2-r1*r1; |
---|
82 | fK=dr2?dz/dr2:0.; |
---|
83 | } |
---|
84 | |
---|
85 | //__________________________________________________________________________________ |
---|
86 | double ParabolicSurface::DistanceToSurf(const G4ThreeVector& p, const G4ThreeVector& v){ |
---|
87 | double perp2=p.perp2(); |
---|
88 | double vperp2=v.perp2(); |
---|
89 | double a = fK*vperp2; |
---|
90 | double b = 2.*fK*(p.x()*v.x()+p.y()*v.y())-v.z(); |
---|
91 | double c = fK*perp2-p.z()+fZpos; |
---|
92 | double d1, d2; |
---|
93 | int nroot=SolveQuadratic(a, b, c, d1, d2); |
---|
94 | |
---|
95 | if ( !nroot ) return kInfinity; |
---|
96 | #ifdef DEBUG |
---|
97 | printf("pos(%.10g, %.10g, %.10g), dir(%.10g, %.10g, %.10g)\n", p.x(), p.y(), p.z(), v.x(), v.y(), v.z()); |
---|
98 | printf("abc: %.10g, %.10g, %.10g\n", a,b,c); |
---|
99 | double d=sqrt(b*b-4*a*c); |
---|
100 | double x1=(-b+d)/2./a; |
---|
101 | printf("s(d)=%.10g, d1:d2: %.10g, %.10g\n",d, (-b-d)/2./a, x1); |
---|
102 | printf("s(d)=%.10g, d1:d2: %.10g, %.10g\n",d, x1, -b/a-x1); |
---|
103 | printf("%i roots: %.10g, %.10g\n", nroot, d1, d2); |
---|
104 | #endif |
---|
105 | G4ThreeVector pos; |
---|
106 | if ( d1>=0. ) { |
---|
107 | pos = p+v*d1; |
---|
108 | double zpos=pos.z(); |
---|
109 | double perpa2=pos.perp2(); |
---|
110 | if ( perpa2<=fR*fR && zpos>=fZmin && zpos<=fZmax ) { |
---|
111 | return d1; |
---|
112 | } |
---|
113 | } |
---|
114 | if ( nroot==1 || d2<0. ) return kInfinity; |
---|
115 | |
---|
116 | pos = p+v*d2; |
---|
117 | double zpos=pos.z(); |
---|
118 | double perpa2=pos.perp2(); |
---|
119 | if ( perpa2<=fR*fR && zpos>=fZmin && zpos<=fZmax ) { |
---|
120 | return d2; |
---|
121 | } |
---|
122 | return kInfinity; |
---|
123 | } |
---|
124 | |
---|
125 | //__________________________________________________________________________________ |
---|
126 | double ParabolicSurface::DistanceToSurfSafe(const G4ThreeVector& p){ |
---|
127 | // |
---|
128 | // return undirectional distance to surface |
---|
129 | // can be underestimated |
---|
130 | // thus returning distance to the bounding tube |
---|
131 | // |
---|
132 | double perp2=p.perp2(); |
---|
133 | double z=p.z(); |
---|
134 | |
---|
135 | if ( perp2<=fR*fR ) { |
---|
136 | if ( z>fZmax ) return z-fZmax; |
---|
137 | if ( z<fZmin ) return fZmin-z; |
---|
138 | return 0.; |
---|
139 | } |
---|
140 | double perp=sqrt(perp2); |
---|
141 | if ( z>fZmax ) return Hyp(perp, z, fR, fZmax); |
---|
142 | if ( z<fZmin ) return Hyp(perp, z, fR, fZmin); |
---|
143 | return perp-fR; |
---|
144 | } |
---|