File indexing completed on 2026-04-09 07:48:50
0001
0002 """
0003 rotate.py
0004 ===========
0005
0006 Make sense of GDML physvol/rotation and global to local transforms
0007
0008 ::
0009
0010 71423 <physvol copynumber="11336" name="pLPMT_Hamamatsu_R128600x353fc90">
0011 71424 <volumeref ref="HamamatsuR12860lMaskVirtual0x3290b70"/>
0012 71425 <position name="pLPMT_Hamamatsu_R128600x353fc90_pos" unit="mm" x="-7148.9484" y="17311.741" z="-5184.2567"/>
0013 71426 <rotation name="pLPMT_Hamamatsu_R128600x353fc90_rot" unit="deg" x="-73.3288783033161" y="-21.5835981926051" z="-96.2863976680901"/>
0014 71427 </physvol>
0015
0016
0017 ::
0018
0019 epsilon:src blyth$ grep \"rotation\" *.cc
0020 G4GDMLReadDefine.cc: if (tag=="rotation") { RotationRead(child); } else
0021 G4GDMLReadParamvol.cc: if (tag=="rotation") { VectorRead(child,rotation); } else
0022 G4GDMLReadSolids.cc: if (tag=="rotation") { VectorRead(child,rotation); } else
0023 G4GDMLReadSolids.cc: if (tag=="rotation") { VectorRead(child,rotation); } else
0024 G4GDMLReadStructure.cc: else if (tag=="rotation")
0025 G4GDMLReadStructure.cc: if (tag=="rotation")
0026 epsilon:src blyth$ pwd
0027 /usr/local/opticks_externals/g4_1042.build/geant4.10.04.p02/source/persistency/gdml/src
0028
0029
0030 ::
0031
0032 g4-cls Rotation
0033
0034 336 HepRotation & rotateX(double delta);
0035 337 // Rotation around the x-axis; equivalent to R = RotationX(delta) * R
0036 338
0037 339 HepRotation & rotateY(double delta);
0038 340 // Rotation around the y-axis; equivalent to R = RotationY(delta) * R
0039 341
0040 342 HepRotation & rotateZ(double delta);
0041 343 // Rotation around the z-axis; equivalent to R = RotationZ(delta) * R
0042 344
0043
0044
0045 """
0046
0047 import os, sympy as sp, numpy as np
0048 from sympy import pprint as pp
0049
0050
0051 def tr_inverse(tt):
0052 """
0053 decompose translate rotate matrix by inspection,
0054 negate the translation and transpose the rotation
0055
0056 In [167]: tr
0057 Out[167]:
0058 array([[ -0.1018, -0.9243, 0.3679, 0. ],
0059 [ 0.2466, -0.3817, -0.8908, 0. ],
0060 [ 0.9638, 0. , 0.2668, 0. ],
0061 [ -0.003 , 0.0127, 19433.9994, 1. ]])
0062
0063 In [168]: np.dot( hit, tr )
0064 Out[168]: array([-112.6704, 165.9216, 109.6381, 1. ])
0065
0066
0067 """
0068 it = np.eye(4)
0069 it[3,:3] = -tt[3,:3]
0070
0071 ir = np.eye(4)
0072 ir[:3,:3] = tt[:3,:3].T
0073
0074 tr = np.dot(it,ir)
0075 return tr
0076
0077
0078 class Instance(object):
0079 def __init__(self, ridx):
0080 """
0081 epsilon:1 blyth$ inp GMergedMesh/?/iidentity.npy GMergedMesh/?/itransforms.npy
0082 a : GMergedMesh/1/iidentity.npy : (25600, 5, 4) : a4a7deb934cae243b9181c80ddc1066b : 20200719-2129
0083 b : GMergedMesh/1/itransforms.npy : (25600, 4, 4) : 29a7bf21dabfd4a6f9228fadb7edabca : 20200719-2129
0084 c : GMergedMesh/2/iidentity.npy : (12612, 6, 4) : 4423ba6434c39aff488e6784df468ae1 : 20200719-2129
0085 d : GMergedMesh/2/itransforms.npy : (12612, 4, 4) : 766b1e274449b0d9f2ecc35d58b52a71 : 20200719-2129
0086 e : GMergedMesh/3/iidentity.npy : (5000, 6, 4) : 52c59e1bb3179c404722c2df4c26ac81 : 20200719-2129
0087 f : GMergedMesh/3/itransforms.npy : (5000, 4, 4) : 1ff4e96acee67137c4740b05e6684c93 : 20200719-2129
0088 g : GMergedMesh/4/iidentity.npy : (2400, 6, 4) : 08846aa446e53c50c1a7cea89674a398 : 20200719-2129
0089 h : GMergedMesh/4/itransforms.npy : (2400, 4, 4) : aafe0245a283080c130d8575b7a83e67 : 20200719-2129
0090
0091 #. iidentity is now reshaped shortly after creation to have same item count as itransforms
0092 """
0093 tt = np.load(os.path.expandvars("$GC/GMergedMesh/%d/itransforms.npy" % ridx))
0094 ii = np.load(os.path.expandvars("$GC/GMergedMesh/%d/iidentity.npy" % ridx))
0095
0096 assert tt.shape[1:] == (4,4)
0097 assert len(ii.shape) == 3 and ii.shape[2] == 4
0098 assert len(tt) == len(ii)
0099 nvol = ii.shape(1)
0100
0101 self.ii = ii
0102 self.tt = tt
0103 self.nvol = nvol
0104
0105 def find_instance_index(self, pmtid):
0106 """
0107 Using vol 0 corresponds to the outer volume of the instance :
0108 but the copyNo is duplicated for all the volumes of the instance
0109 so all 0:nvol are the same.
0110 """
0111 return np.where( self.ii[:,0,3] == pmtid )[0][0]
0112 def find_instance_transform(self, pmtid):
0113 ix = self.find_instance_index(pmtid)
0114 return self.tt[ix]
0115 def find_instance_transform_inverse(self, pmtid):
0116 tt = self.find_instance_transform(pmtid)
0117 return tr_inverse(tt)
0118
0119 def find_local_pos(self, pmtid, global_pos):
0120 assert global_pos.shape == (4,)
0121 tr = self.find_instance_transform_inverse(pmtid)
0122 local_pos = np.dot( global_pos, tr )
0123 return local_pos
0124
0125
0126
0127 def three_to_four(M3):
0128 assert M3.shape == (3,3)
0129 M4 = sp.zeros(4)
0130 for i in range(3):
0131 for j in range(3):
0132 M4[i*4+j] = M3.row(i)[j]
0133 pass
0134 M4[15] = 1
0135 return M4
0136 pass
0137
0138
0139 alpha,beta,gamma = sp.symbols("alpha beta gamma")
0140
0141 row0 = rxx,ryx,rzx,rwx = sp.symbols("rxx,ryx,rzx,rwx")
0142 row1 = rxy,ryy,rzy,rwy = sp.symbols("rxy,ryy,rzy,rwy")
0143 row2 = rxz,ryz,rzz,rwz = sp.symbols("rxz,ryz,rzz,rwz")
0144 row3 = tx,ty,tz,tw = sp.symbols("tx,ty,tz,tw")
0145 RTxyz = sp.Matrix([row0,row1,row2,row3])
0146
0147 v_rid = [
0148 (rxx,1),(ryx,0),(rzx,0),
0149 (rxy,0),(ryy,1),(rzy,0),
0150 (rxz,0),(ryz,0),(rzz,1) ]
0151
0152 v_rw = [(rwx,0),(rwy,0),(rwz,0)]
0153 v_t0 = [(tx,0),(ty,0),(tz,0),(tw,1)]
0154 v_tw = [(tw,1),]
0155
0156 RT = RTxyz.subs(v_rw+v_tw)
0157 R = RTxyz.subs(v_rw+v_t0)
0158 T = RTxyz.subs(v_rid+v_rw+v_tw)
0159
0160
0161 x,y,z,w = sp.symbols("x,y,z,w")
0162 P = sp.Matrix([[x,y,z,w]])
0163
0164 assert P.shape == (1,4)
0165 P1 = P.subs([(w,1)])
0166 P0 = P.subs([(w,0)])
0167
0168
0169
0170 deg = np.pi/180.
0171 v_rot = [(alpha,-73.3288783033161*deg),(beta,-21.5835981926051*deg),(gamma, -96.2863976680901*deg)]
0172 v_pos = [(tx, -7148.9484),(ty,17311.741), (tz,-5184.2567)]
0173
0174 lhit0 = np.array([-112.67072395684227,165.92175413608675,109.63878699927591,1])
0175 v_lhit0 = [(x,lhit0[0]), (y,lhit0[1]), (z,lhit0[2])]
0176
0177 hit = np.array([-7250.504552589168,17122.963751776308,-5263.596996014085, 1])
0178 v_hit = [(x,hit[0]),(y,hit[1]),(z,hit[2]),(w,hit[3])]
0179
0180
0181
0182 pmtid = 11336
0183 it = Instance(3)
0184 tt = it.find_instance_transform(pmtid)
0185 tr = it.find_instance_transform_inverse(pmtid)
0186 lhit = it.find_local_pos(pmtid, hit )
0187
0188 assert np.allclose(lhit0, lhit), lhit0-lhit
0189
0190
0191 zhit = lhit[2]
0192 rhit = np.sqrt(lhit[0]*lhit[0]+lhit[1]*lhit[1])
0193
0194 one = ((zhit*zhit)/(185.*185.))+((rhit*rhit)/(249.*249.))
0195
0196
0197
0198
0199 Rx = three_to_four(sp.rot_axis1(alpha))
0200 IRx = three_to_four(sp.rot_axis1(-alpha))
0201
0202 Ry = three_to_four(sp.rot_axis2(beta))
0203 IRy = three_to_four(sp.rot_axis2(-beta))
0204
0205 Rz = three_to_four(sp.rot_axis3(gamma))
0206 IRz = three_to_four(sp.rot_axis3(-gamma))
0207
0208 R0 = Rz*Ry*Rx
0209 IR0 = IRx*IRy*IRz
0210 assert IR0.transpose() == R0
0211 assert R0.transpose() == IR0
0212
0213 R1 = Rx*Ry*Rz
0214 IR1 = IRz*IRy*IRx
0215 assert IR1.transpose() == R1
0216 assert R1.transpose() == IR1
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226 R1T = sp.Matrix([R1.row(0), R1.row(1), R1.row(2), T.row(3)])
0227 R1T_check = R1*T
0228
0229 assert R1T == R1T_check
0230 assert P*R1*T == P*R1T
0231
0232
0233
0234
0235 """
0236 IR1T
0237 Matrix([
0238 [cos(beta)*cos(gamma), sin(alpha)*sin(beta)*cos(gamma) - sin(gamma)*cos(alpha), sin(alpha)*sin(gamma) + sin(beta)*cos(alpha)*cos(gamma), 0],
0239 [sin(gamma)*cos(beta), sin(alpha)*sin(beta)*sin(gamma) + cos(alpha)*cos(gamma), -sin(alpha)*cos(gamma) + sin(beta)*sin(gamma)*cos(alpha), 0],
0240 [ -sin(beta), sin(alpha)*cos(beta), cos(alpha)*cos(beta), 0],
0241 [ tx, ty, tz, 1]])
0242
0243 """
0244
0245
0246
0247 IR1T = sp.Matrix([IR1.row(0), IR1.row(1), IR1.row(2), T.row(3)])
0248
0249 M = IR1T.subs(v_rot+v_pos)
0250
0251
0252
0253 match = np.allclose( np.array(M, dtype=np.float32 ), tt )
0254 assert match
0255
0256
0257 MI = np.array(M.inv(), dtype=np.float64)
0258
0259 amx = np.abs(MI-tr).max()
0260 assert amx < 1e-3
0261
0262
0263
0264
0265 T2 = sp.Matrix([[1,0,0,0],
0266 [0,1,0,0],
0267 [0,0,1,0],
0268 [tx,ty,tz,1]])
0269
0270 assert T == T2, (T, T2)
0271
0272
0273 IT = sp.Matrix([[1,0,0,0],
0274 [0,1,0,0],
0275 [0,0,1,0],
0276 [-tx,-ty,-tz,1]])
0277
0278
0279
0280
0281
0282
0283
0284
0285 """
0286 71423 <physvol copynumber="11336" name="pLPMT_Hamamatsu_R128600x353fc90">
0287 71424 <volumeref ref="HamamatsuR12860lMaskVirtual0x3290b70"/>
0288 71425 <position name="pLPMT_Hamamatsu_R128600x353fc90_pos" unit="mm" x="-7148.9484" y="17311.741" z="-5184.2567"/>
0289 71426 <rotation name="pLPMT_Hamamatsu_R128600x353fc90_rot" unit="deg" x="-73.3288783033161" y="-21.5835981926051" z="-96.2863976680901"/>
0290 71427 </physvol>
0291 """
0292
0293
0294 if 0:
0295 print("\nRx")
0296 pp(Rx)
0297 print("\nRy")
0298 pp(Ry)
0299 print("\nRz")
0300 pp(Rz)
0301
0302
0303 def rotateX():
0304 """
0305 This demonstrates that HepRotation::rotateX is multiplying to the rhs::
0306
0307 Rxyz*Rx
0308
0309 66 HepRotation & HepRotation::rotateX(double a) { // g4-cls Rotation
0310 67 double c1 = std::cos(a);
0311 68 double s1 = std::sin(a);
0312 69 double x1 = ryx, y1 = ryy, z1 = ryz;
0313 70 ryx = c1*x1 - s1*rzx;
0314 71 ryy = c1*y1 - s1*rzy;
0315 72 ryz = c1*z1 - s1*rzz;
0316 73 rzx = s1*x1 + c1*rzx;
0317 74 rzy = s1*y1 + c1*rzy;
0318 75 rzz = s1*z1 + c1*rzz;
0319 76 return *this;
0320 77 }
0321 """
0322 pass
0323
0324 x1,y1,z1 = sp.symbols("x1,y1,z1")
0325 v_ry = [(ryx,x1),(ryy,y1),(ryz,z1)]
0326
0327 Xlhs = (Rx*R).subs(v_ry)
0328 Xrhs = (R*Rx).subs(v_ry)
0329
0330
0331 print(rotateX.__doc__)
0332
0333 print("\nR")
0334 pp(R)
0335
0336 print("\nv_ry")
0337 pp(v_ry)
0338
0339 print("\nXrhs = (R*Rx).subs(v_ry) ")
0340 pp(Xrhs)
0341
0342
0343
0344
0345 def rotateY():
0346 """
0347 This demonstrates that HepRotation::rotateY is multiplying to the rhs::
0348
0349 Rxyz*Ry
0350
0351 079 HepRotation & HepRotation::rotateY(double a){
0352 80 double c1 = std::cos(a);
0353 81 double s1 = std::sin(a);
0354 82 double x1 = rzx, y1 = rzy, z1 = rzz;
0355 83 rzx = c1*x1 - s1*rxx;
0356 84 rzy = c1*y1 - s1*rxy;
0357 85 rzz = c1*z1 - s1*rxz;
0358 86 rxx = s1*x1 + c1*rxx;
0359 87 rxy = s1*y1 + c1*rxy;
0360 88 rxz = s1*z1 + c1*rxz;
0361 89 return *this;
0362 90 }
0363 """
0364 x1,y1,z1 = sp.symbols("x1,y1,z1")
0365 v_rz = [(rzx,x1),(rzy,y1),(rzz,z1)]
0366
0367 Ylhs = (Ry*R).subs(v_rz)
0368 Yrhs = (R*Ry).subs(v_rz)
0369
0370 print(rotateY.__doc__)
0371
0372 print("\nR")
0373 pp(R)
0374
0375 print("\nv_rz")
0376 pp(v_rz)
0377
0378 print("\nYrhs = (R*Ry).subs(v_rz) ")
0379 pp(Yrhs)
0380
0381
0382
0383 def rotateZ():
0384 """
0385 This demonstrates that HepRotation::rotateZ is multiplying to the rhs::
0386
0387 Rxyz*Rz
0388
0389
0390 092 HepRotation & HepRotation::rotateZ(double a) {
0391 93 double c1 = std::cos(a);
0392 94 double s1 = std::sin(a);
0393 95 double x1 = rxx, y1 = rxy, z1 = rxz;
0394 96 rxx = c1*x1 - s1*ryx;
0395 97 rxy = c1*y1 - s1*ryy;
0396 98 rxz = c1*z1 - s1*ryz;
0397 99 ryx = s1*x1 + c1*ryx;
0398 100 ryy = s1*y1 + c1*ryy;
0399 101 ryz = s1*z1 + c1*ryz;
0400 102 return *this;
0401 103 }
0402 """
0403
0404 x1,y1,z1 = sp.symbols("x1,y1,z1")
0405 v_rx = [(rxx,x1),(rxy,y1),(rxz,z1)]
0406
0407 Zlhs = (Rz*R).subs(v_rx)
0408 Zrhs = (R*Rz).subs(v_rx)
0409
0410 print(rotateZ.__doc__)
0411
0412 print("\nR")
0413 pp(R)
0414
0415 print("\nv_rx")
0416 pp(v_rx)
0417
0418 print("\nZrhs = (R*Rz).subs(v_rx) ")
0419 pp(Zrhs)
0420
0421
0422
0423
0424 def G4GDMLReadStructure():
0425 """
0426
0427 289 void G4GDMLReadStructure::
0428 290 PhysvolRead(const xercesc::DOMElement* const physvolElement,
0429 291 G4AssemblyVolume* pAssembly)
0430 292 {
0431 ...
0432 372 G4Transform3D transform(GetRotationMatrix(rotation).inverse(),position);
0433 373 transform = transform*G4Scale3D(scale.x(),scale.y(),scale.z());
0434
0435
0436 132 G4RotationMatrix
0437 133 G4GDMLReadDefine::GetRotationMatrix(const G4ThreeVector& angles)
0438 134 {
0439 135 G4RotationMatrix rot;
0440 136
0441 137 rot.rotateX(angles.x());
0442 138 rot.rotateY(angles.y());
0443 139 rot.rotateZ(angles.z());
0444 140 rot.rectify(); // Rectify matrix from possible roundoff errors
0445 141
0446 142 return rot;
0447 143 }
0448
0449
0450 g4-cls Transform3D (icc)
0451
0452 029 inline
0453 30 Transform3D::Transform3D(const CLHEP::HepRotation & m, const CLHEP::Hep3Vector & v) {
0454 31 xx_= m.xx(); xy_= m.xy(); xz_= m.xz();
0455 32 yx_= m.yx(); yy_= m.yy(); yz_= m.yz();
0456 33 zx_= m.zx(); zy_= m.zy(); zz_= m.zz();
0457 34 dx_= v.x(); dy_= v.y(); dz_= v.z();
0458 35 }
0459
0460
0461 NB the order (rotateX, rotateY, rotateZ).inverse()
0462
0463
0464 In [18]: t[3218] # use the instance index to give the instance transform : rot matrix and tlate look familiar
0465 Out[18]:
0466 array([[ -0.1018, 0.2466, 0.9638, 0. ],
0467 [ -0.9243, -0.3817, 0. , 0. ],
0468 [ 0.3679, -0.8908, 0.2668, 0. ],
0469 [-7148.948 , 17311.74 , -5184.257 , 1. ]], dtype=float32)
0470
0471
0472 In [70]: pp((Rx*Ry*Rz).transpose().subs(v_rot)*T.subs(v_pos))
0473 -0.101820513179743 0.24656591428434 0.963762332221457 0
0474 -0.924290430171623 -0.381689927419044 8.32667268468867e-17 0
0475 0.367858374634817 -0.890796300632177 0.266762379264878 0
0476 -7148.9484 17311.741 -5184.2567 1
0477
0478
0479 In [52]: (P*IT*R1).subs(v_hit+v_pos+v_rot) ### << MATCHES <<
0480 Out[52]: Matrix([[-112.670723956843, 165.921754136086, 109.638786999275, 1.0]])
0481
0482 In [100]: (P*IT*Rx*Ry*Rz).subs(v_hit+v_pos+v_rot)
0483 Out[100]: Matrix([[-112.670723956843, 165.921754136086, 109.638786999275, 1]])
0484
0485
0486
0487 In [101]: (P*Rx*Ry*Rz*IT).subs(v_hit+v_pos+v_rot)
0488 Out[101]: Matrix([[7036.28119031864, -17145.8318197405, -14140.1045440872, 1]])
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498 (gdb) p local_pos
0499 $7 = {dx = -112.67072395684227, dy = 165.92175413608675, dz = 109.63878699927591, static tolerance = 2.22045e-14}
0500 (gdb) p trans
0501
0502
0503
0504 ## 4th row matches the GDML
0505
0506 71423 <physvol copynumber="11336" name="pLPMT_Hamamatsu_R128600x353fc90">
0507 71424 <volumeref ref="HamamatsuR12860lMaskVirtual0x3290b70"/>
0508 71425 <position name="pLPMT_Hamamatsu_R128600x353fc90_pos" unit="mm" x="-7148.9484" y="17311.741" z="-5184.2567"/>
0509 71426 <rotation name="pLPMT_Hamamatsu_R128600x353fc90_rot" unit="deg" x="-73.3288783033161" y="-21.5835981926051" z="-96.2863976680901"/>
0510 71427 </physvol>
0511
0512
0513 { rxx = -0.10182051317974285, rxy = -0.92429043017162327, rxz = 0.36785837463481702,
0514 ryx = 0.24656591428433955, ryy = -0.38168992741904467, ryz = -0.89079630063217707,
0515 rzx = 0.96376233222145669, rzy = 0, rzz = 0.26676237926487772,
0516 tx = -0.0035142754759363015, ty = 0.012573876562782971, tz = 19434.000031086449}
0517
0518 THIS IS THE INVERSE TRANSFORM
0519
0520
0521 From examples/UseGeant4/UseGeant.cc
0522
0523 dbg_affine_trans Transformation:
0524 rx/x,y,z: -0.101821 -0.92429 0.367858
0525 ry/x,y,z: 0.246566 -0.38169 -0.890796
0526 rz/x,y,z: 0.963762 0 0.266762
0527 tr/x,y,z: -0.00351428 0.0125739 19434
0528
0529
0530 """
0531 R0 = Rx*Ry*Rz
0532 R0T = (Rx*Ry*Rz).T
0533
0534 R1 = Rz*Ry*Rx
0535 R1T = (Rz*Ry*Rx).T
0536
0537
0538 print(G4GDMLReadStructure.__doc__)
0539
0540 if 0:
0541 print("\nR0 = Rx*Ry*Rz \n")
0542 pp(R0)
0543 pp(R)
0544 pp(R0.subs(va))
0545 pass
0546
0547 print("\nR0T = (Rx*Ry*Rz).T THIS MATCHES THE ROTATION PART OF THE ITRANSFORM \n")
0548 pp(R0T)
0549 pp(R)
0550 pp(R0T.subs(v_rot))
0551
0552
0553 if 0:
0554 print("\nR1 = Rz*Ry*Rx\n")
0555 pp(R1)
0556 pp(R)
0557 pp(R1.subs(va))
0558 pass
0559
0560
0561
0562 def translate():
0563 """
0564 Using col3 for the translation as opposed to glm/OpenGL approach
0565 of row3 for the translation is a transpose of the translation matrix,
0566 which means need to transpose the point for shape consistency
0567 and multiply in other order.
0568 """
0569
0570 print("P1")
0571 pp(P1)
0572 print("T")
0573 pp(T)
0574 P1_T = P1*T
0575 print("P1*T")
0576 pp(P1_T)
0577 print("P1*T*T")
0578 pp(P1*T*T)
0579 P1_T_reverse_transpose_check = (T.T*P1.T).T
0580 print("(T.T*P1.T).T")
0581 pp(P1_T_reverse_transpose_check)
0582 assert P1_T_reverse_transpose_check == P1_T
0583
0584
0585 def translate_rotate():
0586 """
0587 P1
0588 x y z 1
0589 TR
0590 rxx ryx rzx 0
0591
0592 rxy ryy rzy 0
0593
0594 rxz ryz rzz 0
0595
0596 tx ty tz tw
0597 P*TR
0598 rxx x + rxy y + rxz z + tx w ryx x + ryy y + ryz z + ty w rzx x + rzy y + rzz z + tz w tw w
0599 P*TR.subs(v_rid)
0600 tx w + x ty w + y tz w + z tw w
0601
0602 """
0603
0604 print("R")
0605 pp(R)
0606 print("T")
0607 pp(T)
0608 print("T*R : row3 has translation and rotation mixed up : ie translation first and then rotation which depends ")
0609 pp(T*R)
0610 print("R*T : familiar row3 as translation : that means rotate then translate ")
0611 pp(R*T)
0612
0613 print("RT")
0614 pp(RT)
0615 assert RT == R*T
0616
0617
0618 print("P1")
0619 pp(P1)
0620 print("P*RT : notice that the translation just gets added to rotated coordinates : ie rotation first and then translation")
0621 pp(P*RT)
0622
0623 P_RT = P*RT
0624 print("P*RT.subs(v_rid) : setting rotation to identity ")
0625 pp(P_RT.subs(v_rid))
0626
0627
0628
0629
0630 if __name__ == '__main__':
0631
0632
0633
0634
0635
0636
0637
0638
0639 G4GDMLReadStructure()
0640
0641
0642