3 module Hkl
.XRD
.Calibration
5 , XRDCalibrationEntry
(..)
10 import Control
.Monad
.IO.Class
(liftIO
)
11 import Data
.ByteString
.Char8
(pack
)
12 import Data
.List
(foldl')
13 import Data
.Text
(Text
)
14 import Data
.Vector
.Storable
22 import Numeric
.LinearAlgebra
29 import Numeric
.GSL
.Minimization
30 ( MinimizeMethod
(NMSimplex2
)
33 import Numeric
.Units
.Dimensional
.Prelude
(meter
, radian
, nano
, (/~
), (*~
))
34 import Pipes
.Safe
(MonadSafe
(..), runSafeT
, bracket)
35 import Prelude
hiding (head, concat, lookup, readFile, writeFile, unlines)
42 import Hkl
.PyFAI
.PoniExt
48 data NptExt a
= NptExt
{ nptExtNpt
:: Npt
49 , nptExtMyMatrix
:: MyMatrix
Double
50 , nptExtDetector
:: Detector a
54 data XRDCalibrationEntry
= XRDCalibrationEntry
{ xrdCalibrationEntryNxs
:: Nxs
55 , xrdCalibrationEntryIdx
:: Int
56 , xrdCalibrationEntryNptPath
:: FilePath
60 data XRDCalibration
= XRDCalibration
{ xrdCalibrationName
:: Text
61 , xrdCalibrationOutputDir
:: FilePath
62 , xrdCalibrationEntries
:: [XRDCalibrationEntry
]
66 withDataItem
:: MonadSafe m
=> File
-> DataItem
-> (Dataset
-> m r
) -> m r
67 withDataItem hid
(DataItem name _
) = bracket (liftIO acquire
') (liftIO
. release
')
69 acquire
' :: IO Dataset
70 acquire
' = openDataset hid
(pack name
) Nothing
72 release
' :: Dataset
-> IO ()
73 release
' = closeDataset
75 getM
:: File
-> DataFrameH5Path
-> Int -> IO (MyMatrix
Double)
76 getM f p i
' = runSafeT
$
77 withDataItem f
(h5pGamma p
) $ \g
' ->
78 withDataItem f
(h5pDelta p
) $ \d
' ->
79 withDataItem f
(h5pWavelength p
) $ \w
' -> liftIO
$ do
84 gamma
<- get_position g
' 0
85 delta
<- get_position d
' i
'
86 wavelength
<- get_position w
' 0
87 let source
= Source
(head wavelength
*~ nano meter
)
88 let positions
= concat [mu
, komega
, kappa
, kphi
, gamma
, delta
]
89 let geometry
= Geometry K6c source positions Nothing
91 m
<- geometryDetectorRotationGet geometry detector
92 return (MyMatrix HklB m
)
94 readXRDCalibrationEntry
:: Detector a
-> XRDCalibrationEntry
-> IO (NptExt a
)
95 readXRDCalibrationEntry d e
=
96 withH5File f
$ \h5file
-> do
97 m
<- getM h5file p idx
98 npt
<- nptFromFile
(xrdCalibrationEntryNptPath e
)
99 return (NptExt npt m d
)
101 idx
= xrdCalibrationEntryIdx e
102 (Nxs f _ p
) = xrdCalibrationEntryNxs e
104 -- | Poni Calibration
106 -- The minimized function is the quadratic difference of the
107 -- theoretical tth angle and for each pixel, the computed tth angle.
109 -- synonyme types use in order to improve the calibration performance
111 type NptEntry
' = (Double, [Vector
Double]) -- tth, detector pixels coordinates
112 type Npt
' = (Double, [NptEntry
']) -- wavelength, [NptEntry']
113 type NptExt
' a
= (Npt
', Matrix
Double, Detector a
)
115 poniEntryFromList
:: PoniEntry
-> [Double] -> PoniEntry
116 poniEntryFromList p
[rot1
, rot2
, rot3
, poni1
, poni2
, d
] =
117 p
{ poniEntryDistance
= d
*~ meter
118 , poniEntryPoni1
= poni1
*~ meter
119 , poniEntryPoni2
= poni2
*~ meter
120 , poniEntryRot1
= rot1
*~ radian
121 , poniEntryRot2
= rot2
*~ radian
122 , poniEntryRot3
= rot3
*~ radian
124 poniEntryFromList _ _
= error "Can not convert to a PoniEntry"
126 poniEntryToList
:: PoniEntry
-> [Double]
127 poniEntryToList p
= [ poniEntryRot1 p
/~ radian
128 , poniEntryRot2 p
/~ radian
129 , poniEntryRot3 p
/~ radian
130 , poniEntryPoni1 p
/~ meter
131 , poniEntryPoni2 p
/~ meter
132 , poniEntryDistance p
/~ meter
135 calibrate
:: XRDCalibration
-> PoniExt
-> Detector a
-> IO PoniExt
136 calibrate c
(PoniExt p _
) d
= do
138 let guess
= fromList
$ poniEntryToList entry
139 -- read all the NptExt
140 npts
<- mapM (readXRDCalibrationEntry d
) (xrdCalibrationEntries c
)
141 -- in order to improve computation speed, pre-compute the pixel coodinates.
143 let (solution
, _p
) = minimizeV NMSimplex2
1E-16 3000 box
(f
(preCalibrate npts
)) guess
144 -- mplot $ drop 3 (toColumns p)
146 return $ PoniExt
[poniEntryFromList entry
(toList solution
)] (MyMatrix HklB
(ident
3))
148 preCalibrate
''' :: Detector a
-> NptEntry
-> NptEntry
'
149 preCalibrate
''' detector
(NptEntry _ tth _ points
) = (tth
/~ radian
, map (coordinates detector
) points
)
151 preCalibrate
'' :: Npt
-> Detector a
-> Npt
'
152 preCalibrate
'' n detector
= (nptWavelength n
/~ meter
, map (preCalibrate
''' detector
) (nptEntries n
))
154 preCalibrate
' :: NptExt a
-> NptExt
' a
155 preCalibrate
' (NptExt n m detector
) = (preCalibrate
'' n detector
, m
', detector
)
157 (MyMatrix _ m
') = changeBase m PyFAIB
159 preCalibrate
:: [NptExt a
] -> [NptExt
' a
]
160 preCalibrate
= map preCalibrate
'
163 box
= fromList
[0.1, 0.1, 0.1, 0.01, 0.01, 0.01]
165 f
:: [NptExt
' a
] -> Vector
Double -> Double
166 f ns params
= foldl' (f
' rotation translation
) 0 ns
168 rot1
= params `atIndex`
0
169 rot2
= params `atIndex`
1
170 rot3
= params `atIndex`
2
172 rotations
= map (uncurry fromAxisAndAngle
)
173 [ (fromList
[0, 0, 1], rot3
*~ radian
)
174 , (fromList
[0, 1, 0], rot2
*~ radian
)
175 , (fromList
[1, 0, 0], rot1
*~ radian
)]
177 rotation
= foldl' (<>) (ident
3) rotations
179 translation
:: Vector
Double
180 translation
= slice
3 3 params
182 f
' :: Matrix
Double -> Vector
Double -> Double -> NptExt
' a
-> Double
183 f
' rotation translation x
((_wavelength
, entries
), m
, _detector
) =
184 foldl' (f
'' translation r
) x entries
189 f
'' :: Vector
Double -> Matrix
Double -> Double -> NptEntry
'-> Double
191 f
'' translation r x
(tth
, pixels
) = foldl' (f
''' translation r tth
) x pixels
193 f
''' :: Vector
Double -> Matrix
Double -> Double -> Double -> Vector
Double -> Double
195 f
''' translation r tth x pixel
= x
+ dtth
* dtth
197 kf
= r
#> (pixel
- translation
)
202 dtth
= tth
- atan2 (sqrt (x
'*x
' + y
'*y
')) (-z
')