Startup
This commit is contained in:
BIN
config/.DS_Store
vendored
BIN
config/.DS_Store
vendored
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
#Tue Nov 06 14:31:07 CET 2018
|
||||
#Wed Mar 20 13:51:54 CET 2019
|
||||
autoSaveScanData=true
|
||||
commandExecutionEvents=false
|
||||
createSessionFiles=true
|
||||
createSessionFiles=false
|
||||
dataLayout=default
|
||||
dataPath={data}/{year}_{month}/{date}/{date}_{time}_{name}
|
||||
dataProvider=h5
|
||||
@@ -11,6 +11,7 @@ dataScanReleaseRecords=false
|
||||
dataServerPort=5573
|
||||
depthDimension=0
|
||||
generateCommandExecutionEvents=true
|
||||
hideServerMessages=false
|
||||
hostName=
|
||||
instanceName=Dev
|
||||
logDaysToLive=50
|
||||
@@ -18,8 +19,9 @@ logLevel=Fine
|
||||
logLevelConsole=Off
|
||||
logPath={logs}/{date}_{time}
|
||||
notificationLevel=Off
|
||||
saveCommandStatistics=true
|
||||
scanStreamerPort=5563
|
||||
serverEnabled=false
|
||||
serverEnabled=true
|
||||
serverPort=8080
|
||||
simulation=false
|
||||
terminalEnabled=false
|
||||
@@ -28,5 +30,5 @@ userAuthenticator=ch.psi.pshell.security.LdapAuthenticator | ldap\://d.psi.ch |
|
||||
userManagement=true
|
||||
versionTrackingEnabled=true
|
||||
versionTrackingLogin={context}/svcusr-hlapp_robot
|
||||
versionTrackingManual=true
|
||||
versionTrackingManual=false
|
||||
versionTrackingRemote=git@git.psi.ch\:pshell_config/dev.git
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dispatcher=ch.psi.pshell.bs.Provider|tcp://localhost:9999|||
|
||||
cam_server_local=ch.psi.pshell.bs.PipelineServer|localhost:8889|||true
|
||||
cam_server=ch.psi.pshell.bs.PipelineServer|sf-daqsync-01:8889|||true
|
||||
#cam_server_local=ch.psi.pshell.bs.PipelineServer|localhost:8889|||true
|
||||
cam_server=ch.psi.pshell.bs.PipelineServer|localhost:8889|||true
|
||||
#ts1=ch.psi.pshell.epics.GenericArray|TESTIOC:TESTWF2:MyWF|||
|
||||
#monit_cam=ch.psi.pshell.imaging.MjpegSource|http://axis-accc8e9cc87b.psi.ch/axis-cgi/mjpg/video.cgi?camera=2 reopen||-200|false
|
||||
#tststr=ch.psi.pshell.epics.ChannelString|TESTIOC:TESTSINUS:SinCalc|||
|
||||
@@ -69,7 +69,7 @@ pv=ch.psi.pshell.epics.ProcessVariable|TESTIOC:TESTCALCOUT:Input|||true
|
||||
shutter=ch.psi.pshell.epics.BinaryPositioner|TESTIOC:TESTBO:MyBO TESTIOC:TESTBO:MyBO|||true
|
||||
$motor=ch.psi.pshell.epics.Motor|MTEST-GOBBO:MOT1|||true
|
||||
$motor2=ch.psi.pshell.epics.Motor|MTEST-GOBBO:MOT2|||true
|
||||
table=ch.psi.pshell.device.MotorGroupBase|motor motor2|||
|
||||
table=ch.psi.pshell.device.MotorGroupBase|motor motor2|||true
|
||||
$manip=ch.psi.pshell.epics.Manipulator||||
|
||||
tab=ch.psi.pshell.device.MotorGroupDiscretePositioner|table|||
|
||||
#tab2=ch.psi.pshell.device.MotorGroupDiscretePositioner|table|||
|
||||
|
||||
38
config/diffcalc/test1.json
Normal file
38
config/diffcalc/test1.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "test1",
|
||||
"crystal": "['cubic', 'Triclinic', 7.723, 7.707, 7.723, 90.0, 89.265, 90.0]",
|
||||
"reflist": {
|
||||
"1": {
|
||||
"tag": null,
|
||||
"hkl": "[0.0, 1.0, 2.0]",
|
||||
"pos": "[5.0, 9.379, 19.7895, 102.6162, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-26T18:02:19.132000"
|
||||
},
|
||||
"2": {
|
||||
"tag": null,
|
||||
"hkl": "[2.0, 0.0, 2.0]",
|
||||
"pos": "[5.0, 19.0754, 20.1865, 11.9693, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-26T18:02:19.148000"
|
||||
},
|
||||
"3": {
|
||||
"tag": null,
|
||||
"hkl": "[2.0, 2.0, 2.0]",
|
||||
"pos": "[5.0, 27.1234, 21.2368, 60.0354, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-26T18:02:19.213000"
|
||||
}
|
||||
},
|
||||
"orientlist": {},
|
||||
"tau": 0,
|
||||
"sigma": 0,
|
||||
"reference": {
|
||||
"n_hkl_configured": null,
|
||||
"n_phi_configured": "[0.0, 0.0, 1.0]"
|
||||
},
|
||||
"u": null,
|
||||
"ub": null,
|
||||
"or0": null,
|
||||
"or1": null
|
||||
}
|
||||
38
config/diffcalc/test2.json
Normal file
38
config/diffcalc/test2.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "test2",
|
||||
"crystal": "['cubic', 'Triclinic', 7.723, 7.707, 7.723, 90.0, 89.265, 90.0]",
|
||||
"reflist": {
|
||||
"1": {
|
||||
"tag": "None",
|
||||
"hkl": "[0.0, 1.0, 2.0]",
|
||||
"pos": "[5.0, 9.379, 19.7895, 102.6162, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-15T11:11:34.710000"
|
||||
},
|
||||
"2": {
|
||||
"tag": "None",
|
||||
"hkl": "[2.0, 0.0, 2.0]",
|
||||
"pos": "[5.0, 19.0754, 20.1865, 11.9693, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-15T11:11:34.772000"
|
||||
},
|
||||
"3": {
|
||||
"tag": "None",
|
||||
"hkl": "[2.0, 2.0, 2.0]",
|
||||
"pos": "[5.0, 27.1234, 21.2368, 60.0354, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-15T11:11:34.864000"
|
||||
}
|
||||
},
|
||||
"orientlist": {},
|
||||
"tau": 0,
|
||||
"sigma": 0,
|
||||
"reference": {
|
||||
"n_hkl_configured": null,
|
||||
"n_phi_configured": "[0.0, 0.0, 1.0]"
|
||||
},
|
||||
"u": null,
|
||||
"ub": null,
|
||||
"or0": null,
|
||||
"or1": null
|
||||
}
|
||||
38
config/diffcalc/x.json
Normal file
38
config/diffcalc/x.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "x",
|
||||
"crystal": "['cubic', 'Triclinic', 7.723, 7.707, 7.723, 90.0, 89.265, 90.0]",
|
||||
"reflist": {
|
||||
"1": {
|
||||
"tag": "None",
|
||||
"hkl": "[0.0, 1.0, 2.0]",
|
||||
"pos": "[5.0, 9.379, 19.7895, 102.6162, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-15T10:46:33.012000"
|
||||
},
|
||||
"2": {
|
||||
"tag": "None",
|
||||
"hkl": "[2.0, 0.0, 2.0]",
|
||||
"pos": "[5.0, 19.0754, 20.1865, 11.9693, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-15T10:46:33.094000"
|
||||
},
|
||||
"3": {
|
||||
"tag": "None",
|
||||
"hkl": "[2.0, 2.0, 2.0]",
|
||||
"pos": "[5.0, 27.1234, 21.2368, 60.0354, 0, 0]",
|
||||
"energy": 9.5,
|
||||
"time": "2019-02-15T10:46:33.292000"
|
||||
}
|
||||
},
|
||||
"orientlist": {},
|
||||
"tau": 0,
|
||||
"sigma": 0,
|
||||
"reference": {
|
||||
"n_hkl_configured": null,
|
||||
"n_phi_configured": "[0.0, 0.0, 1.0]"
|
||||
},
|
||||
"u": null,
|
||||
"ub": null,
|
||||
"or0": null,
|
||||
"or1": null
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#Fri Nov 16 23:08:57 CET 2018
|
||||
ch.psi.jcae.ContextFactory.addressList=127.0.0.1\:54321
|
||||
#Mon Feb 25 08:48:20 CET 2019
|
||||
ch.psi.jcae.ContextFactory.addressList=127.0.0.1\:54321 129.129.144.112
|
||||
ch.psi.jcae.ContextFactory.maxArrayBytes=10000000
|
||||
ch.psi.jcae.ChannelFactory.timeout=200
|
||||
ch.psi.jcae.ChannelFactory.retries=1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
PID.java=enabled
|
||||
MiniPID.java=enabled
|
||||
SpinnerLayoutTest.java=disabled
|
||||
MXSC-1.10.0.jar=disabled
|
||||
ScreenPanel3.java=disabled
|
||||
|
||||
3
config/settings.properties
Normal file
3
config/settings.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
#Tue Feb 26 18:02:18 CET 2019
|
||||
geometry=fourcv
|
||||
test=1
|
||||
@@ -1,21 +1,21 @@
|
||||
#Wed Jan 10 09:07:30 CET 2018
|
||||
configFile={config}/config.properties
|
||||
configFileDevices={config}/devices.properties
|
||||
configFileImageSources={config}/imaging.properties
|
||||
configFilePlugins={config}/plugins.properties
|
||||
configFileTasks={config}/tasks.properties
|
||||
configFileUpdateStrategy={config}/update.properties
|
||||
configPath={home}/config
|
||||
contextPath={outp}/context
|
||||
dataPath={outp}/data
|
||||
devicesPath={home}/devices
|
||||
extensionsPath={home}/extensions
|
||||
imagesPath={outp}/images
|
||||
libraryPath={script}; {script}/Lib; src/main/assembly/script/tutorial
|
||||
#libraryPath={extensions}/JyNI.jar;{extensions};/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload;/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7;/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages;{script}; {script}/Lib; src/main/assembly/script/tutorial
|
||||
logPath={outp}/log
|
||||
pluginsPath={home}/plugins
|
||||
scriptPath={home}/script
|
||||
scriptType=py
|
||||
sessionsPath={outp}/sessions
|
||||
wwwPath={home}/www
|
||||
#Mon Dec 17 16:37:23 CET 2018
|
||||
configFile={config}/config.properties
|
||||
configFileDevices={config}/devices.properties
|
||||
configFileImageSources={config}/imaging.properties
|
||||
configFilePlugins={config}/plugins.properties
|
||||
configFileSettings={config}/settings.properties
|
||||
configFileTasks={config}/tasks.properties
|
||||
configFileUpdateStrategy={config}/update.properties
|
||||
configPath={home}/config
|
||||
contextPath={outp}/context
|
||||
dataPath={outp}/data
|
||||
devicesPath={home}/devices
|
||||
extensionsPath={home}/extensions
|
||||
imagesPath={outp}/images
|
||||
libraryPath={script}; {script}/Lib; src/main/assembly/script/tutorial
|
||||
logPath={outp}/log
|
||||
pluginsPath={home}/plugins
|
||||
scriptPath={home}/script
|
||||
scriptType=py
|
||||
sessionsPath={outp}/sessions
|
||||
wwwPath={home}/www
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
#Wed Oct 25 11:29:41 CEST 2017
|
||||
colormap=Grayscale
|
||||
colormapAutomatic=false
|
||||
colormapMax=NaN
|
||||
colormapMin=NaN
|
||||
flipHorizontally=false
|
||||
flipVertically=false
|
||||
grayscale=false
|
||||
invert=false
|
||||
rescaleFactor=1.0
|
||||
rescaleOffset=0.0
|
||||
roiHeight=-1
|
||||
roiWidth=-1
|
||||
roiX=0
|
||||
roiY=0
|
||||
rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
spatialCalOffsetX=NaN
|
||||
spatialCalOffsetY=NaN
|
||||
spatialCalScaleX=NaN
|
||||
spatialCalScaleY=NaN
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
#Mon Mar 04 17:19:18 CET 2019
|
||||
colormap=Grayscale
|
||||
colormapAutomatic=false
|
||||
colormapLogarithmic=false
|
||||
colormapMax=NaN
|
||||
colormapMin=NaN
|
||||
flipHorizontally=false
|
||||
flipVertically=false
|
||||
grayscale=false
|
||||
invert=false
|
||||
rescaleFactor=1.0
|
||||
rescaleOffset=0.0
|
||||
roiHeight=-1
|
||||
roiWidth=-1
|
||||
roiX=0
|
||||
roiY=0
|
||||
rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
spatialCalOffsetX=NaN
|
||||
spatialCalOffsetY=NaN
|
||||
spatialCalScaleX=NaN
|
||||
spatialCalScaleY=NaN
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
#Mon Oct 23 11:55:12 CEST 2017
|
||||
colormap=Grayscale
|
||||
colormapAutomatic=false
|
||||
colormapMax=NaN
|
||||
colormapMin=NaN
|
||||
flipHorizontally=false
|
||||
flipVertically=false
|
||||
grayscale=false
|
||||
invert=false
|
||||
rescaleFactor=1.0
|
||||
rescaleOffset=0.0
|
||||
roiHeight=-1
|
||||
roiWidth=-1
|
||||
roiX=0
|
||||
roiY=0
|
||||
rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
serverURL=localhost\:8888
|
||||
spatialCalOffsetX=NaN
|
||||
spatialCalOffsetY=NaN
|
||||
spatialCalScaleX=NaN
|
||||
spatialCalScaleY=NaN
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
#Mon Mar 04 17:19:22 CET 2019
|
||||
colormap=Grayscale
|
||||
colormapAutomatic=false
|
||||
colormapLogarithmic=false
|
||||
colormapMax=NaN
|
||||
colormapMin=NaN
|
||||
flipHorizontally=false
|
||||
flipVertically=false
|
||||
grayscale=false
|
||||
invert=false
|
||||
rescaleFactor=1.0
|
||||
rescaleOffset=0.0
|
||||
roiHeight=-1
|
||||
roiWidth=-1
|
||||
roiX=0
|
||||
roiY=0
|
||||
rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
serverURL=localhost\:8888
|
||||
spatialCalOffsetX=NaN
|
||||
spatialCalOffsetY=NaN
|
||||
spatialCalScaleX=NaN
|
||||
spatialCalScaleY=NaN
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#Thu Aug 09 15:37:16 CEST 2018
|
||||
colormap=Flame
|
||||
#Wed Mar 20 10:49:26 CET 2019
|
||||
colormap=Temperature
|
||||
colormapAutomatic=true
|
||||
colormapLogarithmic=false
|
||||
colormapMax=25300.0
|
||||
colormapMin=0.0
|
||||
colormapMax=10000.0
|
||||
colormapMin=100.0
|
||||
custom=12345
|
||||
flipHorizontally=false
|
||||
flipVertically=false
|
||||
@@ -23,9 +23,9 @@ rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
serverURL=http\://gfa-lc6-64\:8889
|
||||
spatialCalOffsetX=-131.47810112809645
|
||||
spatialCalOffsetY=-114.68674851532894
|
||||
spatialCalScaleX=-26.95417819057938
|
||||
spatialCalScaleY=-35.84229324524661
|
||||
spatialCalOffsetX=-637.4980411378614
|
||||
spatialCalOffsetY=-483.5036425564949
|
||||
spatialCalScaleX=-35.21126887460907
|
||||
spatialCalScaleY=-48.38709552593848
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#Tue May 15 17:44:18 CEST 2018
|
||||
#Tue Mar 05 11:53:08 CET 2019
|
||||
colormap=Flame
|
||||
colormapAutomatic=true
|
||||
colormapLogarithmic=false
|
||||
colormapMax=50660.0
|
||||
colormapMin=0.0
|
||||
flipHorizontally=false
|
||||
@@ -16,9 +17,9 @@ roiY=0
|
||||
rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
spatialCalOffsetX=0.0
|
||||
spatialCalOffsetY=0.0
|
||||
spatialCalScaleX=1.0
|
||||
spatialCalScaleY=1.0
|
||||
spatialCalOffsetX=-637.4980411378614
|
||||
spatialCalOffsetY=-483.5036425564949
|
||||
spatialCalScaleX=-35.21126887460907
|
||||
spatialCalScaleY=-48.38709552593848
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
|
||||
17
devices/WireScanner motor.properties
Normal file
17
devices/WireScanner motor.properties
Normal file
@@ -0,0 +1,17 @@
|
||||
#Mon Feb 25 15:03:11 CET 2019
|
||||
defaultSpeed=282.842712474619
|
||||
estbilizationDelay=0
|
||||
hasEnable=false
|
||||
homingType=None
|
||||
maxSpeed=10000.0
|
||||
maxValue=51500.0
|
||||
minSpeed=NaN
|
||||
minValue=-56789.2
|
||||
offset=0.0
|
||||
precision=1
|
||||
resolution=0.5
|
||||
rotation=false
|
||||
scale=1.0
|
||||
sign_bit=0
|
||||
startRetries=1
|
||||
unit=mm
|
||||
@@ -1,4 +1,4 @@
|
||||
#Tue Oct 30 09:23:19 CET 2018
|
||||
#Thu Feb 21 09:17:18 CET 2019
|
||||
colormap=Grayscale
|
||||
colormapAutomatic=false
|
||||
colormapLogarithmic=false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#Thu Aug 09 15:41:34 CEST 2018
|
||||
#Mon Jan 21 11:07:44 CET 2019
|
||||
colormap=Temperature
|
||||
colormapAutomatic=true
|
||||
colormapLogarithmic=false
|
||||
@@ -18,9 +18,9 @@ roiY=0
|
||||
rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
spatialCalOffsetX=-50.048875855327466
|
||||
spatialCalOffsetY=-50.048875855327466
|
||||
spatialCalScaleX=-1.0
|
||||
spatialCalScaleY=-1.0
|
||||
spatialCalOffsetX=0.0
|
||||
spatialCalOffsetY=0.0
|
||||
spatialCalScaleX=1.0
|
||||
spatialCalScaleY=1.0
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Thu Aug 09 15:38:40 CEST 2018
|
||||
colormap=Grayscale
|
||||
colormapAutomatic=false
|
||||
#Fri Dec 14 13:50:04 CET 2018
|
||||
colormap=Temperature
|
||||
colormapAutomatic=true
|
||||
colormapLogarithmic=false
|
||||
colormapMax=NaN
|
||||
colormapMin=NaN
|
||||
@@ -17,9 +17,9 @@ roiY=0
|
||||
rotation=0.0
|
||||
rotationCrop=false
|
||||
scale=1.0
|
||||
spatialCalOffsetX=NaN
|
||||
spatialCalOffsetY=NaN
|
||||
spatialCalScaleX=NaN
|
||||
spatialCalScaleY=NaN
|
||||
spatialCalOffsetX=-634.4956973840979
|
||||
spatialCalOffsetY=-509.5307480984911
|
||||
spatialCalScaleX=-26.954178679632527
|
||||
spatialCalScaleY=-35.8422927936001
|
||||
spatialCalUnits=mm
|
||||
transpose=false
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#Fri Aug 24 11:04:46 CEST 2018
|
||||
#Mon Feb 11 17:24:00 CET 2019
|
||||
defaultSpeed=50.0
|
||||
estbilizationDelay=0
|
||||
maxSpeed=50.0
|
||||
maxValue=360.0
|
||||
maxValue=190.0
|
||||
minSpeed=0.1
|
||||
minValue=-360.0
|
||||
minValue=-19.0
|
||||
offset=0.0
|
||||
precision=2
|
||||
resolution=NaN
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#Thu Sep 13 17:21:24 CEST 2018
|
||||
colormap=Grayscale
|
||||
#Thu Mar 14 16:06:34 CET 2019
|
||||
colormap=Flame
|
||||
colormapAutomatic=false
|
||||
colormapLogarithmic=false
|
||||
colormapMax=NaN
|
||||
colormapMin=NaN
|
||||
colormapMax=25000.0
|
||||
colormapMin=0.0
|
||||
flipHorizontally=false
|
||||
flipVertically=false
|
||||
grayscale=false
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#Fri Aug 24 11:04:56 CEST 2018
|
||||
#Mon Feb 11 17:20:20 CET 2019
|
||||
defaultSpeed=50.0
|
||||
estbilizationDelay=0
|
||||
maxSpeed=50.0
|
||||
maxValue=360.0
|
||||
maxValue=189.0
|
||||
minSpeed=0.1
|
||||
minValue=-360.0
|
||||
minValue=-190.0
|
||||
offset=0.0
|
||||
precision=2
|
||||
resolution=NaN
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#Fri Aug 24 11:49:29 CEST 2018
|
||||
#Mon Feb 11 17:19:49 CET 2019
|
||||
defaultSpeed=50.0
|
||||
estbilizationDelay=0
|
||||
maxSpeed=50.0
|
||||
maxValue=180.0
|
||||
maxValue=164.0
|
||||
minSpeed=0.1
|
||||
minValue=-180.0
|
||||
minValue=-61.0
|
||||
offset=0.0
|
||||
precision=2
|
||||
resolution=NaN
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#Fri Aug 24 11:05:25 CEST 2018
|
||||
#Mon Feb 11 17:18:43 CET 2019
|
||||
defaultSpeed=50.0
|
||||
estbilizationDelay=0
|
||||
maxSpeed=50.0
|
||||
maxValue=360.0
|
||||
maxValue=116.0
|
||||
minSpeed=0.1
|
||||
minValue=-360.0
|
||||
minValue=-13.0
|
||||
offset=0.0
|
||||
precision=2
|
||||
resolution=NaN
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#Mon Aug 06 10:26:59 CEST 2018
|
||||
#Fri Mar 15 07:43:23 CET 2019
|
||||
calOffsetX=NaN
|
||||
calOffsetY=NaN
|
||||
calScaleX=NaN
|
||||
calScaleY=NaN
|
||||
colormap=Temperature
|
||||
colormapAutomatic=true
|
||||
colormapAutomatic=false
|
||||
colormapLogarithmic=false
|
||||
colormapMax=255.0
|
||||
colormapMin=0.0
|
||||
colormapMax=NaN
|
||||
colormapMin=NaN
|
||||
dataMonitoring=false
|
||||
dataPolling=100
|
||||
flipHorizontally=true
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//package com.stormbots;
|
||||
/**
|
||||
* Small, easy to use PID implementation with advanced controller capability.<br>
|
||||
* Minimal usage:<br>
|
||||
@@ -8,7 +9,7 @@
|
||||
*
|
||||
* @see http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-direction/improving-the-beginners-pid-introduction
|
||||
*/
|
||||
public class PID{
|
||||
public class MiniPID{
|
||||
//**********************************
|
||||
// Class private variables
|
||||
//**********************************
|
||||
@@ -50,7 +51,7 @@ public class PID{
|
||||
* @param i Integral gain. Becomes large if setpoint cannot reach target quickly.
|
||||
* @param d Derivative gain. Responds quickly to large changes in error. Small values prevents P and I terms from causing overshoot.
|
||||
*/
|
||||
public PID(double p, double i, double d){
|
||||
public MiniPID(double p, double i, double d){
|
||||
P=p; I=i; D=d;
|
||||
checkSigns();
|
||||
}
|
||||
@@ -63,7 +64,7 @@ public class PID{
|
||||
* @param d Derivative gain. Responds quickly to large changes in error. Small values prevents P and I terms from causing overshoot.
|
||||
* @param f Feed-forward gain. Open loop "best guess" for the output should be. Only useful if setpoint represents a rate.
|
||||
*/
|
||||
public PID(double p, double i, double d, double f){
|
||||
public MiniPID(double p, double i, double d, double f){
|
||||
P=p; I=i; D=d; F=f;
|
||||
checkSigns();
|
||||
}
|
||||
@@ -1053,6 +1053,21 @@
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonReticleActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToggleButton" name="buttonScale">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="getIcon("Scale")" type="code"/>
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" value=" "/>
|
||||
<Property name="toolTipText" type="java.lang.String" value="Show Colormap Scale"/>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="0"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonScaleActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToggleButton" name="buttonTitle">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
|
||||
@@ -523,6 +523,7 @@ public class ScreenPanel3 extends Panel {
|
||||
}
|
||||
});
|
||||
renderer.getPopupMenu().setVisible(false);
|
||||
buttonScale.setSelected(renderer.getShowColormapScale());
|
||||
clearMarker();
|
||||
|
||||
showFit = buttonFit.isSelected();
|
||||
@@ -1000,7 +1001,12 @@ public class ScreenPanel3 extends Panel {
|
||||
imageBuffer.add(currentFrame);
|
||||
if (imageBuffer.size() > imageBufferLenght) {
|
||||
imageBuffer.remove(0);
|
||||
setBufferFull(true);
|
||||
} else {
|
||||
setBufferFull(false);
|
||||
}
|
||||
} else {
|
||||
setBufferFull(true);
|
||||
}
|
||||
//Update data
|
||||
if (!renderer.isPaused()) {
|
||||
@@ -1108,16 +1114,24 @@ public class ScreenPanel3 extends Panel {
|
||||
|
||||
@Override
|
||||
public void onImage(Object o, BufferedImage bi, Data data) {
|
||||
if (continuous) {
|
||||
buffer.add(data);
|
||||
if (buffer.size() >= numImages) {
|
||||
for (Data d : buffer) {
|
||||
process(d);
|
||||
try{
|
||||
if (continuous) {
|
||||
buffer.add(data);
|
||||
if (buffer.size() >= numImages) {
|
||||
for (Data d : buffer) {
|
||||
process(d);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buffer.add(null); //Just to count
|
||||
process(data);
|
||||
}
|
||||
} else {
|
||||
buffer.add(null); //Just to count
|
||||
process(data);
|
||||
} catch (Exception ex){
|
||||
buffer.clear();
|
||||
integration = null;
|
||||
ImageIntegrator.this.pushData(null);
|
||||
ex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
if (buffer.size() >= numImages) {
|
||||
if (continuous) {
|
||||
@@ -1148,6 +1162,17 @@ public class ScreenPanel3 extends Panel {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
boolean bufferFull = true;
|
||||
|
||||
void setBufferFull(boolean value){
|
||||
if (value != bufferFull){
|
||||
SwingUtilities.invokeLater(()->{
|
||||
buttonPause.setBackground(value ? buttonSave.getBackground() : buttonSave.getBackground().brighter());
|
||||
});
|
||||
bufferFull = value;
|
||||
}
|
||||
}
|
||||
|
||||
volatile Dimension imageSize;
|
||||
|
||||
@@ -1163,6 +1188,7 @@ public class ScreenPanel3 extends Panel {
|
||||
renderer.refresh();
|
||||
}
|
||||
|
||||
|
||||
void checkMarker(Point p) throws IOException {
|
||||
if (camera != null) {
|
||||
if (buttonMarker.isSelected()) {
|
||||
@@ -1477,7 +1503,7 @@ public class ScreenPanel3 extends Panel {
|
||||
updateColormap();
|
||||
updateButtons();
|
||||
checkHistogram.setSelected((histogramDialog != null) && (histogramDialog.isShowing()));
|
||||
|
||||
buttonScale.setSelected(renderer.getShowColormapScale());
|
||||
try{
|
||||
Frame frame = getCurrentFrame();
|
||||
if (frame!=lastFrame){
|
||||
@@ -2652,6 +2678,7 @@ public class ScreenPanel3 extends Panel {
|
||||
buttonProfile = new javax.swing.JToggleButton();
|
||||
buttonFit = new javax.swing.JToggleButton();
|
||||
buttonReticle = new javax.swing.JToggleButton();
|
||||
buttonScale = new javax.swing.JToggleButton();
|
||||
buttonTitle = new javax.swing.JToggleButton();
|
||||
pauseSelection = new ch.psi.pshell.swing.ValueSelection();
|
||||
panelCameraSelection = new javax.swing.JPanel();
|
||||
@@ -3335,6 +3362,19 @@ public class ScreenPanel3 extends Panel {
|
||||
});
|
||||
toolBar.add(buttonReticle);
|
||||
|
||||
buttonScale.setIcon(getIcon("Scale"));
|
||||
buttonScale.setSelected(true);
|
||||
buttonScale.setText(" ");
|
||||
buttonScale.setToolTipText("Show Colormap Scale");
|
||||
buttonScale.setFocusable(false);
|
||||
buttonScale.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
buttonScale.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
buttonScaleActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
toolBar.add(buttonScale);
|
||||
|
||||
buttonTitle.setIcon(getIcon("Title"));
|
||||
buttonTitle.setSelected(true);
|
||||
buttonTitle.setText(" ");
|
||||
@@ -3963,6 +4003,14 @@ public class ScreenPanel3 extends Panel {
|
||||
}
|
||||
}//GEN-LAST:event_buttonTitleActionPerformed
|
||||
|
||||
private void buttonScaleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonScaleActionPerformed
|
||||
try {
|
||||
renderer.setShowColormapScale(buttonScale.isSelected());
|
||||
} catch (Exception ex) {
|
||||
showException(ex);
|
||||
}
|
||||
}//GEN-LAST:event_buttonScaleActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton btFixColormapRange;
|
||||
private javax.swing.JRadioButton buttonAutomatic;
|
||||
@@ -3980,6 +4028,7 @@ public class ScreenPanel3 extends Panel {
|
||||
private javax.swing.JToggleButton buttonProfile;
|
||||
private javax.swing.JToggleButton buttonReticle;
|
||||
private javax.swing.JToggleButton buttonSave;
|
||||
private javax.swing.JToggleButton buttonScale;
|
||||
private javax.swing.JRadioButton buttonServer;
|
||||
private javax.swing.JToggleButton buttonSidePanel;
|
||||
private javax.swing.JButton buttonStreamData;
|
||||
|
||||
4067
plugins/ScreenPanel3New.java
Normal file
4067
plugins/ScreenPanel3New.java
Normal file
File diff suppressed because it is too large
Load Diff
1164
plugins/ScreenPanel3OLD.form
Normal file
1164
plugins/ScreenPanel3OLD.form
Normal file
File diff suppressed because it is too large
Load Diff
3934
plugins/ScreenPanel3OLD.java
Normal file
3934
plugins/ScreenPanel3OLD.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -109,7 +109,7 @@
|
||||
<Component class="javax.swing.JSpinner" name="spinnerSteps">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
<SpinnerModel initial="0" maximum="100" minimum="0" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
<SpinnerModel initial="10" maximum="100" minimum="0" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
@@ -63,7 +63,7 @@ public class TestScan extends Panel {
|
||||
jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
|
||||
jLabel3.setText("Steps:");
|
||||
|
||||
spinnerSteps.setModel(new javax.swing.SpinnerNumberModel(0, 0, 100, 1));
|
||||
spinnerSteps.setModel(new javax.swing.SpinnerNumberModel(10, 0, 100, 1));
|
||||
|
||||
buttonStart.setText("Start");
|
||||
buttonStart.addActionListener(new java.awt.event.ActionListener() {
|
||||
@@ -149,9 +149,14 @@ public class TestScan extends Panel {
|
||||
pars.add(spinnerStart.getValue());
|
||||
pars.add(spinnerEnd.getValue());
|
||||
pars.add(spinnerSteps.getValue());
|
||||
runAsync("TestScan", pars);
|
||||
runAsync("test/TestScan", pars).handle((ret, ex)->{
|
||||
if (ex != null){
|
||||
showException((Exception)ex);
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(TestScan.class.getName()).log(Level.SEVERE, null, ex);
|
||||
showException((Exception)ex);
|
||||
}
|
||||
}//GEN-LAST:event_buttonStartActionPerformed
|
||||
|
||||
|
||||
28
plugins/a.form
Normal file
28
plugins/a.form
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="449" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="137" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
</Form>
|
||||
52
plugins/a.java
Normal file
52
plugins/a.java
Normal file
@@ -0,0 +1,52 @@
|
||||
import ch.psi.pshell.ui.Panel;
|
||||
import ch.psi.utils.State;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class a extends Panel {
|
||||
|
||||
public a() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
//Overridable callbacks
|
||||
@Override
|
||||
public void onInitialize(int runCount) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateChange(State state, State former) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecutedFile(String fileName, Object result) {
|
||||
}
|
||||
|
||||
|
||||
//Callback to perform update - in event thread
|
||||
@Override
|
||||
protected void doUpdate() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 449, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 137, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
188
script/2019_0227_023309_XAS_Fe_b.xml
Normal file
188
script/2019_0227_023309_XAS_Fe_b.xml
Normal file
@@ -0,0 +1,188 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<configuration xmlns="http://www.psi.ch/~ebner/models/scan/1.0" numberOfExecution="1" failOnSensorError="true">
|
||||
<data format="txt" fileName="XAS_Fe_b"/>
|
||||
<variable name="K" value="0.0" description="Buffer K spacing for EXAFS k-spacing scans "/>
|
||||
<variable name="N_cycles" value="0.0" description="Buffer N_cycles for EXAFS k-spacing scans "/>
|
||||
<variable name="NINT" value="0.0" description="Counter for file number of Moche files"/>
|
||||
<scan>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/settings/Scripts/GUI_X07MB/X_X07MB_fda_file_to_EPICS.sh ${FILENAME}" checkExitValue="false"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/settings/Scripts/GUI_X07MB/X_X07MB_fda_write_header.py &" checkExitValue="false"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:START-CSMPL" value="0" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:StopAll" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:CollectMode" value="0" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:Apply" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:PresetReal" value="0" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="2" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:SMPL" value="1" operation="put" type="String" delay="0.7"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP-WV1:WT_SET" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<dimension zigzag="false" dataGroup="false">
|
||||
<positioner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="RegionPositioner" name="X07MB-OP-MO:E-SET" readback="X07MB-OP-MO:E-GET" settlingTime="0.2" id="Energy">
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="20"/>
|
||||
<start>7000.0</start>
|
||||
<end>7001.0</end>
|
||||
<stepSize>1.0</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="5"/>
|
||||
<start>7003.0</start>
|
||||
<end>7100.0</end>
|
||||
<stepSize>3.0</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="15"/>
|
||||
<start>7103.0</start>
|
||||
<end>7160.0</end>
|
||||
<stepSize>0.3</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="15"/>
|
||||
<start>7160.5</start>
|
||||
<end>7200.0</end>
|
||||
<stepSize>0.5</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="15.0"/>
|
||||
<start>4.80379024078</start>
|
||||
<end>10.0</end>
|
||||
<stepSize>0.05</stepSize>
|
||||
<function>
|
||||
<mapping xsi:type="VariableParameterMapping" name="K" variable="K_v"/>
|
||||
<mapping xsi:type="ChannelParameterMapping" channel="X07MB-OP2:TOTAL-CYCLES" type="Double" variable="N_Cycles"/>
|
||||
<script>
|
||||
def calculate(parameter):
|
||||
nc=N_Cycles.getValue()
|
||||
nc=nc*1.02
|
||||
N_Cycles.setValue(nc)
|
||||
E_0=7112.0
|
||||
h=6.626e-34
|
||||
m=9.109e-31
|
||||
k=parameter*1e10
|
||||
K_v=k*1e-10
|
||||
hk=(h/(2.*3.1415926))*k
|
||||
E_joule=hk*hk / (2.*m)
|
||||
E_eV=E_joule/1.6021e-19+E_0
|
||||
return E_eV
|
||||
</script>
|
||||
</function>
|
||||
</region>
|
||||
</positioner>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:EraseStart" value="1" operation="putq" type="String" delay="0.075"/>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:SMPL" value="1" operation="put" type="String" delay="0.075"/>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:SMPL-DONE" value="1" operation="wait" type="Integer" delay="0.03"/>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:StopAll" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<guard>
|
||||
<condition channel="ACOAU-ACCU:OP-MODE" value="6" type="Integer"/>
|
||||
</guard>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-ES3-MA1:TRSCANH.VAL" id="ScanX_set"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-ES3-MA1:TRSCANV.VAL" id="ScanY_set"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-MO:E-SET" id="Energy_set"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-MO:BEAM-OFS" id="Mono_offset"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="ARIDI-PCT:CURRENT" id="I_SLS"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP2-SAI_04:MEAN" id="diode"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP2-SAI_07:MEAN" id="I0_KEITHLEY1"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-KEITH1:setGain" id="KEITHLEY1_GAIN"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP2-SAI_08:MEAN" id="I1_KEITHLEY2"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-KEITH2:setGain" id="KEITHLEY2_GAIN"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.R0" id="D2_FeKa"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:dxp2:SCA0Counts" id="D2_FeKa_dxp"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:dxp2:InputCountRate" id="D2_ICR"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:dxp2:OutputCountRate" id="D2_OCR"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.ELTM" id="DD2_ELTM"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.ERTM" id="DD2_ERTM"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.DTIM" id="DD2_DTIM"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ArrayDetector" arraySize="2048" name="X07MB-XMAP:mca2.VAL" id="Spec_2"/>
|
||||
</dimension>
|
||||
<dimension>
|
||||
<positioner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ArrayPositioner" name="X07MB-ES3-MA1:TRSCANH.VAL" readback="X07MB-ES3-MA1:TRSCANH.RBV" id="ScanX">
|
||||
<positions> -2.25</positions>
|
||||
</positioner>
|
||||
<positioner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ArrayPositioner" name="X07MB-ES3-MA1:TRSCANV.VAL" readback="X07MB-ES3-MA1:TRSCANV.RBV" id="ScanY">
|
||||
<positions> 1.0</positions>
|
||||
</positioner>
|
||||
</dimension>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:START-CSMPL" value="1" operation="put" type="String" delay="0.1"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/settings/Scripts/GUI_X07MB/X_X07MB_write_filename_to_file.sh ${FILENAME} &" exitValue="0"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/x07mbop/Data1/Commissioning/Develop/Develop_Moench/X_X07MB_reset_Moench.py &" exitValue="0"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:START-CSMPL" value="1" operation="put" type="String" delay="0.1"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP-WV1:WT_SET" value="0" operation="put" type="String" delay="0.1"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-ES1:userCalc4.INPL" value="0" operation="put" type="String" delay="2.0"/>
|
||||
<manipulation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScriptManipulation" id="D2_TrueICR">
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_ICR" variable="b"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_OCR" variable="c"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="DD2_ERTM" variable="d"/>
|
||||
<script>import math
|
||||
def process(b,c,d):
|
||||
DeadTime = 1.182e-7
|
||||
ICR = b
|
||||
OCR = c
|
||||
|
||||
if (OCR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
if (ICR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
|
||||
Test = 1.e8
|
||||
TestICR = ICR
|
||||
n = 0
|
||||
while ((Test > DeadTime) and (n < 30)):
|
||||
TrueICR = ICR * math.exp(TestICR * DeadTime)
|
||||
Test = (TrueICR - TestICR) / TestICR
|
||||
TestICR = TrueICR
|
||||
n = n + 1
|
||||
if (OCR) <> 0:
|
||||
box = TrueICR
|
||||
if (OCR*d) == 0:
|
||||
box=0.0
|
||||
return box </script>
|
||||
</manipulation>
|
||||
<manipulation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScriptManipulation" id="D2_FeKa_corr">
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_FeKa" variable="a"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_ICR" variable="b"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_OCR" variable="c"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="DD2_ERTM" variable="d"/>
|
||||
<script>import math
|
||||
def process(a,b,c,d):
|
||||
DeadTime = 1.182e-7
|
||||
ICR = b
|
||||
OCR = c
|
||||
|
||||
if (OCR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
if (ICR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
|
||||
Test = 1.e8
|
||||
TestICR = ICR
|
||||
n = 0
|
||||
while ((Test > DeadTime) and (n < 30)):
|
||||
TrueICR = ICR * math.exp(TestICR * DeadTime)
|
||||
Test = (TrueICR - TestICR) / TestICR
|
||||
TestICR = TrueICR
|
||||
n = n + 1
|
||||
if (OCR*d) <> 0:
|
||||
box = a * TrueICR / OCR / d
|
||||
if (OCR*d) == 0:
|
||||
box=0.0
|
||||
return box </script>
|
||||
</manipulation>
|
||||
<manipulation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScriptManipulation" id="FeKa_sum_cps">
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_FeKa_corr" variable="D2_FeKa_corr"/>
|
||||
<script>import math
|
||||
def process(D2_FeKa_corr):
|
||||
SUM_DET = 0.
|
||||
SUM_DET = SUM_DET + D2_FeKa_corr
|
||||
return SUM_DET </script>
|
||||
</manipulation>
|
||||
</scan>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_ICR D2_TrueICR" title="ICR "/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_OCR" title="OCR "/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_FeKa D2_FeKa_dxp" title="D2_FeKa"/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_FeKa_corr" title="D2_FeKa_corr"/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="I0_KEITHLEY1" title="KEITHLEY1 (I0)=f(Energy)"/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="I1_KEITHLEY2" title="KEITHLEY2 (I1)=f(Energy)"/>
|
||||
</configuration>
|
||||
188
script/2019_0227_023309_XAS_Fe_b_TST.xml
Normal file
188
script/2019_0227_023309_XAS_Fe_b_TST.xml
Normal file
@@ -0,0 +1,188 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<configuration xmlns="http://www.psi.ch/~ebner/models/scan/1.0" numberOfExecution="1" failOnSensorError="true">
|
||||
<data format="txt" fileName="XAS_Fe_b"/>
|
||||
<variable name="K" value="0.0" description="Buffer K spacing for EXAFS k-spacing scans "/>
|
||||
<variable name="N_cycles" value="0.0" description="Buffer N_cycles for EXAFS k-spacing scans "/>
|
||||
<variable name="NINT" value="0.0" description="Counter for file number of Moche files"/>
|
||||
<scan>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/settings/Scripts/GUI_X07MB/X_X07MB_fda_file_to_EPICS.sh ${FILENAME}" checkExitValue="false"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/settings/Scripts/GUI_X07MB/X_X07MB_fda_write_header.py &" checkExitValue="false"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:START-CSMPL" value="0" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:StopAll" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:CollectMode" value="0" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:Apply" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:PresetReal" value="0" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="2" operation="put" type="String" delay="0.05"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:SMPL" value="1" operation="put" type="String" delay="0.7"/>
|
||||
<preAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP-WV1:WT_SET" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<dimension zigzag="false" dataGroup="false">
|
||||
<positioner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="RegionPositioner" name="X07MB-OP-MO:E-SET" readback="X07MB-OP-MO:E-GET" settlingTime="0.2" id="Energy">
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="20"/>
|
||||
<start>7000.0</start>
|
||||
<end>7001.0</end>
|
||||
<stepSize>1.0</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="5"/>
|
||||
<start>7003.0</start>
|
||||
<end>7100.0</end>
|
||||
<stepSize>3.0</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="15"/>
|
||||
<start>7103.0</start>
|
||||
<end>7160.0</end>
|
||||
<stepSize>0.3</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="15"/>
|
||||
<start>7160.5</start>
|
||||
<end>7200.0</end>
|
||||
<stepSize>0.5</stepSize>
|
||||
</region>
|
||||
<region>
|
||||
<preAction xsi:type="ChannelAction" channel="X07MB-OP2:TOTAL-CYCLES" value="15.0"/>
|
||||
<start>4.80379024078</start>
|
||||
<end>10.0</end>
|
||||
<stepSize>0.05</stepSize>
|
||||
<function>
|
||||
<mapping xsi:type="VariableParameterMapping" name="K" variable="K_v"/>
|
||||
<!-- <mapping xsi:type="ChannelParameterMapping" channel="X07MB-OP2:TOTAL-CYCLES" type="Double" variable="N_Cycles"/> -->
|
||||
<script>
|
||||
def calculate(parameter):
|
||||
nc=N_Cycles.getValue()
|
||||
nc=nc*1.02
|
||||
N_Cycles.setValue(nc)
|
||||
E_0=7112.0
|
||||
h=6.626e-34
|
||||
m=9.109e-31
|
||||
k=parameter*1e10
|
||||
K_v=k*1e-10
|
||||
hk=(h/(2.*3.1415926))*k
|
||||
E_joule=hk*hk / (2.*m)
|
||||
E_eV=E_joule/1.6021e-19+E_0
|
||||
return E_eV
|
||||
</script>
|
||||
</function>
|
||||
</region>
|
||||
</positioner>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:EraseStart" value="1" operation="putq" type="String" delay="0.075"/>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:SMPL" value="1" operation="put" type="String" delay="0.075"/>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:SMPL-DONE" value="1" operation="wait" type="Integer" delay="0.03"/>
|
||||
<action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-XMAP:StopAll" value="1" operation="put" type="String" delay="0.05"/>
|
||||
<guard>
|
||||
<condition channel="ACOAU-ACCU:OP-MODE" value="6" type="Integer"/>
|
||||
</guard>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-ES3-MA1:TRSCANH.VAL" id="ScanX_set"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-ES3-MA1:TRSCANV.VAL" id="ScanY_set"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-MO:E-SET" id="Energy_set"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-MO:BEAM-OFS" id="Mono_offset"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="ARIDI-PCT:CURRENT" id="I_SLS"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP2-SAI_04:MEAN" id="diode"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP2-SAI_07:MEAN" id="I0_KEITHLEY1"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-KEITH1:setGain" id="KEITHLEY1_GAIN"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP2-SAI_08:MEAN" id="I1_KEITHLEY2"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-OP-KEITH2:setGain" id="KEITHLEY2_GAIN"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.R0" id="D2_FeKa"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:dxp2:SCA0Counts" id="D2_FeKa_dxp"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:dxp2:InputCountRate" id="D2_ICR"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:dxp2:OutputCountRate" id="D2_OCR"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.ELTM" id="DD2_ELTM"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.ERTM" id="DD2_ERTM"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="X07MB-XMAP:mca2.DTIM" id="DD2_DTIM"/>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ArrayDetector" arraySize="2048" name="X07MB-XMAP:mca2.VAL" id="Spec_2"/>
|
||||
</dimension>
|
||||
<dimension>
|
||||
<positioner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ArrayPositioner" name="X07MB-ES3-MA1:TRSCANH.VAL" readback="X07MB-ES3-MA1:TRSCANH.RBV" id="ScanX">
|
||||
<positions> -2.25</positions>
|
||||
</positioner>
|
||||
<positioner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ArrayPositioner" name="X07MB-ES3-MA1:TRSCANV.VAL" readback="X07MB-ES3-MA1:TRSCANV.RBV" id="ScanY">
|
||||
<positions> 1.0</positions>
|
||||
</positioner>
|
||||
</dimension>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:START-CSMPL" value="1" operation="put" type="String" delay="0.1"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/settings/Scripts/GUI_X07MB/X_X07MB_write_filename_to_file.sh ${FILENAME} &" exitValue="0"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ShellAction" command="/sls/X07MB/data/x07mbop/Data1/Commissioning/Develop/Develop_Moench/X_X07MB_reset_Moench.py &" exitValue="0"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP2:START-CSMPL" value="1" operation="put" type="String" delay="0.1"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-OP-WV1:WT_SET" value="0" operation="put" type="String" delay="0.1"/>
|
||||
<postAction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ChannelAction" channel="X07MB-ES1:userCalc4.INPL" value="0" operation="put" type="String" delay="2.0"/>
|
||||
<manipulation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScriptManipulation" id="D2_TrueICR">
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_ICR" variable="b"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_OCR" variable="c"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="DD2_ERTM" variable="d"/>
|
||||
<script>import math
|
||||
def process(b,c,d):
|
||||
DeadTime = 1.182e-7
|
||||
ICR = b
|
||||
OCR = c
|
||||
|
||||
if (OCR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
if (ICR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
|
||||
Test = 1.e8
|
||||
TestICR = ICR
|
||||
n = 0
|
||||
while ((Test > DeadTime) and (n < 30)):
|
||||
TrueICR = ICR * math.exp(TestICR * DeadTime)
|
||||
Test = (TrueICR - TestICR) / TestICR
|
||||
TestICR = TrueICR
|
||||
n = n + 1
|
||||
if (OCR) <> 0:
|
||||
box = TrueICR
|
||||
if (OCR*d) == 0:
|
||||
box=0.0
|
||||
return box </script>
|
||||
</manipulation>
|
||||
<manipulation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScriptManipulation" id="D2_FeKa_corr">
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_FeKa" variable="a"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_ICR" variable="b"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_OCR" variable="c"/>
|
||||
<mapping xsi:type="IDParameterMapping" refid="DD2_ERTM" variable="d"/>
|
||||
<script>import math
|
||||
def process(a,b,c,d):
|
||||
DeadTime = 1.182e-7
|
||||
ICR = b
|
||||
OCR = c
|
||||
|
||||
if (OCR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
if (ICR) == 0:
|
||||
box = 0
|
||||
return box
|
||||
|
||||
Test = 1.e8
|
||||
TestICR = ICR
|
||||
n = 0
|
||||
while ((Test > DeadTime) and (n < 30)):
|
||||
TrueICR = ICR * math.exp(TestICR * DeadTime)
|
||||
Test = (TrueICR - TestICR) / TestICR
|
||||
TestICR = TrueICR
|
||||
n = n + 1
|
||||
if (OCR*d) <> 0:
|
||||
box = a * TrueICR / OCR / d
|
||||
if (OCR*d) == 0:
|
||||
box=0.0
|
||||
return box </script>
|
||||
</manipulation>
|
||||
<manipulation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScriptManipulation" id="FeKa_sum_cps">
|
||||
<mapping xsi:type="IDParameterMapping" refid="D2_FeKa_corr" variable="D2_FeKa_corr"/>
|
||||
<script>import math
|
||||
def process(D2_FeKa_corr):
|
||||
SUM_DET = 0.
|
||||
SUM_DET = SUM_DET + D2_FeKa_corr
|
||||
return SUM_DET </script>
|
||||
</manipulation>
|
||||
</scan>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_ICR D2_TrueICR" title="ICR "/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_OCR" title="OCR "/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_FeKa D2_FeKa_dxp" title="D2_FeKa"/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="D2_FeKa_corr" title="D2_FeKa_corr"/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="I0_KEITHLEY1" title="KEITHLEY1 (I0)=f(Energy)"/>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="I1_KEITHLEY2" title="KEITHLEY2 (I1)=f(Energy)"/>
|
||||
</configuration>
|
||||
@@ -2,8 +2,7 @@ import ch.psi.pshell.bs.Scalar as Scalar
|
||||
import ch.psi.pshell.bs.Waveform as Waveform
|
||||
import ch.psi.pshell.bs.Stream as Stream
|
||||
import ch.psi.pshell.bs.Provider as Provider
|
||||
|
||||
|
||||
a
|
||||
url = camtool.getInstance(camtool.getInstances()[0])["stream"]
|
||||
p=Provider(None, url)
|
||||
s1 = Stream("stream1", p)
|
||||
|
||||
129
script/PID.py
Normal file
129
script/PID.py
Normal file
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# This file is part of IvPID.
|
||||
# Copyright (C) 2015 Ivmech Mechatronics Ltd. <bilgi@ivmech.com>
|
||||
#
|
||||
# IvPID 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IvPID 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# title :PID.py
|
||||
# description :python pid controller
|
||||
# author :Caner Durmusoglu
|
||||
# date :20151218
|
||||
# version :0.1
|
||||
# notes :
|
||||
# python_version :2.7
|
||||
# ==============================================================================
|
||||
|
||||
"""Ivmech PID Controller is simple implementation of a Proportional-Integral-Derivative (PID) Controller in the Python Programming Language.
|
||||
More information about PID Controller: http://en.wikipedia.org/wiki/PID_controller
|
||||
"""
|
||||
import time
|
||||
|
||||
class PID:
|
||||
"""PID Controller
|
||||
"""
|
||||
|
||||
def __init__(self, P=0.2, I=0.0, D=0.0):
|
||||
|
||||
self.Kp = P
|
||||
self.Ki = I
|
||||
self.Kd = D
|
||||
|
||||
self.sample_time = 0.00
|
||||
self.current_time = time.time()
|
||||
self.last_time = self.current_time
|
||||
|
||||
self.clear()
|
||||
|
||||
def clear(self):
|
||||
"""Clears PID computations and coefficients"""
|
||||
self.SetPoint = 0.0
|
||||
|
||||
self.PTerm = 0.0
|
||||
self.ITerm = 0.0
|
||||
self.DTerm = 0.0
|
||||
self.last_error = 0.0
|
||||
|
||||
# Windup Guard
|
||||
self.int_error = 0.0
|
||||
self.windup_guard = 20.0
|
||||
|
||||
self.output = 0.0
|
||||
|
||||
def update(self, feedback_value):
|
||||
"""Calculates PID value for given reference feedback
|
||||
|
||||
.. math::
|
||||
u(t) = K_p e(t) + K_i \int_{0}^{t} e(t)dt + K_d {de}/{dt}
|
||||
|
||||
.. figure:: images/pid_1.png
|
||||
:align: center
|
||||
|
||||
Test PID with Kp=1.2, Ki=1, Kd=0.001 (test_pid.py)
|
||||
|
||||
"""
|
||||
error = self.SetPoint - feedback_value
|
||||
|
||||
self.current_time = time.time()
|
||||
delta_time = self.current_time - self.last_time
|
||||
delta_error = error - self.last_error
|
||||
|
||||
if (delta_time >= self.sample_time):
|
||||
self.PTerm = self.Kp * error
|
||||
self.ITerm += error * delta_time
|
||||
|
||||
if (self.ITerm < -self.windup_guard):
|
||||
self.ITerm = -self.windup_guard
|
||||
elif (self.ITerm > self.windup_guard):
|
||||
self.ITerm = self.windup_guard
|
||||
|
||||
self.DTerm = 0.0
|
||||
if delta_time > 0:
|
||||
self.DTerm = delta_error / delta_time
|
||||
|
||||
# Remember last time and last error for next calculation
|
||||
self.last_time = self.current_time
|
||||
self.last_error = error
|
||||
|
||||
self.output = self.PTerm + (self.Ki * self.ITerm) + (self.Kd * self.DTerm)
|
||||
|
||||
def setKp(self, proportional_gain):
|
||||
"""Determines how aggressively the PID reacts to the current error with setting Proportional Gain"""
|
||||
self.Kp = proportional_gain
|
||||
|
||||
def setKi(self, integral_gain):
|
||||
"""Determines how aggressively the PID reacts to the current error with setting Integral Gain"""
|
||||
self.Ki = integral_gain
|
||||
|
||||
def setKd(self, derivative_gain):
|
||||
"""Determines how aggressively the PID reacts to the current error with setting Derivative Gain"""
|
||||
self.Kd = derivative_gain
|
||||
|
||||
def setWindup(self, windup):
|
||||
"""Integral windup, also known as integrator windup or reset windup,
|
||||
refers to the situation in a PID feedback controller where
|
||||
a large change in setpoint occurs (say a positive change)
|
||||
and the integral terms accumulates a significant error
|
||||
during the rise (windup), thus overshooting and continuing
|
||||
to increase as this accumulated error is unwound
|
||||
(offset by errors in the other direction).
|
||||
The specific problem is the excess overshooting.
|
||||
"""
|
||||
self.windup_guard = windup
|
||||
|
||||
def setSampleTime(self, sample_time):
|
||||
"""PID that should be updated at a regular interval.
|
||||
Based on a pre-determined sampe time, the PID decides if it should compute or return immediately.
|
||||
"""
|
||||
self.sample_time = sample_time
|
||||
@@ -1,18 +1,15 @@
|
||||
###################################################################################################
|
||||
#Resampling a scan record if no beam
|
||||
#Resampling a scan record if there is no beam
|
||||
###################################################################################################
|
||||
|
||||
|
||||
index=0
|
||||
|
||||
|
||||
def before_sampling(rec):
|
||||
while beam_ok.read() == "No":
|
||||
while beam_ok.read() == False:
|
||||
time.sleep(0.1)
|
||||
|
||||
def after_sampling(rec):
|
||||
if beam_ok.read() == "No":
|
||||
if beam_ok.read() == False:
|
||||
rec.invalidate()
|
||||
|
||||
|
||||
a= lscan((m1), (ai1,ai2), (0,), (0.4,), 20, 0.2, before_read=before_sampling, after_read=after_sampling)
|
||||
ret = lscan(motor, (out, sin), 0.0, 2.0, 0.1, 0.2,\
|
||||
before_read=before_sampling, \
|
||||
after_read=after_sampling)
|
||||
|
||||
41
script/Test.xml
Normal file
41
script/Test.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<configuration xmlns="http://www.psi.ch/~ebner/models/scan/1.0" numberOfExecution="1" failOnSensorError="true">
|
||||
<data format="txt" fileName=""/>
|
||||
<variable name="K" value="0.0" description="Buffer K spacing for EXAFS k-spacing scans "/>
|
||||
<variable name="N_cycles" value="0.0" description="Buffer N_cycles for EXAFS k-spacing scans "/>
|
||||
<variable name="NINT" value="0.0" description="Counter for file number of Moche files"/>
|
||||
<scan>
|
||||
<dimension zigzag="false" dataGroup="false">
|
||||
<positioner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="RegionPositioner" name="TESTIOC:TESTCALCOUT:Input" readback="TESTIOC:TESTCALCOUT:Input" settlingTime="0.1" asynchronous="false" id="Energy">
|
||||
<region>
|
||||
<start>0.0</start>
|
||||
<end>10.0</end>
|
||||
<stepSize>1.0</stepSize>
|
||||
<function>
|
||||
<mapping xsi:type="VariableParameterMapping" name="K" variable="K_v"/>
|
||||
<mapping xsi:type="ChannelParameterMapping" channel="TESTIOC:TESTCALCOUT:Output" type="Double" variable="Ch"/>
|
||||
<script>def calculate(parameter):
|
||||
print "X"
|
||||
nc=Ch.getValue()
|
||||
print nc
|
||||
#nc=nc*1.02
|
||||
#N_Cycles.setValue(nc)
|
||||
return parameter * 2
|
||||
E_0=7112.0
|
||||
h=6.626e-34
|
||||
m=9.109e-31
|
||||
k=parameter*1e10
|
||||
K_v=k*1e-10
|
||||
hk=(h/(2.*3.1415926))*k
|
||||
E_joule=hk*hk / (2.*m)
|
||||
E_eV=E_joule/1.6021e-19+E_0
|
||||
|
||||
return E_eV</script>
|
||||
</function>
|
||||
</region>
|
||||
</positioner>
|
||||
<detector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ScalarDetector" type="Double" name="TESTIOC:TESTSINUS:SinCalc" id="SIN"/>
|
||||
</dimension>
|
||||
</scan>
|
||||
<visualization xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinePlot" x="Energy" y="SIN" title="Sin"/>
|
||||
</configuration>
|
||||
338
script/WireScanner.py
Normal file
338
script/WireScanner.py
Normal file
@@ -0,0 +1,338 @@
|
||||
import ch.psi.pshell.epics.Motor
|
||||
|
||||
|
||||
class WireScanInfo(DeviceBase):
|
||||
def __init__(self, name, prefix):
|
||||
DeviceBase.__init__(self, name)
|
||||
self.prefix = prefix
|
||||
self.nb_cycles = Channel(self.prefix + ":NB_CYCL_SP", 'l')
|
||||
self.curr_cycl = Channel(self.prefix + ":CURR_CYCL", 'l', callback = self.on_cycle_change)
|
||||
self.curr_cycl.set_monitored(True)
|
||||
set_device_alias(self.curr_cycl, "current_cycle")
|
||||
self.current_cycle = self.curr_cycl.get()
|
||||
self.status_channels=[]
|
||||
for s in ("SCANNING", "SCAN_DONE", "INITIALIZING", "INIT_DONE", "ABORTED", "ERROR"):
|
||||
c = Channel(self.prefix + ":" + s, 'i', callback = self.on_status_change);
|
||||
c.set_monitored(True)
|
||||
self.status_channels.append(c)
|
||||
self.cycles = self.nb_cycles.get()
|
||||
self.on_status_change(None)
|
||||
self.initialize()
|
||||
|
||||
self.home_offsets = []
|
||||
for s in ("W1X_U0_SP", "W1Y_U0_SP", "W2X_U0_SP", "W2Y_U0_SP", "FOIL_U0_SP"):
|
||||
self.home_offsets.append(caget(self.prefix + ":" +s, 'd'))
|
||||
|
||||
def on_status_change(self, val):
|
||||
try:
|
||||
if self.status_channels[0].get() == 1:
|
||||
self.setCache("Scanning " + str(self.current_cycle) + "/" + str(self.cycles), None)
|
||||
self.setState(State.Busy)
|
||||
elif self.status_channels[1].get() == 1:
|
||||
self.setCache("Scan done", None)
|
||||
self.setState(State.Ready)
|
||||
elif self.status_channels[2].get() == 1:
|
||||
self.setCache("Traveling", None)
|
||||
self.setState(State.Paused)
|
||||
elif self.status_channels[3].get() == 1:
|
||||
self.setCache("At start", None)
|
||||
self.setState(State.Ready)
|
||||
elif self.status_channels[4].get() == 1:
|
||||
self.setCache("Abort", None)
|
||||
self.setState(State.Ready)
|
||||
elif self.status_channels[5].get() == 1:
|
||||
self.setCache("Error", None)
|
||||
self.setState(State.Fault)
|
||||
else:
|
||||
pass #All zero, a transition
|
||||
except:
|
||||
self.setCache("offline", None)
|
||||
self.setState(State.Offline)
|
||||
|
||||
def on_cycle_change(self, val):
|
||||
#print "Wire scan cycle change: ", val
|
||||
self.current_cycle = val
|
||||
self.on_status_change(val)
|
||||
|
||||
def doClose(self):
|
||||
self.nb_cycles.close()
|
||||
self.curr_cycl.close()
|
||||
for c in self.status_channels:
|
||||
c.close()
|
||||
|
||||
def get_wire_pos(self, pos_motor):
|
||||
if (pos_motor is None) or math.isnan(pos_motor):
|
||||
return [pos_motor] * 4
|
||||
w1x = (pos_motor - self.home_offsets[0]) / -(math.sqrt(2))
|
||||
w1y = (pos_motor - self.home_offsets[1]) / (math.sqrt(2))
|
||||
w2x = (pos_motor - self.home_offsets[2]) / -(math.sqrt(2))
|
||||
w2y = (pos_motor - self.home_offsets[3]) / (math.sqrt(2))
|
||||
return [w1x, w1y, w2x, w2y]
|
||||
|
||||
def get_motor_pos(self, pos_wire, wire_type):
|
||||
if (pos_wire is None) or math.isnan(pos_wire):
|
||||
return pos_wire
|
||||
if wire_type == WireScanner.WireX1: return self.home_offsets[0] - pos_wire * math.sqrt(2)
|
||||
if wire_type == WireScanner.WireY1: return self.home_offsets[1] + pos_wire * math.sqrt(2)
|
||||
if wire_type == WireScanner.WireX2: return self.home_offsets[2] - pos_wire * math.sqrt(2)
|
||||
if wire_type == WireScanner.WireY2: return self.home_offsets[3] + pos_wire * math.sqrt(2)
|
||||
return None
|
||||
|
||||
def is_valid(self):
|
||||
return caget(self.prefix + ":VALID", 'i')==1
|
||||
|
||||
def _get_channel(self, bunch, wire, name):
|
||||
return self.prefix + ":B" + str(int(bunch)) + "_" + wire.upper() + "_" + name
|
||||
|
||||
def set_out_com(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "CENTER_OF_MASS"), float(value))
|
||||
|
||||
def set_out_rms(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "RMS"), float(value))
|
||||
|
||||
def set_out_amp(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "FIT_AMPLITUDE"), float(value))
|
||||
|
||||
def set_out_mean(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "FIT_MEAN"), float(value))
|
||||
|
||||
def set_out_off(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "FIT_OFFSET"), float(value))
|
||||
|
||||
def set_out_sigma(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "FIT_STANDARD_DEVIATION"), float(value))
|
||||
|
||||
def set_out_pos(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "POSITION"), to_array(value, 'd'))
|
||||
|
||||
def set_out_samples(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "AMPLITUDE"), to_array(value, 'd'))
|
||||
|
||||
def set_out_gauss(self, bunch, wire, value):
|
||||
caput(self._get_channel(bunch, wire, "FIT_GAUSS_FUNCTION"), to_array(value, 'd'))
|
||||
|
||||
|
||||
def new_scan_info_device(name, prefix):
|
||||
return WireScanInfo(name, prefix)
|
||||
|
||||
def get_wire_pos(wire_scanner, pos):
|
||||
return wire_scanner.get_wire_pos(pos)
|
||||
|
||||
def get_scan_selection(scan_type, index = 0):
|
||||
if scan_type == WireScanner.WireX1: return WireScanner.W1X
|
||||
if scan_type == WireScanner.WireY1: return WireScanner.W1Y
|
||||
if scan_type == WireScanner.WireX2: return WireScanner.W2X
|
||||
if scan_type == WireScanner.WireY2: return WireScanner.W2Y
|
||||
if scan_type == WireScanner.Set1: return WireScanner.W1X if (index==0) else WireScanner.W1Y
|
||||
if scan_type == WireScanner.Set2: return WireScanner.W2X if (index==0) else WireScanner.W2Y
|
||||
return None
|
||||
|
||||
class WireScanner(WireScanInfo):
|
||||
|
||||
ScanType = [WireX1, WireY1, WireX2, WireY2, Set1, Set2, BackGarage, BackFoil] = ['X1', 'Y1', 'X2', 'Y2', 'Set1', 'Set2', 'BackgroundGarage', 'BackgroundFoil']
|
||||
Selection = [Garage, W1X, W1Y, W2X, W2Y, Foil] = "GARAGE", "W1X", "W1Y", "W2X", "W2Y", "FOIL"
|
||||
|
||||
def __init__(self, prefix, scan_range, cycles=None, velocity=None, continuous = None):
|
||||
WireScanInfo.__init__(self, "Wire Scan " + prefix, prefix)
|
||||
self.motor = ch.psi.pshell.epics.Motor("WireScanner motor", self.prefix + ":MOTOR_1")
|
||||
self.motor.uploadConfig()
|
||||
self.motor.initialize()
|
||||
#self.motor_bs_readback = Channel(self.prefix + ":ENC_1_BS") #, callback = self.on_readback_change)
|
||||
self.motor_bs_readback = Channel("TESTIOC:TESTCALCOUT:Output")
|
||||
#self.motor_bs_readback.set_monitored(True)
|
||||
self.wire_velocity = Channel(self.prefix + ":SCAN_VELO_SP") #wire coordinates
|
||||
self.motor_velocity = Channel(self.prefix + ":SCAN_M_VELO") #motor coordinates
|
||||
self.travel_velocity = Channel(self.prefix + ":TRAVEL_VELO_SP") #motor coordinates
|
||||
self.wire_sel = Channel(self.prefix + ":WIRE_SP", 'l')
|
||||
self.selection = None
|
||||
self.u0 = None
|
||||
self.offset = None
|
||||
self.range = None
|
||||
self.start = None
|
||||
self.end = None
|
||||
self.scan_range = scan_range
|
||||
|
||||
if velocity is not None:
|
||||
self.set_velocity(velocity)
|
||||
if cycles is not None:
|
||||
self.nb_cycles.write(int(cycles))
|
||||
if continuous is not None:
|
||||
caputq(self.prefix + ":SCAN_MODE_SP", 0 if continuous else 1)
|
||||
|
||||
self.readback = self.motor_bs_readback.get()
|
||||
self.cycles = self.nb_cycles.get()
|
||||
self.velocity = self.wire_velocity.get()
|
||||
self.initialize()
|
||||
|
||||
#def on_readback_change(self, val):
|
||||
# self.readback = val
|
||||
|
||||
def set_velocity(self, velocity):
|
||||
self.wire_velocity.write(float(velocity))
|
||||
self.velocity = self.wire_velocity.get()
|
||||
|
||||
def set_travel_velocity(self):
|
||||
tv = self.travel_velocity.read()
|
||||
self.set_velocity(tv/math.sqrt(2))
|
||||
self.motor.speed=(tv)
|
||||
|
||||
|
||||
def set_selection(self, sel):
|
||||
if not sel in WireScanner.Selection:
|
||||
raise Exception("Invalid Wire Scan selection: " + str(sel))
|
||||
self.selection = sel
|
||||
self.u0 = Channel(self.prefix + ":" + self.selection + "_U0_SP")
|
||||
self.offset = Channel(self.prefix + ":" + self.selection + "_OFF_SP")
|
||||
self.range = Channel(self.prefix + ":" + self.selection + "_RANGE_SP")
|
||||
self.start = Channel(self.prefix + ":" + self.selection + "_START_SP")
|
||||
self.end = Channel(self.prefix + ":" + self.selection + "_END_SP")
|
||||
self.wire_sel.put(WireScanner.Selection.index(sel))
|
||||
|
||||
#Setting parameters
|
||||
if self.scan_range is not None:
|
||||
if sel in ["W1X", "W2X"]: self.start.write(float(self.scan_range[0]))
|
||||
if sel in ["W1Y", "W2Y"]: self.start.write(float(self.scan_range[2]))
|
||||
if sel in ["W1X", "W2X"]: self.end.write(float(self.scan_range[1]))
|
||||
if sel in ["W1Y", "W2Y"]: self.end.write(float(self.scan_range[3]))
|
||||
print "Sel: ", sel
|
||||
print "Range: ", self.scan_range
|
||||
print "Scan start: ", self.start.read()
|
||||
print "End start: ", self.end.read()
|
||||
|
||||
|
||||
def abort(self):
|
||||
caputq(self.prefix + ":ABORT.PROC", 1)
|
||||
|
||||
def init(self, wait=False):
|
||||
#if self.selection is not None:
|
||||
# self.wire_sel.put(WireScanner.Selection.index(self.selection))
|
||||
caputq(self.prefix + ":INIT.PROC", 1)
|
||||
if wait:
|
||||
self.wait_in_selection()
|
||||
|
||||
def park(self, wait=False):
|
||||
caputq(self.prefix + ":GARAGE_SEL.PROC", 1)
|
||||
caputq(self.prefix + ":INIT.PROC", 1)
|
||||
if wait:
|
||||
self.wait_in_selection()
|
||||
|
||||
def wait_in_selection(self):
|
||||
time.sleep(0.5) #Some time for the status change
|
||||
self.waitValue("At start", 60000)
|
||||
|
||||
def scan(self):
|
||||
self.cycles = self.nb_cycles.get()
|
||||
caputq(self.prefix + ":SCAN_WIRE", 1)
|
||||
|
||||
def get_sel_wire_pos(self, pos_motor=None):
|
||||
if pos_motor is None:
|
||||
pos_motor = self.motor_bs_readback.get()
|
||||
wire_pos = self.get_wire_pos(pos_motor)
|
||||
if self.selection == WireScanner.W1X: return wire_pos[0]
|
||||
if self.selection == WireScanner.W1Y: return wire_pos[1]
|
||||
if self.selection == WireScanner.W2X: return wire_pos[2]
|
||||
if self.selection == WireScanner.W2Y: return wire_pos[3]
|
||||
return float('nan')
|
||||
|
||||
def doClose(self):
|
||||
WireScanInfo.doClose(self)
|
||||
self.motor.close()
|
||||
self.motor_bs_readback.close()
|
||||
self.wire_velocity.close()
|
||||
self.motor_velocity.close()
|
||||
self.travel_velocity.close()
|
||||
self.wire_sel.close()
|
||||
if self.u0 is not None: self.u0.close()
|
||||
if self.offset is not None: self.offset.close()
|
||||
if self.range is not None: self.range.close()
|
||||
if self.start is not None: self.start.close()
|
||||
if self.end is not None: self.end.close()
|
||||
"""
|
||||
def get_cicle_time(self):
|
||||
range = abs(self.start.get() -self.end.get())
|
||||
speed = self.motor_velocity.get()
|
||||
return (range / speed)
|
||||
|
||||
def get_total_time(self):
|
||||
return self.get_cicle_time() * self.cycles
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
prefix="STEST-DWSC"
|
||||
scan_range = None
|
||||
cycles = 1
|
||||
|
||||
if scan_range is None or len(scan_range) !=4:
|
||||
scan_range = [ caget(prefix+":W2X_START_SP", 'd'), \
|
||||
caget(prefix+":W2X_END_SP", 'd'), \
|
||||
caget(prefix+":W2Y_START_SP", 'd'), \
|
||||
caget(prefix+":W2Y_END_SP", 'd') ]
|
||||
|
||||
scan_range = [ caget(prefix+":W1X_START_SP", 'd'), \
|
||||
caget(prefix+":W1X_END_SP", 'd'), \
|
||||
caget(prefix+":W1Y_START_SP", 'd'), \
|
||||
caget(prefix+":W1Y_END_SP", 'd') ]
|
||||
|
||||
velocity = abs(scan_range[1]-scan_range[0])*100/2000
|
||||
|
||||
print scan_range
|
||||
print velocity
|
||||
|
||||
scanner = WireScanner(prefix, scan_range = scan_range, cycles=cycles, velocity=None, continuous = True)
|
||||
add_device(scanner, True)
|
||||
add_device(scanner.motor , True)
|
||||
scanner.motor.monitored=True
|
||||
|
||||
|
||||
#"m_pos" -> scanner.motor_bs_readback
|
||||
m_pos = scanner.motor.readback
|
||||
class w_pos(Readable):
|
||||
def read(self):
|
||||
return scanner.get_sel_wire_pos(m_pos.take())
|
||||
|
||||
|
||||
|
||||
|
||||
scanner.park(wait=True)
|
||||
scanner.set_velocity(velocity)
|
||||
scanner.set_selection(WireScanner.W1X)
|
||||
scanner.init(wait=True)
|
||||
scanner.curr_cycl.write(0)
|
||||
scan_complete=False
|
||||
cur_cycle = 1.0
|
||||
#Scan
|
||||
|
||||
|
||||
scanner.scan() #scanner.waitState(State.Busy, 60000) Not needed as stream filter will make the wait
|
||||
|
||||
|
||||
def check_end_scan(record, scan):
|
||||
global scan_complete,cur_cycle
|
||||
print scanner.take()
|
||||
if scanner.take() == "Scan done":
|
||||
print "Done"
|
||||
scan_complete=True
|
||||
scan.abort()
|
||||
record.cancel() #So it won't be saved
|
||||
|
||||
try:
|
||||
l=[w_pos()] ; #l.extend(st.getReadables()); l.append(Timestamp())
|
||||
print "Start scan"
|
||||
#mscan (st, l, -1, -1, take_initial = True, after_read = check_end_scan)
|
||||
mscan (m_pos, l, -1, -1, take_initial = True, after_read = check_end_scan)
|
||||
#print "End scan"
|
||||
#tscan([w_pos()] + st.getReadables() + [Timestamp(),], 10, 0.5)
|
||||
except:
|
||||
print sys.exc_info()[1]
|
||||
if not scanner.isReady():
|
||||
print "Aborting scan"
|
||||
scanner.abort()
|
||||
if not scan_complete:
|
||||
raise
|
||||
finally:
|
||||
print "Finished"
|
||||
#scanner.close()
|
||||
#st.close()
|
||||
|
||||
2529
script/__Lib/_startup.py
Normal file
2529
script/__Lib/_startup.py
Normal file
File diff suppressed because it is too large
Load Diff
1
script/__Lib/diffcalc-2.1/.cache/v/cache/lastfailed
vendored
Executable file
1
script/__Lib/diffcalc-2.1/.cache/v/cache/lastfailed
vendored
Executable file
@@ -0,0 +1 @@
|
||||
{}
|
||||
9
script/__Lib/diffcalc-2.1/.gitignore
vendored
Executable file
9
script/__Lib/diffcalc-2.1/.gitignore
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
*.class
|
||||
*~
|
||||
*.pyc
|
||||
doc/build/
|
||||
.pydevproject
|
||||
.project
|
||||
.tox
|
||||
.DS_Store
|
||||
.idea
|
||||
29
script/__Lib/diffcalc-2.1/.settings/com.wdev91.eclipse.copyright.xml
Executable file
29
script/__Lib/diffcalc-2.1/.settings/com.wdev91.eclipse.copyright.xml
Executable file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<project>
|
||||
<owner>Diamond Light Source Ltd.</owner>
|
||||
<copyright><![CDATA[ Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
This file is part of Diffcalc.
|
||||
|
||||
Diffcalc 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Diffcalc 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.]]></copyright>
|
||||
<header contentId="org.eclipse.core.runtime.text" postBlankLines="2" lineFormat="false" preserveFirstLine="false">
|
||||
<beginLine><![CDATA[###]]></beginLine>
|
||||
<linePrefix><![CDATA[#]]></linePrefix>
|
||||
<endLine><![CDATA[###]]></endLine>
|
||||
</header>
|
||||
<header contentId="org.python.pydev.pythonfile" postBlankLines="1" lineFormat="false" preserveFirstLine="false">
|
||||
<beginLine><![CDATA[###]]></beginLine>
|
||||
<linePrefix><![CDATA[#]]></linePrefix>
|
||||
<endLine><![CDATA[###]]></endLine>
|
||||
</header>
|
||||
</project>
|
||||
3
script/__Lib/diffcalc-2.1/.settings/org.eclipse.core.resources.prefs
Executable file
3
script/__Lib/diffcalc-2.1/.settings/org.eclipse.core.resources.prefs
Executable file
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//doc/source/conf.py=utf-8
|
||||
encoding/<project>=UTF-8
|
||||
2
script/__Lib/diffcalc-2.1/.settings/org.eclipse.core.runtime.prefs
Executable file
2
script/__Lib/diffcalc-2.1/.settings/org.eclipse.core.runtime.prefs
Executable file
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
line.separator=\n
|
||||
21
script/__Lib/diffcalc-2.1/.travis.yml
Executable file
21
script/__Lib/diffcalc-2.1/.travis.yml
Executable file
@@ -0,0 +1,21 @@
|
||||
# based on https://www.topbug.net/blog/2012/05/27/use-travis-ci-with-jython/
|
||||
|
||||
language: python
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
|
||||
env:
|
||||
- JYTHON=false
|
||||
- JYTHON=true
|
||||
|
||||
install:
|
||||
- if [ "$JYTHON" == "true" ]; then . install-jython-environment.sh; fi
|
||||
- if [ "$JYTHON" == "false" ]; then pip install --upgrade pytest; pip install pytest-xdist; fi
|
||||
|
||||
before_script:
|
||||
- if [ "$JYTHON" == "true" ]; then export PYTEST=$HOME/jython/bin/pytest; else export PYTEST=pytest; fi
|
||||
- echo PYTEST:- $PYTEST
|
||||
|
||||
script: $PYTEST
|
||||
|
||||
674
script/__Lib/diffcalc-2.1/COPYING
Executable file
674
script/__Lib/diffcalc-2.1/COPYING
Executable file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
52
script/__Lib/diffcalc-2.1/Makefile
Executable file
52
script/__Lib/diffcalc-2.1/Makefile
Executable file
@@ -0,0 +1,52 @@
|
||||
|
||||
test-all: test-python test-jython test-integration test-launcher
|
||||
|
||||
test-python:
|
||||
py.test
|
||||
|
||||
test-jython:
|
||||
export CLASSPATH=$(HOME)/lib/Jama-1.0.3.jar:$(CLASSPATH); echo $$CLASSPATH; $(HOME)/jython/bin/py.test
|
||||
|
||||
test-integration:
|
||||
py.test --boxed integration_checks.py
|
||||
|
||||
test-launcher:
|
||||
./diffcalc.py --help
|
||||
./diffcalc.py --modules
|
||||
./diffcalc.py --non-interactive --python sixcircle
|
||||
|
||||
install-jython:
|
||||
./install-jython-environment.sh
|
||||
|
||||
doc-source:
|
||||
./diffcalc.py --non-interactive --make-manuals-source
|
||||
|
||||
doc-html:
|
||||
cd doc; make html
|
||||
|
||||
doc-pdf:
|
||||
cd doc; make pdf
|
||||
|
||||
doc-all:
|
||||
cd doc; make all
|
||||
|
||||
doc-clean:
|
||||
cd doc; make clean
|
||||
|
||||
help:
|
||||
@echo
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo
|
||||
@echo " test-all"
|
||||
@echo " test-python"
|
||||
@echo " test-jython"
|
||||
@echo " test-integration"
|
||||
@echo " test-launcher"
|
||||
@echo " install-jython"
|
||||
@echo
|
||||
@echo " doc-source : to expand *_template.rst to *.rst"
|
||||
@echo " doc-html"
|
||||
@echo " doc-pdf"
|
||||
@echo " doc-all"
|
||||
@echo " doc-clean"
|
||||
@echo
|
||||
513
script/__Lib/diffcalc-2.1/README.rst
Executable file
513
script/__Lib/diffcalc-2.1/README.rst
Executable file
@@ -0,0 +1,513 @@
|
||||
Diffcalc - A Diffraction Condition Calculator for Diffractometer Control
|
||||
========================================================================
|
||||
|
||||
Diffcalc is a python/jython based diffraction condition calculator used for
|
||||
controlling diffractometers within reciprocal lattice space. It performs the
|
||||
same task as the fourc, sixc, twoc, kappa, psic and surf macros from SPEC.
|
||||
|
||||
There is a `user guide <https://diffcalc.readthedocs.io/en/latest/youmanual.html>`_ and `developer guide <https://diffcalc.readthedocs.io/en/latest/developer/contents.html>`_, both at `diffcalc.readthedocs.io <https://diffcalc.readthedocs.io>`_
|
||||
|
||||
|Travis| |Read the docs|
|
||||
|
||||
.. |Travis| image:: https://travis-ci.org/DiamondLightSource/diffcalc.svg?branch=master
|
||||
:target: https://travis-ci.org/DiamondLightSource/diffcalc
|
||||
:alt: Build Status
|
||||
|
||||
.. |Read the docs| image:: https://readthedocs.org/projects/diffcalc/badge/?version=latest
|
||||
:target: http://diffcalc.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. contents::
|
||||
|
||||
.. section-numbering::
|
||||
|
||||
Software compatibility
|
||||
----------------------
|
||||
|
||||
- Written in Python using numpy
|
||||
- Works in Jython using Jama
|
||||
- Runs directly in `OpenGDA<http://www.opengda.org>`
|
||||
- Runs in in Python or IPython using minimal OpenGda emulation (included)
|
||||
- Contact us for help running in your environment
|
||||
|
||||
Diffractometer compatibility
|
||||
----------------------------
|
||||
|
||||
Diffcalc’s standard calculation engine is an implementation of [You1999]_ and
|
||||
[Busing1967]_. Diffcalc works with any diffractometer which is a subset of:
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/DiamondLightSource/diffcalc/master/doc/source/youmanual_images/4s_2d_diffractometer.png
|
||||
:alt: 4s + 2d six-circle diffractometer, from H.You (1999)
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
Diffcalc can be configured to work with any diffractometer geometry which is a
|
||||
subset of this. For example, a five-circle diffractometer might be missing the
|
||||
nu circle above.
|
||||
|
||||
Note that the first versions of Diffcalc were based on [Vlieg1993]_ and
|
||||
[Vlieg1998]_ and a ‘Vlieg’ engine is still available. There is also an engine
|
||||
based on [Willmott2011]_. The ‘You’ engine is more generic and the plan is to
|
||||
remove the old ‘Vlieg’ engine once beamlines have been migrated.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Check it out::
|
||||
|
||||
$ git clone https://github.com/DiamondLightSource/diffcalc.git
|
||||
Cloning into 'diffcalc'...
|
||||
|
||||
At Diamond Diffcalc may be installed within an OpenGDA deployment and is
|
||||
available via the 'module' system from bash.
|
||||
|
||||
Starting
|
||||
--------
|
||||
|
||||
Start diffcalc in ipython using a sixcircle dummy diffractometer::
|
||||
|
||||
$ cd diffcalc
|
||||
$ ./diffcalc.py --help
|
||||
...
|
||||
|
||||
$ ./diffcalc.py sixcircle
|
||||
|
||||
Running: "ipython --no-banner --HistoryManager.hist_file=/tmp/ipython_hist_zrb13439.sqlite -i -m diffcmd.start sixcircle False"
|
||||
|
||||
---------------------------------- DIFFCALC -----------------------------------
|
||||
Startup script: '/Users/zrb13439/git/diffcalc/startup/sixcircle.py'
|
||||
Loading ub calculation: 'test'
|
||||
------------------------------------ Help -------------------------------------
|
||||
Quick: https://github.com/DiamondLightSource/diffcalc/blob/master/README.rst
|
||||
Manual: https://diffcalc.readthedocs.io
|
||||
Type: > help ub
|
||||
> help hkl
|
||||
-------------------------------------------------------------------------------
|
||||
In [1]:
|
||||
|
||||
Within Diamond use::
|
||||
|
||||
$ module load diffcalc
|
||||
$ diffcalc --help
|
||||
...
|
||||
$ diffcalc sixcircle
|
||||
|
||||
Trying it out
|
||||
-------------
|
||||
|
||||
Type ``demo.all()`` to see it working and then move try the following quick
|
||||
start guide::
|
||||
|
||||
>>> demo.all()
|
||||
...
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
To view help with orientation and then moving in hkl space::
|
||||
|
||||
>>> help ub
|
||||
...
|
||||
>>> help hkl
|
||||
...
|
||||
|
||||
Configuring a UB calculation
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To load the last used UB-calculation::
|
||||
|
||||
>>> lastub
|
||||
Loading ub calculation: 'mono-Si'
|
||||
|
||||
To load a previous UB-calculation::
|
||||
|
||||
>>> listub
|
||||
UB calculations in: /Users/walton/.diffcalc/i16
|
||||
|
||||
0) mono-Si 15 Feb 2017 (22:32)
|
||||
1) i16-32 13 Feb 2017 (18:32)
|
||||
|
||||
>>> loadub 0
|
||||
|
||||
To create a new UB-calculation::
|
||||
|
||||
>>> newub 'example'
|
||||
>>> setlat '1Acube' 1 1 1 90 90 90
|
||||
|
||||
Find U matrix from two reflections::
|
||||
|
||||
>>> pos wl 1
|
||||
wl: 1.0000
|
||||
>>> c2th [0 0 1]
|
||||
59.99999999999999
|
||||
|
||||
>>> pos sixc [0 60 0 30 90 0]
|
||||
sixc: mu: 0.0000 delta: 60.0000 gam: 0.0000 eta: 30.0000 chi: 90.0000 phi: 0.0000
|
||||
>>> addref [0 0 1]
|
||||
|
||||
>>> pos sixc [0 90 0 45 45 90]
|
||||
sixc: mu: 0.0000 delta: 90.0000 gam: 0.0000 eta: 45.0000 chi: 45.0000 phi: 90.0000
|
||||
>>> addref [0 1 1]
|
||||
Calculating UB matrix.
|
||||
|
||||
|
||||
Check that it looks good::
|
||||
|
||||
>>> checkub
|
||||
|
||||
ENERGY H K L H_COMP K_COMP L_COMP TAG
|
||||
1 12.3984 0.00 0.00 1.00 0.0000 0.0000 1.0000
|
||||
2 12.3984 0.00 1.00 1.00 0.0000 1.0000 1.0000
|
||||
|
||||
To see the resulting UB-calculation::
|
||||
|
||||
>>> ub
|
||||
UBCALC
|
||||
|
||||
name: example
|
||||
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
|
||||
CRYSTAL
|
||||
|
||||
name: 1Acube
|
||||
|
||||
a, b, c: 1.00000 1.00000 1.00000
|
||||
90.00000 90.00000 90.00000
|
||||
|
||||
B matrix: 6.28319 0.00000 0.00000
|
||||
0.00000 6.28319 0.00000
|
||||
0.00000 0.00000 6.28319
|
||||
|
||||
UB MATRIX
|
||||
|
||||
U matrix: 1.00000 0.00000 0.00000
|
||||
0.00000 1.00000 0.00000
|
||||
0.00000 0.00000 1.00000
|
||||
|
||||
U angle: 0
|
||||
|
||||
UB matrix: 6.28319 0.00000 0.00000
|
||||
0.00000 6.28319 0.00000
|
||||
0.00000 0.00000 6.28319
|
||||
|
||||
REFLECTIONS
|
||||
|
||||
ENERGY H K L MU DELTA GAM ETA CHI PHI TAG
|
||||
1 12.398 0.00 0.00 1.00 0.0000 60.0000 0.0000 30.0000 90.0000 0.0000
|
||||
2 12.398 0.00 1.00 1.00 0.0000 90.0000 0.0000 45.0000 45.0000 90.0000
|
||||
|
||||
Setting the reference vector
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
By default the reference vector is set parallel to the phi axis. That is,
|
||||
along the z-axis of the phi coordinate frame.
|
||||
|
||||
The `ub` command shows the current reference vector, along with any inferred
|
||||
miscut, at the top its report (or it can be shown by calling ``setnphi`` or
|
||||
``setnhkl'`` with no args)::
|
||||
|
||||
>>> ub
|
||||
...
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
...
|
||||
|
||||
Constraining solutions for moving in hkl space
|
||||
----------------------------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To get help and see current constraints::
|
||||
|
||||
>>> help con
|
||||
...
|
||||
|
||||
>>> con
|
||||
DET REF SAMP
|
||||
------ ------ ------
|
||||
delta --> a_eq_b --> mu
|
||||
--> gam alpha eta
|
||||
qaz beta chi
|
||||
naz psi phi
|
||||
mu_is_gam
|
||||
|
||||
gam : 0.0000
|
||||
a_eq_b
|
||||
mu : 0.0000
|
||||
|
||||
Type 'help con' for instructions
|
||||
|
||||
Three constraints can be given: zero or one from the DET and REF columns and the
|
||||
remainder from the SAMP column. Not all combinations are currently available.
|
||||
Use ``help con`` to see a summary if you run into troubles.
|
||||
|
||||
To configure four-circle vertical scattering::
|
||||
|
||||
>>> con gam 0 mu 0 a_eq_b
|
||||
gam : 0.0000
|
||||
a_eq_b
|
||||
mu : 0.0000
|
||||
|
||||
Moving in hkl space
|
||||
-------------------
|
||||
|
||||
Simulate moving to a reflection::
|
||||
|
||||
>>> sim hkl [0 1 1]
|
||||
sixc would move to:
|
||||
mu : 0.0000
|
||||
delta : 90.0000
|
||||
gam : 0.0000
|
||||
eta : 45.0000
|
||||
chi : 45.0000
|
||||
phi : 90.0000
|
||||
|
||||
alpha : 30.0000
|
||||
beta : 30.0000
|
||||
naz : 35.2644
|
||||
psi : 90.0000
|
||||
qaz : 90.0000
|
||||
tau : 45.0000
|
||||
theta : 45.0000
|
||||
|
||||
Move to reflection::
|
||||
|
||||
>>> pos hkl [0 1 1]
|
||||
hkl: h: 0.00000 k: 1.00000 l: 1.00000
|
||||
|
||||
>>> pos sixc
|
||||
sixc: mu: 0.0000 delta: 90.0000 gam: 0.0000 eta: 45.0000 chi: 45.0000 phi: 90.0000
|
||||
|
||||
|
||||
Scanning in hkl space
|
||||
---------------------
|
||||
|
||||
Scan an hkl axis (and read back settings)::
|
||||
|
||||
>>> scan l 0 1 .2 sixc
|
||||
l mu delta gam eta chi phi
|
||||
------- ------- -------- ------- -------- ------- --------
|
||||
0.00000 0.0000 60.0000 0.0000 30.0000 0.0000 90.0000
|
||||
0.20000 0.0000 61.3146 0.0000 30.6573 11.3099 90.0000
|
||||
0.40000 0.0000 65.1654 0.0000 32.5827 21.8014 90.0000
|
||||
0.60000 0.0000 71.3371 0.0000 35.6685 30.9638 90.0000
|
||||
0.80000 0.0000 79.6302 0.0000 39.8151 38.6598 90.0000
|
||||
1.00000 0.0000 90.0000 0.0000 45.0000 45.0000 90.0000
|
||||
|
||||
Scan a constraint (and read back virtual angles and eta)::
|
||||
|
||||
>>> con psi
|
||||
gam : 0.0000
|
||||
! psi : ---
|
||||
mu : 0.0000
|
||||
>>> scan psi 70 110 10 hklverbose [0 1 1] eta
|
||||
psi eta h k l theta qaz alpha naz tau psi beta
|
||||
-------- -------- ------- ------- ------- -------- -------- -------- -------- -------- -------- --------
|
||||
70.00000 26.1183 0.00000 1.00000 1.00000 45.00000 90.00000 19.20748 45.28089 45.00000 70.00000 42.14507
|
||||
80.00000 35.1489 -0.00000 1.00000 1.00000 45.00000 90.00000 24.40450 40.12074 45.00000 80.00000 35.93196
|
||||
90.00000 45.0000 0.00000 1.00000 1.00000 45.00000 90.00000 30.00000 35.26439 45.00000 90.00000 30.00000
|
||||
100.00000 54.8511 -0.00000 1.00000 1.00000 45.00000 90.00000 35.93196 30.68206 45.00000 100.00000 24.40450
|
||||
110.00000 63.8817 -0.00000 1.00000 1.00000 45.00000 90.00000 42.14507 26.34100 45.00000 110.00000 19.20748
|
||||
|
||||
|
||||
Orientation Commands
|
||||
--------------------
|
||||
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **STATE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- newub** {'name'} | start a new ub calculation name |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- loadub** 'name' | num | load an existing ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- lastub** | load the last used ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- listub** | list the ub calculations available to load |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- rmub** 'name'|num | remove existing ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- saveubas** 'name' | save the ub calculation with a new name |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **LATTICE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** | interactively enter lattice parameters (Angstroms |
|
||||
| | and Deg) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a | assumes cubic |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b | assumes tetragonal |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | assumes ortho |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | assumes mon/hex with gam not equal to 90 |
|
||||
| gamma | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | arbitrary |
|
||||
| alpha beta gamma | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- c2th** [h k l] | calculate two-theta angle for reflection |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- hklangle** [h1 k1 l1] | calculate angle between [h1 k1 l1] and [h2 k2 l2] |
|
||||
| [h2 k2 l2] | crystal planes |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **REFERENCE (SURFACE)** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setnphi** {[x y z]} | sets or displays n_phi reference |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setnhkl** {[h k l]} | sets or displays n_hkl reference |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **REFLECTIONS** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- showref** | shows full reflection list |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** | add reflection interactively |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** [h k l] | add reflection with current position and energy |
|
||||
| {'tag'} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** [h k l] (p1, | add arbitrary reflection |
|
||||
| .., pN) energy {'tag'} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- editref** num | interactively edit a reflection |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- delref** num | deletes a reflection (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- clearref** | deletes all the reflections |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swapref** | swaps first two reflections used for calculating |
|
||||
| | U matrix |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swapref** num1 num2 | swaps two reflections (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **CRYSTAL ORIENTATIONS** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- showorient** | shows full list of crystal orientations |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addorient** | add crystal orientation interactively |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addorient** [h k l] | add crystal orientation in laboratory frame |
|
||||
| [x y z] {'tag'} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- editorient** num | interactively edit a crystal orientation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- delorient** num | deletes a crystal orientation (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- clearorient** | deletes all the crystal orientations |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swaporient** | swaps first two crystal orientations used for |
|
||||
| | calculating U matrix |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swaporient** num1 num2 | swaps two crystal orientations (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **UB MATRIX** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- checkub** | show calculated and entered hkl values for |
|
||||
| | reflections |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setu** | manually set u matrix |
|
||||
| {[[..][..][..]]} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setub** | manually set ub matrix |
|
||||
| {[[..][..][..]]} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- calcub** | (re)calculate u matrix from ref1 and ref2 |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- trialub** | (re)calculate u matrix from ref1 only (check |
|
||||
| | carefully) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- refineub** {[h k l]} | refine unit cell dimensions and U matrix to match |
|
||||
| {pos} | diffractometer angles for a given hkl value |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addmiscut** angle | apply miscut to U matrix using a specified miscut |
|
||||
| {[x y z]} | angle in degrees and a rotation axis |
|
||||
| | (default: [0 1 0]) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setmiscut** angle | manually set U matrix using a specified miscut |
|
||||
| {[x y z]} | angle in degrees and a rotation axis |
|
||||
| | (default: [0 1 0]) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
|
||||
Motion Commands
|
||||
---------------
|
||||
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **CONSTRAINTS** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** | list available constraints and values |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** <name> {val} | constrains and optionally sets one constraint |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** <name> {val} | clears and then fully constrains |
|
||||
| <name> {val} <name> {val} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- uncon** <name> | remove constraint |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **HKL** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- allhkl** [h k l] | print all hkl solutions ignoring limits |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **HARDWARE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- hardware** | show diffcalc limits and cuts |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setcut** {name {val}} | sets cut angle |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setmin** {axis {val}} | set lower limits used by auto sector code (None |
|
||||
| | to clear) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setmax** {name {val}} | sets upper limits used by auto sector code (None |
|
||||
| | to clear) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **MOTION** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** hkl scn | simulates moving scannable (not all) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sixc** | show Eularian position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** sixc [mu, delta, | move to Eularian position(None holds an axis |
|
||||
| gam, eta, chi, phi] | still) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** sixc [mu, delta, | simulate move to Eulerian positionsixc |
|
||||
| gam, eta, chi, phi] | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- hkl** | show hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** hkl [h k l] | move to hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** {h | k | l} val | move h, k or l to val |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** hkl [h k l] | simulate move to hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
.. [You1999] H. You. *Angle calculations for a '4S+2D' six-circle diffractometer.*
|
||||
J. Appl. Cryst. (1999). **32**, 614-623. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1999/04/00/hn0093/hn0093.pdf>`__.
|
||||
|
||||
.. [Busing1967] W. R. Busing and H. A. Levy. *Angle calculations for 3- and 4-circle X-ray
|
||||
and neutron diffractometers.* Acta Cryst. (1967). **22**, 457-464. `(pdf link)
|
||||
<http://journals.iucr.org/q/issues/1967/04/00/a05492/a05492.pdf>`__.
|
||||
|
||||
.. [Vlieg1993] Martin Lohmeier and Elias Vlieg. *Angle calculations for a six-circle
|
||||
surface x-ray diffractometer.* J. Appl. Cryst. (1993). **26**, 706-716. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1993/05/00/la0044/la0044.pdf>`__.
|
||||
|
||||
.. [Vlieg1998] Elias Vlieg. *A (2+3)-type surface diffractometer: mergence of the z-axis and
|
||||
(2+2)-type geometries.* J. Appl. Cryst. (1998). **31**, 198-203. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1998/02/00/pe0028/pe0028.pdf>`__.
|
||||
|
||||
.. [Willmott2011] C. M. Schlepütz, S. O. Mariager, S. A. Pauli, R. Feidenhans'l and
|
||||
P. R. Willmott. *Angle calculations for a (2+3)-type diffractometer: focus
|
||||
on area detectors.* J. Appl. Cryst. (2011). **44**, 73-83. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/2011/01/00/db5088/db5088.pdf>`__.
|
||||
267
script/__Lib/diffcalc-2.1/README_template.rst
Executable file
267
script/__Lib/diffcalc-2.1/README_template.rst
Executable file
@@ -0,0 +1,267 @@
|
||||
Diffcalc - A Diffraction Condition Calculator for Diffractometer Control
|
||||
========================================================================
|
||||
|
||||
Diffcalc is a python/jython based diffraction condition calculator used for
|
||||
controlling diffractometers within reciprocal lattice space. It performs the
|
||||
same task as the fourc, sixc, twoc, kappa, psic and surf macros from SPEC.
|
||||
|
||||
There is a `user guide <https://diffcalc.readthedocs.io/en/latest/youmanual.html>`_ and `developer guide <https://diffcalc.readthedocs.io/en/latest/developer/contents.html>`_, both at `diffcalc.readthedocs.io <https://diffcalc.readthedocs.io>`_
|
||||
|
||||
|Travis| |Read the docs|
|
||||
|
||||
.. |Travis| image:: https://travis-ci.org/DiamondLightSource/diffcalc.svg?branch=master
|
||||
:target: https://travis-ci.org/DiamondLightSource/diffcalc
|
||||
:alt: Build Status
|
||||
|
||||
.. |Read the docs| image:: https://readthedocs.org/projects/diffcalc/badge/?version=latest
|
||||
:target: http://diffcalc.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. contents::
|
||||
|
||||
.. section-numbering::
|
||||
|
||||
Software compatibility
|
||||
----------------------
|
||||
|
||||
- Written in Python using numpy
|
||||
- Works in Jython using Jama
|
||||
- Runs directly in `OpenGDA<http://www.opengda.org>`
|
||||
- Runs in in Python or IPython using minimal OpenGda emulation (included)
|
||||
- Contact us for help running in your environment
|
||||
|
||||
Diffractometer compatibility
|
||||
----------------------------
|
||||
|
||||
Diffcalc’s standard calculation engine is an implementation of [You1999]_ and
|
||||
[Busing1967]_. Diffcalc works with any diffractometer which is a subset of:
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/DiamondLightSource/diffcalc/master/doc/source/youmanual_images/4s_2d_diffractometer.png
|
||||
:alt: 4s + 2d six-circle diffractometer, from H.You (1999)
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
Diffcalc can be configured to work with any diffractometer geometry which is a
|
||||
subset of this. For example, a five-circle diffractometer might be missing the
|
||||
nu circle above.
|
||||
|
||||
Note that the first versions of Diffcalc were based on [Vlieg1993]_ and
|
||||
[Vlieg1998]_ and a ‘Vlieg’ engine is still available. There is also an engine
|
||||
based on [Willmott2011]_. The ‘You’ engine is more generic and the plan is to
|
||||
remove the old ‘Vlieg’ engine once beamlines have been migrated.
|
||||
|
||||
If we choose the x axis parallel to b, the yaxis intheplaneofblandb2,andthezaxis perpendicular to that plane,
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Check it out::
|
||||
|
||||
$ git clone https://github.com/DiamondLightSource/diffcalc.git
|
||||
Cloning into 'diffcalc'...
|
||||
|
||||
At Diamond Diffcalc may be installed within an OpenGDA deployment and is
|
||||
available via the 'module' system from bash.
|
||||
|
||||
Starting
|
||||
--------
|
||||
|
||||
Start diffcalc in ipython using a sixcircle dummy diffractometer::
|
||||
|
||||
$ cd diffcalc
|
||||
$ ./diffcalc.py --help
|
||||
...
|
||||
|
||||
$ ./diffcalc.py sixcircle
|
||||
|
||||
Running: "ipython --no-banner --HistoryManager.hist_file=/tmp/ipython_hist_zrb13439.sqlite -i -m diffcmd.start sixcircle False"
|
||||
|
||||
---------------------------------- DIFFCALC -----------------------------------
|
||||
Startup script: '/Users/zrb13439/git/diffcalc/startup/sixcircle.py'
|
||||
Loading ub calculation: 'test'
|
||||
------------------------------------ Help -------------------------------------
|
||||
Quick: https://github.com/DiamondLightSource/diffcalc/blob/master/README.rst
|
||||
Manual: https://diffcalc.readthedocs.io
|
||||
Type: > help ub
|
||||
> help hkl
|
||||
-------------------------------------------------------------------------------
|
||||
In [1]:
|
||||
|
||||
Within Diamond use::
|
||||
|
||||
$ module load diffcalc
|
||||
$ diffcalc --help
|
||||
...
|
||||
$ diffcalc sixcircle
|
||||
|
||||
Trying it out
|
||||
-------------
|
||||
|
||||
Type ``demo.all()`` to see it working and then move try the following quick
|
||||
start guide::
|
||||
|
||||
>>> demo.all()
|
||||
...
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
To view help with orientation and then moving in hkl space::
|
||||
|
||||
>>> help ub
|
||||
...
|
||||
>>> help hkl
|
||||
...
|
||||
|
||||
Configuring a UB calculation
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To load the last used UB-calculation::
|
||||
|
||||
>>> lastub
|
||||
Loading ub calculation: 'mono-Si'
|
||||
|
||||
To load a previous UB-calculation::
|
||||
|
||||
>>> listub
|
||||
UB calculations in: /Users/walton/.diffcalc/i16
|
||||
|
||||
0) mono-Si 15 Feb 2017 (22:32)
|
||||
1) i16-32 13 Feb 2017 (18:32)
|
||||
|
||||
>>> loadub 0
|
||||
|
||||
To create a new UB-calculation::
|
||||
|
||||
==> newub 'example'
|
||||
==> setlat '1Acube' 1 1 1 90 90 90
|
||||
|
||||
where the basis is defined by Busing & Levy:
|
||||
|
||||
"...we choose the x axis parallel to b, the y axis in the plane of bl
|
||||
and b2, and the zaxis perpendicular to that plane."
|
||||
|
||||
|
||||
Find U matrix from two reflections::
|
||||
|
||||
==> pos wl 1
|
||||
==> c2th [0 0 1]
|
||||
59.99999999999999
|
||||
|
||||
==> pos sixc [0 60 0 30 90 0]
|
||||
==> addref [0 0 1]
|
||||
|
||||
==> pos sixc [0 90 0 45 45 90]
|
||||
==> addref [0 1 1]
|
||||
|
||||
|
||||
Check that it looks good::
|
||||
|
||||
==> checkub
|
||||
|
||||
To see the resulting UB-calculation::
|
||||
|
||||
==> ub
|
||||
|
||||
Setting the reference vector
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
By default the reference vector is set parallel to the phi axis. That is,
|
||||
along the z-axis of the phi coordinate frame.
|
||||
|
||||
The `ub` command shows the current reference vector, along with any inferred
|
||||
miscut, at the top its report (or it can be shown by calling ``setnphi`` or
|
||||
``setnhkl'`` with no args)::
|
||||
|
||||
>>> ub
|
||||
...
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
...
|
||||
|
||||
Constraining solutions for moving in hkl space
|
||||
----------------------------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To get help and see current constraints::
|
||||
|
||||
>>> help con
|
||||
...
|
||||
|
||||
==> con
|
||||
|
||||
Three constraints can be given: zero or one from the DET and REF columns and the
|
||||
remainder from the SAMP column. Not all combinations are currently available.
|
||||
Use ``help con`` to see a summary if you run into troubles.
|
||||
|
||||
To configure four-circle vertical scattering::
|
||||
|
||||
==> con gam 0 mu 0 a_eq_b
|
||||
|
||||
Moving in hkl space
|
||||
-------------------
|
||||
|
||||
Simulate moving to a reflection::
|
||||
|
||||
==> sim hkl [0 1 1]
|
||||
|
||||
Move to reflection::
|
||||
|
||||
==> pos hkl [0 1 1]
|
||||
|
||||
==> pos sixc
|
||||
|
||||
|
||||
Scanning in hkl space
|
||||
---------------------
|
||||
|
||||
Scan an hkl axis (and read back settings)::
|
||||
|
||||
==> scan l 0 1 .2 sixc
|
||||
|
||||
Scan a constraint (and read back virtual angles and eta)::
|
||||
|
||||
==> con psi
|
||||
==> scan psi 70 110 10 hklverbose [0 1 1] eta
|
||||
|
||||
|
||||
Orientation Commands
|
||||
--------------------
|
||||
|
||||
==> UB_HELP_TABLE
|
||||
|
||||
Motion Commands
|
||||
---------------
|
||||
|
||||
==> HKL_HELP_TABLE
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
.. [You1999] H. You. *Angle calculations for a '4S+2D' six-circle diffractometer.*
|
||||
J. Appl. Cryst. (1999). **32**, 614-623. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1999/04/00/hn0093/hn0093.pdf>`__.
|
||||
|
||||
.. [Busing1967] W. R. Busing and H. A. Levy. *Angle calculations for 3- and 4-circle X-ray
|
||||
and neutron diffractometers.* Acta Cryst. (1967). **22**, 457-464. `(pdf link)
|
||||
<http://journals.iucr.org/q/issues/1967/04/00/a05492/a05492.pdf>`__.
|
||||
|
||||
.. [Vlieg1993] Martin Lohmeier and Elias Vlieg. *Angle calculations for a six-circle
|
||||
surface x-ray diffractometer.* J. Appl. Cryst. (1993). **26**, 706-716. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1993/05/00/la0044/la0044.pdf>`__.
|
||||
|
||||
.. [Vlieg1998] Elias Vlieg. *A (2+3)-type surface diffractometer: mergence of the z-axis and
|
||||
(2+2)-type geometries.* J. Appl. Cryst. (1998). **31**, 198-203. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1998/02/00/pe0028/pe0028.pdf>`__.
|
||||
|
||||
.. [Willmott2011] C. M. Schlepütz, S. O. Mariager, S. A. Pauli, R. Feidenhans'l and
|
||||
P. R. Willmott. *Angle calculations for a (2+3)-type diffractometer: focus
|
||||
on area detectors.* J. Appl. Cryst. (2011). **44**, 73-83. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/2011/01/00/db5088/db5088.pdf>`__.
|
||||
5
script/__Lib/diffcalc-2.1/buckminster.cspec
Executable file
5
script/__Lib/diffcalc-2.1/buckminster.cspec
Executable file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><cs:cspec xmlns:cs="http://www.eclipse.org/buckminster/CSpec-1.0" name="diffcalc" componentType="buckminster" version="1.1.0">
|
||||
<cs:artifacts>
|
||||
<cs:public name="containsDocumentationSource"/>
|
||||
</cs:artifacts>
|
||||
</cs:cspec>
|
||||
9
script/__Lib/diffcalc-2.1/diffcalc.py
Executable file
9
script/__Lib/diffcalc-2.1/diffcalc.py
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
|
||||
from diffcmd.diffcalc_launcher import main
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/dc/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/dc/__init__.py
Executable file
24
script/__Lib/diffcalc-2.1/diffcalc/dc/common.py
Executable file
24
script/__Lib/diffcalc-2.1/diffcalc/dc/common.py
Executable file
@@ -0,0 +1,24 @@
|
||||
from diffcalc.util import allnum, command, DiffcalcException
|
||||
|
||||
|
||||
def sim(scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError()
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"The first argument does not support simulated moves")
|
||||
|
||||
def energy_to_wavelength(energy):
|
||||
try:
|
||||
return 12.39842 / energy
|
||||
except ZeroDivisionError:
|
||||
raise DiffcalcException(
|
||||
"Cannot calculate hkl position as Energy is set to 0")
|
||||
76
script/__Lib/diffcalc-2.1/diffcalc/dc/dcvlieg.py
Executable file
76
script/__Lib/diffcalc-2.1/diffcalc/dc/dcvlieg.py
Executable file
@@ -0,0 +1,76 @@
|
||||
from diffcalc.dc.common import energy_to_wavelength
|
||||
|
||||
from diffcalc import settings
|
||||
from diffcalc.hkl.vlieg.transform import VliegTransformSelector,\
|
||||
TransformCommands, VliegPositionTransformer
|
||||
from diffcalc.dc.help import compile_extra_motion_commands_for_help
|
||||
import diffcalc.hkl.vlieg.calc
|
||||
|
||||
|
||||
# reload to aid testing only
|
||||
import diffcalc.ub.ub as _ub
|
||||
reload(_ub)
|
||||
from diffcalc import hardware as _hardware
|
||||
#reload(_hardware)
|
||||
import diffcalc.hkl.vlieg.hkl as _hkl
|
||||
reload(_hkl)
|
||||
|
||||
from diffcalc.ub.ub import * # @UnusedWildImport
|
||||
from diffcalc.hardware import * # @UnusedWildImport
|
||||
from diffcalc.hkl.vlieg.hkl import * # @UnusedWildImport
|
||||
from diffcalc.gdasupport.scannable.sim import sim
|
||||
|
||||
_transform_selector = VliegTransformSelector()
|
||||
_transform_commands = TransformCommands(_transform_selector)
|
||||
_transformer = VliegPositionTransformer(settings.geometry, settings.hardware,
|
||||
_transform_selector)
|
||||
|
||||
transform = _transform_commands.transform
|
||||
transforma = _transform_commands.transforma
|
||||
transformb = _transform_commands.transformb
|
||||
transformc = _transform_commands.transformc
|
||||
|
||||
|
||||
on = 'on'
|
||||
off = 'off'
|
||||
auto = 'auto'
|
||||
manual = 'manual'
|
||||
|
||||
def hkl_to_angles(h, k, l, energy=None):
|
||||
"""Convert a given hkl vector to a set of diffractometer angles"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
position, params = hklcalc.hklToAngles(h, k, l, energy_to_wavelength(energy))
|
||||
position = _transformer.transform(position)
|
||||
angle_tuple = settings.geometry.internal_position_to_physical_angles(position) # @UndefinedVariable
|
||||
angle_tuple = settings.hardware.cut_angles(angle_tuple) # @UndefinedVariable
|
||||
|
||||
return angle_tuple, params
|
||||
|
||||
|
||||
def angles_to_hkl(angleTuple, energy=None):
|
||||
"""Converts a set of diffractometer angles to an hkl position
|
||||
((h, k, l), paramDict)=angles_to_hkl(self, (a1, a2,aN), energy=None)"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
i_pos = settings.geometry.physical_angles_to_internal_position(angleTuple) # @UndefinedVariable
|
||||
return hklcalc.anglesToHkl(i_pos, energy_to_wavelength(energy))
|
||||
|
||||
|
||||
settings.ubcalc_strategy = diffcalc.hkl.vlieg.calc.VliegUbCalcStrategy()
|
||||
settings.angles_to_hkl_function = diffcalc.hkl.vlieg.calc.vliegAnglesToHkl
|
||||
settings.include_sigtau = True
|
||||
|
||||
ub_commands_for_help = _ub.commands_for_help
|
||||
|
||||
hkl_commands_for_help = (_hkl.commands_for_help +
|
||||
_hardware.commands_for_help +
|
||||
['Transform',
|
||||
transform,
|
||||
transforma,
|
||||
transformb,
|
||||
transformc] +
|
||||
compile_extra_motion_commands_for_help())
|
||||
|
||||
47
script/__Lib/diffcalc-2.1/diffcalc/dc/dcwillmot.py
Executable file
47
script/__Lib/diffcalc-2.1/diffcalc/dc/dcwillmot.py
Executable file
@@ -0,0 +1,47 @@
|
||||
# This file differs from dcyou in only two places
|
||||
|
||||
from diffcalc import settings
|
||||
from diffcalc.dc.common import energy_to_wavelength
|
||||
from diffcalc.dc.help import compile_extra_motion_commands_for_help
|
||||
import diffcalc.hkl.willmott.calc
|
||||
|
||||
|
||||
# reload to aid testing only
|
||||
from diffcalc.ub import ub as _ub
|
||||
reload(_ub)
|
||||
from diffcalc import hardware as _hardware
|
||||
#reload(_hardware)
|
||||
from diffcalc.hkl.you import hkl as _hkl
|
||||
reload(_hkl)
|
||||
|
||||
from diffcalc.ub.ub import * # @UnusedWildImport
|
||||
from diffcalc.hardware import * # @UnusedWildImport
|
||||
from diffcalc.hkl.willmot.hkl import * # @UnusedWildImport
|
||||
from diffcalc.gdasupport.scannable.sim import sim
|
||||
|
||||
def hkl_to_angles(h, k, l, energy=None):
|
||||
"""Convert a given hkl vector to a set of diffractometer angles"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
(pos, params) = hklcalc.hklToAngles(h, k, l, energy_to_wavelength(energy))
|
||||
angle_tuple = settings.geometry.internal_position_to_physical_angles(pos) # @UndefinedVariable
|
||||
angle_tuple = settings.hardware.cut_angles(angle_tuple) # @UndefinedVariable
|
||||
|
||||
return angle_tuple, params
|
||||
|
||||
def angles_to_hkl(angleTuple, energy=None):
|
||||
"""Converts a set of diffractometer angles to an hkl position
|
||||
((h, k, l), paramDict)=angles_to_hkl(self, (a1, a2,aN), energy=None)"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
i_pos = settings.geometry.physical_angles_to_internal_position(angleTuple) # @UndefinedVariable
|
||||
return hklcalc.anglesToHkl(i_pos, energy_to_wavelength(energy))
|
||||
|
||||
settings.ubcalc_strategy = diffcalc.hkl.willmott.calc.WillmottHorizontalUbCalcStrategy()
|
||||
settings.angles_to_hkl_function = diffcalc.hkl.willmott.calc.angles_to_hkl
|
||||
|
||||
|
||||
ub_commands_for_help = _ub.commands_for_help
|
||||
|
||||
hkl_commands_for_help = _hkl.commands_for_help + _hardware.commands_for_help + compile_extra_motion_commands_for_help()
|
||||
56
script/__Lib/diffcalc-2.1/diffcalc/dc/dcyou.py
Executable file
56
script/__Lib/diffcalc-2.1/diffcalc/dc/dcyou.py
Executable file
@@ -0,0 +1,56 @@
|
||||
from diffcalc import settings
|
||||
from diffcalc.dc.common import energy_to_wavelength
|
||||
from diffcalc.dc.help import compile_extra_motion_commands_for_help
|
||||
|
||||
import diffcalc.hkl.you.calc
|
||||
settings.ubcalc_strategy = diffcalc.hkl.you.calc.YouUbCalcStrategy()
|
||||
settings.angles_to_hkl_function = diffcalc.hkl.you.calc.youAnglesToHkl
|
||||
settings.include_reference = True
|
||||
|
||||
# reload to aid testing only
|
||||
from diffcalc.ub import ub as _ub
|
||||
|
||||
reload(_ub)
|
||||
from diffcalc import hardware as _hardware
|
||||
#reload(_hardware)
|
||||
from diffcalc.hkl.you import hkl as _hkl
|
||||
reload(_hkl)
|
||||
|
||||
from diffcalc.ub.ub import * # @UnusedWildImport
|
||||
from diffcalc.hardware import * # @UnusedWildImport
|
||||
from diffcalc.hkl.you.hkl import * # @UnusedWildImport
|
||||
|
||||
|
||||
def hkl_to_angles(h, k, l, energy=None):
|
||||
"""Convert a given hkl vector to a set of diffractometer angles
|
||||
|
||||
return angle tuple and params dictionary
|
||||
|
||||
"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
(pos, params) = hklcalc.hklToAngles(h, k, l, energy_to_wavelength(energy))
|
||||
angle_tuple = settings.geometry.internal_position_to_physical_angles(pos) # @UndefinedVariable
|
||||
angle_tuple = settings.hardware.cut_angles(angle_tuple) # @UndefinedVariable
|
||||
|
||||
return angle_tuple, params
|
||||
|
||||
|
||||
def angles_to_hkl(angleTuple, energy=None):
|
||||
"""Converts a set of diffractometer angles to an hkl position
|
||||
|
||||
Return hkl tuple and params dictionary
|
||||
|
||||
"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
i_pos = settings.geometry.physical_angles_to_internal_position(angleTuple) # @UndefinedVariable
|
||||
return hklcalc.anglesToHkl(i_pos, energy_to_wavelength(energy))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ub_commands_for_help = _ub.commands_for_help
|
||||
hkl_commands_for_help = _hkl.commands_for_help + _hardware.commands_for_help + compile_extra_motion_commands_for_help()
|
||||
161
script/__Lib/diffcalc-2.1/diffcalc/dc/help.py
Executable file
161
script/__Lib/diffcalc-2.1/diffcalc/dc/help.py
Executable file
@@ -0,0 +1,161 @@
|
||||
'''
|
||||
Created on 6 May 2016
|
||||
|
||||
@author: walton
|
||||
'''
|
||||
from diffcalc import settings
|
||||
from diffcalc.gdasupport.scannable.sim import sim
|
||||
import textwrap
|
||||
from diffcalc.util import bold
|
||||
|
||||
|
||||
class ExternalCommand(object):
|
||||
"""Instances found in a command_list by format_command_help will
|
||||
result in documentation for a command without there actually being one.
|
||||
"""
|
||||
def __init__(self, docstring):
|
||||
"""Set the docstring that will be pulled off by format_command_help.
|
||||
"""
|
||||
self.__doc__ = docstring
|
||||
self.__name__ = ''
|
||||
|
||||
|
||||
WIDTH = 27
|
||||
INDENT = 3
|
||||
|
||||
|
||||
def format_command_help(command_list):
|
||||
|
||||
row_list = _command_list_to_table_cells(command_list)
|
||||
lines = []
|
||||
for row_cells in row_list:
|
||||
if len(row_cells) == 1:
|
||||
heading = row_cells[0]
|
||||
lines.append('')
|
||||
lines.append(bold(heading))
|
||||
lines.append('')
|
||||
elif len(row_cells) == 2:
|
||||
cell1, cell2 = row_cells
|
||||
|
||||
cell1_lines = textwrap.wrap(cell1, WIDTH, subsequent_indent=' ')
|
||||
cell2_lines = textwrap.wrap(cell2, 79 - INDENT - 3 - WIDTH)
|
||||
|
||||
first_line = True
|
||||
while cell1_lines or cell2_lines:
|
||||
line = ' ' * INDENT
|
||||
if cell1_lines:
|
||||
line += cell1_lines.pop(0).ljust(WIDTH)
|
||||
else:
|
||||
line += ' ' * (WIDTH)
|
||||
line += ' : ' if first_line else ' '
|
||||
if cell2_lines:
|
||||
line += cell2_lines.pop(0)
|
||||
lines.append(line)
|
||||
first_line = False
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def format_commands_for_rst_table(title, command_list):
|
||||
W1 = WIDTH # internal width
|
||||
W2 = 79 - W1 - 3 # internal width
|
||||
HORIZ_LINE = '+-' + '-' * W1 + '-+-' + '-' * W2 + '-+'
|
||||
|
||||
row_list = _command_list_to_table_cells(command_list)
|
||||
|
||||
lines = []
|
||||
|
||||
lines.append(HORIZ_LINE) # Top line
|
||||
for row_cells in row_list:
|
||||
if len(row_cells) == 1:
|
||||
lines.append('| ' + ('**' + row_cells[0] + '**').ljust(W1 + W2 + 3) + ' |')
|
||||
|
||||
elif len(row_cells) == 2:
|
||||
cmd_and_args = row_cells[0].split(' ', 1)
|
||||
cmd = cmd_and_args[0]
|
||||
args = cmd_and_args[1] if len(cmd_and_args) == 2 else ''
|
||||
cell1 = '**-- %s** %s' % (cmd, args)
|
||||
cell1_lines = textwrap.wrap(cell1, W1) #, subsequent_indent=' ')
|
||||
cell2_lines = textwrap.wrap(row_cells[1], W2)
|
||||
|
||||
while cell1_lines or cell2_lines:
|
||||
line = '| '
|
||||
line += (cell1_lines.pop(0) if cell1_lines else '').ljust(W1)
|
||||
line += ' | '
|
||||
line += (cell2_lines.pop(0) if cell2_lines else '').ljust(W2)
|
||||
line += ' |'
|
||||
lines.append(line)
|
||||
|
||||
else:
|
||||
assert False
|
||||
|
||||
lines.append(HORIZ_LINE)
|
||||
return lines
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _command_list_to_table_cells(command_list):
|
||||
row_list = []
|
||||
for obj in command_list:
|
||||
|
||||
if isinstance(obj, basestring): # group heading
|
||||
row_list.append([obj.upper()])
|
||||
|
||||
else: # individual command
|
||||
doc_before_empty_line = obj.__doc__.split('\n\n')[0]
|
||||
doc_lines = [s.strip() for s in doc_before_empty_line.split('\n')]
|
||||
for doc_line in doc_lines:
|
||||
if doc_line == '':
|
||||
continue
|
||||
if obj.__name__ in ('ub', 'hkl'):
|
||||
continue
|
||||
name, args, desc = _split_doc_line(doc_line)
|
||||
desc = desc.strip()
|
||||
args = args.strip()
|
||||
if desc and desc[-1] == '.':
|
||||
desc = desc[:-1]
|
||||
|
||||
row_list.append([name + (' ' if args else '') + args, desc])
|
||||
|
||||
return row_list
|
||||
|
||||
|
||||
def _split_doc_line(docLine):
|
||||
name, _, right = docLine.partition(' ')
|
||||
args, _, desc = right.partition('-- ')
|
||||
return name, args, desc
|
||||
|
||||
|
||||
def compile_extra_motion_commands_for_help():
|
||||
|
||||
_hwname = settings.hardware.name # @UndefinedVariable
|
||||
_angles = ', '.join(settings.hardware.get_axes_names()) # @UndefinedVariable
|
||||
|
||||
commands = []
|
||||
|
||||
commands.append('Motion')
|
||||
commands.append(sim)
|
||||
commands.append(ExternalCommand(
|
||||
'%(_hwname)s -- show Eularian position' % vars()))
|
||||
commands.append(ExternalCommand(
|
||||
'pos %(_hwname)s [%(_angles)s] -- move to Eularian position'
|
||||
'(None holds an axis still)' % vars()))
|
||||
commands.append(ExternalCommand(
|
||||
'sim %(_hwname)s [%(_angles)s] -- simulate move to Eulerian position'
|
||||
'%(_hwname)s' % vars()))
|
||||
|
||||
commands.append(ExternalCommand(
|
||||
'hkl -- show hkl position'))
|
||||
commands.append(ExternalCommand(
|
||||
'pos hkl [h k l] -- move to hkl position'))
|
||||
commands.append(ExternalCommand(
|
||||
'pos {h | k | l} val -- move h, k or l to val'))
|
||||
commands.append(ExternalCommand(
|
||||
'sim hkl [h k l] -- simulate move to hkl position'))
|
||||
|
||||
# if engine_name != 'vlieg':
|
||||
# pass
|
||||
# # TODO: remove sigtau command and 'Surface' string
|
||||
return commands
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/minigda/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/minigda/__init__.py
Executable file
322
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/minigda/command.py
Executable file
322
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/minigda/command.py
Executable file
@@ -0,0 +1,322 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
#try:
|
||||
# from gda.device import Scannable
|
||||
#except ImportError:
|
||||
# from diffcalc.gdasupport.minigda.scannable import Scannable
|
||||
from diffcalc.gdasupport.minigda.scannable import Scannable
|
||||
from diffcalc.util import getMessageFromException, allnum, bold
|
||||
import math
|
||||
|
||||
|
||||
ROOT_NAMESPACE_DICT = {}
|
||||
|
||||
class Pos(object):
|
||||
|
||||
def __init__(self):
|
||||
self.__name__ = 'pos'
|
||||
|
||||
def __call__(self, *posargs):
|
||||
if len(posargs) == 0:
|
||||
|
||||
keys = dict(ROOT_NAMESPACE_DICT).keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
val = ROOT_NAMESPACE_DICT[key]
|
||||
if isinstance(val, Scannable):
|
||||
print self.posReturningReport(val)
|
||||
else:
|
||||
print self.posReturningReport(*posargs)
|
||||
|
||||
def posReturningReport(self, *posargs):
|
||||
# report position of this scannable
|
||||
if len(posargs) == 1:
|
||||
scannable = posargs[0]
|
||||
self._assert_scannable(scannable)
|
||||
return self._generatePositionReport(scannable)
|
||||
|
||||
# Move the scannable and report
|
||||
elif len(posargs) == 2:
|
||||
scannable = posargs[0]
|
||||
self._assert_scannable(scannable)
|
||||
# Move it
|
||||
scannable.asynchronousMoveTo(posargs[1])
|
||||
# TODO: minigda assumes all moves complete instantly, so no need
|
||||
# yet to check the move is complete
|
||||
return self._generatePositionReport(scannable)
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
"Invlaid arguements: 'pos [ scannable [ value ] ]'")
|
||||
|
||||
def _assert_scannable(self, obj):
|
||||
if not isinstance(obj, Scannable):
|
||||
raise TypeError(
|
||||
"The first argument to the pos command must be scannable. "
|
||||
"Not: " + str(type(obj)))
|
||||
|
||||
def _generatePositionReport(self, scannable):
|
||||
fieldNames = (tuple(scannable.getInputNames()) +
|
||||
tuple(scannable.getExtraNames()))
|
||||
# All scannables
|
||||
result = "%s:" % scannable.getName()
|
||||
result = result.ljust(10)
|
||||
try:
|
||||
pos = scannable.getPosition()
|
||||
except Exception, e:
|
||||
return result + "Error: %s" % getMessageFromException(e)
|
||||
if pos is None:
|
||||
return result + "---"
|
||||
# Single field scannable:
|
||||
if len(fieldNames) == 1:
|
||||
try:
|
||||
result += "%s" % scannable.formatPositionFields(pos)[0]
|
||||
except AttributeError:
|
||||
result += str(scannable())
|
||||
# Multi field scannable:
|
||||
else:
|
||||
try:
|
||||
formatted = scannable.formatPositionFields(pos)
|
||||
for name, formattedValue in zip(fieldNames, formatted):
|
||||
result += "%s: %s " % (name, formattedValue)
|
||||
except AttributeError:
|
||||
result += str(scannable())
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class ScanDataHandler:
|
||||
def __init__(self):
|
||||
self.scannables = None
|
||||
|
||||
def callAtScanStart(self, scannables):
|
||||
pass
|
||||
|
||||
def callWithScanPoint(self, PositionDictIndexedByScannable):
|
||||
pass
|
||||
|
||||
def callAtScanEnd(self):
|
||||
pass
|
||||
|
||||
|
||||
class ScanDataPrinter(ScanDataHandler):
|
||||
|
||||
def __init__(self):
|
||||
self.first_point_printed = False
|
||||
self.widths = []
|
||||
self.scannables = []
|
||||
|
||||
def callAtScanStart(self, scannables):
|
||||
self.first_point_printed = False
|
||||
self.scannables = scannables
|
||||
|
||||
def print_first_point(self, position_dict):
|
||||
# also sets self.widths
|
||||
header_strings = []
|
||||
for scn in self.scannables:
|
||||
field_names = list(scn.getInputNames()) + list(scn.getExtraNames())
|
||||
if len(field_names) == 1:
|
||||
header_strings.append(scn.getName())
|
||||
else:
|
||||
for field_name in field_names:
|
||||
header_strings.append(field_name)
|
||||
|
||||
first_row_strings = []
|
||||
for scn in self.scannables:
|
||||
pos = position_dict[scn]
|
||||
first_row_strings.extend(scn.formatPositionFields(pos))
|
||||
|
||||
self.widths = []
|
||||
for header, pos_string in zip(header_strings, first_row_strings):
|
||||
self.widths.append(max(len(header), len(pos_string)))
|
||||
|
||||
header_cells = []
|
||||
for heading, width in zip(header_strings, self.widths):
|
||||
header_cells.append(heading.rjust(width))
|
||||
|
||||
underline_cells = ['-' * w for w in self.widths]
|
||||
|
||||
first_row_cells = []
|
||||
for pos, width in zip(first_row_strings, self.widths):
|
||||
first_row_cells.append(pos.rjust(width))
|
||||
|
||||
#table_width = sum(self.widths) + len(self.widths * 2) - 2
|
||||
lines = []
|
||||
#lines.append('=' * table_width)
|
||||
lines.append(bold(' '.join(header_cells)))
|
||||
lines.append(' '.join(underline_cells))
|
||||
lines.append(' '.join(first_row_cells))
|
||||
print '\n'.join(lines)
|
||||
|
||||
def callWithScanPoint(self, position_dict):
|
||||
if not self.first_point_printed:
|
||||
self.print_first_point(position_dict)
|
||||
self.first_point_printed = True
|
||||
else:
|
||||
row_strings = []
|
||||
for scn in self.scannables:
|
||||
pos = position_dict[scn]
|
||||
row_strings.extend(scn.formatPositionFields(pos))
|
||||
|
||||
row_cells = []
|
||||
for pos, width in zip(row_strings, self.widths):
|
||||
row_cells.append(pos.rjust(width))
|
||||
|
||||
print ' '.join(row_cells)
|
||||
|
||||
def callAtScanEnd(self):
|
||||
#table_width = sum(self.widths) + len(self.widths * 2) - 2
|
||||
#print '=' * table_width
|
||||
pass
|
||||
|
||||
|
||||
class Scan(object):
|
||||
class Group:
|
||||
def __init__(self, scannable):
|
||||
self.scannable = scannable
|
||||
self.args = []
|
||||
|
||||
def __cmp__(self, other):
|
||||
return(self.scannable.getLevel() - other.scannable.getLevel())
|
||||
|
||||
def __repr__(self):
|
||||
return "Group(%s, %s)" % (self.scannable.getName(), str(self.args))
|
||||
|
||||
def shouldTriggerLoop(self):
|
||||
return len(self.args) == 3
|
||||
|
||||
def __init__(self, scanDataHandlers):
|
||||
# scanDataHandlers should be list
|
||||
if type(scanDataHandlers) not in (tuple, list):
|
||||
scanDataHandlers = (scanDataHandlers,)
|
||||
self.dataHandlers = scanDataHandlers
|
||||
|
||||
def __call__(self, *scanargs):
|
||||
groups = self._parseScanArgsIntoScannableArgGroups(scanargs)
|
||||
groups = self._reorderInnerGroupsAccordingToLevel(groups)
|
||||
# Configure data handlers for a new scan
|
||||
for handler in self.dataHandlers: handler.callAtScanStart(
|
||||
[grp.scannable for grp in groups])
|
||||
# Perform the scan
|
||||
self._performScan(groups, currentRecursionLevel=0)
|
||||
# Inform data handlers of scan completion
|
||||
for handler in self.dataHandlers: handler.callAtScanEnd()
|
||||
|
||||
def _parseScanArgsIntoScannableArgGroups(self, scanargs):
|
||||
"""
|
||||
-> [ Group(scnA, (a1, a2, a2)), Group((scnB), (b1)), ...
|
||||
... Group((scnC),()), Group((scnD),(d1))]
|
||||
"""
|
||||
result = []
|
||||
if not isinstance(scanargs[0], Scannable):
|
||||
raise TypeError("First scan argument must be a scannable")
|
||||
|
||||
# Parse out scannables followed by non-scannable args
|
||||
for arg in scanargs:
|
||||
if isinstance(arg, Scannable):
|
||||
result.append(Scan.Group(arg))
|
||||
else:
|
||||
result[-1].args.append(arg)
|
||||
return result
|
||||
|
||||
def _reorderInnerGroupsAccordingToLevel(self, groups):
|
||||
# Find the first group not to trigger a loop
|
||||
for idx, group in enumerate(groups):
|
||||
if not group.shouldTriggerLoop():
|
||||
break
|
||||
latter = groups[idx:]; latter.sort() # Horrible hack not needed in python 3!
|
||||
return groups[:idx] + latter
|
||||
|
||||
def _performScan(self, groups, currentRecursionLevel):
|
||||
# groups[currentRecursionLevel:] will start with either:
|
||||
# a) A loop triggering group
|
||||
# b) A number (possibly 0) of non-loop triggering groups
|
||||
unprocessedGroups = groups[currentRecursionLevel:]
|
||||
|
||||
# 1) If first remaining group should trigger a loop, perform this loop,
|
||||
# recursively calling this method on the remaining groups
|
||||
if len(unprocessedGroups) > 0:
|
||||
first = unprocessedGroups[0]
|
||||
# If groups starts with a request to loop:
|
||||
if first.shouldTriggerLoop():
|
||||
posList = self._frange(first.args[0], first.args[1], first.args[2])
|
||||
for pos in posList:
|
||||
first.scannable.asynchronousMoveTo(pos)
|
||||
# TODO: Should wait. minigda assumes all moves complete immediately
|
||||
self._performScan(groups, currentRecursionLevel + 1)
|
||||
return
|
||||
|
||||
# 2) Move all non-loop triggering groups (may be zero)
|
||||
self._moveNonLoopTriggeringGroups(unprocessedGroups)
|
||||
|
||||
# 3) Sample position of all scannables
|
||||
posDict = self._samplePositionsOfAllScannables(groups)
|
||||
|
||||
# 4) Inform the data handlers that this point has been recorded
|
||||
for handler in self.dataHandlers: handler.callWithScanPoint(posDict)
|
||||
|
||||
def _moveNonLoopTriggeringGroups(self, groups):
|
||||
# TODO: Should wait. minigda assumes all moves complete immediately. groups could be zero lengthed.
|
||||
for grp in groups:
|
||||
if len(grp.args) == 0:
|
||||
pass
|
||||
elif len(grp.args) == 1:
|
||||
grp.scannable.asynchronousMoveTo(grp.args[0])
|
||||
elif len(grp.args) == 2:
|
||||
raise Exception("Scannables followed by two args not supported by minigda's scan command ")
|
||||
else:
|
||||
raise Exception("Scannable: %s args%s" % (grp.scannable, str(grp.args)))
|
||||
|
||||
def _samplePositionsOfAllScannables(self, groups):
|
||||
posDict = {}
|
||||
for grp in groups:
|
||||
posDict[grp.scannable] = grp.scannable.getPosition()
|
||||
return posDict
|
||||
|
||||
def _frange(self, limit1, limit2, increment):
|
||||
"""Range function that accepts floats (and integers).
|
||||
"""
|
||||
# limit1 = float(limit1)
|
||||
# limit2 = float(limit2)
|
||||
try:
|
||||
increment = float(increment)
|
||||
except TypeError:
|
||||
raise TypeError(
|
||||
"Only scaler values are supported, not GDA format vectors.")
|
||||
count = int(math.ceil(((limit2 - limit1) + increment / 100.) / increment))
|
||||
result = []
|
||||
for n in range(count):
|
||||
result.append(limit1 + n * increment)
|
||||
return result
|
||||
|
||||
|
||||
def sim(scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError()
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"The first argument does not support simulated moves")
|
||||
511
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/minigda/scannable.py
Executable file
511
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/minigda/scannable.py
Executable file
@@ -0,0 +1,511 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
import time
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableBase
|
||||
except ImportError:
|
||||
class Scannable(object):
|
||||
pass
|
||||
|
||||
class ScannableBase(Scannable):
|
||||
"""Implemtation of a subset of OpenGDA's Scannable interface
|
||||
"""
|
||||
|
||||
level = 5
|
||||
inputNames = []
|
||||
extraNames = []
|
||||
outputFormat = []
|
||||
|
||||
def isBusy(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def rawGetPosition(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def rawAsynchronousMoveTo(self, newpos):
|
||||
raise NotImplementedError()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
while self.isBusy():
|
||||
time.sleep(.1)
|
||||
|
||||
def getPosition(self):
|
||||
return self.rawGetPosition()
|
||||
|
||||
def asynchronousMoveTo(self, newpos):
|
||||
self.rawAsynchronousMoveTo(newpos)
|
||||
|
||||
def atScanStart(self):
|
||||
pass
|
||||
|
||||
def atScanEnd(self):
|
||||
pass
|
||||
|
||||
def atCommandFailure(self):
|
||||
pass
|
||||
|
||||
###
|
||||
|
||||
def __repr__(self):
|
||||
pos = self.getPosition()
|
||||
formattedValues = self.formatPositionFields(pos)
|
||||
if len(tuple(self.getInputNames()) + tuple(self.getExtraNames())) > 1:
|
||||
result = self.getName() + ': '
|
||||
else:
|
||||
result = ''
|
||||
|
||||
names = tuple(self.getInputNames()) + tuple(self.getExtraNames())
|
||||
for name, val in zip(names, formattedValues):
|
||||
result += ' ' + name + ': ' + val
|
||||
return result
|
||||
###
|
||||
|
||||
def formatPositionFields(self, pos):
|
||||
"""Returns position as array of formatted strings"""
|
||||
# Make sure pos is a tuple or list
|
||||
if type(pos) not in (tuple, list):
|
||||
pos = tuple([pos])
|
||||
|
||||
# Sanity check
|
||||
if len(pos) != len(self.getOutputFormat()):
|
||||
raise Exception(
|
||||
"In scannable '%s':number of position fields differs from "
|
||||
"number format strings specified" % self.getName())
|
||||
|
||||
result = []
|
||||
for field, format in zip(pos, self.getOutputFormat()):
|
||||
if field is None:
|
||||
result.append('???')
|
||||
else:
|
||||
s = (format % field)
|
||||
## if width!=None:
|
||||
## s = s.ljust(width)
|
||||
result.append(s)
|
||||
|
||||
return result
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def setName(self, value):
|
||||
self.name = value
|
||||
|
||||
def getLevel(self):
|
||||
return self.level
|
||||
|
||||
def setLevel(self, value):
|
||||
self.level = value
|
||||
|
||||
def getInputNames(self):
|
||||
return self.inputNames
|
||||
|
||||
def setInputNames(self, value):
|
||||
self.inputNames = value
|
||||
|
||||
def getExtraNames(self):
|
||||
return self.extraNames
|
||||
|
||||
def setExtraNames(self, value):
|
||||
self.extraNames = value
|
||||
|
||||
def getOutputFormat(self):
|
||||
return self.outputFormat
|
||||
|
||||
def setOutputFormat(self, value):
|
||||
if type(value) not in (tuple, list):
|
||||
raise TypeError(
|
||||
"%s.setOutputFormat() expects tuple or list; not %s" %
|
||||
(self.getName(), str(type(value))))
|
||||
self.outputFormat = value
|
||||
|
||||
def __call__(self, newpos=None):
|
||||
if newpos is None:
|
||||
return self.getPosition()
|
||||
self.asynchronousMoveTo(newpos)
|
||||
|
||||
class ScannableAdapter(Scannable):
|
||||
'''Wrap up a Scannable and give it a new name and optionally an offset
|
||||
(added to the delegate when reading up and subtracting when setting down
|
||||
'''
|
||||
|
||||
def __init__(self, delegate_scn, name, offset=0):
|
||||
assert len(delegate_scn.getInputNames()) == 1
|
||||
assert len(delegate_scn.getExtraNames()) == 0
|
||||
self.delegate_scn = delegate_scn
|
||||
self.name = name
|
||||
self.offset = offset
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.delegate_scn, name)
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getInputNames(self):
|
||||
return [self.name]
|
||||
|
||||
def getPosition(self):
|
||||
return self.delegate_scn.getPosition() + self.offset
|
||||
|
||||
def asynchronousMoveTo(self, newpos):
|
||||
self.delegate_scn.asynchronousMoveTo(newpos - self.offset)
|
||||
|
||||
def __repr__(self):
|
||||
pos = self.getPosition()
|
||||
formatted_values = self.delegate_scn.formatPositionFields(pos)
|
||||
return self.name + ': ' + formatted_values[0] + ' ' + self.get_hint()
|
||||
|
||||
def get_hint(self):
|
||||
if self.offset:
|
||||
offset_hint = ' + ' if self.offset >= 0 else ' - '
|
||||
offset_hint += str(self.offset)
|
||||
else:
|
||||
offset_hint = ''
|
||||
return '(%s%s)' % (self.delegate_scn.name, offset_hint)
|
||||
|
||||
def __call__(self, newpos=None):
|
||||
if newpos is None:
|
||||
return self.getPosition()
|
||||
self.asynchronousMoveTo(newpos)
|
||||
|
||||
class SingleFieldDummyScannable(ScannableBase):
|
||||
|
||||
def __init__(self, name, initial_position=0.):
|
||||
self.name = name
|
||||
self.inputNames = [name]
|
||||
self.outputFormat = ['% 6.4f']
|
||||
self.level = 3
|
||||
self._current_position = float(initial_position)
|
||||
|
||||
def isBusy(self):
|
||||
return False
|
||||
|
||||
def waitWhileBusy(self):
|
||||
return
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
self._current_position = float(new_position)
|
||||
|
||||
def getPosition(self):
|
||||
return self._current_position
|
||||
|
||||
|
||||
class DummyPD(SingleFieldDummyScannable):
|
||||
"""For compatability with the gda's dummy_pd module"""
|
||||
pass
|
||||
|
||||
|
||||
class MultiInputExtraFieldsDummyScannable(ScannableBase):
|
||||
'''Multi input Dummy PD Class supporting input and extra fields'''
|
||||
def __init__(self, name, inputNames, extraNames):
|
||||
self.setName(name)
|
||||
self.setInputNames(inputNames)
|
||||
self.setExtraNames(extraNames)
|
||||
self.setOutputFormat(['%6.4f'] * (len(inputNames) + len(extraNames)))
|
||||
self.setLevel(3)
|
||||
self.currentposition = [0.0] * len(inputNames)
|
||||
|
||||
def isBusy(self):
|
||||
return 0
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
if type(new_position) == type(1) or type(new_position) == type(1.0):
|
||||
new_position = [new_position]
|
||||
msg = "Wrong new_position size"
|
||||
assert len(new_position) == len(self.currentposition), msg
|
||||
for i in range(len(new_position)):
|
||||
if new_position[i] != None:
|
||||
self.currentposition[i] = float(new_position[i])
|
||||
|
||||
def getPosition(self):
|
||||
extraValues = range(100, 100 + (len(self.getExtraNames())))
|
||||
return self.currentposition + map(float, extraValues)
|
||||
|
||||
|
||||
class ZeroInputExtraFieldsDummyScannable(ScannableBase):
|
||||
'''Zero input/extra field dummy pd
|
||||
'''
|
||||
def __init__(self, name):
|
||||
self.setName(name)
|
||||
self.setInputNames([])
|
||||
self.setOutputFormat([])
|
||||
|
||||
def isBusy(self):
|
||||
return 0
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
pass
|
||||
|
||||
def getPosition(self):
|
||||
pass
|
||||
|
||||
|
||||
class ScannableGroup(ScannableBase):
|
||||
"""wraps up motors. Simulates motors if non given."""
|
||||
|
||||
def __init__(self, name, motorList):
|
||||
|
||||
self.setName(name)
|
||||
# Set input format
|
||||
motorNames = []
|
||||
for scn in motorList:
|
||||
motorNames.append(scn.getName())
|
||||
self.setInputNames(motorNames)
|
||||
# Set output format
|
||||
format = []
|
||||
for motor in motorList:
|
||||
format.append(motor.getOutputFormat()[0])
|
||||
self.setOutputFormat(format)
|
||||
self.__motors = motorList
|
||||
|
||||
def asynchronousMoveTo(self, position):
|
||||
# if input has any Nones, then replace these with the current positions
|
||||
if None in position:
|
||||
position = list(position)
|
||||
current = self.getPosition()
|
||||
for idx, val in enumerate(position):
|
||||
if val is None:
|
||||
position[idx] = current[idx]
|
||||
|
||||
for scn, pos in zip(self.__motors, position):
|
||||
scn.asynchronousMoveTo(pos)
|
||||
|
||||
def getPosition(self):
|
||||
return [scn.getPosition() for scn in self.__motors]
|
||||
|
||||
def isBusy(self):
|
||||
for scn in self.__motors:
|
||||
if scn.isBusy():
|
||||
return True
|
||||
return False
|
||||
|
||||
def configure(self):
|
||||
pass
|
||||
|
||||
|
||||
class ScannableMotionWithScannableFieldsBase(ScannableBase):
|
||||
'''
|
||||
This extended version of ScannableMotionBase contains a
|
||||
completeInstantiation() method which adds a dictionary of
|
||||
MotionScannableParts to an instance. Each part allows one of the
|
||||
instances fields to be interacted with like it itself is a scannable.
|
||||
Fields are dynamically added to the instance linking to these parts
|
||||
allowing dotted access from Jython. They may also be accessed using
|
||||
Jython container access methods (via the __getitem__() method). To acess
|
||||
them from Jave use the getComponent(name) method.
|
||||
|
||||
When moving a part (via either a pos or scan command), the part calls
|
||||
the parent to perform the actual task. The parts asynchronousMoveto
|
||||
command will call the parent with a list of None values except for the
|
||||
field it represents which will be passed the desired position value.
|
||||
|
||||
The asynchronousMoveTo method in class that inherats from this base
|
||||
class then must handle these Nones. In some cases the method may
|
||||
actually be able to move the underlying system assoiciated with one
|
||||
field individually from others. If this is not possible the best
|
||||
behaviour may be to simply not support this beahviour and exception or
|
||||
alternatively to substitute the None values with actual current position
|
||||
of parent's scannables associated fields.
|
||||
|
||||
ScannableMotionBaseWithMemory() inherats from this calss and provides a
|
||||
solution useful for some scenarious: it keeps track of the last position
|
||||
moved to, and replaces the Nones in an asynchronousMoveTo request with
|
||||
these values. There are a number of dangers associated with this which
|
||||
are addressed in that class's documentation, but it provides a way to
|
||||
move one axis within a group of non-orthogonal axis while keeping the
|
||||
others still.
|
||||
'''
|
||||
childrenDict = {}
|
||||
numInputFields = None
|
||||
numExtraFields = None
|
||||
|
||||
def completeInstantiation(self):
|
||||
'''This method should be called at the end of all user defined
|
||||
consructors'''
|
||||
# self.validate()
|
||||
self.numInputFields = len(self.getInputNames())
|
||||
self.numExtraFields = len(self.getExtraNames())
|
||||
self.addScannableParts()
|
||||
self.autoCompletePartialMoveToTargets = False
|
||||
self.positionAtScanStart = None
|
||||
|
||||
def setAutoCompletePartialMoveToTargets(self, b):
|
||||
self.autoCompletePartialMoveToTargets = b
|
||||
|
||||
def atScanStart(self):
|
||||
self.positionAtScanStart = self.getPosition()
|
||||
|
||||
def atCommandFailure(self):
|
||||
self.positionAtScanStart = None
|
||||
|
||||
def atScanEnd(self):
|
||||
self.positionAtScanStart = None
|
||||
|
||||
###
|
||||
|
||||
def __repr__(self):
|
||||
pos = self.getPosition()
|
||||
formattedValues = self.formatPositionFields(pos)
|
||||
if len(tuple(self.getInputNames()) + tuple(self.getExtraNames())) > 1:
|
||||
result = self.getName() + ': '
|
||||
else:
|
||||
result = ''
|
||||
|
||||
names = tuple(self.getInputNames()) + tuple(self.getExtraNames())
|
||||
for name, val in zip(names, formattedValues):
|
||||
result += ' ' + name + ': ' + val
|
||||
return result
|
||||
###
|
||||
|
||||
def formatPositionFields(self, pos):
|
||||
"""Returns position as array of formatted strings"""
|
||||
# Make sure pos is a tuple or list
|
||||
if type(pos) not in (tuple, list):
|
||||
pos = tuple([pos])
|
||||
|
||||
# Sanity check
|
||||
if len(pos) != len(self.getOutputFormat()):
|
||||
raise Exception(
|
||||
"In scannable '%s':number of position fields differs from "
|
||||
"number format strings specified" % self.getName())
|
||||
|
||||
result = []
|
||||
for field, format in zip(pos, self.getOutputFormat()):
|
||||
if field is None:
|
||||
result.append('???')
|
||||
else:
|
||||
s = (format % field)
|
||||
## if width!=None:
|
||||
## s = s.ljust(width)
|
||||
result.append(s)
|
||||
|
||||
return result
|
||||
|
||||
###
|
||||
|
||||
def addScannableParts(self):
|
||||
'''
|
||||
Creates an array of MotionScannableParts each of which allows access to
|
||||
the scannable's fields. See this class's documentation for more info.
|
||||
'''
|
||||
self.childrenDict = {}
|
||||
# Add parts to access the input fields
|
||||
for index in range(len(self.getInputNames())):
|
||||
scannableName = self.getInputNames()[index]
|
||||
self.childrenDict[scannableName] = self.MotionScannablePart(
|
||||
scannableName, index, self, isInputField=1)
|
||||
|
||||
# Add parts to access the extra fields
|
||||
for index in range(len(self.getExtraNames())):
|
||||
scannableName = self.getExtraNames()[index]
|
||||
self.childrenDict[scannableName] = self.MotionScannablePart(
|
||||
scannableName, index + len(self.getInputNames()),
|
||||
self, isInputField=0)
|
||||
|
||||
def asynchronousMoveTo(self, newpos):
|
||||
if self.autoCompletePartialMoveToTargets:
|
||||
newpos = self.completePosition(newpos)
|
||||
ScannableBase.asynchronousMoveTo(self, newpos)
|
||||
|
||||
def completePosition(self, position):
|
||||
'''
|
||||
If position contains any null or None values, these are replaced with
|
||||
the corresponding fields from the scannables current position and then
|
||||
returned.'''
|
||||
# Just return position if it does not need padding
|
||||
if None not in position:
|
||||
return position
|
||||
if self.positionAtScanStart is not None:
|
||||
basePosition = self.positionAtScanStart
|
||||
else:
|
||||
basePosition = self.getPosition()[:self.numInputFields]
|
||||
for i in range(self.numInputFields):
|
||||
if position[i] is None:
|
||||
position[i] = basePosition[i]
|
||||
return position
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self.childrenDict[name]
|
||||
except:
|
||||
raise AttributeError("No child named:" + name)
|
||||
|
||||
def __getitem__(self, key):
|
||||
'''Provides container like access from Jython'''
|
||||
return self.childrenDict[key]
|
||||
|
||||
def getPart(self, name):
|
||||
'''Returns the a compnent scannable'''
|
||||
return self.childrenDict[name]
|
||||
|
||||
class MotionScannablePart(ScannableBase):
|
||||
'''
|
||||
A scannable to be placed in the parent's childrenDict that allows
|
||||
access to the parent's individual fields.'''
|
||||
|
||||
def __init__(self, scannableName, index, parentScannable,
|
||||
isInputField):
|
||||
self.setName(scannableName)
|
||||
if isInputField:
|
||||
self.setInputNames([scannableName])
|
||||
else:
|
||||
self.setExtraNames([scannableName])
|
||||
self.index = index
|
||||
self.parentScannable = parentScannable
|
||||
self.setOutputFormat(
|
||||
[self.parentScannable.getOutputFormat()[index]])
|
||||
|
||||
def isBusy(self):
|
||||
return self.parentScannable.isBusy()
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
if self.parentScannable.isBusy():
|
||||
raise Exception(
|
||||
self.parentScannable.getName() + "." + self.getName() +
|
||||
" cannot be moved because " +
|
||||
self.parentScannable.getName() + " is already moving")
|
||||
|
||||
toMoveTo = [None] * len(self.parentScannable.getInputNames())
|
||||
toMoveTo[self.index] = new_position
|
||||
self.parentScannable.asynchronousMoveTo(toMoveTo)
|
||||
|
||||
def moveTo(self, new_position):
|
||||
self.asynchronousMoveTo(new_position)
|
||||
self.waitWhileBusy()
|
||||
|
||||
def getPosition(self):
|
||||
return self.parentScannable.getPosition()[self.index]
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
# Get the name of this field
|
||||
# (assume its an input field first and correct if wrong)
|
||||
name = self.getInputNames()[0]
|
||||
|
||||
if name == 'value':
|
||||
name = self.getExtraNames()[0]
|
||||
parentName = self.parentScannable.getName()
|
||||
return parentName + "." + name + " : " + str(self.getPosition())
|
||||
|
||||
|
||||
|
||||
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/__init__.py
Executable file
62
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/base.py
Executable file
62
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/base.py
Executable file
@@ -0,0 +1,62 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import PseudoDevice
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as PseudoDevice
|
||||
|
||||
|
||||
class ScannableGroup(PseudoDevice):
|
||||
|
||||
def __init__(self, name, motorList):
|
||||
|
||||
self.setName(name)
|
||||
# Set input format
|
||||
motorNames = []
|
||||
for scn in motorList:
|
||||
motorNames.append(scn.getName())
|
||||
self.setInputNames(motorNames)
|
||||
# Set output format
|
||||
format = []
|
||||
for motor in motorList:
|
||||
format.append(motor.getOutputFormat()[0])
|
||||
self.setOutputFormat(format)
|
||||
self.__motors = motorList
|
||||
|
||||
def asynchronousMoveTo(self, position):
|
||||
# if input has any Nones, then replace these with the current positions
|
||||
if None in position:
|
||||
position = list(position)
|
||||
current = self.getPosition()
|
||||
for idx, val in enumerate(position):
|
||||
if val is None:
|
||||
position[idx] = current[idx]
|
||||
|
||||
for scn, pos in zip(self.__motors, position):
|
||||
scn.asynchronousMoveTo(pos)
|
||||
|
||||
def getPosition(self):
|
||||
return [scn.getPosition() for scn in self.__motors]
|
||||
|
||||
def isBusy(self):
|
||||
for scn in self.__motors:
|
||||
if scn.isBusy():
|
||||
return True
|
||||
return False
|
||||
126
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/diffractometer.py
Executable file
126
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/diffractometer.py
Executable file
@@ -0,0 +1,126 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableMotionBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as ScannableMotionBase
|
||||
|
||||
from diffcalc.util import getMessageFromException
|
||||
|
||||
# TODO: Split into a base class when making other scannables
|
||||
|
||||
|
||||
class DiffractometerScannableGroup(ScannableMotionBase):
|
||||
""""
|
||||
Wraps up a scannableGroup of axis to tweak the way the resulting
|
||||
object is displayed and to add a simulate move to method.
|
||||
|
||||
The scannable group should have the same geometry as that expected
|
||||
by the diffractometer hardware geometry used in the diffraction
|
||||
calculator.
|
||||
|
||||
The optional parameter slaveDriver can be used to provide a
|
||||
slave_driver. This is useful for triggering a move of an incidental
|
||||
axis whose position depends on that of the diffractometer, but whose
|
||||
position need not be included in the DiffractometerScannableGroup
|
||||
itself. This parameter is exposed as a field and can be set or
|
||||
cleared to null at will without effecting the core calculation code.
|
||||
"""
|
||||
|
||||
def __init__(self, name, diffcalc_module, scannableGroup,
|
||||
slave_driver=None, hint_generator=None):
|
||||
# if motorList is None, will create a dummy __group
|
||||
self.diffcalc_module = diffcalc_module
|
||||
self.__group = scannableGroup
|
||||
self.slave_driver = slave_driver
|
||||
self.setName(name)
|
||||
self.hint_generator = hint_generator
|
||||
|
||||
def getInputNames(self):
|
||||
return self.__group.getInputNames()
|
||||
|
||||
def getExtraNames(self):
|
||||
if self.slave_driver is None:
|
||||
return []
|
||||
else:
|
||||
return self.slave_driver.getScannableNames()
|
||||
|
||||
def getOutputFormat(self):
|
||||
if self.slave_driver is None:
|
||||
slave_formats = []
|
||||
else:
|
||||
slave_formats = self.slave_driver.getScannableNames()
|
||||
return list(self.__group.getOutputFormat()) + slave_formats
|
||||
|
||||
def asynchronousMoveTo(self, position):
|
||||
self.__group.asynchronousMoveTo(position)
|
||||
if self.slave_driver is not None:
|
||||
self.slave_driver.triggerAsynchronousMove(position)
|
||||
|
||||
def getPosition(self):
|
||||
if self.slave_driver is None:
|
||||
slave_positions = []
|
||||
else:
|
||||
slave_positions = self.slave_driver.getPositions()
|
||||
return list(self.__group.getPosition()) + list(slave_positions)
|
||||
|
||||
def isBusy(self):
|
||||
if self.slave_driver is None:
|
||||
return self.__group.isBusy()
|
||||
else:
|
||||
return self.__group.isBusy() or self.slave_driver.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
self.__group.waitWhileBusy()
|
||||
if self.slave_driver is not None:
|
||||
self.slave_driver.waitWhileBusy()
|
||||
|
||||
def simulateMoveTo(self, pos):
|
||||
if len(pos) != len(self.getInputNames()):
|
||||
raise ValueError('Wrong number of inputs')
|
||||
try:
|
||||
(hkl, params) = self.diffcalc_module.angles_to_hkl(pos)
|
||||
except Exception, e:
|
||||
return "Error: %s" % getMessageFromException(e)
|
||||
width = max(len(k) for k in params)
|
||||
|
||||
lines = ([' ' + 'hkl'.rjust(width) + ' : % 9.4f %.4f %.4f' %
|
||||
(hkl[0], hkl[1], hkl[2])])
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
fmt = ' %' + str(width) + 's : % 9.4f'
|
||||
for k in sorted(params):
|
||||
lines.append(fmt % (k, params[k]))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def __repr__(self):
|
||||
position = self.getPosition()
|
||||
names = list(self.getInputNames()) + list(self.getExtraNames())
|
||||
if self.hint_generator is None:
|
||||
hint_list = [''] * len(self.getInputNames())
|
||||
else:
|
||||
hint_list = self.hint_generator()
|
||||
|
||||
lines = [self.name + ':']
|
||||
width = max(len(k) for k in names)
|
||||
fmt = ' %' + str(width) + 's : % 9.4f %s'
|
||||
for name, pos, hint in zip(names, position, hint_list):
|
||||
lines.append(fmt % (name, pos, hint))
|
||||
lines[len(self.getInputNames())] += '\n'
|
||||
return '\n'.join(lines)
|
||||
135
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/hkl.py
Executable file
135
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/hkl.py
Executable file
@@ -0,0 +1,135 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
import platform
|
||||
|
||||
DEBUG = False
|
||||
|
||||
try:
|
||||
from gda.device.scannable.scannablegroup import \
|
||||
ScannableMotionWithScannableFieldsBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableMotionWithScannableFieldsBase
|
||||
|
||||
from diffcalc.util import getMessageFromException, DiffcalcException
|
||||
|
||||
|
||||
class _DynamicDocstringMetaclass(type):
|
||||
|
||||
def _get_doc(self):
|
||||
return Hkl.dynamic_docstring
|
||||
|
||||
__doc__ = property(_get_doc) # @ReservedAssignment
|
||||
|
||||
|
||||
class Hkl(ScannableMotionWithScannableFieldsBase):
|
||||
|
||||
if platform.system() != 'Java':
|
||||
__metaclass__ = _DynamicDocstringMetaclass # TODO: Removed to fix Jython
|
||||
|
||||
dynamic_docstring = 'Hkl Scannable'
|
||||
|
||||
def _get_doc(self):
|
||||
return Hkl.dynamic_docstring
|
||||
|
||||
__doc__ = property(_get_doc) # @ReservedAssignment
|
||||
|
||||
def __init__(self, name, diffractometerObject, diffcalcObject,
|
||||
virtualAnglesToReport=None):
|
||||
self.diffhw = diffractometerObject
|
||||
self._diffcalc = diffcalcObject
|
||||
if type(virtualAnglesToReport) is str:
|
||||
virtualAnglesToReport = (virtualAnglesToReport,)
|
||||
self.vAngleNames = virtualAnglesToReport
|
||||
|
||||
self.setName(name)
|
||||
self.setInputNames(['h', 'k', 'l'])
|
||||
self.setOutputFormat(['%7.5f'] * 3)
|
||||
if self.vAngleNames:
|
||||
self.setExtraNames(self.vAngleNames)
|
||||
self.setOutputFormat(['%7.5f'] * (3 + len(self.vAngleNames)))
|
||||
|
||||
self.completeInstantiation()
|
||||
self.setAutoCompletePartialMoveToTargets(True)
|
||||
self.dynamic_class_doc = 'Hkl Scannable xyz'
|
||||
|
||||
def rawAsynchronousMoveTo(self, hkl):
|
||||
if len(hkl) != 3: raise ValueError('Hkl device expects three inputs')
|
||||
try:
|
||||
(pos, _) = self._diffcalc.hkl_to_angles(hkl[0], hkl[1], hkl[2])
|
||||
except DiffcalcException, e:
|
||||
if DEBUG:
|
||||
raise
|
||||
else:
|
||||
raise DiffcalcException(e.message)
|
||||
self.diffhw.asynchronousMoveTo(pos)
|
||||
|
||||
def rawGetPosition(self):
|
||||
pos = self.diffhw.getPosition() # a tuple
|
||||
(hkl , params) = self._diffcalc.angles_to_hkl(pos)
|
||||
result = list(hkl)
|
||||
if self.vAngleNames:
|
||||
for vAngleName in self.vAngleNames:
|
||||
result.append(params[vAngleName])
|
||||
return result
|
||||
|
||||
def getFieldPosition(self, i):
|
||||
return self.getPosition()[i]
|
||||
|
||||
def isBusy(self):
|
||||
return self.diffhw.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
return self.diffhw.waitWhileBusy()
|
||||
|
||||
def simulateMoveTo(self, hkl):
|
||||
if type(hkl) not in (list, tuple):
|
||||
raise ValueError('Hkl device expects three inputs')
|
||||
if len(hkl) != 3:
|
||||
raise ValueError('Hkl device expects three inputs')
|
||||
(pos, params) = self._diffcalc.hkl_to_angles(hkl[0], hkl[1], hkl[2])
|
||||
|
||||
width = max(len(k) for k in (params.keys() + list(self.diffhw.getInputNames())))
|
||||
fmt = ' %' + str(width) + 's : % 9.4f'
|
||||
|
||||
lines = [self.diffhw.getName() + ' would move to:']
|
||||
for idx, name in enumerate(self.diffhw.getInputNames()):
|
||||
lines.append(fmt % (name, pos[idx]))
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
for k in sorted(params):
|
||||
lines.append(fmt % (k, params[k]))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
lines = ['hkl:']
|
||||
pos = self.diffhw.getPosition()
|
||||
try:
|
||||
(hkl, params) = self._diffcalc.angles_to_hkl(pos)
|
||||
except Exception, e:
|
||||
return "<hkl: %s>" % getMessageFromException(e)
|
||||
|
||||
width = max(len(k) for k in params)
|
||||
lines.append(' ' + 'hkl'.rjust(width) + ' : %9.4f %.4f %.4f' % (hkl[0], hkl[1], hkl[2]))
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
fmt = ' %' + str(width) + 's : % 9.4f'
|
||||
for k in sorted(params):
|
||||
lines.append(fmt % (k, params[k]))
|
||||
return '\n'.join(lines)
|
||||
47
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/mock.py
Executable file
47
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/mock.py
Executable file
@@ -0,0 +1,47 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableMotionBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as ScannableMotionBase
|
||||
|
||||
|
||||
class MockMotor(ScannableMotionBase):
|
||||
|
||||
def __init__(self, name='mock'):
|
||||
self.pos = 0.0
|
||||
self._busy = False
|
||||
self.name = name
|
||||
|
||||
def asynchronousMoveTo(self, pos):
|
||||
self._busy = True
|
||||
self.pos = float(pos)
|
||||
|
||||
def getPosition(self):
|
||||
return self.pos
|
||||
|
||||
def isBusy(self):
|
||||
return self._busy
|
||||
|
||||
def makeNotBusy(self):
|
||||
self._busy = False
|
||||
|
||||
def getOutputFormat(self):
|
||||
return ['%f']
|
||||
45
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/parameter.py
Executable file
45
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/parameter.py
Executable file
@@ -0,0 +1,45 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableMotionBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as ScannableMotionBase
|
||||
|
||||
|
||||
class DiffractionCalculatorParameter(ScannableMotionBase):
|
||||
|
||||
def __init__(self, name, parameterName, parameter_manager):
|
||||
|
||||
self.parameter_manager = parameter_manager
|
||||
self.parameterName = parameterName
|
||||
|
||||
self.setName(name)
|
||||
self.setInputNames([parameterName])
|
||||
self.setOutputFormat(['%5.5f'])
|
||||
self.setLevel(3)
|
||||
|
||||
def asynchronousMoveTo(self, value):
|
||||
self.parameter_manager.set_constraint(self.parameterName, value)
|
||||
|
||||
def getPosition(self):
|
||||
return self.parameter_manager.get_constraint(self.parameterName)
|
||||
|
||||
def isBusy(self):
|
||||
return False
|
||||
21
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/sim.py
Executable file
21
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/sim.py
Executable file
@@ -0,0 +1,21 @@
|
||||
'''
|
||||
Created on 7 May 2016
|
||||
|
||||
@author: walton
|
||||
'''
|
||||
from diffcalc.util import allnum
|
||||
|
||||
def sim(scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"The first argument does not support simulated moves")
|
||||
139
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/simulation.py
Executable file
139
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/simulation.py
Executable file
@@ -0,0 +1,139 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
import time
|
||||
from math import sqrt, pi, exp
|
||||
|
||||
try:
|
||||
from gda.device.scannable import PseudoDevice
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as PseudoDevice
|
||||
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.hkl.you.calc import youAnglesToHkl
|
||||
from diffcalc.hkl.vlieg.calc import vliegAnglesToHkl
|
||||
from diffcalc.hkl.you.geometry import calcCHI, calcPHI
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class Equation(object):
|
||||
|
||||
def __call__(self, dh, dk, dl):
|
||||
raise Exception('Abstract')
|
||||
|
||||
def __str__(self):
|
||||
"Abstract equation"
|
||||
|
||||
|
||||
class Gaussian(Equation):
|
||||
|
||||
def __init__(self, variance):
|
||||
self.variance = float(variance)
|
||||
|
||||
def __call__(self, dh, dk, dl):
|
||||
dr_squared = dh * dh + dk * dk + dl * dl
|
||||
return (1 / sqrt(2 * pi * self.variance) *
|
||||
exp(-dr_squared / (2 * self.variance)))
|
||||
|
||||
|
||||
class SimulatedCrystalCounter(PseudoDevice):
|
||||
|
||||
def __init__(self, name, diffractometerScannable, geometryPlugin,
|
||||
wavelengthScannable, equation=Gaussian(.01), engine='you'):
|
||||
self.setName(name)
|
||||
self.setInputNames([name + '_count'])
|
||||
self.setOutputFormat(['%7.5f'])
|
||||
self.exposureTime = 1
|
||||
self.pause = True
|
||||
self.diffractometerScannable = diffractometerScannable
|
||||
self.geometry = geometryPlugin
|
||||
self.wavelengthScannable = wavelengthScannable
|
||||
self.equation = equation
|
||||
self.engine = engine
|
||||
|
||||
self.cut = None
|
||||
self.UB = None
|
||||
self.chiMissmount = 0.
|
||||
self.phiMissmount = 0.
|
||||
self.setCrystal('cubic', 1, 1, 1, 90, 90, 90)
|
||||
|
||||
def setCrystal(self, name, a, b, c, alpha, beta, gamma):
|
||||
self.cut = CrystalUnderTest(name, a, b, c, alpha, beta, gamma)
|
||||
self.calcUB()
|
||||
|
||||
def setChiMissmount(self, chi):
|
||||
self.chiMissmount = chi
|
||||
self.calcUB()
|
||||
|
||||
def setPhiMissmount(self, phi):
|
||||
self.phiMissmount = phi
|
||||
self.calcUB()
|
||||
|
||||
def calcUB(self):
|
||||
CHI = calcCHI(self.chiMissmount * TORAD)
|
||||
PHI = calcPHI(self.phiMissmount * TORAD)
|
||||
self.UB = CHI * PHI * self.cut.B
|
||||
|
||||
def asynchronousMoveTo(self, exposureTime):
|
||||
self.exposureTime = exposureTime
|
||||
if self.pause:
|
||||
time.sleep(exposureTime) # Should not technically block!
|
||||
|
||||
def getPosition(self):
|
||||
h, k, l = self.getHkl()
|
||||
dh, dk, dl = h - round(h), k - round(k), l - round(l)
|
||||
count = self.equation(dh, dk, dl)
|
||||
#return self.exposureTime, count*self.exposureTime
|
||||
return count * self.exposureTime
|
||||
|
||||
def getHkl(self):
|
||||
pos = self.geometry.physical_angles_to_internal_position(
|
||||
self.diffractometerScannable.getPosition())
|
||||
pos.changeToRadians()
|
||||
wavelength = self.wavelengthScannable.getPosition()
|
||||
if self.engine.lower() == 'vlieg':
|
||||
return vliegAnglesToHkl(pos, wavelength, self.UB)
|
||||
elif self.engine.lower() == 'you':
|
||||
return youAnglesToHkl(pos, wavelength, self.UB)
|
||||
else:
|
||||
raise ValueError(self.engine)
|
||||
|
||||
def isBusy(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
s = 'simulated crystal detector: %s\n' % self.getName()
|
||||
h, k, l = self.getHkl()
|
||||
s += ' h : %f\n' % h
|
||||
s += ' k : %f\n' % k
|
||||
s += ' l : %f\n' % l
|
||||
s += self.cut.__str__() + '\n'
|
||||
s += "chi orientation: %s\n" % self.chiMissmount
|
||||
s += "phi orientation: %s\n" % self.phiMissmount
|
||||
ub = self.UB.tolist()
|
||||
s += "UB:\n"
|
||||
s += " % 18.13f% 18.13f% 18.12f\n" % (ub[0][0], ub[0][1], ub[0][2])
|
||||
s += " % 18.13f% 18.13f% 18.12f\n" % (ub[1][0], ub[1][1], ub[1][2])
|
||||
s += " % 18.13f% 18.13f% 18.12f\n" % (ub[2][0], ub[2][1], ub[2][2])
|
||||
return s
|
||||
109
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/slave_driver.py
Executable file
109
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/slave_driver.py
Executable file
@@ -0,0 +1,109 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, tan, sin, atan, cos, atan2
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class SlaveScannableDriver(object):
|
||||
|
||||
def __init__(self, scannables):
|
||||
self.scannables = scannables
|
||||
|
||||
def isBusy(self):
|
||||
for scn in self.scannables:
|
||||
if scn.isBusy():
|
||||
return True
|
||||
return False
|
||||
|
||||
def waitWhileBusy(self):
|
||||
for scn in self.scannables:
|
||||
scn.waitWhileBusy()
|
||||
|
||||
def triggerAsynchronousMove(self, triggerPos):
|
||||
nu = self.slaveFromTriggerPos(triggerPos)
|
||||
for scn in self.scannables:
|
||||
scn.asynchronousMoveTo(nu)
|
||||
|
||||
def getPosition(self):
|
||||
return self.scannables[0].getPosition()
|
||||
|
||||
def slaveFromTriggerPos(self, triggerPos):
|
||||
raise Exception("Abstract")
|
||||
|
||||
def getScannableNames(self):
|
||||
return [scn.name for scn in self.scannables]
|
||||
|
||||
def getOutputFormat(self):
|
||||
return [list(scn.outputFormat)[0] for scn in self.scannables]
|
||||
|
||||
def getPositions(self):
|
||||
return [float(scn.getPosition()) for scn in self.scannables]
|
||||
|
||||
|
||||
"""
|
||||
Based on: Elias Vlieg, "A (2+3)-Type Surface Diffractometer: Mergence of the
|
||||
z-axis and (2+2)-Type Geometries", J. Appl. Cryst. (1998). 31. 198-203
|
||||
"""
|
||||
|
||||
|
||||
class NuDriverForSixCirclePlugin(SlaveScannableDriver):
|
||||
|
||||
def slaveFromTriggerPos(self, triggerPos):
|
||||
|
||||
alpha, delta, gamma, _, _, _ = triggerPos
|
||||
alpha = alpha * TORAD
|
||||
delta = delta * TORAD
|
||||
gamma = gamma * TORAD
|
||||
|
||||
### Equation16 RHS ###
|
||||
rhs = -1 * tan(gamma - alpha) * sin(delta)
|
||||
nu = atan(rhs) # -pi/2 <= nu <= pi/2
|
||||
return nu * TODEG
|
||||
|
||||
|
||||
class NuDriverForWillmottHorizontalGeometry(SlaveScannableDriver):
|
||||
|
||||
"""
|
||||
Based on: Phillip Willmott, "Angle calculations for a (2+3)-type
|
||||
diffractometer: focus on area detectors", J. Appl. Cryst. (2011). 44.
|
||||
73-83
|
||||
"""
|
||||
|
||||
def __init__(self, scannables, area_detector=False):
|
||||
SlaveScannableDriver.__init__(self, scannables)
|
||||
self.area_detector = area_detector
|
||||
|
||||
def slaveFromTriggerPos(self, triggerPos):
|
||||
|
||||
delta, gamma, omegah, _ = triggerPos
|
||||
delta *= TORAD
|
||||
gamma *= TORAD
|
||||
omegah *= TORAD
|
||||
if self.area_detector:
|
||||
nu = atan2(sin(delta - omegah), tan(gamma)) # (66)
|
||||
else:
|
||||
top = -sin(gamma) * sin(omegah)
|
||||
bot = (sin(omegah) * cos(gamma) * sin(delta) +
|
||||
cos(omegah) * cos(delta))
|
||||
nu = atan2(top, bot) # (61)
|
||||
|
||||
print 'nu:', nu * TODEG
|
||||
return nu * TODEG
|
||||
184
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/vrmlanimator.py
Executable file
184
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/vrmlanimator.py
Executable file
@@ -0,0 +1,184 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
import time
|
||||
import threading
|
||||
import socket
|
||||
PORT = 4567
|
||||
|
||||
from gda.device.scannable import ScannableMotionWithScannableFieldsBaseTest
|
||||
|
||||
#import scannable.vrmlModelDriver
|
||||
#reload(scannable.vrmlModelDriver);from scannable.vrmlModelDriver import \
|
||||
# VrmlModelDriver, LinearProfile, MoveThread
|
||||
#fc=VrmlModelDriver(
|
||||
# 'fc',['alpha','delta','omega', 'chi','phi'], speed=30, host='diamrl5104')
|
||||
#alpha = fc.alpha
|
||||
#delta = fc.delta
|
||||
#omega = fc.omega
|
||||
#chi = fc.chi
|
||||
#phi = fc.phi
|
||||
|
||||
|
||||
def connect_to_socket(host, port):
|
||||
print "Connecting to %s on port %d" % (host, port)
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.connect((host, port))
|
||||
print "Connected"
|
||||
socketfile = sock.makefile('rw', 0)
|
||||
return socketfile
|
||||
|
||||
|
||||
class LinearProfile(object):
|
||||
|
||||
def __init__(self, v, t_accel, startList, endList):
|
||||
assert len(startList) == len(endList)
|
||||
self.v = float(v)
|
||||
self.start = startList
|
||||
self.end = endList
|
||||
self.t_accel = t_accel
|
||||
|
||||
distances = [e - s for e, s in zip(self.end, self.start)]
|
||||
max_distance = max([abs(d) for d in distances])
|
||||
if max_distance == 0:
|
||||
self.delta_time = 0
|
||||
else:
|
||||
self.delta_time = abs(max_distance / self.v)
|
||||
self.speeds = [d / self.delta_time for d in distances]
|
||||
self.start_time = time.time()
|
||||
|
||||
def getPosition(self):
|
||||
if self.start_time is None:
|
||||
return self.start
|
||||
if not self.isMoving():
|
||||
return self.end
|
||||
t = abs(float(time.time() - self.start_time))
|
||||
if t > self.delta_time:
|
||||
# we are in the deceleration phase (i.e paused for now)
|
||||
return self.end
|
||||
return [s + v * t for s, v in zip(self.start, self.speeds)]
|
||||
|
||||
def isMoving(self):
|
||||
return time.time() < self.start_time + self.delta_time + self.t_accel
|
||||
|
||||
|
||||
class MoveThread(threading.Thread):
|
||||
|
||||
def __init__(self, profile, socketfile, axisNames):
|
||||
threading.Thread.__init__(self)
|
||||
self.profile = profile
|
||||
self.socketfile = socketfile
|
||||
self.axisNames = axisNames
|
||||
|
||||
def run(self):
|
||||
while self.profile.isMoving():
|
||||
self.update()
|
||||
time.sleep(.1)
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
pos = self.profile.getPosition()
|
||||
d = dict(zip(map(str, self.axisNames), pos))
|
||||
if self.socketfile:
|
||||
self.socketfile.write(repr(d) + '\n')
|
||||
|
||||
|
||||
class VrmlModelDriver(ScannableMotionWithScannableFieldsBaseTest):
|
||||
|
||||
def __init__(self, name, axes_names, host=None, speed=60, t_accel=.1,
|
||||
format='%.3f'):
|
||||
self.name = name
|
||||
self.inputNames = list(axes_names)
|
||||
self.extraNames = []
|
||||
self.outputFormat = [format] * len(self.inputNames)
|
||||
self.completeInstantiation()
|
||||
self.__last_target = [0.] * len(self.inputNames)
|
||||
self.verbose = False
|
||||
self.move_thread = None
|
||||
self.speed = speed
|
||||
self.host = host
|
||||
self.t_accel = t_accel
|
||||
self.socketfile = None
|
||||
if self.host:
|
||||
try:
|
||||
self.connect()
|
||||
except socket.error:
|
||||
print "Failed to connect to %s:%r" % (self.host, PORT)
|
||||
print "Connect with: %s.connect()" % self.name
|
||||
|
||||
def connect(self):
|
||||
self.socketfile = connect_to_socket(self.host, PORT)
|
||||
self.rawAsynchronousMoveTo(self.__last_target)
|
||||
|
||||
def isBusy(self):
|
||||
if self.move_thread is None:
|
||||
return False
|
||||
return self.move_thread.profile.isMoving()
|
||||
|
||||
def rawGetPosition(self):
|
||||
if self.move_thread is None:
|
||||
return self.__last_target
|
||||
else:
|
||||
return self.move_thread.profile.getPosition()
|
||||
|
||||
def rawAsynchronousMoveTo(self, targetList):
|
||||
if self.isBusy():
|
||||
raise Exception(self.name + ' is already moving')
|
||||
if self.verbose:
|
||||
print self.name + ".rawAsynchronousMoveTo(%r)" % targetList
|
||||
|
||||
for i, target in enumerate(targetList):
|
||||
if target is None:
|
||||
targetList[i] = self.__last_target[i]
|
||||
profile = LinearProfile(
|
||||
self.speed, self.t_accel, self.__last_target, targetList)
|
||||
self.move_thread = MoveThread(
|
||||
profile, self.socketfile, self.inputNames)
|
||||
self.move_thread.start()
|
||||
self.__last_target = targetList
|
||||
|
||||
def getFieldPosition(self, index):
|
||||
return self.getPosition()[index]
|
||||
|
||||
def __del__(self):
|
||||
self.socketfile.close()
|
||||
|
||||
#class TrapezoidProfile(object):
|
||||
#
|
||||
# def __init__(self, t_accel, v_max, delta_x):
|
||||
# self.t_a = t_accel
|
||||
# self.v_m = v_max
|
||||
# self.delta_x = delta_x
|
||||
#
|
||||
# self.t_c = (self.X - self.v_m*self.t_a) / self.v_m
|
||||
#
|
||||
# def x(self, t):
|
||||
# if self.t_c <=0:
|
||||
# return self.__xshort(t)
|
||||
# else:
|
||||
# return self.__xlong(t)
|
||||
#
|
||||
# def __xshort(self, t):
|
||||
# delta_t = 2 * sqrt(self.delta_x*self.t_a/self.v_m)
|
||||
# if t <= .5*delta_t:
|
||||
# return (.5*self.v_m/self.t_a) * t**2
|
||||
# else:
|
||||
# v_peak = (self.v_m/self.t_a) * .5*delta_t
|
||||
# return (t-.5*delta_t)*v_peak - (t-.5*delta_t)**2 ####HERE, bugged
|
||||
# self.delta_x/2
|
||||
50
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/wavelength.py
Executable file
50
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/scannable/wavelength.py
Executable file
@@ -0,0 +1,50 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gdascripts.pd.dummy_pds import DummyPD
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import DummyPD
|
||||
|
||||
|
||||
class Wavelength(DummyPD):
|
||||
|
||||
def __init__(self, name, energyScannable,
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
self.energyScannable = energyScannable
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
|
||||
DummyPD.__init__(self, name)
|
||||
|
||||
def asynchronousMoveTo(self, pos):
|
||||
self.energyScannable.asynchronousMoveTo(
|
||||
(12.39842 / pos) / self.energyScannableMultiplierToGetKeV)
|
||||
|
||||
def getPosition(self):
|
||||
energy = self.energyScannable.getPosition()
|
||||
if energy == 0:
|
||||
raise Exception(
|
||||
"The energy is 0, so no wavelength could be calculated.run_All()")
|
||||
return 12.39842 / (energy * self.energyScannableMultiplierToGetKeV)
|
||||
|
||||
def isBusy(self):
|
||||
return self.energyScannable.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
return self.energyScannable.waitWhileBusy()
|
||||
113
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/you.py
Executable file
113
script/__Lib/diffcalc-2.1/diffcalc/gdasupport/you.py
Executable file
@@ -0,0 +1,113 @@
|
||||
from diffcalc.gdasupport.scannable.diffractometer import DiffractometerScannableGroup
|
||||
from diffcalc.gdasupport.scannable.hkl import Hkl
|
||||
from diffcalc.gdasupport.scannable.simulation import SimulatedCrystalCounter
|
||||
from diffcalc.gdasupport.scannable.wavelength import Wavelength
|
||||
from diffcalc.gdasupport.scannable.parameter import DiffractionCalculatorParameter
|
||||
|
||||
|
||||
from diffcalc.dc import dcyou as _dc
|
||||
from diffcalc.dc.help import format_command_help
|
||||
reload(_dc)
|
||||
from diffcalc.dc.dcyou import * # @UnusedWildImport
|
||||
from diffcalc import settings
|
||||
|
||||
try:
|
||||
import gda # @UnusedImport @UnresolvedImport
|
||||
GDA = True
|
||||
except:
|
||||
GDA = False
|
||||
|
||||
if not GDA:
|
||||
from diffcalc.gdasupport.minigda import command
|
||||
_pos = command.Pos()
|
||||
_scan = command.Scan(command.ScanDataPrinter())
|
||||
|
||||
def pos(*args):
|
||||
"""
|
||||
pos show position of all Scannables
|
||||
pos scn show position of scn
|
||||
pos scn targetmove scn to target (a number)
|
||||
"""
|
||||
return _pos(*args)
|
||||
|
||||
def scan(*args):
|
||||
"""
|
||||
scan scn start stop step {scn {target}} {det t}
|
||||
"""
|
||||
return _scan(*args)
|
||||
|
||||
|
||||
from diffcalc.gdasupport.scannable.sim import sim # @UnusedImport
|
||||
|
||||
_scn_group = settings.axes_scannable_group
|
||||
_diff_scn_name = settings.geometry.name # @UndefinedVariable
|
||||
_energy_scannable = settings.energy_scannable
|
||||
|
||||
|
||||
# Create diffractometer scannable
|
||||
_diff_scn = DiffractometerScannableGroup(_diff_scn_name, _dc, _scn_group)
|
||||
globals()[_diff_scn_name] = _diff_scn
|
||||
|
||||
# Create hkl scannables
|
||||
hkl = Hkl('hkl', _scn_group, _dc)
|
||||
h = hkl.h
|
||||
k = hkl.k
|
||||
l = hkl.l
|
||||
|
||||
Hkl.dynamic_docstring = format_command_help(hkl_commands_for_help) # must be on the class
|
||||
ub.__doc__ = format_command_help(ub_commands_for_help)
|
||||
|
||||
_virtual_angles = ('theta', 'qaz', 'alpha', 'naz', 'tau', 'psi', 'beta')
|
||||
hklverbose = Hkl('hklverbose', _scn_group, _dc, _virtual_angles)
|
||||
|
||||
|
||||
# Create wavelength scannable
|
||||
wl = Wavelength(
|
||||
'wl', _energy_scannable, settings.energy_scannable_multiplier_to_get_KeV)
|
||||
if not GDA:
|
||||
wl.asynchronousMoveTo(1) # Angstrom
|
||||
_energy_scannable.level = 3
|
||||
wl.level = 3
|
||||
|
||||
|
||||
# Create simulated counter timer
|
||||
ct = SimulatedCrystalCounter('ct', _scn_group, settings.geometry, wl)
|
||||
ct.level = 10
|
||||
|
||||
|
||||
# Create constraint scannables
|
||||
def _create_constraint_scannable(con_name, scn_name=None):
|
||||
if not scn_name:
|
||||
scn_name = con_name
|
||||
return DiffractionCalculatorParameter(
|
||||
scn_name, con_name, _dc.constraint_manager)
|
||||
|
||||
# Detector constraints
|
||||
def isconstrainable(name):
|
||||
return not constraint_manager.is_constraint_fixed(name)
|
||||
|
||||
if isconstrainable('delta'): delta_con = _create_constraint_scannable('delta', 'delta_con')
|
||||
if isconstrainable('gam'): gam_con = _create_constraint_scannable('gam', 'gam_con')
|
||||
if isconstrainable('qaz'): qaz = _create_constraint_scannable('qaz')
|
||||
if isconstrainable('naz'): naz = _create_constraint_scannable('naz')
|
||||
|
||||
# Reference constraints
|
||||
alpha = _create_constraint_scannable('alpha')
|
||||
beta = _create_constraint_scannable('beta')
|
||||
psi = _create_constraint_scannable('psi')
|
||||
a_eq_b = 'a_eq_b'
|
||||
|
||||
# Sample constraints
|
||||
if isconstrainable('mu'): mu_con = _create_constraint_scannable('mu', 'mu_con')
|
||||
if isconstrainable('eta'): eta_con = _create_constraint_scannable('eta', 'eta_con')
|
||||
if isconstrainable('chi'): chi_con = _create_constraint_scannable('chi', 'chi_con')
|
||||
if isconstrainable('phi'): phi_con = _create_constraint_scannable('phi', 'phi_con')
|
||||
if isconstrainable('mu') and isconstrainable('gam'): mu_is_gam = 'mu_is_gam'
|
||||
|
||||
|
||||
# Cleanup to allow "from gdasupport.you import *"
|
||||
del DiffractometerScannableGroup, Hkl, SimulatedCrystalCounter
|
||||
del Wavelength, DiffractionCalculatorParameter
|
||||
|
||||
# Cleanup other cruft
|
||||
del format_command_help
|
||||
382
script/__Lib/diffcalc-2.1/diffcalc/hardware.py
Executable file
382
script/__Lib/diffcalc-2.1/diffcalc/hardware.py
Executable file
@@ -0,0 +1,382 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from diffcalc.util import DiffcalcException
|
||||
from diffcalc import settings
|
||||
|
||||
SMALL = 1e-8
|
||||
|
||||
from diffcalc.util import command
|
||||
|
||||
__all__ = ['hardware', 'setcut', 'setmin', 'setmax']
|
||||
|
||||
|
||||
def getNameFromScannableOrString(o):
|
||||
try: # it may be a scannable
|
||||
return o.getName()
|
||||
except AttributeError:
|
||||
return str(o)
|
||||
|
||||
|
||||
|
||||
@command
|
||||
def hardware():
|
||||
"""hardware -- show diffcalc limits and cuts"""
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setcut(scannable_or_string=None, val=None):
|
||||
"""setcut {name {val}} -- sets cut angle
|
||||
"""
|
||||
if scannable_or_string is None and val is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
else:
|
||||
name = getNameFromScannableOrString(scannable_or_string)
|
||||
if val is None:
|
||||
print '%s: %f' % (name, settings.hardware.get_cuts()[name]) # @UndefinedVariable
|
||||
else:
|
||||
oldcut = settings.hardware.get_cuts()[name] # @UndefinedVariable
|
||||
settings.hardware.set_cut(name, float(val)) # @UndefinedVariable
|
||||
newcut = settings.hardware.get_cuts()[name] # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setmin(name=None, val=None):
|
||||
"""setmin {axis {val}} -- set lower limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, val, settings.hardware.set_lower_limit) # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setmax(name=None, val=None):
|
||||
"""setmax {name {val}} -- sets upper limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, val, settings.hardware.set_upper_limit) # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setrange(name=None, lower=None, upper=None):
|
||||
"""setrange {axis {min} {max}} -- set lower and upper limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, lower, settings.hardware.set_lower_limit) # @UndefinedVariable
|
||||
_setMinOrMax(name, upper, settings.hardware.set_upper_limit) # @UndefinedVariable
|
||||
|
||||
def _setMinOrMax(name, val, setMethod):
|
||||
if name is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
else:
|
||||
name = getNameFromScannableOrString(name)
|
||||
if val is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts(name) # @UndefinedVariable
|
||||
else:
|
||||
setMethod(name, float(val))
|
||||
|
||||
|
||||
commands_for_help = ['Hardware',
|
||||
hardware,
|
||||
setcut,
|
||||
setmin,
|
||||
setmax]
|
||||
|
||||
|
||||
class HardwareAdapter(object):
|
||||
|
||||
def __init__(self, diffractometerAngleNames, defaultCuts={},
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
|
||||
self._diffractometerAngleNames = diffractometerAngleNames
|
||||
self._upperLimitDict = {}
|
||||
self._lowerLimitDict = {}
|
||||
self._cut_angles = {}
|
||||
self._configure_cuts(defaultCuts)
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
self._name = 'base'
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def get_axes_names(self):
|
||||
return tuple(self._diffractometerAngleNames)
|
||||
|
||||
def get_position(self):
|
||||
"""pos = get_position() -- returns the current physical diffractometer
|
||||
position as a diffcalc.util object in degrees
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms
|
||||
"""
|
||||
return 12.39842 / self.get_energy()
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv """
|
||||
raise NotImplementedError()
|
||||
|
||||
def __str__(self):
|
||||
s = self.name + ":\n"
|
||||
s += " energy : " + str(self.get_energy()) + " keV\n"
|
||||
s += " wavelength : " + str(self.get_wavelength()) + " Angstrom\n"
|
||||
names = self._diffractometerAngleNames
|
||||
for name, pos in zip(names, self.get_position()):
|
||||
s += " %s : %r deg\n" % (name, pos)
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def get_position_by_name(self, angleName):
|
||||
names = list(self._diffractometerAngleNames)
|
||||
return self.get_position()[names.index(angleName)]
|
||||
|
||||
### Limits ###
|
||||
|
||||
def get_lower_limit(self, name):
|
||||
'''returns lower limits by axis name. Limit may be None if not set
|
||||
'''
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError("No angle called %s. Try one of: %s" %
|
||||
(name, self._diffractometerAngleNames))
|
||||
return self._lowerLimitDict.get(name)
|
||||
|
||||
def get_upper_limit(self, name):
|
||||
'''returns upper limit by axis name. Limit may be None if not set
|
||||
'''
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError("No angle called %s. Try one of: %s" %
|
||||
name, self._diffractometerAngleNames)
|
||||
return self._upperLimitDict.get(name)
|
||||
|
||||
def set_lower_limit(self, name, value):
|
||||
"""value may be None to remove limit"""
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError(
|
||||
"Cannot set lower Diffcalc limit: No angle called %s. Try one "
|
||||
"of: %s" % (name, self._diffractometerAngleNames))
|
||||
if value is None:
|
||||
try:
|
||||
del self._lowerLimitDict[name]
|
||||
except KeyError:
|
||||
print ("WARNING: There was no lower Diffcalc limit %s set to "
|
||||
"clear" % name)
|
||||
else:
|
||||
self._lowerLimitDict[name] = value
|
||||
|
||||
def set_upper_limit(self, name, value):
|
||||
"""value may be None to remove limit"""
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError(
|
||||
"Cannot set upper Diffcalc limit: No angle called %s. Try one "
|
||||
"of: %s" % (name, self._diffractometerAngleNames))
|
||||
if value is None:
|
||||
try:
|
||||
del self._upperLimitDict[name]
|
||||
except KeyError:
|
||||
print ("WARNING: There was no upper Diffcalc limit %s set to "
|
||||
"clear" % name)
|
||||
else:
|
||||
self._upperLimitDict[name] = value
|
||||
|
||||
def is_position_within_limits(self, positionArray):
|
||||
"""
|
||||
where position array is in degrees and cut to be between -180 and 180
|
||||
"""
|
||||
names = self._diffractometerAngleNames
|
||||
for axis_name, value in zip(names, positionArray):
|
||||
if not self.is_axis_value_within_limits(axis_name, value):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_axis_value_within_limits(self, axis_name, value):
|
||||
if axis_name in self._upperLimitDict:
|
||||
if value > self._upperLimitDict[axis_name]:
|
||||
return False
|
||||
if axis_name in self._lowerLimitDict:
|
||||
if value < self._lowerLimitDict[axis_name]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def repr_sector_limits_and_cuts(self, name=None):
|
||||
if name is None:
|
||||
s = ''
|
||||
for name in self.get_axes_names():
|
||||
s += self.repr_sector_limits_and_cuts(name) + '\n'
|
||||
s += "Note: When auto sector/transforms are used,\n "
|
||||
s += " cuts are applied before checking limits."
|
||||
return s
|
||||
# limits:
|
||||
low = self.get_lower_limit(name)
|
||||
high = self.get_upper_limit(name)
|
||||
s = ' '
|
||||
if low is not None:
|
||||
s += "% 6.1f <= " % low
|
||||
else:
|
||||
s += ' ' * 10
|
||||
s += '%5s' % name
|
||||
if high is not None:
|
||||
s += " <= % 6.1f" % high
|
||||
else:
|
||||
s += ' ' * 10
|
||||
# cuts:
|
||||
try:
|
||||
if self.get_cuts()[name] is not None:
|
||||
s += " (cut: % 6.1f)" % self.get_cuts()[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return s
|
||||
|
||||
### Cutting Stuff ###
|
||||
|
||||
def _configure_cuts(self, defaultCutsDict):
|
||||
# 1. Set default cut angles
|
||||
self._cut_angles = dict.fromkeys(self._diffractometerAngleNames, -180.)
|
||||
if 'phi' in self._cut_angles:
|
||||
self._cut_angles['phi'] = 0.
|
||||
# 2. Overide with user-specified cuts
|
||||
for name, val in defaultCutsDict.iteritems():
|
||||
self.set_cut(name, val)
|
||||
|
||||
def set_cut(self, name, value):
|
||||
if name in self._cut_angles:
|
||||
self._cut_angles[name] = value
|
||||
else:
|
||||
raise KeyError("Diffractometer has no angle %s. Try: %s." %
|
||||
(name, self._diffractometerAngleNames))
|
||||
|
||||
def get_cuts(self):
|
||||
return self._cut_angles
|
||||
|
||||
def cut_angles(self, positionArray):
|
||||
'''Assumes each angle in positionArray is between -360 and 360
|
||||
'''
|
||||
cutArray = []
|
||||
names = self._diffractometerAngleNames
|
||||
for axis_name, value in zip(names, positionArray):
|
||||
cutArray.append(self.cut_angle(axis_name, value))
|
||||
return tuple(cutArray)
|
||||
|
||||
def cut_angle(self, axis_name, value):
|
||||
cut_angle = self._cut_angles[axis_name]
|
||||
if cut_angle is None:
|
||||
return value
|
||||
return cut_angle_at(cut_angle, value)
|
||||
|
||||
|
||||
def cut_angle_at(cut_angle, value):
|
||||
if (cut_angle == 0 and (abs(value - 360) < SMALL) or
|
||||
(abs(value + 360) < SMALL) or
|
||||
(abs(value) < SMALL)):
|
||||
value = 0.
|
||||
if value < (cut_angle - SMALL):
|
||||
return value + 360.
|
||||
elif value >= cut_angle + 360. + SMALL:
|
||||
return value - 360.
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class DummyHardwareAdapter(HardwareAdapter):
|
||||
|
||||
def __init__(self, diffractometerAngleNames):
|
||||
super(self.__class__, self).__init__(diffractometerAngleNames)
|
||||
# HardwareAdapter.__init__(self, diffractometerAngleNames)
|
||||
|
||||
self._position = [0.] * len(diffractometerAngleNames)
|
||||
self._wavelength = 1.
|
||||
self.energyScannableMultiplierToGetKeV = 1
|
||||
self._name = "Dummy"
|
||||
|
||||
# Required methods
|
||||
|
||||
def get_position(self):
|
||||
"""
|
||||
pos = getDiffractometerPosition() -- returns the current physical
|
||||
diffractometer position as a list in degrees
|
||||
"""
|
||||
return self._position
|
||||
|
||||
def _set_position(self, pos):
|
||||
assert len(pos) == len(self.get_axes_names()), \
|
||||
"Wrong length of input list"
|
||||
self._position = pos
|
||||
|
||||
position = property(get_position, _set_position)
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv """
|
||||
if self._wavelength is None:
|
||||
raise DiffcalcException(
|
||||
"Energy or wavelength have not been set")
|
||||
return (12.39842 /
|
||||
(self._wavelength * self.energyScannableMultiplierToGetKeV))
|
||||
|
||||
def _set_energy(self, energy):
|
||||
self._wavelength = 12.39842 / energy
|
||||
|
||||
energy = property(get_energy, _set_energy)
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms"""
|
||||
if self._wavelength is None:
|
||||
raise DiffcalcException(
|
||||
"Energy or wavelength have not been set")
|
||||
return self._wavelength
|
||||
|
||||
def _set_wavelength(self, wavelength):
|
||||
self._wavelength = wavelength
|
||||
|
||||
wavelength = property(get_wavelength, _set_wavelength)
|
||||
|
||||
|
||||
class ScannableHardwareAdapter(HardwareAdapter):
|
||||
|
||||
def __init__(self, diffractometerScannable, energyScannable,
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
input_names = diffractometerScannable.getInputNames()
|
||||
super(self.__class__, self).__init__(input_names)
|
||||
# HardwareAdapter.__init__(self, input_names)
|
||||
self.diffhw = diffractometerScannable
|
||||
self.energyhw = energyScannable
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
self._name = "ScannableHarwdareMonitor"
|
||||
|
||||
# Required methods
|
||||
|
||||
def get_position(self):
|
||||
"""
|
||||
pos = getDiffractometerPosition() -- returns the current physical
|
||||
diffractometer position as a list in degrees
|
||||
"""
|
||||
return self.diffhw.getPosition()
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv (NOT eV!) """
|
||||
multiplier = self.energyScannableMultiplierToGetKeV
|
||||
energy = self.energyhw.getPosition() * multiplier
|
||||
if energy is None:
|
||||
raise DiffcalcException("Energy has not been set")
|
||||
return energy
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms"""
|
||||
energy = self.get_energy()
|
||||
return 12.39842 / energy
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.diffhw.getName()
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/__init__.py
Executable file
155
script/__Lib/diffcalc-2.1/diffcalc/hkl/calcbase.py
Executable file
155
script/__Lib/diffcalc-2.1/diffcalc/hkl/calcbase.py
Executable file
@@ -0,0 +1,155 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi
|
||||
|
||||
from diffcalc.util import DiffcalcException, differ
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class HklCalculatorBase(object):
|
||||
|
||||
def __init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=False):
|
||||
|
||||
self._ubcalc = ubcalc # to get the UBMatrix, tau and sigma
|
||||
self._geometry = geometry # to access information about the
|
||||
# diffractometer geometry and mode_selector
|
||||
self._hardware = hardware # Used for tracking parameters only
|
||||
self.raiseExceptionsIfAnglesDoNotMapBackToHkl = \
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl
|
||||
|
||||
def anglesToHkl(self, pos, wavelength):
|
||||
"""
|
||||
Return hkl tuple and dictionary of all virtual angles in degrees from
|
||||
Position in degrees and wavelength in Angstroms.
|
||||
"""
|
||||
|
||||
h, k, l = self._anglesToHkl(pos.inRadians(), wavelength)
|
||||
paramDict = self.anglesToVirtualAngles(pos, wavelength)
|
||||
return ((h, k, l), paramDict)
|
||||
|
||||
def anglesToVirtualAngles(self, pos, wavelength):
|
||||
"""
|
||||
Return dictionary of all virtual angles in degrees from Position object
|
||||
in degrees and wavelength in Angstroms.
|
||||
"""
|
||||
anglesDict = self._anglesToVirtualAngles(pos.inRadians(), wavelength)
|
||||
for name in anglesDict:
|
||||
anglesDict[name] = anglesDict[name] * TODEG
|
||||
return anglesDict
|
||||
|
||||
def hklToAngles(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return verified Position and all virtual angles in degrees from
|
||||
h, k & l and wavelength in Angstroms.
|
||||
|
||||
The calculated Position is verified by checking that it maps back using
|
||||
anglesToHkl() to the requested hkl value.
|
||||
|
||||
Those virtual angles fixed or generated while calculating the position
|
||||
are verified by by checking that they map back using
|
||||
anglesToVirtualAngles to the virtual angles for the given position.
|
||||
|
||||
Throws a DiffcalcException if either check fails and
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl is True, otherwise displays a
|
||||
warning.
|
||||
"""
|
||||
|
||||
# Update tracked parameters. During this calculation parameter values
|
||||
# will be read directly from self._parameters instead of via
|
||||
# self.getParameter which would trigger another potentially time-costly
|
||||
# position update.
|
||||
self.parameter_manager.update_tracked()
|
||||
|
||||
pos, virtualAngles = self._hklToAngles(h, k, l, wavelength) # in rad
|
||||
|
||||
# to degrees:
|
||||
pos.changeToDegrees()
|
||||
|
||||
for key, val in virtualAngles.items():
|
||||
if val is not None:
|
||||
virtualAngles[key] = val * TODEG
|
||||
|
||||
self._verify_pos_map_to_hkl(h, k, l, wavelength, pos)
|
||||
|
||||
virtualAnglesReadback = self._verify_virtual_angles(h, k, l, wavelength, pos, virtualAngles)
|
||||
|
||||
return pos, virtualAnglesReadback
|
||||
|
||||
def _verify_pos_map_to_hkl(self, h, k, l, wavelength, pos):
|
||||
hkl, _ = self.anglesToHkl(pos, wavelength)
|
||||
e = 0.001
|
||||
if ((abs(hkl[0] - h) > e) or (abs(hkl[1] - k) > e) or
|
||||
(abs(hkl[2] - l) > e)):
|
||||
s = "ERROR: The angles calculated for hkl=(%f,%f,%f) were %s.\n" % (h, k, l, str(pos))
|
||||
s += "Converting these angles back to hkl resulted in hkl="\
|
||||
"(%f,%f,%f)" % (hkl[0], hkl[1], hkl[2])
|
||||
if self.raiseExceptionsIfAnglesDoNotMapBackToHkl:
|
||||
raise DiffcalcException(s)
|
||||
else:
|
||||
print s
|
||||
|
||||
def _verify_virtual_angles(self, h, k, l, wavelength, pos, virtualAngles):
|
||||
# Check that the virtual angles calculated/fixed during the hklToAngles
|
||||
# those read back from pos using anglesToVirtualAngles
|
||||
virtualAnglesReadback = self.anglesToVirtualAngles(pos, wavelength)
|
||||
for key, val in virtualAngles.items():
|
||||
if val != None: # Some values calculated in some mode_selector
|
||||
r = virtualAnglesReadback[key]
|
||||
if ((differ(val, r, .00001) and differ(val, r + 360, .00001) and differ(val, r - 360, .00001))):
|
||||
s = "ERROR: The angles calculated for hkl=(%f,%f,%f) with"\
|
||||
" mode=%s were %s.\n" % (h, k, l, self.repr_mode(), str(pos))
|
||||
s += "During verification the virtual angle %s resulting "\
|
||||
"from (or set for) this calculation of %f" % (key, val)
|
||||
s += "did not match that calculated by "\
|
||||
"anglesToVirtualAngles of %f" % virtualAnglesReadback[key]
|
||||
if self.raiseExceptionsIfAnglesDoNotMapBackToHkl:
|
||||
raise DiffcalcException(s)
|
||||
else:
|
||||
print s
|
||||
|
||||
return virtualAnglesReadback
|
||||
|
||||
def repr_mode(self):
|
||||
pass
|
||||
|
||||
### Collect all math access to context here
|
||||
|
||||
def _getUBMatrix(self):
|
||||
return self._ubcalc.UB
|
||||
|
||||
def _getMode(self):
|
||||
return self.mode_selector.getMode()
|
||||
|
||||
def _getSigma(self):
|
||||
return self._ubcalc.sigma
|
||||
|
||||
def _getTau(self):
|
||||
return self._ubcalc.tau
|
||||
|
||||
def _getParameter(self, name):
|
||||
# Does not use context.getParameter as this will trigger a costly
|
||||
# parameter collection
|
||||
pm = self.parameter_manager
|
||||
return pm.getParameterWithoutUpdatingTrackedParemeters(name)
|
||||
|
||||
def _getGammaParameterName(self):
|
||||
return self._gammaParameterName
|
||||
55
script/__Lib/diffcalc-2.1/diffcalc/hkl/common.py
Executable file
55
script/__Lib/diffcalc-2.1/diffcalc/hkl/common.py
Executable file
@@ -0,0 +1,55 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
from diffcalc.util import allnum
|
||||
|
||||
def getNameFromScannableOrString(o):
|
||||
try: # it may be a scannable
|
||||
return o.getName()
|
||||
except AttributeError:
|
||||
return str(o)
|
||||
raise TypeError()
|
||||
|
||||
|
||||
class DummyParameterManager(object):
|
||||
|
||||
def getParameterDict(self):
|
||||
return {}
|
||||
|
||||
def _setParameter(self, name, value):
|
||||
raise KeyError(name)
|
||||
|
||||
def _getParameter(self, name):
|
||||
raise KeyError(name)
|
||||
|
||||
def update_tracked(self):
|
||||
pass
|
||||
|
||||
|
||||
def sim(self, scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError("The first argument does not support simulated moves")
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/__init__.py
Executable file
846
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/calc.py
Executable file
846
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/calc.py
Executable file
@@ -0,0 +1,846 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, asin, acos, sin, cos, sqrt, atan2, fabs, atan
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
from numjy.linalg import norm
|
||||
|
||||
from diffcalc.hkl.calcbase import HklCalculatorBase
|
||||
from diffcalc.hkl.vlieg.transform import TransformCInRadians
|
||||
from diffcalc.util import dot3, cross3, bound, differ
|
||||
from diffcalc.hkl.vlieg.geometry import createVliegMatrices, \
|
||||
createVliegsPsiTransformationMatrix, \
|
||||
createVliegsSurfaceTransformationMatrices, calcPHI
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition
|
||||
from diffcalc.hkl.vlieg.constraints import VliegParameterManager
|
||||
from diffcalc.hkl.vlieg.constraints import ModeSelector
|
||||
from diffcalc.ub.calc import PaperSpecificUbCalcStrategy
|
||||
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
transformC = TransformCInRadians()
|
||||
|
||||
|
||||
PREFER_POSITIVE_CHI_SOLUTIONS = True
|
||||
|
||||
I = matrix('1 0 0; 0 1 0; 0 0 1')
|
||||
y = matrix('0; 1; 0')
|
||||
|
||||
|
||||
def check(condition, ErrorOrStringOrCallable, *args):
|
||||
"""
|
||||
fail = check(condition, ErrorOrString) -- if condition is false raises the
|
||||
Exception passed in, or creates one from a string. If a callable function
|
||||
is passed in this is called with any args specified and the thing returns
|
||||
false.
|
||||
"""
|
||||
# TODO: Remove (really nasty) check function
|
||||
if condition == False:
|
||||
if callable(ErrorOrStringOrCallable):
|
||||
ErrorOrStringOrCallable(*args)
|
||||
return False
|
||||
elif isinstance(ErrorOrStringOrCallable, str):
|
||||
raise Exception(ErrorOrStringOrCallable)
|
||||
else: # assume input is an exception
|
||||
raise ErrorOrStringOrCallable
|
||||
return True
|
||||
|
||||
|
||||
def sign(x):
|
||||
if x < 0:
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
def vliegAnglesToHkl(pos, wavelength, UBMatrix):
|
||||
"""
|
||||
Returns hkl indices from pos object in radians.
|
||||
"""
|
||||
wavevector = 2 * pi / wavelength
|
||||
|
||||
# Create transformation matrices
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
|
||||
# Create the plane normal vector in the alpha axis coordinate frame
|
||||
qa = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [wavevector], [0]])
|
||||
|
||||
# Transform the plane normal vector from the alpha frame to reciprical
|
||||
# lattice frame.
|
||||
hkl = UBMatrix.I * PHI.I * CHI.I * OMEGA.I * qa
|
||||
|
||||
return hkl[0, 0], hkl[1, 0], hkl[2, 0]
|
||||
|
||||
|
||||
class VliegUbCalcStrategy(PaperSpecificUbCalcStrategy):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
|
||||
u1a = (DELTA * GAMMA - ALPHA.I) * y
|
||||
u1p = PHI.I * CHI.I * OMEGA.I * u1a
|
||||
return u1p
|
||||
|
||||
|
||||
class VliegHklCalculator(HklCalculatorBase):
|
||||
|
||||
def __init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=True):
|
||||
r = raiseExceptionsIfAnglesDoNotMapBackToHkl
|
||||
HklCalculatorBase.__init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=r)
|
||||
self._gammaParameterName = ({'arm': 'gamma', 'base': 'oopgamma'}
|
||||
[self._geometry.gamma_location])
|
||||
self.mode_selector = ModeSelector(self._geometry, None,
|
||||
self._gammaParameterName)
|
||||
self.parameter_manager = VliegParameterManager(
|
||||
self._geometry, self._hardware, self.mode_selector,
|
||||
self._gammaParameterName)
|
||||
self.mode_selector.setParameterManager(self.parameter_manager)
|
||||
|
||||
def __str__(self):
|
||||
# should list paramemeters and indicate which are used in selected mode
|
||||
result = "Available mode_selector:\n"
|
||||
result += self.mode_selector.reportAvailableModes()
|
||||
result += '\nCurrent mode:\n'
|
||||
result += self.mode_selector.reportCurrentMode()
|
||||
result += '\n\nParameters:\n'
|
||||
result += self.parameter_manager.reportAllParameters()
|
||||
return result
|
||||
|
||||
def _anglesToHkl(self, pos, wavelength):
|
||||
"""
|
||||
Return hkl tuple from VliegPosition in radians and wavelength in
|
||||
Angstroms.
|
||||
"""
|
||||
return vliegAnglesToHkl(pos, wavelength, self._getUBMatrix())
|
||||
|
||||
def _anglesToVirtualAngles(self, pos, wavelength):
|
||||
"""
|
||||
Return dictionary of all virtual angles in radians from VliegPosition
|
||||
object win radians and wavelength in Angstroms. The virtual angles are:
|
||||
Bin, Bout, azimuth and 2theta.
|
||||
"""
|
||||
|
||||
# Create transformation matrices
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
|
||||
S = TAU * SIGMA
|
||||
y_vector = matrix([[0], [1], [0]])
|
||||
|
||||
# Calculate Bin from equation 15:
|
||||
surfacenormal_alpha = OMEGA * CHI * PHI * S * matrix([[0], [0], [1]])
|
||||
incoming_alpha = ALPHA.I * y_vector
|
||||
minusSinBetaIn = dot3(surfacenormal_alpha, incoming_alpha)
|
||||
Bin = asin(bound(-minusSinBetaIn))
|
||||
|
||||
# Calculate Bout from equation 16:
|
||||
# surfacenormal_alpha has just ben calculated
|
||||
outgoing_alpha = DELTA * GAMMA * y_vector
|
||||
sinBetaOut = dot3(surfacenormal_alpha, outgoing_alpha)
|
||||
Bout = asin(bound(sinBetaOut))
|
||||
|
||||
# Calculate 2theta from equation 25:
|
||||
|
||||
cosTwoTheta = dot3(ALPHA * DELTA * GAMMA * y_vector, y_vector)
|
||||
twotheta = acos(bound(cosTwoTheta))
|
||||
psi = self._anglesToPsi(pos, wavelength)
|
||||
|
||||
return {'Bin': Bin, 'Bout': Bout, 'azimuth': psi, '2theta': twotheta}
|
||||
|
||||
def _hklToAngles(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return VliegPosition and virtual angles in radians from h, k & l and
|
||||
wavelength in Angstroms. The virtual angles are those fixed or
|
||||
generated while calculating the position: Bin, Bout and 2theta; and
|
||||
azimuth in four and five circle modes.
|
||||
"""
|
||||
|
||||
if self._getMode().group in ("fourc", "fivecFixedGamma",
|
||||
"fivecFixedAlpha"):
|
||||
return self._hklToAnglesFourAndFiveCirclesModes(h, k, l,
|
||||
wavelength)
|
||||
elif self._getMode().group == "zaxis":
|
||||
return self._hklToAnglesZaxisModes(h, k, l, wavelength)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'The current mode (%s) has an unrecognised group: %s.'
|
||||
% (self._getMode().name, self._getMode().group))
|
||||
|
||||
def _hklToAnglesFourAndFiveCirclesModes(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return VliegPosition and virtual angles in radians from h, k & l and
|
||||
wavelength in Angstrom for four and five circle modes. The virtual
|
||||
angles are those fixed or generated while calculating the position:
|
||||
Bin, Bout, 2theta and azimuth.
|
||||
"""
|
||||
|
||||
# Results in radians during calculations, returned in degreess
|
||||
pos = VliegPosition(None, None, None, None, None, None)
|
||||
|
||||
# Normalise hkl
|
||||
wavevector = 2 * pi / wavelength
|
||||
hklNorm = matrix([[h], [k], [l]]) / wavevector
|
||||
|
||||
# Compute hkl in phi axis coordinate frame
|
||||
hklPhiNorm = self._getUBMatrix() * hklNorm
|
||||
|
||||
# Determine Bin and Bout
|
||||
if self._getMode().name == '4cPhi':
|
||||
Bin = Bout = None
|
||||
else:
|
||||
Bin, Bout = self._determineBinAndBoutInFourAndFiveCirclesModes(
|
||||
hklNorm)
|
||||
|
||||
# Determine alpha and gamma
|
||||
if self._getMode().group == 'fourc':
|
||||
pos.alpha, pos.gamma = \
|
||||
self._determineAlphaAndGammaForFourCircleModes(hklPhiNorm)
|
||||
else:
|
||||
pos.alpha, pos.gamma = \
|
||||
self._determineAlphaAndGammaForFiveCircleModes(Bin, hklPhiNorm)
|
||||
if pos.alpha < -pi:
|
||||
pos.alpha += 2 * pi
|
||||
if pos.alpha > pi:
|
||||
pos.alpha -= 2 * pi
|
||||
|
||||
# Determine delta
|
||||
(pos.delta, twotheta) = self._determineDelta(hklPhiNorm, pos.alpha,
|
||||
pos.gamma)
|
||||
|
||||
# Determine omega, chi & phi
|
||||
pos.omega, pos.chi, pos.phi, psi = \
|
||||
self._determineSampleAnglesInFourAndFiveCircleModes(
|
||||
hklPhiNorm, pos.alpha, pos.delta, pos.gamma, Bin)
|
||||
# (psi will be None in fixed phi mode)
|
||||
|
||||
# Ensure that by default omega is between -90 and 90, by possibly
|
||||
# transforming the sample angles
|
||||
if self._getMode().name != '4cPhi': # not in fixed-phi mode
|
||||
if pos.omega < -pi / 2 or pos.omega > pi / 2:
|
||||
pos = transformC.transform(pos)
|
||||
|
||||
# Gather up the virtual angles calculated along the way...
|
||||
# -pi<psi<=pi
|
||||
if psi is not None:
|
||||
if psi > pi:
|
||||
psi -= 2 * pi
|
||||
if psi < (-1 * pi):
|
||||
psi += 2 * pi
|
||||
|
||||
v = {'2theta': twotheta, 'Bin': Bin, 'Bout': Bout, 'azimuth': psi}
|
||||
return pos, v
|
||||
|
||||
def _hklToAnglesZaxisModes(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return VliegPosition and virtual angles in radians from h, k & l and
|
||||
wavelength in Angstroms for z-axis modes. The virtual angles are those
|
||||
fixed or generated while calculating the position: Bin, Bout, and
|
||||
2theta.
|
||||
"""
|
||||
# Section 6:
|
||||
|
||||
# Results in radians during calculations, returned in degreess
|
||||
pos = VliegPosition(None, None, None, None, None, None)
|
||||
|
||||
# Normalise hkl
|
||||
wavevector = 2 * pi / wavelength
|
||||
hkl = matrix([[h], [k], [l]])
|
||||
hklNorm = hkl * (1.0 / wavevector)
|
||||
|
||||
# Compute hkl in phi axis coordinate frame
|
||||
hklPhi = self._getUBMatrix() * hkl
|
||||
hklPhiNorm = self._getUBMatrix() * hklNorm
|
||||
|
||||
# Determine Chi and Phi (Equation 29):
|
||||
pos.phi = -self._getTau() * TORAD
|
||||
pos.chi = -self._getSigma() * TORAD
|
||||
|
||||
# Equation 30:
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
None, None, None, None, pos.chi, pos.phi)
|
||||
del ALPHA, DELTA, GAMMA, OMEGA
|
||||
Hw = CHI * PHI * hklPhi
|
||||
|
||||
# Determine Bin and Bout:
|
||||
(Bin, Bout) = self._determineBinAndBoutInZaxisModes(
|
||||
Hw[2, 0] / wavevector)
|
||||
|
||||
# Determine Alpha and Gamma (Equation 32):
|
||||
pos.alpha = Bin
|
||||
pos.gamma = Bout
|
||||
|
||||
# Determine Delta:
|
||||
(pos.delta, twotheta) = self._determineDelta(hklPhiNorm, pos.alpha,
|
||||
pos.gamma)
|
||||
|
||||
# Determine Omega:
|
||||
delta = pos.delta
|
||||
gamma = pos.gamma
|
||||
d1 = (Hw[1, 0] * sin(delta) * cos(gamma) - Hw[0, 0] *
|
||||
(cos(delta) * cos(gamma) - cos(pos.alpha)))
|
||||
d2 = (Hw[0, 0] * sin(delta) * cos(gamma) + Hw[1, 0] *
|
||||
(cos(delta) * cos(gamma) - cos(pos.alpha)))
|
||||
|
||||
if fabs(d2) < 1e-30:
|
||||
pos.omega = sign(d1) * sign(d2) * pi / 2.0
|
||||
else:
|
||||
pos.omega = atan2(d1, d2)
|
||||
|
||||
# Gather up the virtual angles calculated along the way
|
||||
return pos, {'2theta': twotheta, 'Bin': Bin, 'Bout': Bout}
|
||||
|
||||
###
|
||||
|
||||
def _determineBinAndBoutInFourAndFiveCirclesModes(self, hklNorm):
|
||||
"""(Bin, Bout) = _determineBinAndBoutInFourAndFiveCirclesModes()"""
|
||||
BinModes = ('4cBin', '5cgBin', '5caBin')
|
||||
BoutModes = ('4cBout', '5cgBout', '5caBout')
|
||||
BeqModes = ('4cBeq', '5cgBeq', '5caBeq')
|
||||
azimuthModes = ('4cAzimuth')
|
||||
fixedBusingAndLeviWmodes = ('4cFixedw')
|
||||
|
||||
# Calculate RHS of equation 20
|
||||
# RHS (1/K)(S^-1*U*B*H)_3 where H/K = hklNorm
|
||||
UB = self._getUBMatrix()
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
#S = SIGMA * TAU
|
||||
S = TAU * SIGMA
|
||||
RHS = (S.I * UB * hklNorm)[2, 0]
|
||||
|
||||
if self._getMode().name in BinModes:
|
||||
Bin = self._getParameter('betain')
|
||||
check(Bin != None, "The parameter betain must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bin = Bin * TORAD
|
||||
sinBout = RHS - sin(Bin)
|
||||
check(fabs(sinBout) <= 1, "Could not compute Bout")
|
||||
Bout = asin(sinBout)
|
||||
|
||||
elif self._getMode().name in BoutModes:
|
||||
Bout = self._getParameter('betaout')
|
||||
check(Bout != None, "The parameter Bout must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bout = Bout * TORAD
|
||||
sinBin = RHS - sin(Bout)
|
||||
check(fabs(sinBin) <= 1, "Could not compute Bin")
|
||||
Bin = asin(sinBin)
|
||||
|
||||
elif self._getMode().name in BeqModes:
|
||||
sinBeq = RHS / 2
|
||||
check(fabs(sinBeq) <= 1, "Could not compute Bin=Bout")
|
||||
Bin = Bout = asin(sinBeq)
|
||||
|
||||
elif self._getMode().name in azimuthModes:
|
||||
azimuth = self._getParameter('azimuth')
|
||||
check(azimuth != None, "The parameter azimuth must be set for "
|
||||
"mode %s" % self._getMode().name)
|
||||
del azimuth
|
||||
# TODO: codeit
|
||||
raise NotImplementedError()
|
||||
|
||||
elif self._getMode().name in fixedBusingAndLeviWmodes:
|
||||
bandlomega = self._getParameter('blw')
|
||||
check(bandlomega != None, "The parameter abandlomega must be set "
|
||||
"for mode %s" % self._getMode().name)
|
||||
del bandlomega
|
||||
# TODO: codeit
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
raise RuntimeError("AngleCalculator does not know how to handle "
|
||||
"mode %s" % self._getMode().name)
|
||||
|
||||
return (Bin, Bout)
|
||||
|
||||
def _determineBinAndBoutInZaxisModes(self, Hw3OverK):
|
||||
"""(Bin, Bout) = _determineBinAndBoutInZaxisModes(HwOverK)"""
|
||||
BinModes = ('6czBin')
|
||||
BoutModes = ('6czBout')
|
||||
BeqModes = ('6czBeq')
|
||||
|
||||
if self._getMode().name in BinModes:
|
||||
Bin = self._getParameter('betain')
|
||||
check(Bin != None, "The parameter betain must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bin = Bin * TORAD
|
||||
# Equation 32a:
|
||||
Bout = asin(Hw3OverK - sin(Bin))
|
||||
|
||||
elif self._getMode().name in BoutModes:
|
||||
Bout = self._getParameter('betaout')
|
||||
check(Bout != None, "The parameter Bout must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bout = Bout * TORAD
|
||||
# Equation 32b:
|
||||
Bin = asin(Hw3OverK - sin(Bout))
|
||||
|
||||
elif self._getMode().name in BeqModes:
|
||||
# Equation 32c:
|
||||
Bin = Bout = asin(Hw3OverK / 2)
|
||||
|
||||
return (Bin, Bout)
|
||||
|
||||
###
|
||||
|
||||
def _determineAlphaAndGammaForFourCircleModes(self, hklPhiNorm):
|
||||
|
||||
if self._getMode().group == 'fourc':
|
||||
alpha = self._getParameter('alpha') * TORAD
|
||||
gamma = self._getParameter(self._getGammaParameterName()) * TORAD
|
||||
check(alpha != None, "alpha parameter must be set in fourc modes")
|
||||
check(gamma != None, "gamma parameter must be set in fourc modes")
|
||||
return alpha, gamma
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"determineAlphaAndGammaForFourCirclesModes() "
|
||||
"is not appropriate for %s modes" % self._getMode().group)
|
||||
|
||||
def _determineAlphaAndGammaForFiveCircleModes(self, Bin, hklPhiNorm):
|
||||
|
||||
## Solve equation 34 for one possible Y, Yo
|
||||
# Calculate surface normal in phi frame
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
S = TAU * SIGMA
|
||||
surfaceNormalPhi = S * matrix([[0], [0], [1]])
|
||||
# Compute beta in vector
|
||||
BetaVector = matrix([[0], [-sin(Bin)], [cos(Bin)]])
|
||||
# Find Yo
|
||||
Yo = self._findMatrixToTransformAIntoB(surfaceNormalPhi, BetaVector)
|
||||
|
||||
## Calculate Hv from equation 39
|
||||
Z = matrix([[1, 0, 0],
|
||||
[0, cos(Bin), sin(Bin)],
|
||||
[0, -sin(Bin), cos(Bin)]])
|
||||
Hv = Z * Yo * hklPhiNorm
|
||||
# Fixed gamma:
|
||||
if self._getMode().group == 'fivecFixedGamma':
|
||||
gamma = self._getParameter(self._getGammaParameterName())
|
||||
check(gamma != None,
|
||||
"gamma parameter must be set in fivecFixedGamma modes")
|
||||
gamma = gamma * TORAD
|
||||
H2 = (hklPhiNorm[0, 0] ** 2 + hklPhiNorm[1, 0] ** 2 +
|
||||
hklPhiNorm[2, 0] ** 2)
|
||||
a = -(0.5 * H2 * sin(Bin) - Hv[2, 0])
|
||||
b = -(1.0 - 0.5 * H2) * cos(Bin)
|
||||
c = cos(Bin) * sin(gamma)
|
||||
check((b * b + a * a - c * c) >= 0, 'Could not solve for alpha')
|
||||
alpha = 2 * atan2(-(b + sqrt(b * b + a * a - c * c)), -(a + c))
|
||||
|
||||
# Fixed Alpha:
|
||||
elif self._getMode().group == 'fivecFixedAlpha':
|
||||
alpha = self._getParameter('alpha')
|
||||
check(alpha != None,
|
||||
"alpha parameter must be set in fivecFixedAlpha modes")
|
||||
alpha = alpha * TORAD
|
||||
H2 = (hklPhiNorm[0, 0] ** 2 + hklPhiNorm[1, 0] ** 2 +
|
||||
hklPhiNorm[2, 0] ** 2)
|
||||
t0 = ((2 * cos(alpha) * Hv[2, 0] - sin(Bin) * cos(alpha) * H2 +
|
||||
cos(Bin) * sin(alpha) * H2 - 2 * cos(Bin) * sin(alpha)) /
|
||||
(cos(Bin) * 2.0))
|
||||
check(abs(t0) <= 1, "Cannot compute gamma: sin(gamma)>1")
|
||||
gamma = asin(t0)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"determineAlphaAndGammaInFiveCirclesModes() is not "
|
||||
"appropriate for %s modes" % self._getMode().group)
|
||||
|
||||
return (alpha, gamma)
|
||||
|
||||
###
|
||||
|
||||
def _determineDelta(self, hklPhiNorm, alpha, gamma):
|
||||
"""
|
||||
(delta, twotheta) = _determineDelta(hklPhiNorm, alpha, gamma) --
|
||||
computes delta for all modes. Also returns twotheta for sanity
|
||||
checking. hklPhiNorm is a 3X1 matrix.
|
||||
|
||||
alpha, gamma & delta - in radians.
|
||||
h k & l normalised to wavevector and in phi axis coordinates
|
||||
"""
|
||||
h = hklPhiNorm[0, 0]
|
||||
k = hklPhiNorm[1, 0]
|
||||
l = hklPhiNorm[2, 0]
|
||||
# See Vlieg section 5 (with K=1)
|
||||
cosdelta = ((1 + sin(gamma) * sin(alpha) - (h * h + k * k + l * l) / 2)
|
||||
/ (cos(gamma) * cos(alpha)))
|
||||
costwotheta = (cos(alpha) * cos(gamma) * bound(cosdelta) -
|
||||
sin(alpha) * sin(gamma))
|
||||
return (acos(bound(cosdelta)), acos(bound(costwotheta)))
|
||||
|
||||
def _determineSampleAnglesInFourAndFiveCircleModes(self, hklPhiNorm, alpha,
|
||||
delta, gamma, Bin):
|
||||
"""
|
||||
(omega, chi, phi, psi)=determineNonZAxisSampleAngles(hklPhiNorm, alpha,
|
||||
delta, gamma, sigma, tau) where hkl has been normalised by the
|
||||
wavevector and is in the phi Axis coordinate frame. All angles in
|
||||
radians. hklPhiNorm is a 3X1 matrix
|
||||
"""
|
||||
|
||||
def equation49through59(psi):
|
||||
# equation 49 R = (D^-1)*PI*D*Ro
|
||||
PSI = createVliegsPsiTransformationMatrix(psi)
|
||||
R = D.I * PSI * D * Ro
|
||||
|
||||
# eq 57: extract omega from R
|
||||
if abs(R[0, 2]) < 1e-20:
|
||||
omega = -sign(R[1, 2]) * sign(R[0, 2]) * pi / 2
|
||||
else:
|
||||
omega = -atan2(R[1, 2], R[0, 2])
|
||||
|
||||
# eq 58: extract chi from R
|
||||
sinchi = sqrt(pow(R[0, 2], 2) + pow(R[1, 2], 2))
|
||||
sinchi = bound(sinchi)
|
||||
check(abs(sinchi) <= 1, 'could not compute chi')
|
||||
# (there are two roots to this equation, but only the first is also
|
||||
# a solution to R33=cos(chi))
|
||||
chi = asin(sinchi)
|
||||
|
||||
# eq 59: extract phi from R
|
||||
if abs(R[2, 0]) < 1e-20:
|
||||
phi = sign(R[2, 1]) * sign(R[2, 1]) * pi / 2
|
||||
else:
|
||||
phi = atan2(-R[2, 1], -R[2, 0])
|
||||
return omega, chi, phi
|
||||
|
||||
def checkSolution(omega, chi, phi):
|
||||
_, _, _, OMEGA, CHI, PHI = createVliegMatrices(
|
||||
None, None, None, omega, chi, phi)
|
||||
R = OMEGA * CHI * PHI
|
||||
RtimesH_phi = R * H_phi
|
||||
print ("R*H_phi=%s, Q_alpha=%s" %
|
||||
(R * H_phi.tolist(), Q_alpha.tolist()))
|
||||
return not differ(RtimesH_phi, Q_alpha, .0001)
|
||||
|
||||
# Using Vlieg section 7.2
|
||||
|
||||
# Needed througout:
|
||||
[ALPHA, DELTA, GAMMA, _, _, _] = createVliegMatrices(
|
||||
alpha, delta, gamma, None, None, None)
|
||||
|
||||
## Find Ro, one possible solution to equation 46: R*H_phi=Q_alpha
|
||||
|
||||
# Normalise hklPhiNorm (As it is currently normalised only to the
|
||||
# wavevector)
|
||||
normh = norm(hklPhiNorm)
|
||||
check(normh >= 1e-10, "reciprical lattice vector too close to zero")
|
||||
H_phi = hklPhiNorm * (1 / normh)
|
||||
|
||||
# Create Q_alpha from equation 47, (it comes normalised)
|
||||
Q_alpha = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [1], [0]])
|
||||
Q_alpha = Q_alpha * (1 / norm(Q_alpha))
|
||||
|
||||
if self._getMode().name == '4cPhi':
|
||||
### Use the fixed value of phi as the final constraint ###
|
||||
phi = self._getParameter('phi') * TORAD
|
||||
PHI = calcPHI(phi)
|
||||
H_chi = PHI * H_phi
|
||||
omega, chi = _findOmegaAndChiToRotateHchiIntoQalpha(H_chi, Q_alpha)
|
||||
return (omega, chi, phi, None) # psi = None as not calculated
|
||||
else:
|
||||
### Use Bin as the final constraint ###
|
||||
|
||||
# Find a solution Ro to Ro*H_phi=Q_alpha
|
||||
Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha)
|
||||
|
||||
## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]])
|
||||
D = self._findMatrixToTransformAIntoB(
|
||||
Q_alpha, matrix([[1], [0], [0]]))
|
||||
|
||||
## Find psi and create PSI
|
||||
|
||||
# eq 54: compute u=D*Ro*S*[[0],[0],[1]], the surface normal in
|
||||
# psi frame
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
S = TAU * SIGMA
|
||||
[u1], [u2], [u3] = (D * Ro * S * matrix([[0], [0], [1]])).tolist()
|
||||
# TODO: If u points along 100, then any psi is a solution. Choose 0
|
||||
if not differ([u1, u2, u3], [1, 0, 0], 1e-9):
|
||||
psi = 0
|
||||
omega, chi, phi = equation49through59(psi)
|
||||
else:
|
||||
# equation 53: V=A*(D^-1)
|
||||
V = ALPHA * D.I
|
||||
v21 = V[1, 0]
|
||||
v22 = V[1, 1]
|
||||
v23 = V[1, 2]
|
||||
# equation 55
|
||||
a = v22 * u2 + v23 * u3
|
||||
b = v22 * u3 - v23 * u2
|
||||
c = -sin(Bin) - v21 * u1 # TODO: changed sign from paper
|
||||
|
||||
# equation 44
|
||||
# Try first root:
|
||||
def myatan2(y, x):
|
||||
if abs(x) < 1e-20 and abs(y) < 1e-20:
|
||||
return pi / 2
|
||||
else:
|
||||
return atan2(y, x)
|
||||
psi = 2 * myatan2(-(b - sqrt(b * b + a * a - c * c)), -(a + c))
|
||||
#psi = -acos(c/sqrt(a*a+b*b))+atan2(b,a)# -2*pi
|
||||
omega, chi, phi = equation49through59(psi)
|
||||
|
||||
# if u points along z axis, the psi could have been either 0 or 180
|
||||
if (not differ([u1, u2, u3], [0, 0, 1], 1e-9) and
|
||||
abs(psi - pi) < 1e-10):
|
||||
# Choose 0 to match that read up by angles-to-virtual-angles
|
||||
psi = 0.
|
||||
# if u points a long
|
||||
return (omega, chi, phi, psi)
|
||||
|
||||
def _anglesToPsi(self, pos, wavelength):
|
||||
"""
|
||||
pos assumed in radians. -180<= psi <= 180
|
||||
"""
|
||||
# Using Vlieg section 7.2
|
||||
|
||||
# Needed througout:
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
|
||||
# Solve equation 49 for psi, the rotation of the a reference solution
|
||||
# about Qalpha or H_phi##
|
||||
|
||||
# Find Ro, the reference solution to equation 46: R*H_phi=Q_alpha
|
||||
|
||||
# Create Q_alpha from equation 47, (it comes normalised)
|
||||
Q_alpha = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [1], [0]])
|
||||
Q_alpha = Q_alpha * (1 / norm(Q_alpha))
|
||||
|
||||
# Finh H_phi
|
||||
h, k, l = self._anglesToHkl(pos, wavelength)
|
||||
H_phi = self._getUBMatrix() * matrix([[h], [k], [l]])
|
||||
normh = norm(H_phi)
|
||||
check(normh >= 1e-10, "reciprical lattice vector too close to zero")
|
||||
H_phi = H_phi * (1 / normh)
|
||||
|
||||
# Find a solution Ro to Ro*H_phi=Q_alpha
|
||||
# This the reference solution with zero azimuth (psi)
|
||||
Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha)
|
||||
|
||||
# equation 48:
|
||||
R = OMEGA * CHI * PHI
|
||||
|
||||
## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]])
|
||||
D = self._findMatrixToTransformAIntoB(Q_alpha, matrix([[1], [0], [0]]))
|
||||
|
||||
# solve equation 49 for psi
|
||||
# D*R = PSI*D*Ro
|
||||
# D*R*(D*Ro)^-1 = PSI
|
||||
PSI = D * R * ((D * Ro).I)
|
||||
|
||||
# Find psi within PSI as defined in equation 51
|
||||
PSI_23 = PSI[1, 2]
|
||||
PSI_33 = PSI[2, 2]
|
||||
psi = atan2(PSI_23, PSI_33)
|
||||
|
||||
#print "PSI: ", PSI.tolist()
|
||||
return psi
|
||||
|
||||
def _findMatrixToTransformAIntoB(self, a, b):
|
||||
"""
|
||||
Finds a particular matrix Mo that transforms the unit vector a into the
|
||||
unit vector b. Thats is it finds Mo Mo*a=b. a and b 3x1 matrixes and Mo
|
||||
is a 3x3 matrix.
|
||||
|
||||
Throws an exception if this is not possible.
|
||||
"""
|
||||
# Maths from the appendix of "Angle caluculations
|
||||
# for a 5-circle diffractometer used for surface X-ray diffraction",
|
||||
# E. Vlieg, J.F. van der Veen, J.E. Macdonald and M. Miller, J. of
|
||||
# Applied Cryst. 20 (1987) 330.
|
||||
# - courtesy of Elias Vlieg again
|
||||
|
||||
# equation A2: compute angle xi between vectors a and b
|
||||
cosxi = dot3(a, b)
|
||||
try:
|
||||
cosxi = bound(cosxi)
|
||||
except ValueError:
|
||||
raise Exception("Could not compute cos(xi), vectors a=%f and b=%f "
|
||||
"must be of unit length" % (norm(a), norm(b)))
|
||||
xi = acos(cosxi)
|
||||
|
||||
# Mo is identity matrix if xi zero (math below would blow up)
|
||||
if abs(xi) < 1e-10:
|
||||
return I
|
||||
|
||||
# equation A3: c=cross(a,b)/sin(xi)
|
||||
c = cross3(a, b) * (1 / sin(xi))
|
||||
|
||||
# equation A4: find D matrix that transforms a into the frame
|
||||
# x = a; y = c x a; z = c. */
|
||||
a1 = a[0, 0]
|
||||
a2 = a[1, 0]
|
||||
a3 = a[2, 0]
|
||||
c1 = c[0, 0]
|
||||
c2 = c[1, 0]
|
||||
c3 = c[2, 0]
|
||||
D = matrix([[a1, a2, a3],
|
||||
[c2 * a3 - c3 * a2, c3 * a1 - c1 * a3, c1 * a2 - c2 * a1],
|
||||
[c1, c2, c3]])
|
||||
|
||||
# equation A5: create Xi to rotate by xi about z-axis
|
||||
XI = matrix([[cos(xi), -sin(xi), 0],
|
||||
[sin(xi), cos(xi), 0],
|
||||
[0, 0, 1]])
|
||||
|
||||
# eq A6: compute Mo
|
||||
return D.I * XI * D
|
||||
|
||||
|
||||
def _findOmegaAndChiToRotateHchiIntoQalpha(h_chi, q_alpha):
|
||||
"""
|
||||
(omega, chi) = _findOmegaAndChiToRotateHchiIntoQalpha(H_chi, Q_alpha)
|
||||
|
||||
Solves for omega and chi in OMEGA*CHI*h_chi = q_alpha where h_chi and
|
||||
q_alpha are 3x1 matrices with unit length. Omega and chi are returned in
|
||||
radians.
|
||||
|
||||
Throws an exception if this is not possible.
|
||||
"""
|
||||
|
||||
def solve(a, b, c):
|
||||
"""
|
||||
x1,x2 = solve(a , b, c)
|
||||
solves for the two solutions to x in equations of the form
|
||||
a*sin(x) + b*cos(x) = c
|
||||
by using the trigonometric identity
|
||||
a*sin(x) + b*cos(x) = a*sin(x)+b*cos(x)=sqrt(a**2+b**2)-sin(x+p)
|
||||
where
|
||||
p = atan(b/a) + {0 if a>=0
|
||||
{pi if a<0
|
||||
"""
|
||||
if a == 0:
|
||||
p = pi / 2 if b >= 0 else - pi / 2
|
||||
else:
|
||||
p = atan(b / a)
|
||||
if a < 0:
|
||||
p = p + pi
|
||||
guts = c / sqrt(a ** 2 + b ** 2)
|
||||
if guts < -1:
|
||||
guts = -1
|
||||
elif guts > 1:
|
||||
guts = 1
|
||||
left1 = asin(guts)
|
||||
left2 = pi - left1
|
||||
return (left1 - p, left2 - p)
|
||||
|
||||
def ne(a, b):
|
||||
"""
|
||||
shifts a and b in between -pi and pi and tests for near equality
|
||||
"""
|
||||
def shift(a):
|
||||
if a > pi:
|
||||
return a - 2 * pi
|
||||
elif a <= -pi:
|
||||
return a + 2 * pi
|
||||
else:
|
||||
return a
|
||||
return abs(shift(a) - shift(b)) < .0000001
|
||||
|
||||
# 1. Compute some solutions
|
||||
h_chi1 = h_chi[0, 0]
|
||||
h_chi2 = h_chi[1, 0]
|
||||
h_chi3 = h_chi[2, 0]
|
||||
q_alpha1 = q_alpha[0, 0]
|
||||
q_alpha2 = q_alpha[1, 0]
|
||||
q_alpha3 = q_alpha[2, 0]
|
||||
|
||||
try:
|
||||
# a) Solve for chi using Equation 3
|
||||
chi1, chi2 = solve(-h_chi1, h_chi3, q_alpha3)
|
||||
|
||||
# b) Solve for omega Equation 1 and each chi
|
||||
B = h_chi1 * cos(chi1) + h_chi3 * sin(chi1)
|
||||
eq1omega11, eq1omega12 = solve(h_chi2, B, q_alpha1)
|
||||
B = h_chi1 * cos(chi2) + h_chi3 * sin(chi2)
|
||||
eq1omega21, eq1omega22 = solve(h_chi2, B, q_alpha1)
|
||||
|
||||
# c) Solve for omega Equation 2 and each chi
|
||||
A = -h_chi1 * cos(chi1) - h_chi3 * sin(chi1)
|
||||
eq2omega11, eq2omega12 = solve(A, h_chi2, q_alpha2)
|
||||
A = -h_chi1 * cos(chi2) - h_chi3 * sin(chi2)
|
||||
eq2omega21, eq2omega22 = solve(A, h_chi2, q_alpha2)
|
||||
|
||||
except ValueError, e:
|
||||
raise ValueError(
|
||||
str(e) + ":\nProblem in fixed-phi calculation for:\nh_chi: " +
|
||||
str(h_chi.tolist()) + " q_alpha: " + str(q_alpha.tolist()))
|
||||
|
||||
# 2. Choose values of chi and omega that are solutions to equations 1 and 2
|
||||
solutions = []
|
||||
# a) Check the chi1 solutions
|
||||
print "_findOmegaAndChiToRotateHchiIntoQalpha:"
|
||||
if ne(eq1omega11, eq2omega11) or ne(eq1omega11, eq2omega12):
|
||||
# print "1: eq1omega11, chi1 = ", eq1omega11, chi1
|
||||
solutions.append((eq1omega11, chi1))
|
||||
if ne(eq1omega12, eq2omega11) or ne(eq1omega12, eq2omega12):
|
||||
# print "2: eq1omega12, chi1 = ", eq1omega12, chi1
|
||||
solutions.append((eq1omega12, chi1))
|
||||
# b) Check the chi2 solutions
|
||||
if ne(eq1omega21, eq2omega21) or ne(eq1omega21, eq2omega22):
|
||||
# print "3: eq1omega21, chi2 = ", eq1omega21, chi2
|
||||
solutions.append((eq1omega21, chi2))
|
||||
if ne(eq1omega22, eq2omega21) or ne(eq1omega22, eq2omega22):
|
||||
# print "4: eq1omega22, chi2 = ", eq1omega22, chi2
|
||||
solutions.append((eq1omega22, chi2))
|
||||
# print solutions
|
||||
# print "*"
|
||||
|
||||
if len(solutions) == 0:
|
||||
e = "h_chi: " + str(h_chi.tolist())
|
||||
e += " q_alpha: " + str(q_alpha.tolist())
|
||||
e += ("\nchi1:%4f eq1omega11:%4f eq1omega12:%4f eq2omega11:%4f "
|
||||
"eq2omega12:%4f" % (chi1 * TODEG, eq1omega11 * TODEG,
|
||||
eq1omega12 * TODEG, eq2omega11 * TODEG, eq2omega12 * TODEG))
|
||||
e += ("\nchi2:%4f eq1omega21:%4f eq1omega22:%4f eq2omega21:%4f "
|
||||
"eq2omega22:%4f" % (chi2 * TODEG, eq1omega21 * TODEG,
|
||||
eq1omega22 * TODEG, eq2omega21 * TODEG, eq2omega22 * TODEG))
|
||||
raise Exception("Could not find simultaneous solution for this fixed "
|
||||
"phi mode problem\n" + e)
|
||||
|
||||
if not PREFER_POSITIVE_CHI_SOLUTIONS:
|
||||
return solutions[0]
|
||||
|
||||
positive_chi_solutions = [sol for sol in solutions if sol[1] > 0]
|
||||
|
||||
if len(positive_chi_solutions) == 0:
|
||||
print "WARNING: A +ve chi solution was requested, but none were found."
|
||||
print " Returning a -ve one. Try the mapper"
|
||||
return solutions[0]
|
||||
|
||||
if len(positive_chi_solutions) > 1:
|
||||
print ("INFO: Multiple +ve chi solutions were found [(omega, chi) ...]"
|
||||
" = " + str(positive_chi_solutions))
|
||||
print " Returning the first"
|
||||
|
||||
return positive_chi_solutions[0]
|
||||
336
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/constraints.py
Executable file
336
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/constraints.py
Executable file
@@ -0,0 +1,336 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from copy import copy
|
||||
|
||||
from diffcalc.util import DiffcalcException
|
||||
|
||||
|
||||
class Mode(object):
|
||||
|
||||
def __init__(self, index, name, group, description, parameterNames,
|
||||
implemented=True):
|
||||
self.index = index
|
||||
self.group = group
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.parameterNames = parameterNames
|
||||
self.implemented = implemented
|
||||
|
||||
def __repr__(self):
|
||||
return "%i) %s" % (self.index, self.description)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def usesParameter(self, name):
|
||||
return name in self.parameterNames
|
||||
|
||||
|
||||
class ModeSelector(object):
|
||||
|
||||
def __init__(self, geometry, parameterManager=None,
|
||||
gammaParameterName='gamma'):
|
||||
self.parameter_manager = parameterManager
|
||||
self._geometry = geometry
|
||||
self._gammaParameterName = gammaParameterName
|
||||
self._modelist = {} # indexed by non-contiguous mode number
|
||||
self._configureAvailableModes()
|
||||
self._selectedIndex = 1
|
||||
|
||||
def setParameterManager(self, manager):
|
||||
"""
|
||||
Required as a ParameterManager and ModelSelector are mutually tied
|
||||
together in practice
|
||||
"""
|
||||
self.parameter_manager = manager
|
||||
|
||||
def _configureAvailableModes(self):
|
||||
|
||||
gammaName = self._gammaParameterName
|
||||
|
||||
ml = self._modelist
|
||||
|
||||
ml[0] = Mode(0, '4cFixedw', 'fourc', 'fourc fixed-bandlw',
|
||||
['alpha', gammaName, 'blw'], False)
|
||||
|
||||
ml[1] = Mode(1, '4cBeq', 'fourc', 'fourc bisecting',
|
||||
['alpha', gammaName])
|
||||
|
||||
ml[2] = Mode(2, '4cBin', 'fourc', 'fourc incoming',
|
||||
['alpha', gammaName, 'betain'])
|
||||
|
||||
ml[3] = Mode(3, '4cBout', 'fourc', 'fourc outgoing',
|
||||
['alpha', gammaName, 'betaout'])
|
||||
|
||||
ml[4] = Mode(4, '4cAzimuth', 'fourc', 'fourc azimuth',
|
||||
['alpha', gammaName, 'azimuth'], False)
|
||||
|
||||
ml[5] = Mode(5, '4cPhi', 'fourc', 'fourc fixed-phi',
|
||||
['alpha', gammaName, 'phi'])
|
||||
|
||||
ml[10] = Mode(10, '5cgBeq', 'fivecFixedGamma', 'fivec bisecting',
|
||||
[gammaName])
|
||||
|
||||
ml[11] = Mode(11, '5cgBin', 'fivecFixedGamma', 'fivec incoming',
|
||||
[gammaName, 'betain'])
|
||||
|
||||
ml[12] = Mode(12, '5cgBout', 'fivecFixedGamma', 'fivec outgoing',
|
||||
[gammaName, 'betaout'])
|
||||
|
||||
ml[13] = Mode(13, '5caBeq', 'fivecFixedAlpha', 'fivec bisecting',
|
||||
['alpha'])
|
||||
|
||||
ml[14] = Mode(14, '5caBin', 'fivecFixedAlpha', 'fivec incoming',
|
||||
['alpha', 'betain'])
|
||||
|
||||
ml[15] = Mode(15, '5caBout', 'fivecFixedAlpha', 'fivec outgoing',
|
||||
['alpha', 'betaout'])
|
||||
|
||||
ml[20] = Mode(20, '6czBeq', 'zaxis', 'zaxis bisecting',
|
||||
[])
|
||||
|
||||
ml[21] = Mode(21, '6czBin', 'zaxis', 'zaxis incoming',
|
||||
['betain'])
|
||||
|
||||
ml[22] = Mode(22, '6czBout', 'zaxis', 'zaxiz outgoing',
|
||||
['betaout'])
|
||||
|
||||
def setModeByIndex(self, index):
|
||||
if index in self._modelist:
|
||||
self._selectedIndex = index
|
||||
else:
|
||||
raise DiffcalcException("mode %r is not defined" % index)
|
||||
|
||||
def setModeByName(self, name):
|
||||
def findModeWithName(name):
|
||||
for index, mode in self._modelist.items():
|
||||
if mode.name == name:
|
||||
return index, mode
|
||||
raise ValueError
|
||||
|
||||
try:
|
||||
index, mode = findModeWithName(name)
|
||||
except ValueError:
|
||||
raise DiffcalcException(
|
||||
'Unknown mode. The diffraction calculator supports these '
|
||||
'modeSelector: %s' % self._supportedModes.keys())
|
||||
if self._geometry.supports_mode_group(mode.group):
|
||||
self._selectedIndex = index
|
||||
else:
|
||||
raise DiffcalcException(
|
||||
"Mode %s not supported for this diffractometer (%s)." %
|
||||
(name, self._geometry.name))
|
||||
|
||||
def getMode(self):
|
||||
return self._modelist[self._selectedIndex]
|
||||
|
||||
def reportCurrentMode(self):
|
||||
return self.getMode().__str__()
|
||||
|
||||
def reportAvailableModes(self):
|
||||
result = ''
|
||||
indecis = self._modelist.keys()
|
||||
indecis.sort()
|
||||
for index in indecis:
|
||||
mode = self._modelist[index]
|
||||
if self._geometry.supports_mode_group(mode.group):
|
||||
paramString = ''
|
||||
flags = ''
|
||||
pm = self.parameter_manager
|
||||
for paramName in pm.getUserChangableParametersForMode(mode):
|
||||
paramString += paramName + ", "
|
||||
if paramString:
|
||||
paramString = paramString[:-2] # remove trailing commas
|
||||
if not mode.implemented:
|
||||
flags += "(Not impl.)"
|
||||
result += ('%2i) %-15s (%s) %s\n' % (mode.index,
|
||||
mode.description, paramString, flags))
|
||||
return result
|
||||
|
||||
|
||||
class VliegParameterManager(object):
|
||||
|
||||
def __init__(self, geometry, hardware, modeSelector,
|
||||
gammaParameterName='gamma'):
|
||||
self._geometry = geometry
|
||||
self._hardware = hardware
|
||||
self._modeSelector = modeSelector
|
||||
self._gammaParameterName = gammaParameterName
|
||||
self._parameters = {}
|
||||
self._defineParameters()
|
||||
|
||||
def _defineParameters(self):
|
||||
# Set default fixed values (In degrees if angles)
|
||||
self._parameters = {}
|
||||
self._parameters['alpha'] = 0
|
||||
self._parameters[self._gammaParameterName] = 0
|
||||
self._parameters['blw'] = None # Busing and Levi omega!
|
||||
self._parameters['betain'] = None
|
||||
self._parameters['betaout'] = None
|
||||
self._parameters['azimuth'] = None
|
||||
self._parameters['phi'] = None
|
||||
|
||||
self._parameterDisplayOrder = (
|
||||
'alpha', self._gammaParameterName, 'betain', 'betaout', 'azimuth',
|
||||
'phi', 'blw')
|
||||
self._trackableParameters = ('alpha', self._gammaParameterName, 'phi')
|
||||
self._trackedParameters = []
|
||||
|
||||
# Overide parameters that are unchangable for this diffractometer
|
||||
for (name, value) in self._geometry.fixed_parameters.items():
|
||||
if name not in self._parameters:
|
||||
raise RuntimeError(
|
||||
"The %s diffractometer geometry specifies a fixed "
|
||||
"parameter %s that is not used by the diffractometer "
|
||||
"calculator" % (self._geometry.getName, name))
|
||||
self._parameters[name] = value
|
||||
|
||||
def reportAllParameters(self):
|
||||
self.update_tracked()
|
||||
result = ''
|
||||
for name in self._parameterDisplayOrder:
|
||||
flags = ""
|
||||
if not self._modeSelector.getMode().usesParameter(name):
|
||||
flags += '(not relevant in this mode)'
|
||||
if self._geometry.parameter_fixed(name):
|
||||
flags += ' (fixed by this diffractometer)'
|
||||
if self.isParameterTracked(name):
|
||||
flags += ' (tracking hardware)'
|
||||
value = self._parameters[name]
|
||||
if value is None:
|
||||
value = '---'
|
||||
else:
|
||||
value = float(value)
|
||||
result += '%s: %s %s\n' % (name.rjust(8), value, flags)
|
||||
return result
|
||||
|
||||
def reportParametersUsedInCurrentMode(self):
|
||||
self.update_tracked()
|
||||
result = ''
|
||||
for name in self.getUserChangableParametersForMode(
|
||||
self._modeSelector.getMode()):
|
||||
flags = ""
|
||||
value = self._parameters[name]
|
||||
if value is None:
|
||||
value = '---'
|
||||
else:
|
||||
value = float(value)
|
||||
if self.isParameterTracked(name):
|
||||
flags += ' (tracking hardware)'
|
||||
result += '%s: %s %s\n' % (name.rjust(8), value, flags)
|
||||
return result
|
||||
|
||||
def getUserChangableParametersForMode(self, mode=None):
|
||||
"""
|
||||
(p1,p2...p3) = getUserChangableParametersForMode(mode) returns a list
|
||||
of parameters names used in this mode for this diffractometer geometry.
|
||||
Checks current mode if no mode specified.
|
||||
"""
|
||||
if mode is None:
|
||||
mode = self._mode
|
||||
result = []
|
||||
for name in self._parameterDisplayOrder:
|
||||
if self._isParameterChangeable(name, mode):
|
||||
result += [name]
|
||||
return result
|
||||
|
||||
### Fixed parameters stuff ###
|
||||
|
||||
def set_constraint(self, name, value):
|
||||
if not name in self._parameters:
|
||||
raise DiffcalcException("No fixed parameter %s is used by the "
|
||||
"diffraction calculator" % name)
|
||||
if self._geometry.parameter_fixed(name):
|
||||
raise DiffcalcException(
|
||||
"The parameter %s cannot be changed: It has been fixed by the "
|
||||
"%s diffractometer geometry"
|
||||
% (name, self._geometry.name))
|
||||
if self.isParameterTracked(name):
|
||||
# for safety and to avoid confusion:
|
||||
raise DiffcalcException(
|
||||
"Cannot change parameter %s as it is set to track an axis.\n"
|
||||
"To turn this off use a command like 'trackalpha 0'." % name)
|
||||
|
||||
if not self.isParameterUsedInSelectedMode(name):
|
||||
print ("WARNING: The parameter %s is not used in mode %i" %
|
||||
(name, self._modeSelector.getMode().index))
|
||||
self._parameters[name] = value
|
||||
|
||||
def isParameterUsedInSelectedMode(self, name):
|
||||
return self._modeSelector.getMode().usesParameter(name)
|
||||
|
||||
def getParameterWithoutUpdatingTrackedParemeters(self, name):
|
||||
try:
|
||||
return self._parameters[name]
|
||||
except KeyError:
|
||||
raise DiffcalcException("No fixed parameter %s is used by the "
|
||||
"diffraction calculator" % name)
|
||||
|
||||
def get_constraint(self, name):
|
||||
self.update_tracked()
|
||||
return self.getParameterWithoutUpdatingTrackedParemeters(name)
|
||||
|
||||
def getParameterDict(self):
|
||||
self.update_tracked()
|
||||
return copy(self._parameters)
|
||||
|
||||
@property
|
||||
def settable_constraint_names(self):
|
||||
"""list of all available constraints that have settable values"""
|
||||
return sorted(self.getParameterDict().keys())
|
||||
|
||||
def setTrackParameter(self, name, switch):
|
||||
if not name in self._parameters.keys():
|
||||
raise DiffcalcException("No fixed parameter %s is used by the "
|
||||
"diffraction calculator" % name)
|
||||
if not name in self._trackableParameters:
|
||||
raise DiffcalcException("Parameter %s is not trackable" % name)
|
||||
if not self._isParameterChangeable(name):
|
||||
print ("WARNING: Parameter %s is not used in mode %i" %
|
||||
(name, self._mode.index))
|
||||
if switch:
|
||||
if name not in self._trackedParameters:
|
||||
self._trackedParameters.append(name)
|
||||
else:
|
||||
if name in self._trackedParameters:
|
||||
self._trackedParameters.remove(name)
|
||||
|
||||
def isParameterTracked(self, name):
|
||||
return (name in self._trackedParameters)
|
||||
|
||||
def update_tracked(self):
|
||||
"""Note that the name of a tracked parameter MUST map into the name of
|
||||
an external diffractometer angle
|
||||
"""
|
||||
if self._trackedParameters:
|
||||
externalAnglePositionArray = self._hardware.get_position()
|
||||
externalAngleNames = list(self._hardware.get_axes_names())
|
||||
for name in self._trackedParameters:
|
||||
self._parameters[name] = \
|
||||
externalAnglePositionArray[externalAngleNames.index(name)]
|
||||
|
||||
def _isParameterChangeable(self, name, mode=None):
|
||||
"""
|
||||
Returns true if parameter is used in a mode (current mode if none
|
||||
specified), AND if it is not locked by the diffractometer geometry
|
||||
"""
|
||||
if mode is None:
|
||||
mode = self._modeSelector.getMode()
|
||||
return (mode.usesParameter(name) and
|
||||
not self._geometry.parameter_fixed(name))
|
||||
523
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/geometry.py
Executable file
523
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/geometry.py
Executable file
@@ -0,0 +1,523 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import tan, cos, sin, asin, atan, pi, fabs
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
from diffcalc.util import x_rotation, z_rotation, y_rotation
|
||||
from diffcalc.util import AbstractPosition
|
||||
from diffcalc.util import bound, nearlyEqual
|
||||
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
def calcALPHA(alpha):
|
||||
return x_rotation(alpha)
|
||||
|
||||
|
||||
def calcDELTA(delta):
|
||||
return z_rotation(-delta)
|
||||
|
||||
|
||||
def calcGAMMA(gamma):
|
||||
return x_rotation(gamma)
|
||||
|
||||
|
||||
def calcOMEGA(omega):
|
||||
return z_rotation(-omega)
|
||||
|
||||
|
||||
def calcCHI(chi):
|
||||
return y_rotation(chi)
|
||||
|
||||
|
||||
def calcPHI(phi):
|
||||
return z_rotation(-phi)
|
||||
|
||||
|
||||
def createVliegMatrices(alpha=None, delta=None, gamma=None, omega=None,
|
||||
chi=None, phi=None):
|
||||
|
||||
ALPHA = None if alpha is None else calcALPHA(alpha)
|
||||
DELTA = None if delta is None else calcDELTA(delta)
|
||||
GAMMA = None if gamma is None else calcGAMMA(gamma)
|
||||
OMEGA = None if omega is None else calcOMEGA(omega)
|
||||
CHI = None if chi is None else calcCHI(chi)
|
||||
PHI = None if phi is None else calcPHI(phi)
|
||||
return ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI
|
||||
|
||||
|
||||
def createVliegsSurfaceTransformationMatrices(sigma, tau):
|
||||
"""[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(sigma, tau)
|
||||
angles in radians
|
||||
"""
|
||||
SIGMA = matrix([[cos(sigma), 0, sin(sigma)],
|
||||
[0, 1, 0], \
|
||||
[-sin(sigma), 0, cos(sigma)]])
|
||||
|
||||
TAU = matrix([[cos(tau), sin(tau), 0],
|
||||
[-sin(tau), cos(tau), 0],
|
||||
[0, 0, 1]])
|
||||
return(SIGMA, TAU)
|
||||
|
||||
|
||||
def createVliegsPsiTransformationMatrix(psi):
|
||||
"""PSI = createPsiTransformationMatrices(psi)
|
||||
angles in radians
|
||||
"""
|
||||
return matrix([[1, 0, 0],
|
||||
[0, cos(psi), sin(psi)],
|
||||
[0, -sin(psi), cos(psi)]])
|
||||
|
||||
|
||||
class VliegPosition(AbstractPosition):
|
||||
"""The position of all six diffractometer axis"""
|
||||
def __init__(self, alpha=None, delta=None, gamma=None, omega=None,
|
||||
chi=None, phi=None):
|
||||
self.alpha = alpha
|
||||
self.delta = delta
|
||||
self.gamma = gamma
|
||||
self.omega = omega
|
||||
self.chi = chi
|
||||
self.phi = phi
|
||||
|
||||
def clone(self):
|
||||
return VliegPosition(self.alpha, self.delta, self.gamma, self.omega,
|
||||
self.chi, self.phi)
|
||||
|
||||
def changeToRadians(self):
|
||||
self.alpha *= TORAD
|
||||
self.delta *= TORAD
|
||||
self.gamma *= TORAD
|
||||
self.omega *= TORAD
|
||||
self.chi *= TORAD
|
||||
self.phi *= TORAD
|
||||
|
||||
def changeToDegrees(self):
|
||||
self.alpha *= TODEG
|
||||
self.delta *= TODEG
|
||||
self.gamma *= TODEG
|
||||
self.omega *= TODEG
|
||||
self.chi *= TODEG
|
||||
self.phi *= TODEG
|
||||
|
||||
def inRadians(self):
|
||||
pos = self.clone()
|
||||
pos.changeToRadians()
|
||||
return pos
|
||||
|
||||
def inDegrees(self):
|
||||
pos = self.clone()
|
||||
pos.changeToDegrees()
|
||||
return pos
|
||||
|
||||
def nearlyEquals(self, pos2, maxnorm):
|
||||
for a, b in zip(self.totuple(), pos2.totuple()):
|
||||
if abs(a - b) > maxnorm:
|
||||
return False
|
||||
return True
|
||||
|
||||
def totuple(self):
|
||||
return (self.alpha, self.delta, self.gamma, self.omega,
|
||||
self.chi, self.phi)
|
||||
|
||||
def __str__(self):
|
||||
return ("VliegPosition(alpha %r delta: %r gamma: %r omega: %r chi: %r"
|
||||
" phi: %r)" % self.totuple())
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __eq__(self, b):
|
||||
return self.nearlyEquals(b, .001)
|
||||
|
||||
|
||||
class VliegGeometry(object):
|
||||
|
||||
# Required methods
|
||||
|
||||
def __init__(self, name, supported_mode_groups, fixed_parameters,
|
||||
gamma_location):
|
||||
"""
|
||||
Set geometry name (String), list of supported mode groups (list of
|
||||
strings), list of axis names (list of strings). Define the parameters
|
||||
e.g. alpha and gamma for a four circle (dictionary). Define wether the
|
||||
gamma angle is on the 'arm' or the 'base'; used only by AngleCalculator
|
||||
to interpret the gamma parameter in fixed gamma mode: for instruments
|
||||
with gamma on the base, rather than on the arm as the code assume
|
||||
internally, the two methods physical_angles_to_internal_position and
|
||||
internal_position_to_physical_angles must still be used.
|
||||
"""
|
||||
if gamma_location not in ('arm', 'base', None):
|
||||
raise RuntimeError(
|
||||
"Gamma must be on either 'arm' or 'base' or None")
|
||||
|
||||
self.name = name
|
||||
self.supported_mode_groups = supported_mode_groups
|
||||
self.fixed_parameters = fixed_parameters
|
||||
self.gamma_location = gamma_location
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
raise NotImplementedError()
|
||||
|
||||
def internal_position_to_physical_angles(self, physicalAngles):
|
||||
raise NotImplementedError()
|
||||
|
||||
### Do not overide these these ###
|
||||
|
||||
def supports_mode_group(self, name):
|
||||
return name in self.supported_mode_groups
|
||||
|
||||
def parameter_fixed(self, name): # parameter_fixed
|
||||
return name in self.fixed_parameters.keys()
|
||||
|
||||
|
||||
class SixCircleGammaOnArmGeometry(VliegGeometry):
|
||||
"""
|
||||
This six-circle diffractometer geometry simply passes through the
|
||||
angles from a six circle diffractometer with the same geometry and
|
||||
angle names as those defined in Vliegs's paper defined internally.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(
|
||||
self,
|
||||
name='sixc_gamma_on_arm',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma',
|
||||
'fivecFixedAlpha', 'zaxis'),
|
||||
fixed_parameters={},
|
||||
gamma_location='arm')
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 6), "Wrong length of input list"
|
||||
return VliegPosition(*physicalAngles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
return internalPosition.totuple()
|
||||
|
||||
|
||||
class SixCircleGeometry(VliegGeometry):
|
||||
"""
|
||||
This six-circle diffractometer geometry simply passes through the
|
||||
angles from a six circle diffractometer with the same geometry and
|
||||
angle names as those defined in Vliegs's paper defined internally.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(
|
||||
self,
|
||||
name='sixc',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma',
|
||||
'fivecFixedAlpha', 'zaxis'),
|
||||
fixed_parameters={},
|
||||
gamma_location='base')
|
||||
self.hardwareMonitor = None
|
||||
#(deltaA, gammaA) = gammaOnBaseToArm(deltaB, gammaB, alpha) (all in radians)
|
||||
#(deltaB, gammaB) = gammaOnArmToBase(deltaA, gammaA, alpha) (all in radians)
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 6), "Wrong length of input list"
|
||||
alpha, deltaB, gammaB, omega, chi, phi = physicalAngles
|
||||
(deltaA, gammaA) = gammaOnBaseToArm(
|
||||
deltaB * TORAD, gammaB * TORAD, alpha * TORAD)
|
||||
return VliegPosition(
|
||||
alpha, deltaA * TODEG, gammaA * TODEG, omega, chi, phi)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
alpha, deltaA, gammaA, omega, chi, phi = internalPosition.totuple()
|
||||
deltaB, gammaB = gammaOnArmToBase(
|
||||
deltaA * TORAD, gammaA * TORAD, alpha * TORAD)
|
||||
deltaB, gammaB = deltaB * TODEG, gammaB * TODEG
|
||||
|
||||
if self.hardwareMonitor is not None:
|
||||
gammaName = self.hardwareMonitor.get_axes_names()[2]
|
||||
minGamma = self.hardwareMonitor.get_lower_limit(gammaName)
|
||||
maxGamma = self.hardwareMonitor.get_upper_limit(gammaName)
|
||||
|
||||
if maxGamma is not None:
|
||||
if gammaB > maxGamma:
|
||||
gammaB = gammaB - 180
|
||||
deltaB = 180 - deltaB
|
||||
if minGamma is not None:
|
||||
if gammaB < minGamma:
|
||||
gammaB = gammaB + 180
|
||||
deltaB = 180 - deltaB
|
||||
|
||||
return alpha, deltaB, gammaB, omega, chi, phi
|
||||
|
||||
|
||||
class FivecWithGammaOnBase(SixCircleGeometry):
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(
|
||||
self,
|
||||
name='fivec_with_gamma',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma'),
|
||||
fixed_parameters={'alpha': 0.0},
|
||||
gamma_location='base')
|
||||
self.hardwareMonitor = None
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 5), "Wrong length of input list"
|
||||
return SixCircleGeometry.physical_angles_to_internal_position(
|
||||
self, (0,) + tuple(physicalAngles))
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
return SixCircleGeometry.internal_position_to_physical_angles(
|
||||
self, internalPosition)[1:]
|
||||
|
||||
|
||||
class Fivec(VliegGeometry):
|
||||
"""
|
||||
This five-circle diffractometer geometry is for diffractometers with the
|
||||
same geometry and angle names as those defined in Vliegs's paper defined
|
||||
internally, but with no out plane detector arm gamma."""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(self,
|
||||
name='fivec',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma'),
|
||||
fixed_parameters={'gamma': 0.0},
|
||||
gamma_location='arm'
|
||||
)
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 5), "Wrong length of input list"
|
||||
physicalAngles = tuple(physicalAngles)
|
||||
angles = physicalAngles[0:2] + (0.0,) + physicalAngles[2:]
|
||||
return VliegPosition(*angles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
sixAngles = internalPosition.totuple()
|
||||
return sixAngles[0:2] + sixAngles[3:]
|
||||
|
||||
|
||||
class Fourc(VliegGeometry):
|
||||
"""
|
||||
This five-circle diffractometer geometry is for diffractometers with the
|
||||
same geometry and angle names as those defined in Vliegs's paper defined
|
||||
internally, but with no out plane detector arm gamma."""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(self,
|
||||
name='fourc',
|
||||
supported_mode_groups=('fourc'),
|
||||
fixed_parameters={'gamma': 0.0, 'alpha': 0.0},
|
||||
gamma_location='arm'
|
||||
)
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 4), "Wrong length of input list"
|
||||
physicalAngles = tuple(physicalAngles)
|
||||
angles = (0.0, physicalAngles[0], 0.0) + physicalAngles[1:]
|
||||
return VliegPosition(*angles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
sixAngles = internalPosition.totuple()
|
||||
return sixAngles[1:2] + sixAngles[3:]
|
||||
|
||||
|
||||
def sign(x):
|
||||
if x < 0:
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
"""
|
||||
Based on: Elias Vlieg, "A (2+3)-Type Surface Diffractometer: Mergence of
|
||||
the z-axis and (2+2)-Type Geometries", J. Appl. Cryst. (1998). 31.
|
||||
198-203
|
||||
"""
|
||||
|
||||
|
||||
def solvesEq8(alpha, deltaA, gammaA, deltaB, gammaB):
|
||||
tol = 1e-6
|
||||
return (nearlyEqual(sin(deltaA) * cos(gammaA), sin(deltaB), tol) and
|
||||
nearlyEqual(cos(deltaA) * cos(gammaA),
|
||||
cos(gammaB - alpha) * cos(deltaB), tol) and
|
||||
nearlyEqual(sin(gammaA), sin(gammaB - alpha) * cos(deltaB), tol))
|
||||
|
||||
|
||||
GAMMAONBASETOARM_WARNING = '''
|
||||
WARNING: This diffractometer has the gamma circle attached to the
|
||||
base rather than the end of
|
||||
the delta arm as Vlieg's paper defines. A conversion has
|
||||
been made from the physical angles to their internal
|
||||
representation (gamma-on-base-to-arm). This conversion has
|
||||
forced gamma to be positive by applying the mapping:
|
||||
|
||||
delta --> 180+delta
|
||||
gamma --> 180+gamma.
|
||||
|
||||
This should have no adverse effect.
|
||||
'''
|
||||
|
||||
|
||||
def gammaOnBaseToArm(deltaB, gammaB, alpha):
|
||||
"""
|
||||
(deltaA, gammaA) = gammaOnBaseToArm(deltaB, gammaB, alpha) (all in
|
||||
radians)
|
||||
|
||||
Maps delta and gamma for an instrument where the gamma circle rests on
|
||||
the base to the case where it is on the delta arm.
|
||||
|
||||
There are always two possible solutions. To get the second apply the
|
||||
transform:
|
||||
|
||||
delta --> 180+delta (flip to opposite side of circle)
|
||||
gamma --> 180+gamma (flip to opposite side of circle)
|
||||
|
||||
This code will return the solution where gamma is between 0 and 180.
|
||||
"""
|
||||
|
||||
### Equation11 ###
|
||||
if fabs(cos(gammaB - alpha)) < 1e-20:
|
||||
deltaA1 = sign(tan(deltaB)) * sign(cos(gammaB - alpha)) * pi / 2
|
||||
else:
|
||||
deltaA1 = atan(tan(deltaB) / cos(gammaB - alpha))
|
||||
# ...second root
|
||||
if deltaA1 <= 0:
|
||||
deltaA2 = deltaA1 + pi
|
||||
else:
|
||||
deltaA2 = deltaA1 - pi
|
||||
|
||||
### Equation 12 ###
|
||||
gammaA1 = asin(bound(cos(deltaB) * sin(gammaB - alpha)))
|
||||
# ...second root
|
||||
if gammaA1 >= 0:
|
||||
gammaA2 = pi - gammaA1
|
||||
else:
|
||||
gammaA2 = -pi - gammaA1
|
||||
|
||||
# Choose the delta solution that fits equations 8
|
||||
if solvesEq8(alpha, deltaA1, gammaA1, deltaB, gammaB):
|
||||
deltaA, gammaA = deltaA1, gammaA1
|
||||
elif solvesEq8(alpha, deltaA2, gammaA1, deltaB, gammaB):
|
||||
deltaA, gammaA = deltaA2, gammaA1
|
||||
print "gammaOnBaseToArm choosing 2nd delta root (to internal)"
|
||||
elif solvesEq8(alpha, deltaA1, gammaA2, deltaB, gammaB):
|
||||
print "gammaOnBaseToArm choosing 2nd gamma root (to internal)"
|
||||
deltaA, gammaA = deltaA1, gammaA2
|
||||
elif solvesEq8(alpha, deltaA2, gammaA2, deltaB, gammaB):
|
||||
print "gammaOnBaseToArm choosing 2nd delta root and 2nd gamma root"
|
||||
deltaA, gammaA = deltaA2, gammaA2
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"No valid solutions found mapping from gamma-on-base to gamma-on-arm")
|
||||
|
||||
return deltaA, gammaA
|
||||
|
||||
GAMMAONARMTOBASE_WARNING = '''
|
||||
WARNING: This diffractometer has the gamma circle attached to the base
|
||||
rather than the end of the delta arm as Vlieg's paper defines.
|
||||
A conversion has been made from the internal representation of
|
||||
angles to physical angles (gamma-on-arm-to-base). This
|
||||
conversion has forced gamma to be positive by applying the
|
||||
mapping:
|
||||
|
||||
delta --> 180-delta
|
||||
gamma --> 180+gamma.
|
||||
|
||||
This should have no adverse effect.
|
||||
'''
|
||||
|
||||
|
||||
def gammaOnArmToBase(deltaA, gammaA, alpha):
|
||||
"""
|
||||
(deltaB, gammaB) = gammaOnArmToBase(deltaA, gammaA, alpha) (all in
|
||||
radians)
|
||||
|
||||
Maps delta and gamma for an instrument where the gamma circle is on
|
||||
the delta arm to the case where it rests on the base.
|
||||
|
||||
There are always two possible solutions. To get the second apply the
|
||||
transform:
|
||||
|
||||
delta --> 180-delta (reflect and flip to opposite side)
|
||||
gamma --> 180+gamma (flip to opposite side)
|
||||
|
||||
This code will return the solution where gamma is positive, but will
|
||||
warn if a sign change was made.
|
||||
"""
|
||||
|
||||
### Equation 9 ###
|
||||
deltaB1 = asin(bound(sin(deltaA) * cos(gammaA)))
|
||||
# ...second root:
|
||||
if deltaB1 >= 0:
|
||||
deltaB2 = pi - deltaB1
|
||||
else:
|
||||
deltaB2 = -pi - deltaB1
|
||||
|
||||
### Equation 10 ###:
|
||||
if fabs(cos(deltaA)) < 1e-20:
|
||||
gammaB1 = sign(tan(gammaA)) * sign(cos(deltaA)) * pi / 2 + alpha
|
||||
else:
|
||||
gammaB1 = atan(tan(gammaA) / cos(deltaA)) + alpha
|
||||
#... second root:
|
||||
if gammaB1 <= 0:
|
||||
gammaB2 = gammaB1 + pi
|
||||
else:
|
||||
gammaB2 = gammaB1 - pi
|
||||
|
||||
### Choose the solution that fits equation 8 ###
|
||||
if (solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB1) and
|
||||
0 <= gammaB1 <= pi):
|
||||
deltaB, gammaB = deltaB1, gammaB1
|
||||
elif (solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB1) and
|
||||
0 <= gammaB1 <= pi):
|
||||
deltaB, gammaB = deltaB2, gammaB1
|
||||
print "gammaOnArmToBase choosing 2nd delta root (to physical)"
|
||||
elif (solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB2) and
|
||||
0 <= gammaB2 <= pi):
|
||||
print "gammaOnArmToBase choosing 2nd gamma root (to physical)"
|
||||
deltaB, gammaB = deltaB1, gammaB2
|
||||
elif (solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB2)
|
||||
and 0 <= gammaB2 <= pi):
|
||||
print "gammaOnArmToBase choosing 2nd delta root and 2nd gamma root"
|
||||
deltaB, gammaB = deltaB2, gammaB2
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"No valid solutions found mapping gamma-on-arm to gamma-on-base")
|
||||
|
||||
return deltaB, gammaB
|
||||
139
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/hkl.py
Executable file
139
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/hkl.py
Executable file
@@ -0,0 +1,139 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.hkl.common import getNameFromScannableOrString
|
||||
from diffcalc.util import command
|
||||
from diffcalc import settings
|
||||
|
||||
|
||||
from diffcalc.ub import ub
|
||||
from diffcalc.hkl.vlieg.calc import VliegHklCalculator
|
||||
|
||||
|
||||
__all__ = ['hklmode', 'setpar', 'trackalpha', 'trackgamma', 'trackphi',
|
||||
'parameter_manager', 'hklcalc']
|
||||
|
||||
|
||||
hklcalc = VliegHklCalculator(ub.ubcalc, settings.geometry, settings.hardware)
|
||||
|
||||
parameter_manager = hklcalc.parameter_manager
|
||||
|
||||
def __str__(self):
|
||||
return hklcalc.__str__()
|
||||
|
||||
@command
|
||||
def hklmode(num=None):
|
||||
"""hklmode {num} -- changes mode or shows current and available modes and all settings""" #@IgnorePep8
|
||||
|
||||
if num is None:
|
||||
print hklcalc.__str__()
|
||||
else:
|
||||
hklcalc.mode_selector.setModeByIndex(int(num))
|
||||
pm = hklcalc.parameter_manager
|
||||
print (hklcalc.mode_selector.reportCurrentMode() + "\n" +
|
||||
pm.reportParametersUsedInCurrentMode())
|
||||
|
||||
def _setParameter(name, value):
|
||||
hklcalc.parameter_manager.set_constraint(name, value)
|
||||
|
||||
def _getParameter(name):
|
||||
return hklcalc.parameter_manager.get_constraint(name)
|
||||
|
||||
@command
|
||||
def setpar(scannable_or_string=None, val=None):
|
||||
"""setpar {parameter_scannable {{val}} -- sets or shows a parameter'
|
||||
setpar {parameter_name {val}} -- sets or shows a parameter'
|
||||
"""
|
||||
|
||||
if scannable_or_string is None:
|
||||
#show all
|
||||
parameterDict = hklcalc.parameter_manager.getParameterDict()
|
||||
names = parameterDict.keys()
|
||||
names.sort()
|
||||
for name in names:
|
||||
print _representParameter(name)
|
||||
else:
|
||||
name = getNameFromScannableOrString(scannable_or_string)
|
||||
if val is None:
|
||||
_representParameter(name)
|
||||
else:
|
||||
oldval = _getParameter(name)
|
||||
_setParameter(name, float(val))
|
||||
print _representParameter(name, oldval, float(val))
|
||||
|
||||
def _representParameter(name, oldval=None, newval=None):
|
||||
flags = ''
|
||||
if hklcalc.parameter_manager.isParameterTracked(name):
|
||||
flags += '(tracking hardware) '
|
||||
if settings.geometry.parameter_fixed(name): # @UndefinedVariable
|
||||
flags += '(fixed by geometry) '
|
||||
pm = hklcalc.parameter_manager
|
||||
if not pm.isParameterUsedInSelectedMode(name):
|
||||
flags += '(not relevant in this mode) '
|
||||
if oldval is None:
|
||||
val = _getParameter(name)
|
||||
if val is None:
|
||||
val = "---"
|
||||
else:
|
||||
val = str(val)
|
||||
return "%s: %s %s" % (name, val, flags)
|
||||
else:
|
||||
return "%s: %s --> %f %s" % (name, oldval, newval, flags)
|
||||
|
||||
def _checkInputAndSetOrShowParameterTracking(name, b=None):
|
||||
"""
|
||||
for track-parameter commands: If no args displays parameter settings,
|
||||
otherwise sets the tracking switch for the given parameter and displays
|
||||
settings.
|
||||
"""
|
||||
# set if arg given
|
||||
if b is not None:
|
||||
hklcalc.parameter_manager.setTrackParameter(name, b)
|
||||
# Display:
|
||||
lastValue = _getParameter(name)
|
||||
if lastValue is None:
|
||||
lastValue = "---"
|
||||
else:
|
||||
lastValue = str(lastValue)
|
||||
flags = ''
|
||||
if hklcalc.parameter_manager.isParameterTracked(name):
|
||||
flags += '(tracking hardware)'
|
||||
print "%s: %s %s" % (name, lastValue, flags)
|
||||
|
||||
@command
|
||||
def trackalpha(b=None):
|
||||
"""trackalpha {boolean} -- determines wether alpha parameter will track alpha axis""" #@IgnorePep8
|
||||
_checkInputAndSetOrShowParameterTracking('alpha', b)
|
||||
|
||||
@command
|
||||
def trackgamma(b=None):
|
||||
"""trackgamma {boolean} -- determines wether gamma parameter will track alpha axis""" #@IgnorePep8
|
||||
_checkInputAndSetOrShowParameterTracking('gamma', b)
|
||||
|
||||
@command
|
||||
def trackphi(b=None):
|
||||
"""trackphi {boolean} -- determines wether phi parameter will track phi axis""" #@IgnorePep8
|
||||
_checkInputAndSetOrShowParameterTracking('phi', b)
|
||||
|
||||
|
||||
commands_for_help = ['Mode',
|
||||
hklmode,
|
||||
setpar,
|
||||
trackalpha,
|
||||
trackgamma,
|
||||
trackphi]
|
||||
480
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/transform.py
Executable file
480
script/__Lib/diffcalc-2.1/diffcalc/hkl/vlieg/transform.py
Executable file
@@ -0,0 +1,480 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.util import command
|
||||
|
||||
from copy import copy
|
||||
from math import pi
|
||||
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition as P
|
||||
|
||||
SMALL = 1e-10
|
||||
|
||||
|
||||
class Transform(object):
|
||||
|
||||
def transform(self, pos):
|
||||
raise RuntimeError('Not implemented')
|
||||
|
||||
|
||||
### Transforms, currently for definition and testing the theory only
|
||||
|
||||
class TransformC(Transform):
|
||||
'''Flip omega, invert chi and flip phi
|
||||
'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
pos.omega -= 180
|
||||
pos.chi *= -1
|
||||
pos.phi -= 180
|
||||
return pos
|
||||
|
||||
|
||||
class TransformB(Transform):
|
||||
'''Flip chi, and invert and flip omega
|
||||
'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
pos.chi -= 180
|
||||
pos.omega = 180 - pos.omega
|
||||
return pos
|
||||
|
||||
|
||||
class TransformA(Transform):
|
||||
'''Invert scattering plane: invert delta and omega and flip chi'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
pos.delta *= -1
|
||||
pos.omega *= -1
|
||||
pos.chi -= 180
|
||||
return pos
|
||||
|
||||
|
||||
class TransformCInRadians(Transform):
|
||||
'''
|
||||
Flip omega, invert chi and flip phi. Using radians and keeping
|
||||
-pi<omega<=pi and 0<=phi<=360
|
||||
'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
if pos.omega > 0:
|
||||
pos.omega -= pi
|
||||
else:
|
||||
pos.omega += pi
|
||||
pos.chi *= -1
|
||||
pos.phi += pi
|
||||
return pos
|
||||
|
||||
|
||||
###
|
||||
|
||||
transformsFromSector = {
|
||||
0: (),
|
||||
1: ('c',),
|
||||
2: ('a',),
|
||||
3: ('a', 'c'),
|
||||
4: ('b', 'c'),
|
||||
5: ('b',),
|
||||
6: ('a', 'b', 'c'),
|
||||
7: ('a', 'b')
|
||||
}
|
||||
|
||||
sectorFromTransforms = {}
|
||||
for k, v in transformsFromSector.iteritems():
|
||||
sectorFromTransforms[v] = k
|
||||
|
||||
|
||||
class VliegPositionTransformer(object):
|
||||
|
||||
def __init__(self, geometry, hardware, solution_transformer):
|
||||
self._geometry = geometry
|
||||
self._hardware = hardware
|
||||
self._solution_transformer = solution_transformer
|
||||
solution_transformer.limitCheckerFunction = self.is_position_within_limits
|
||||
|
||||
def transform(self, pos):
|
||||
# 1. Choose the correct sector/transforms
|
||||
return self._solution_transformer.transformPosition(pos)
|
||||
|
||||
def is_position_within_limits(self, position):
|
||||
'''where position is Position object in degrees'''
|
||||
angleTuple = self._geometry.internal_position_to_physical_angles(position)
|
||||
angleTuple = self._hardware.cut_angles(angleTuple)
|
||||
return self._hardware.is_position_within_limits(angleTuple)
|
||||
|
||||
|
||||
class VliegTransformSelector(object):
|
||||
'''All returned angles are between -180. and 180. -180.<=angle<180.
|
||||
'''
|
||||
### basic sector selection
|
||||
|
||||
def __init__(self):
|
||||
self.transforms = []
|
||||
self.autotransforms = []
|
||||
self.autosectors = []
|
||||
self.limitCheckerFunction = None # inject
|
||||
self.sector = None
|
||||
self.setSector(0)
|
||||
|
||||
def setSector(self, sector):
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
self.sector = sector
|
||||
self.transforms = list(transformsFromSector[sector])
|
||||
|
||||
def setTransforms(self, transformList):
|
||||
transformList = list(transformList)
|
||||
transformList.sort()
|
||||
self.sector = sectorFromTransforms[tuple(transformList)]
|
||||
self.transforms = transformList
|
||||
|
||||
def addTransorm(self, transformName):
|
||||
if transformName not in ('a', 'b', 'c'):
|
||||
raise ValueError('%s is not a recognised transform. Try a, b or c'
|
||||
% transformName)
|
||||
if transformName in self.transforms:
|
||||
print "WARNING, transform %s is already selected"
|
||||
else:
|
||||
self.setTransforms(self.transforms + [transformName])
|
||||
|
||||
def removeTransorm(self, transformName):
|
||||
if transformName not in ('a', 'b', 'c'):
|
||||
raise ValueError('%s is not a recognised transform. Try a, b or c'
|
||||
% transformName)
|
||||
if transformName in self.transforms:
|
||||
new = copy(self.transforms)
|
||||
new.remove(transformName)
|
||||
self.setTransforms(new)
|
||||
else:
|
||||
print "WARNING, transform %s was not selected" % transformName
|
||||
|
||||
def addAutoTransorm(self, transformOrSector):
|
||||
'''
|
||||
If input is a string (letter), tags one of the transofrms as being a
|
||||
candidate for auto application. If a number, tags a sector as being a
|
||||
candidate for auto application, and removes similar tags for any
|
||||
transforms (as the two are incompatable).
|
||||
'''
|
||||
if type(transformOrSector) == str:
|
||||
transform = transformOrSector
|
||||
if transform not in ('a', 'b', 'c'):
|
||||
raise ValueError(
|
||||
'%s is not a recognised transform. Try a, b or c' %
|
||||
transform)
|
||||
if transform not in self.autotransforms:
|
||||
self.autosectors = []
|
||||
self.autotransforms.append(transform)
|
||||
else:
|
||||
print "WARNING: %s is already set to auto apply" % transform
|
||||
elif type(transformOrSector) == int:
|
||||
sector = transformOrSector
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
if sector not in self.autosectors:
|
||||
self.autotransforms = []
|
||||
self.autosectors.append(sector)
|
||||
else:
|
||||
print "WARNING: %i is already set to auto apply" % sector
|
||||
else:
|
||||
raise ValueError("Input must be 'a', 'b' or 'c', "
|
||||
"or 1,2,3,4,5,6 or 7.")
|
||||
|
||||
def removeAutoTransform(self, transformOrSector):
|
||||
if type(transformOrSector) == str:
|
||||
transform = transformOrSector
|
||||
if transform not in ('a', 'b', 'c'):
|
||||
raise ValueError("%s is not a recognised transform. "
|
||||
"Try a, b or c" % transform)
|
||||
if transform in self.autotransforms:
|
||||
self.autotransforms.remove(transform)
|
||||
else:
|
||||
print "WARNING: %s is not set to auto apply" % transform
|
||||
elif type(transformOrSector) == int:
|
||||
sector = transformOrSector
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
if sector in self.autosectors:
|
||||
self.autosectors.remove(sector)
|
||||
else:
|
||||
print "WARNING: %s is not set to auto apply" % sector
|
||||
else:
|
||||
raise ValueError("Input must be 'a', 'b' or 'c', "
|
||||
"or 1,2,3,4,5,6 or 7.")
|
||||
|
||||
def setAutoSectors(self, sectorList):
|
||||
for sector in sectorList:
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
self.autosectors = list(sectorList)
|
||||
|
||||
def transformPosition(self, pos):
|
||||
pos = self.transformNWithoutCut(self.sector, pos)
|
||||
cutpos = self.cutPosition(pos)
|
||||
# -180 <= cutpos < 180, NOT the externally applied cuts
|
||||
if len(self.autosectors) > 0:
|
||||
if self.is_position_within_limits(cutpos):
|
||||
return cutpos
|
||||
else:
|
||||
return self.autoTransformPositionBySector(cutpos)
|
||||
if len(self.autotransforms) > 0:
|
||||
if self.is_position_within_limits(cutpos):
|
||||
return cutpos
|
||||
else:
|
||||
return self.autoTransformPositionByTransforms(pos)
|
||||
#else
|
||||
return cutpos
|
||||
|
||||
def transformNWithoutCut(self, n, pos):
|
||||
|
||||
if n == 0:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
pos.omega, pos.chi, pos.phi)
|
||||
if n == 1:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
pos.omega - 180., -pos.chi, pos.phi - 180.)
|
||||
if n == 2:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
-pos.omega, pos.chi - 180., pos.phi)
|
||||
if n == 3:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
180. - pos.omega, 180. - pos.chi, pos.phi - 180.)
|
||||
if n == 4:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
-pos.omega, 180. - pos.chi, pos.phi - 180.)
|
||||
if n == 5:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
180. - pos.omega, pos.chi - 180., pos.phi)
|
||||
if n == 6:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
pos.omega, -pos.chi, pos.phi - 180.)
|
||||
if n == 7:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
pos.omega - 180., pos.chi, pos.phi)
|
||||
else:
|
||||
raise Exception("sector must be between 0 and 7")
|
||||
|
||||
### autosector
|
||||
|
||||
def hasAutoSectorsOrTransformsToApply(self):
|
||||
return len(self.autosectors) > 0 or len(self.autotransforms) > 0
|
||||
|
||||
def autoTransformPositionBySector(self, pos):
|
||||
okaysectors = []
|
||||
okaypositions = []
|
||||
for sector in self.autosectors:
|
||||
newpos = self.transformNWithoutCut(sector, pos)
|
||||
if self.is_position_within_limits(newpos):
|
||||
okaysectors.append(sector)
|
||||
okaypositions.append(newpos)
|
||||
if len(okaysectors) == 0:
|
||||
raise Exception(
|
||||
"Autosector could not find a sector (from %s) to move %s into "
|
||||
"limits." % (self.autosectors, str(pos)))
|
||||
if len(okaysectors) > 1:
|
||||
print ("WARNING: Autosector found multiple sectors that would "
|
||||
"move %s to move into limits: %s" % (str(pos), okaysectors))
|
||||
|
||||
print ("INFO: Autosector changed sector from %i to %i" %
|
||||
(self.sector, okaysectors[0]))
|
||||
self.sector = okaysectors[0]
|
||||
return okaypositions[0]
|
||||
|
||||
def autoTransformPositionByTransforms(self, pos):
|
||||
possibleTransforms = self.createListOfPossibleTransforms()
|
||||
okaytransforms = []
|
||||
okaypositions = []
|
||||
for transforms in possibleTransforms:
|
||||
sector = sectorFromTransforms[tuple(transforms)]
|
||||
newpos = self.cutPosition(self.transformNWithoutCut(sector, pos))
|
||||
if self.is_position_within_limits(newpos):
|
||||
okaytransforms.append(transforms)
|
||||
okaypositions.append(newpos)
|
||||
if len(okaytransforms) == 0:
|
||||
raise Exception(
|
||||
"Autosector could not find a sector (from %r) to move %r into "
|
||||
"limits." % (self.autosectors, pos))
|
||||
if len(okaytransforms) > 1:
|
||||
print ("WARNING: Autosector found multiple sectors that would "
|
||||
"move %s to move into limits: %s" %
|
||||
(repr(pos), repr(okaytransforms)))
|
||||
|
||||
print ("INFO: Autosector changed selected transforms from %r to %r" %
|
||||
(self.transforms, okaytransforms[0]))
|
||||
self.setTransforms(okaytransforms[0])
|
||||
return okaypositions[0]
|
||||
|
||||
def createListOfPossibleTransforms(self):
|
||||
def vary(possibleTransforms, name):
|
||||
result = []
|
||||
for transforms in possibleTransforms:
|
||||
# add the original.
|
||||
result.append(transforms)
|
||||
# add a modified one
|
||||
toadd = list(copy(transforms))
|
||||
if name in transforms:
|
||||
toadd.remove(name)
|
||||
else:
|
||||
toadd.append(name)
|
||||
toadd.sort()
|
||||
result.append(toadd)
|
||||
return result
|
||||
# start with the currently selected list of transforms
|
||||
if len(self.transforms) == 0:
|
||||
possibleTransforms = [()]
|
||||
else:
|
||||
possibleTransforms = copy(self.transforms)
|
||||
|
||||
for name in self.autotransforms:
|
||||
possibleTransforms = vary(possibleTransforms, name)
|
||||
|
||||
return possibleTransforms
|
||||
|
||||
def is_position_within_limits(self, pos):
|
||||
'''where pos os a poistion object in degrees'''
|
||||
return self.limitCheckerFunction(pos)
|
||||
|
||||
def __repr__(self):
|
||||
def createPrefix(transform):
|
||||
if transform in self.transforms:
|
||||
s = '*on* '
|
||||
else:
|
||||
s = 'off '
|
||||
if len(self.autotransforms) > 0:
|
||||
if transform in self.autotransforms:
|
||||
s += '*auto*'
|
||||
else:
|
||||
s += ' '
|
||||
return s
|
||||
s = 'Transforms/sector:\n'
|
||||
s += (' %s (a transform) Invert scattering plane: invert delta and '
|
||||
'omega and flip chi\n' % createPrefix('a'))
|
||||
s += (' %s (b transform) Flip chi, and invert and flip omega\n' %
|
||||
createPrefix('b'))
|
||||
s += (' %s (c transform) Flip omega, invert chi and flip phi\n' %
|
||||
createPrefix('c'))
|
||||
s += ' Current sector: %i (Spec fourc equivalent)\n' % self.sector
|
||||
if len(self.autosectors) > 0:
|
||||
s += ' Auto sectors: %s\n' % self.autosectors
|
||||
return s
|
||||
|
||||
def cutPosition(self, position):
|
||||
'''Cuts angles at -180.; moves each argument between -180. and 180.
|
||||
'''
|
||||
def cut(a):
|
||||
if a is None:
|
||||
return None
|
||||
else:
|
||||
if a < (-180. - SMALL):
|
||||
return a + 360.
|
||||
if a > (180. + SMALL):
|
||||
return a - 360.
|
||||
return a
|
||||
return P(cut(position.alpha), cut(position.delta), cut(position.gamma),
|
||||
cut(position.omega), cut(position.chi), cut(position.phi))
|
||||
|
||||
|
||||
def getNameFromScannableOrString(o):
|
||||
try: # it may be a scannable
|
||||
return o.getName()
|
||||
except AttributeError:
|
||||
return str(o)
|
||||
|
||||
|
||||
class TransformCommands(object):
|
||||
|
||||
def __init__(self, sector_selector):
|
||||
self._sectorSelector = sector_selector
|
||||
|
||||
@command
|
||||
def transform(self):
|
||||
"""transform -- show transform configuration"""
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
@command
|
||||
def transforma(self, *args):
|
||||
"""transforma {on|off|auto|manual} -- configure transform A application
|
||||
"""
|
||||
self._transform('transforma', 'a', args)
|
||||
|
||||
@command
|
||||
def transformb(self, *args):
|
||||
"""transformb {on|off|auto|manual} -- configure transform B application
|
||||
"""
|
||||
self._transform('transformb', 'b', args)
|
||||
|
||||
@command
|
||||
def transformc(self, *args):
|
||||
"""transformc {on|off|auto|manual} -- configure transform C application
|
||||
"""
|
||||
|
||||
self._transform('transformc', 'c', args)
|
||||
|
||||
def _transform(self, commandName, transformName, args):
|
||||
if len(args) == 0:
|
||||
print self._sectorSelector.__repr__()
|
||||
return
|
||||
# get name
|
||||
if len(args) != 1:
|
||||
raise TypeError()
|
||||
if type(args[0]) is not str:
|
||||
raise TypeError()
|
||||
|
||||
ss = self._sectorSelector
|
||||
if args[0] == 'on':
|
||||
ss.addTransorm(transformName)
|
||||
elif args[0] == 'off':
|
||||
ss.removeTransorm(transformName)
|
||||
elif args[0] == 'auto':
|
||||
ss.addAutoTransorm(transformName)
|
||||
elif args[0] == 'manual':
|
||||
ss.removeAutoTransform(transformName)
|
||||
else:
|
||||
raise TypeError()
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
@command
|
||||
def sector(self, sector=None):
|
||||
"""sector {0-7} -- Select or display sector (a la Spec)
|
||||
"""
|
||||
if sector is None:
|
||||
print self._sectorSelector.__repr__()
|
||||
else:
|
||||
if type(sector) is not int and not (0 <= sector <= 7):
|
||||
raise TypeError()
|
||||
self._sectorSelector.setSector(sector)
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
@command
|
||||
def autosector(self, *args):
|
||||
"""autosector [None] [0-7] [0-7]... -- Set sectors that might be automatically applied""" #@IgnorePep8
|
||||
if len(args) == 0:
|
||||
print self._sectorSelector.__repr__()
|
||||
elif len(args) == 1 and args[0] is None:
|
||||
self._sectorSelector.setAutoSectors([])
|
||||
print self._sectorSelector.__repr__()
|
||||
else:
|
||||
sectorList = []
|
||||
for arg in args:
|
||||
if type(arg) is not int:
|
||||
raise TypeError()
|
||||
sectorList.append(arg)
|
||||
self._sectorSelector.setAutoSectors(sectorList)
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
|
||||
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/__init__.py
Executable file
292
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/calc.py
Executable file
292
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/calc.py
Executable file
@@ -0,0 +1,292 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, asin, acos, atan2, sin, cos, sqrt
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
from diffcalc.log import logging
|
||||
from diffcalc.util import bound, AbstractPosition, DiffcalcException,\
|
||||
x_rotation, z_rotation
|
||||
from diffcalc.hkl.vlieg.geometry import VliegGeometry
|
||||
from diffcalc.ub.calc import PaperSpecificUbCalcStrategy
|
||||
from diffcalc.hkl.calcbase import HklCalculatorBase
|
||||
from diffcalc.hkl.common import DummyParameterManager
|
||||
|
||||
logger = logging.getLogger("diffcalc.hkl.willmot.calcwill")
|
||||
|
||||
CHOOSE_POSITIVE_GAMMA = True
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
I = matrix('1 0 0; 0 1 0; 0 0 1')
|
||||
SMALL = 1e-10
|
||||
|
||||
TEMPORARY_CONSTRAINTS_DICT_RAD = {'betain': 2 * TORAD}
|
||||
|
||||
|
||||
def create_matrices(delta, gamma, omegah, phi):
|
||||
return (calc_DELTA(delta), calc_GAMMA(gamma), calc_OMEGAH(omegah),
|
||||
calc_PHI(phi))
|
||||
|
||||
|
||||
def calc_DELTA(delta):
|
||||
return x_rotation(delta) # (39)
|
||||
|
||||
|
||||
def calc_GAMMA(gamma):
|
||||
return z_rotation(gamma) # (40)
|
||||
|
||||
|
||||
def calc_OMEGAH(omegah):
|
||||
return x_rotation(omegah) # (41)
|
||||
|
||||
|
||||
def calc_PHI(phi):
|
||||
return z_rotation(phi) # (42)
|
||||
|
||||
|
||||
def angles_to_hkl_phi(delta, gamma, omegah, phi):
|
||||
"""Calculate hkl matrix in phi frame in units of 2*pi/lambda
|
||||
"""
|
||||
DELTA, GAMMA, OMEGAH, PHI = create_matrices(delta, gamma, omegah, phi)
|
||||
H_lab = (GAMMA * DELTA - I) * matrix([[0], [1], [0]]) # (43)
|
||||
H_phi = PHI.I * OMEGAH.I * H_lab # (44)
|
||||
return H_phi
|
||||
|
||||
|
||||
def angles_to_hkl(delta, gamma, omegah, phi, wavelength, UB):
|
||||
"""Calculate hkl matrix in reprical lattice space in units of 1/Angstrom
|
||||
"""
|
||||
H_phi = angles_to_hkl_phi(delta, gamma, omegah, phi) * 2 * pi / wavelength
|
||||
hkl = UB.I * H_phi # (5)
|
||||
return hkl
|
||||
|
||||
|
||||
class WillmottHorizontalPosition(AbstractPosition):
|
||||
|
||||
def __init__(self, delta=None, gamma=None, omegah=None, phi=None):
|
||||
self.delta = delta
|
||||
self.gamma = gamma
|
||||
self.omegah = omegah
|
||||
self.phi = phi
|
||||
|
||||
def clone(self):
|
||||
return WillmottHorizontalPosition(self.delta, self.gamma, self.omegah,
|
||||
self.phi)
|
||||
|
||||
def changeToRadians(self):
|
||||
self.delta *= TORAD
|
||||
self.gamma *= TORAD
|
||||
self.omegah *= TORAD
|
||||
self.phi *= TORAD
|
||||
|
||||
def changeToDegrees(self):
|
||||
self.delta *= TODEG
|
||||
self.gamma *= TODEG
|
||||
self.omegah *= TODEG
|
||||
self.phi *= TODEG
|
||||
|
||||
def totuple(self):
|
||||
return (self.delta, self.gamma, self.omegah, self.phi)
|
||||
|
||||
def __str__(self):
|
||||
return ('WillmottHorizontalPosition('
|
||||
'delta: %.4f gamma: %.4f omegah: %.4f phi: %.4f)' %
|
||||
(self.delta, self.gamma, self.omegah, self.phi))
|
||||
|
||||
|
||||
class WillmottHorizontalGeometry(object):
|
||||
|
||||
def __init__(self):
|
||||
self.name = 'willmott_horizontal'
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
return WillmottHorizontalPosition(*physicalAngles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
return internalPosition.totuple()
|
||||
|
||||
def create_position(self, delta, gamma, omegah, phi):
|
||||
return WillmottHorizontalPosition(delta, gamma, omegah, phi)
|
||||
|
||||
|
||||
class WillmottHorizontalUbCalcStrategy(PaperSpecificUbCalcStrategy):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
H_phi = angles_to_hkl_phi(*pos.totuple())
|
||||
return matrix(H_phi.tolist())
|
||||
|
||||
|
||||
class DummyConstraints(object):
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return TEMPORARY_CONSTRAINTS_DICT_RAD
|
||||
|
||||
|
||||
class ConstraintAdapter(object):
|
||||
|
||||
def __init__(self, constraints):
|
||||
self._constraints = constraints
|
||||
|
||||
def getParameterDict(self):
|
||||
names = self._constraints.available
|
||||
return dict(zip(names, [None] * len(names)))
|
||||
|
||||
def setParameter(self, name, value):
|
||||
self._constraints.set_constraint(name, value)
|
||||
|
||||
def get(self, name):
|
||||
if name in self._constraints.all:
|
||||
val = self._constraints.get_value(name)
|
||||
return 999 if val is None else val
|
||||
else:
|
||||
return 999
|
||||
|
||||
def update_tracked(self):
|
||||
pass
|
||||
|
||||
|
||||
class WillmottHorizontalCalculator(HklCalculatorBase):
|
||||
|
||||
def __init__(self, ubcalc, geometry, hardware, constraints,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=True):
|
||||
""""
|
||||
Where constraints.reference is a one element dict with the key either
|
||||
('betain', 'betaout' or 'equal') and the value a number or None for
|
||||
'betain_eq_betaout'
|
||||
"""
|
||||
|
||||
HklCalculatorBase.__init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl)
|
||||
|
||||
if constraints is not None:
|
||||
self.constraints = constraints
|
||||
self.parameter_manager = ConstraintAdapter(constraints)
|
||||
else:
|
||||
self.constraints = DummyConstraints()
|
||||
self.parameter_manager = DummyParameterManager()
|
||||
|
||||
@property
|
||||
def _UB(self):
|
||||
return self._ubcalc.UB
|
||||
|
||||
def _anglesToHkl(self, pos, wavelength):
|
||||
"""
|
||||
Calculate miller indices from position in radians.
|
||||
"""
|
||||
hkl_matrix = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
|
||||
wavelength, self._UB)
|
||||
return hkl_matrix[0, 0], hkl_matrix[1, 0], hkl_matrix[2, 0],
|
||||
|
||||
def _anglesToVirtualAngles(self, pos, wavelength):
|
||||
"""
|
||||
Calculate virtual-angles in radians from position in radians.
|
||||
|
||||
Return theta, alpha, and beta in a dictionary.
|
||||
"""
|
||||
|
||||
betain = pos.omegah # (52)
|
||||
|
||||
hkl = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
|
||||
wavelength, self._UB)
|
||||
H_phi = self._UB * hkl
|
||||
H_phi = H_phi / (2 * pi / wavelength)
|
||||
l_phi = H_phi[2, 0]
|
||||
sin_betaout = l_phi - sin(betain)
|
||||
betaout = asin(bound(sin_betaout)) # (54)
|
||||
|
||||
cos_2theta = cos(pos.delta) * cos(pos.gamma)
|
||||
theta = acos(bound(cos_2theta)) / 2.
|
||||
|
||||
return {'theta': theta, 'betain': betain, 'betaout': betaout}
|
||||
|
||||
def _hklToAngles(self, h, k, l, wavelength):
|
||||
"""
|
||||
Calculate position and virtual angles in radians for a given hkl.
|
||||
"""
|
||||
|
||||
H_phi = self._UB * matrix([[h], [k], [l]]) # units: 1/Angstrom
|
||||
H_phi = H_phi / (2 * pi / wavelength) # units: 2*pi/wavelength
|
||||
h_phi = H_phi[0, 0]
|
||||
k_phi = H_phi[1, 0]
|
||||
l_phi = H_phi[2, 0] # (5)
|
||||
|
||||
### determine betain (omegah) and betaout ###
|
||||
|
||||
if not self.constraints.reference:
|
||||
raise ValueError("No reference constraint has been constrained.")
|
||||
|
||||
ref_name, ref_value = self.constraints.reference.items()[0]
|
||||
if ref_value is not None:
|
||||
ref_value *= TORAD
|
||||
if ref_name == 'betain':
|
||||
betain = ref_value
|
||||
betaout = asin(bound(l_phi - sin(betain))) # (53)
|
||||
elif ref_name == 'betaout':
|
||||
betaout = ref_value
|
||||
betain = asin(bound(l_phi - sin(betaout))) # (54)
|
||||
elif ref_name == 'bin_eq_bout':
|
||||
betain = betaout = asin(bound(l_phi / 2)) # (55)
|
||||
else:
|
||||
raise ValueError("Unexpected constraint name'%s'." % ref_name)
|
||||
|
||||
if abs(betain) < SMALL:
|
||||
raise DiffcalcException('required betain was 0 degrees (requested '
|
||||
'q is perpendicular to surface normal)')
|
||||
if betain < -SMALL:
|
||||
raise DiffcalcException("betain was -ve (%.4f)" % betain)
|
||||
# logger.info('betain = %.4f, betaout = %.4f',
|
||||
# betain * TODEG, betaout * TODEG)
|
||||
omegah = betain # (52)
|
||||
|
||||
### determine H_lab (X, Y and Z) ###
|
||||
|
||||
Y = -(h_phi ** 2 + k_phi ** 2 + l_phi ** 2) / 2 # (45)
|
||||
|
||||
Z = (sin(betaout) + sin(betain) * (Y + 1)) / cos(omegah) # (47)
|
||||
|
||||
X_squared = (h_phi ** 2 + k_phi ** 2 -
|
||||
((cos(betain) * Y + sin(betain) * Z) ** 2)) # (48)
|
||||
if (X_squared < 0) and (abs(X_squared) < SMALL):
|
||||
X_squared = 0
|
||||
Xpositive = sqrt(X_squared)
|
||||
if CHOOSE_POSITIVE_GAMMA:
|
||||
X = -Xpositive
|
||||
else:
|
||||
X = Xpositive
|
||||
# logger.info('H_lab (X,Y,Z) = [%.4f, %.4f, %.4f]', X, Y, Z)
|
||||
### determine diffractometer angles ###
|
||||
|
||||
gamma = atan2(-X, Y + 1) # (49)
|
||||
if (abs(gamma) < SMALL):
|
||||
# degenerate case, only occurs when q || z
|
||||
delta = 2 * omegah
|
||||
else:
|
||||
delta = atan2(Z * sin(gamma), -X) # (50)
|
||||
M = cos(betain) * Y + sin(betain) * Z
|
||||
phi = atan2(h_phi * M - k_phi * X, h_phi * X + k_phi * M) # (51)
|
||||
|
||||
pos = WillmottHorizontalPosition(delta, gamma, omegah, phi)
|
||||
virtual_angles = {'betain': betain, 'betaout': betaout}
|
||||
return pos, virtual_angles
|
||||
58
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/commands.py
Executable file
58
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/commands.py
Executable file
@@ -0,0 +1,58 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.hkl.common import getNameFromScannableOrString
|
||||
from diffcalc.util import command
|
||||
|
||||
|
||||
class WillmottHklCommands(object):
|
||||
|
||||
def __init__(self, hklcalc):
|
||||
self._hklcalc = hklcalc
|
||||
self.commands = [self.con,
|
||||
self.uncon,
|
||||
self.cons]
|
||||
|
||||
def __str__(self):
|
||||
return self._hklcalc.__str__()
|
||||
|
||||
@command
|
||||
def con(self, scn_or_string):
|
||||
"""con <constraint> -- constrains constraint
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
self._hklcalc.constraints.constrain(name)
|
||||
print self._report_constraints()
|
||||
|
||||
@command
|
||||
def uncon(self, scn_or_string):
|
||||
"""uncon <constraint> -- unconstrains constraint
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
self._hklcalc.constraints.unconstrain(name)
|
||||
print self._report_constraints()
|
||||
|
||||
@command
|
||||
def cons(self):
|
||||
"""cons -- list available constraints and values
|
||||
"""
|
||||
print self._report_constraints()
|
||||
|
||||
def _report_constraints(self):
|
||||
return (self._hklcalc.constraints.build_display_table_lines() + '\n\n' +
|
||||
self._hklcalc.constraints._report_constraints())
|
||||
156
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/constraints.py
Executable file
156
script/__Lib/diffcalc-2.1/diffcalc/hkl/willmott/constraints.py
Executable file
@@ -0,0 +1,156 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.util import DiffcalcException
|
||||
|
||||
|
||||
def filter_dict(d, keys):
|
||||
"""Return a copy of d containing only keys that are in keys"""
|
||||
##return {k: d[k] for k in keys} # requires Python 2.6
|
||||
return dict((k, d[k]) for k in keys if k in d.keys())
|
||||
|
||||
|
||||
ref_constraints = ('betain', 'betaout', 'bin_eq_bout')
|
||||
valueless_constraints = ('bin_eq_bout')
|
||||
all_constraints = ref_constraints
|
||||
|
||||
|
||||
class WillmottConstraintManager(object):
|
||||
"""Constraints in degrees.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._constrained = {'bin_eq_bout': None}
|
||||
|
||||
@property
|
||||
def available_constraint_names(self):
|
||||
"""list of all available constraints"""
|
||||
return all_constraints
|
||||
|
||||
@property
|
||||
def all(self): # @ReservedAssignment
|
||||
"""dictionary of all constrained values"""
|
||||
return self._constrained.copy()
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return filter_dict(self.all, ref_constraints)
|
||||
|
||||
@property
|
||||
def constrained_names(self):
|
||||
"""ordered tuple of constained circles"""
|
||||
names = self.all.keys()
|
||||
names.sort(key=lambda name: list(all_constraints).index(name))
|
||||
return tuple(names)
|
||||
|
||||
def is_constrained(self, name):
|
||||
return name in self._constrained
|
||||
|
||||
def get_value(self, name):
|
||||
return self._constrained[name]
|
||||
|
||||
def _build_display_table(self):
|
||||
constraint_types = (ref_constraints,)
|
||||
num_rows = max([len(col) for col in constraint_types])
|
||||
max_name_width = max(
|
||||
[len(name) for name in sum(constraint_types[:2], ())])
|
||||
# headings
|
||||
lines = [' ' + 'REF'.ljust(max_name_width)]
|
||||
lines.append(' ' + '=' * max_name_width + ' ')
|
||||
|
||||
# constraint rows
|
||||
for n_row in range(num_rows):
|
||||
cells = []
|
||||
for col in constraint_types:
|
||||
name = col[n_row] if n_row < len(col) else ''
|
||||
cells.append(self._label_constraint(name))
|
||||
cells.append(('%-' + str(max_name_width) + 's ') % name)
|
||||
lines.append(''.join(cells))
|
||||
lines.append
|
||||
return '\n'.join(lines)
|
||||
|
||||
def _report_constraints(self):
|
||||
if not self.reference:
|
||||
return "!!! No reference constraint set"
|
||||
name, val = self.reference.items()[0]
|
||||
if name in valueless_constraints:
|
||||
return " %s" % name
|
||||
else:
|
||||
if val is None:
|
||||
return "!!! %s: ---" % name
|
||||
else:
|
||||
return " %s: %.4f" % (name, val)
|
||||
|
||||
def _label_constraint(self, name):
|
||||
if name == '':
|
||||
label = ' '
|
||||
elif (self.is_constrained(name) and (self.get_value(name) is None) and
|
||||
name not in valueless_constraints):
|
||||
label = 'o-> '
|
||||
elif self.is_constrained(name):
|
||||
label = '--> '
|
||||
else:
|
||||
label = ' '
|
||||
return label
|
||||
|
||||
def constrain(self, name):
|
||||
if name in self.all:
|
||||
return "%s is already constrained." % name.capitalize()
|
||||
elif name in ref_constraints:
|
||||
return self._constrain_reference(name)
|
||||
else:
|
||||
raise DiffcalcException('%s is not a valid constraint name')
|
||||
|
||||
def _constrain_reference(self, name):
|
||||
if self.reference:
|
||||
constrained_name = self.reference.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return '%s constraint replaced.' % constrained_name.capitalize()
|
||||
else:
|
||||
self._constrained[name] = None
|
||||
|
||||
def unconstrain(self, name):
|
||||
if name in self._constrained:
|
||||
del self._constrained[name]
|
||||
else:
|
||||
return "%s was not already constrained." % name.capitalize()
|
||||
|
||||
###
|
||||
def _check_constraint_settable(self, name, verb):
|
||||
if name not in all_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this is not an available '
|
||||
'constraint.' % locals())
|
||||
elif name not in self.all.keys():
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this is not currently '
|
||||
'constrained.' % locals())
|
||||
elif name in valueless_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this constraint takes no '
|
||||
'value.' % locals())
|
||||
|
||||
def set_constraint(self, name, value): # @ReservedAssignment
|
||||
self._check_constraint_settable(name, 'set')
|
||||
old_value = self.all[name]
|
||||
old = str(old_value) if old_value is not None else '---'
|
||||
self._constrained[name] = float(value)
|
||||
new = str(value)
|
||||
return "%(name)s : %(old)s --> %(new)s" % locals()
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/__init__.py
Executable file
1162
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/calc.py
Executable file
1162
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/calc.py
Executable file
File diff suppressed because it is too large
Load Diff
377
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/constraints.py
Executable file
377
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/constraints.py
Executable file
@@ -0,0 +1,377 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
from diffcalc.util import DiffcalcException, bold
|
||||
|
||||
TODEG = 180 / pi
|
||||
TORAD = pi / 180
|
||||
|
||||
NUNAME = 'gam'
|
||||
|
||||
def filter_dict(d, keys):
|
||||
"""Return a copy of d containing only keys that are in keys"""
|
||||
##return {k: d[k] for k in keys} # requires Python 2.6
|
||||
return dict((k, d[k]) for k in keys if k in d.keys())
|
||||
|
||||
|
||||
det_constraints = ('delta', NUNAME, 'qaz', 'naz')
|
||||
ref_constraints = ('a_eq_b', 'alpha', 'beta', 'psi')
|
||||
samp_constraints = ('mu', 'eta', 'chi', 'phi', 'mu_is_' + NUNAME)
|
||||
|
||||
valueless_constraints = ('a_eq_b', 'mu_is_' + NUNAME)
|
||||
all_constraints = det_constraints + ref_constraints + samp_constraints
|
||||
|
||||
|
||||
number_single_sample = (len(det_constraints) * len(ref_constraints) *
|
||||
len(samp_constraints))
|
||||
|
||||
|
||||
class YouConstraintManager(object):
|
||||
|
||||
def __init__(self, hardware, fixed_constraints = {}):
|
||||
self._hardware = hardware
|
||||
self._constrained = {}
|
||||
# self._tracking = []
|
||||
self.n_phi = matrix([[0], [0], [1]])
|
||||
self._hide_detector_constraint = False # default
|
||||
self._fixed_samp_constraints = ()
|
||||
self._fix_constraints(fixed_constraints)
|
||||
|
||||
def __str__(self):
|
||||
lines = []
|
||||
# TODO: Put somewhere with access to UB matrix!
|
||||
# WIDTH = 13
|
||||
# n_phi = self.n_phi
|
||||
# fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
# lines.append(" n_phi:".ljust(WIDTH) +
|
||||
# fmt % (n_phi[0, 0], n_phi[1, 0], n_phi[2, 0]))
|
||||
# if self._getUBMatrix():
|
||||
# n_cryst = self._getUMatrix().I * self.n_phi
|
||||
# lines.append(" n_cryst:".ljust(WIDTH) +
|
||||
# fmt % (n_cryst[0, 0], n_cryst[1, 0], n_cryst[2, 0]))
|
||||
# n_recip = self._getUBMatrix().I * self.n_phi
|
||||
# lines.append(" n_recip:".ljust(WIDTH) +
|
||||
# fmt % (n_recip[0, 0], n_recip[1, 0], n_recip[2, 0]))
|
||||
# else:
|
||||
# lines.append(
|
||||
# " n_cryst:".ljust(WIDTH) + ' "<<< No U matrix >>>"')
|
||||
# lines.append(
|
||||
# " n_recip:".ljust(WIDTH) + ' "<<< No UB matrix >>>"')
|
||||
|
||||
lines.extend(self.build_display_table_lines())
|
||||
lines.append("")
|
||||
lines.extend(self.report_constraints_lines())
|
||||
lines.append("")
|
||||
if (self.is_fully_constrained() and
|
||||
not self.is_current_mode_implemented()):
|
||||
lines.append(
|
||||
" Sorry, this constraint combination is not implemented")
|
||||
lines.append(" Type 'help con' for available combinations")
|
||||
else:
|
||||
lines.append(" Type 'help con' for instructions") # okay
|
||||
return '\n'.join(lines)
|
||||
|
||||
@property
|
||||
def available_constraint_names(self):
|
||||
"""list of all available constraints"""
|
||||
return all_constraints
|
||||
|
||||
@property
|
||||
def settable_constraint_names(self):
|
||||
"""list of all available constraints that have settable values"""
|
||||
all_copy = list(all_constraints)
|
||||
for valueless in valueless_constraints:
|
||||
all_copy.remove(valueless)
|
||||
return all_copy
|
||||
|
||||
@property
|
||||
def all(self): # @ReservedAssignment
|
||||
"""dictionary of all constrained values"""
|
||||
return self._constrained.copy()
|
||||
|
||||
@property
|
||||
def detector(self):
|
||||
"""dictionary of constrained detector circles"""
|
||||
return filter_dict(self.all, det_constraints[:-1])
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return filter_dict(self.all, ref_constraints)
|
||||
|
||||
@property
|
||||
def sample(self):
|
||||
"""dictionary of constrained sample circles"""
|
||||
return filter_dict(self.all, samp_constraints)
|
||||
|
||||
@property
|
||||
def naz(self):
|
||||
"""dictionary with naz and value if constrained"""
|
||||
return filter_dict(self.all, ('naz',))
|
||||
|
||||
@property
|
||||
def constrained_names(self):
|
||||
"""ordered tuple of constained circles"""
|
||||
names = self.all.keys()
|
||||
names.sort(key=lambda name: list(all_constraints).index(name))
|
||||
return tuple(names)
|
||||
|
||||
def _fix_constraints(self, fixed_constraints):
|
||||
for name in fixed_constraints:
|
||||
self.constrain(name)
|
||||
self.set_constraint(name, fixed_constraints[name])
|
||||
|
||||
if self.detector or self.naz:
|
||||
self._hide_detector_constraint = True
|
||||
|
||||
fixed_samp_constraints = list(self.sample.keys())
|
||||
if 'mu' in self.sample or NUNAME in self.detector:
|
||||
fixed_samp_constraints.append('mu_is_' + NUNAME)
|
||||
self._fixed_samp_constraints = tuple(fixed_samp_constraints)
|
||||
|
||||
|
||||
def is_constrained(self, name):
|
||||
return name in self._constrained
|
||||
|
||||
def get_value(self, name):
|
||||
return self._constrained[name]
|
||||
|
||||
def build_display_table_lines(self):
|
||||
unfixed_samp_constraints = list(samp_constraints)
|
||||
for name in self._fixed_samp_constraints:
|
||||
unfixed_samp_constraints.remove(name)
|
||||
if self._hide_detector_constraint:
|
||||
constraint_types = (ref_constraints, unfixed_samp_constraints)
|
||||
else:
|
||||
constraint_types = (det_constraints, ref_constraints,
|
||||
unfixed_samp_constraints)
|
||||
num_rows = max([len(col) for col in constraint_types])
|
||||
max_name_width = max(
|
||||
[len(name) for name in sum(constraint_types[:-1], ())])
|
||||
|
||||
cells = []
|
||||
|
||||
header_cells = []
|
||||
if not self._hide_detector_constraint:
|
||||
header_cells.append(bold(' ' + 'DET'.ljust(max_name_width)))
|
||||
header_cells.append(bold(' ' + 'REF'.ljust(max_name_width)))
|
||||
header_cells.append(bold(' ' + 'SAMP'))
|
||||
cells.append(header_cells)
|
||||
|
||||
underline_cells = [' ' + '-' * max_name_width] * len(constraint_types)
|
||||
cells.append(underline_cells)
|
||||
|
||||
for n_row in range(num_rows):
|
||||
row_cells = []
|
||||
for col in constraint_types:
|
||||
name = col[n_row] if n_row < len(col) else ''
|
||||
row_cells.append(self._label_constraint(name))
|
||||
row_cells.append(('%-' + str(max_name_width) + 's') % name)
|
||||
cells.append(row_cells)
|
||||
|
||||
lines = [' '.join(row_cells).rstrip() for row_cells in cells]
|
||||
return lines
|
||||
|
||||
def _report_constraint(self, name):
|
||||
val = self.get_constraint(name)
|
||||
if name in valueless_constraints:
|
||||
return " %s" % name
|
||||
else:
|
||||
if val is None:
|
||||
return "! %-5s: ---" % name
|
||||
else:
|
||||
return " %-5s: %.4f" % (name, val)
|
||||
|
||||
def report_constraints_lines(self):
|
||||
lines = []
|
||||
required = 3 - len(self.all)
|
||||
if required == 0:
|
||||
pass
|
||||
elif required == 1:
|
||||
lines.append('! 1 more constraint required')
|
||||
else:
|
||||
lines.append('! %d more constraints required' % required)
|
||||
constraints = []
|
||||
constraints.extend(self.detector.keys())
|
||||
constraints.extend(self.naz.keys())
|
||||
constraints.extend(self.reference.keys())
|
||||
constraints.extend(sorted(self.sample.keys()))
|
||||
for name in constraints:
|
||||
lines.append(self._report_constraint(name))
|
||||
return lines
|
||||
|
||||
def is_fully_constrained(self):
|
||||
return len(self.all) == 3
|
||||
|
||||
def is_current_mode_implemented(self):
|
||||
if not self.is_fully_constrained():
|
||||
raise ValueError("Three constraints required")
|
||||
|
||||
if len(self.sample) == 3:
|
||||
if set(self.sample.keys()) == set(['chi', 'phi', 'eta']):
|
||||
return True
|
||||
return False
|
||||
|
||||
if len(self.sample) == 1:
|
||||
return True
|
||||
|
||||
if len(self.reference) == 1:
|
||||
return (set(self.sample.keys()) == set(['chi', 'phi']) or
|
||||
set(self.sample.keys()) == set(['chi', 'eta']) or
|
||||
set(self.sample.keys()) == set(['chi', 'mu']) or
|
||||
set(self.sample.keys()) == set(['mu', 'eta']))
|
||||
|
||||
if len(self.detector) == 1:
|
||||
return (set(self.sample.keys()) == set(['chi', 'phi']) or
|
||||
set(self.sample.keys()) == set(['mu', 'eta']) or
|
||||
set(self.sample.keys()) == set(['mu', 'phi'])
|
||||
)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _label_constraint(self, name):
|
||||
if name == '':
|
||||
label = ' '
|
||||
# elif self.is_tracking(name): # implies constrained
|
||||
# label = '~~> '
|
||||
elif (self.is_constrained(name) and (self.get_value(name) is None) and
|
||||
name not in valueless_constraints):
|
||||
label = 'o->'
|
||||
elif self.is_constrained(name):
|
||||
label = '-->'
|
||||
else:
|
||||
label = ' '
|
||||
return label
|
||||
|
||||
def constrain(self, name):
|
||||
if self.is_constraint_fixed(name):
|
||||
raise DiffcalcException('%s is not a valid constraint name' % name)
|
||||
if name in self.all:
|
||||
return "%s is already constrained." % name.capitalize()
|
||||
elif name in det_constraints:
|
||||
return self._constrain_detector(name)
|
||||
elif name in ref_constraints:
|
||||
return self._constrain_reference(name)
|
||||
elif name in samp_constraints:
|
||||
return self._constrain_sample(name)
|
||||
else:
|
||||
raise DiffcalcException("%s is not a valid constraint name. Type 'con' for a table of constraint name" % name)
|
||||
|
||||
def is_constraint_fixed(self, name):
|
||||
return ((name in det_constraints and self._hide_detector_constraint) or
|
||||
(name in samp_constraints and name in self._fixed_samp_constraints))
|
||||
|
||||
def _constrain_detector(self, name):
|
||||
if self.naz:
|
||||
del self._constrained['naz']
|
||||
self._constrained[name] = None
|
||||
return 'Naz constraint replaced.'
|
||||
elif self.detector:
|
||||
constrained_name = self.detector.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return'%s constraint replaced.' % constrained_name.capitalize()
|
||||
elif len(self.all) == 3: # and no detector
|
||||
raise self._could_not_constrain_exception(name)
|
||||
else:
|
||||
self._constrained[name] = None
|
||||
|
||||
def _could_not_constrain_exception(self, name):
|
||||
return DiffcalcException(
|
||||
"%s could not be constrained. First un-constrain one of the\n"
|
||||
"angles %s, %s or %s (with 'uncon')" %
|
||||
((name.capitalize(),) + self.constrained_names))
|
||||
|
||||
def _constrain_reference(self, name):
|
||||
if self.reference:
|
||||
constrained_name = self.reference.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return '%s constraint replaced.' % constrained_name.capitalize()
|
||||
elif len(self.all) == 3: # and no reference
|
||||
raise self._could_not_constrain_exception(name)
|
||||
else:
|
||||
self._constrained[name] = None
|
||||
|
||||
def _constrain_sample(self, name):
|
||||
if len(self._constrained) < 3:
|
||||
# okay, more to add
|
||||
self._constrained[name] = None
|
||||
# else: three constraints are set
|
||||
elif len(self.sample) == 1:
|
||||
# (detector and reference constraints set)
|
||||
# it is clear which sample constraint to remove
|
||||
constrained_name = self.sample.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return '%s constraint replaced.' % constrained_name.capitalize()
|
||||
else:
|
||||
raise self._could_not_constrain_exception(name)
|
||||
|
||||
def unconstrain(self, name):
|
||||
if self.is_constraint_fixed(name):
|
||||
raise DiffcalcException('%s is not a valid constraint name')
|
||||
if name in self._constrained:
|
||||
del self._constrained[name]
|
||||
else:
|
||||
return "%s was not already constrained." % name.capitalize()
|
||||
|
||||
def _check_constraint_settable(self, name):
|
||||
if name not in all_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not set %(name)s. This is not an available '
|
||||
'constraint.' % locals())
|
||||
elif name not in self.all.keys():
|
||||
raise DiffcalcException(
|
||||
'Could not set %(name)s. This is not currently '
|
||||
'constrained.' % locals())
|
||||
elif name in valueless_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not set %(name)s. This constraint takes no '
|
||||
'value.' % locals())
|
||||
|
||||
def clear_constraints(self):
|
||||
self._constrained = {}
|
||||
|
||||
def set_constraint(self, name, value): # @ReservedAssignment
|
||||
if self.is_constraint_fixed(name):
|
||||
raise DiffcalcException('%s is not a valid constraint name')
|
||||
self._check_constraint_settable(name)
|
||||
# if name in self._tracking:
|
||||
# raise DiffcalcException(
|
||||
# "Could not set %s as this constraint is configured to track "
|
||||
# "its associated\nphysical angle. First remove this tracking "
|
||||
# "(use 'untrack %s').""" % (name, name))
|
||||
old_value = self.get_constraint(name)
|
||||
old = str(old_value) if old_value is not None else '---'
|
||||
self._constrained[name] = float(value) * TORAD
|
||||
new = str(value)
|
||||
return "%(name)s : %(old)s --> %(new)s" % locals()
|
||||
|
||||
def get_constraint(self, name):
|
||||
value = self.all[name]
|
||||
return None if value is None else value * TODEG
|
||||
|
||||
219
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/geometry.py
Executable file
219
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/geometry.py
Executable file
@@ -0,0 +1,219 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi
|
||||
|
||||
from diffcalc.util import AbstractPosition, DiffcalcException
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
from diffcalc.util import x_rotation, z_rotation, y_rotation
|
||||
|
||||
from diffcalc.hkl.you.constraints import NUNAME
|
||||
|
||||
class YouGeometry(object):
|
||||
|
||||
def __init__(self, name, fixed_constraints, beamline_axes_transform=None):
|
||||
self.name = name
|
||||
self.fixed_constraints = fixed_constraints
|
||||
# beamline_axes_transform matrix is composed of the diffcalc basis vector coordinates
|
||||
# in the beamline coordinate system, i.e. it transforms the beamline coordinate system
|
||||
# into the reference diffcalc one.
|
||||
self.beamline_axes_transform = beamline_axes_transform
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
raise NotImplementedError()
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_position(self, *args):
|
||||
return YouPosition(*args, unit='DEG')
|
||||
|
||||
|
||||
#==============================================================================
|
||||
#==============================================================================
|
||||
# Geometry plugins for use with 'You' hkl calculation engine
|
||||
#==============================================================================
|
||||
#==============================================================================
|
||||
|
||||
|
||||
class SixCircle(YouGeometry):
|
||||
def __init__(self, beamline_axes_transform=None):
|
||||
YouGeometry.__init__(self, 'sixc', {}, beamline_axes_transform)
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
# mu, delta, nu, eta, chi, phi
|
||||
return YouPosition(*physical_angle_tuple, unit='DEG')
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
clone_position = internal_position.clone()
|
||||
clone_position.changeToDegrees()
|
||||
return clone_position.totuple()
|
||||
|
||||
|
||||
class FourCircle(YouGeometry):
|
||||
"""For a diffractometer with angles:
|
||||
delta, eta, chi, phi
|
||||
"""
|
||||
def __init__(self, beamline_axes_transform=None):
|
||||
YouGeometry.__init__(self, 'fourc', {'mu': 0, NUNAME: 0}, beamline_axes_transform)
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
# mu, delta, nu, eta, chi, phi
|
||||
delta, eta, chi, phi = physical_angle_tuple
|
||||
return YouPosition(0, delta, 0, eta, chi, phi, 'DEG')
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
clone_position = internal_position.clone()
|
||||
clone_position.changeToDegrees()
|
||||
_, delta, _, eta, chi, phi = clone_position.totuple()
|
||||
return delta, eta, chi, phi
|
||||
|
||||
|
||||
class FiveCircle(YouGeometry):
|
||||
"""For a diffractometer with angles:
|
||||
delta, nu, eta, chi, phi
|
||||
"""
|
||||
def __init__(self, beamline_axes_transform=None):
|
||||
YouGeometry.__init__(self, 'fivec', {'mu': 0}, beamline_axes_transform)
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
# mu, delta, nu, eta, chi, phi
|
||||
delta, nu, eta, chi, phi = physical_angle_tuple
|
||||
return YouPosition(0, delta, nu, eta, chi, phi, 'DEG')
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
clone_position = internal_position.clone()
|
||||
clone_position.changeToDegrees()
|
||||
_, delta, nu, eta, chi, phi = clone_position.totuple()
|
||||
return delta, nu, eta, chi, phi
|
||||
|
||||
|
||||
#==============================================================================
|
||||
|
||||
|
||||
def create_you_matrices(mu=None, delta=None, nu=None, eta=None, chi=None,
|
||||
phi=None):
|
||||
"""
|
||||
Create transformation matrices from H. You's paper.
|
||||
"""
|
||||
MU = None if mu is None else calcMU(mu)
|
||||
DELTA = None if delta is None else calcDELTA(delta)
|
||||
NU = None if nu is None else calcNU(nu)
|
||||
ETA = None if eta is None else calcETA(eta)
|
||||
CHI = None if chi is None else calcCHI(chi)
|
||||
PHI = None if phi is None else calcPHI(phi)
|
||||
return MU, DELTA, NU, ETA, CHI, PHI
|
||||
|
||||
|
||||
def calcNU(nu):
|
||||
return x_rotation(nu)
|
||||
|
||||
|
||||
def calcDELTA(delta):
|
||||
return z_rotation(-delta)
|
||||
|
||||
|
||||
def calcMU(mu_or_alpha):
|
||||
return x_rotation(mu_or_alpha)
|
||||
|
||||
|
||||
def calcETA(eta):
|
||||
return z_rotation(-eta)
|
||||
|
||||
|
||||
def calcCHI(chi):
|
||||
return y_rotation(chi)
|
||||
|
||||
|
||||
def calcPHI(phi):
|
||||
return z_rotation(-phi)
|
||||
|
||||
|
||||
def you_position_names():
|
||||
return ('mu', 'delta', NUNAME, 'eta', 'chi', 'phi')
|
||||
|
||||
class YouPosition(AbstractPosition):
|
||||
|
||||
def __init__(self, mu, delta, nu, eta, chi, phi, unit):
|
||||
self.mu = mu
|
||||
self.delta = delta
|
||||
self.nu = nu
|
||||
self.eta = eta
|
||||
self.chi = chi
|
||||
self.phi = phi
|
||||
if unit not in ['DEG', 'RAD']:
|
||||
raise DiffcalcException("Invalid angle unit value %s." % str(unit))
|
||||
else:
|
||||
self.unit = unit
|
||||
|
||||
def clone(self):
|
||||
return YouPosition(self.mu, self.delta, self.nu, self.eta, self.chi,
|
||||
self.phi, self.unit)
|
||||
|
||||
def changeToRadians(self):
|
||||
if self.unit == 'DEG':
|
||||
self.mu *= TORAD
|
||||
self.delta *= TORAD
|
||||
self.nu *= TORAD
|
||||
self.eta *= TORAD
|
||||
self.chi *= TORAD
|
||||
self.phi *= TORAD
|
||||
self.unit = 'RAD'
|
||||
elif self.unit == 'RAD':
|
||||
return
|
||||
else:
|
||||
raise DiffcalcException("Invalid angle unit value %s." % str(self.unit))
|
||||
|
||||
def changeToDegrees(self):
|
||||
if self.unit == 'RAD':
|
||||
self.mu *= TODEG
|
||||
self.delta *= TODEG
|
||||
self.nu *= TODEG
|
||||
self.eta *= TODEG
|
||||
self.chi *= TODEG
|
||||
self.phi *= TODEG
|
||||
self.unit = 'DEG'
|
||||
elif self.unit == 'DEG':
|
||||
return
|
||||
else:
|
||||
raise DiffcalcException("Invalid angle unit value %s." % str(self.unit))
|
||||
|
||||
def totuple(self):
|
||||
return (self.mu, self.delta, self.nu, self.eta, self.chi, self.phi)
|
||||
|
||||
def __str__(self):
|
||||
mu, delta, nu, eta, chi, phi = self.totuple()
|
||||
return ("YouPosition(mu %r delta: %r nu: %r eta: %r chi: %r phi: %r) in %s"
|
||||
% (mu, delta, nu, eta, chi, phi, self.unit))
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.totuple() == other.totuple()
|
||||
|
||||
|
||||
class WillmottHorizontalPosition(YouPosition):
|
||||
|
||||
def __init__(self, delta=None, gamma=None, omegah=None, phi=None):
|
||||
self.mu = 0
|
||||
self.delta = delta
|
||||
self.nu = gamma
|
||||
self.eta = omegah
|
||||
self.chi = -90
|
||||
self.phi = phi
|
||||
self.unit= 'DEG'
|
||||
187
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/hkl.py
Executable file
187
script/__Lib/diffcalc-2.1/diffcalc/hkl/you/hkl.py
Executable file
@@ -0,0 +1,187 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from diffcalc.hkl.common import getNameFromScannableOrString
|
||||
from diffcalc.util import command
|
||||
from diffcalc.hkl.you.calc import YouHklCalculator
|
||||
from diffcalc import settings
|
||||
|
||||
|
||||
|
||||
import diffcalc.ub.ub
|
||||
from diffcalc.hkl.you.constraints import YouConstraintManager
|
||||
|
||||
__all__ = ['allhkl', 'con', 'uncon', 'hklcalc', 'constraint_manager']
|
||||
|
||||
|
||||
_fixed_constraints = settings.geometry.fixed_constraints # @UndefinedVariable
|
||||
|
||||
constraint_manager = YouConstraintManager(settings.hardware, _fixed_constraints)
|
||||
|
||||
hklcalc = YouHklCalculator(
|
||||
diffcalc.ub.ub.ubcalc, settings.geometry, settings.hardware, constraint_manager)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return hklcalc.__str__()
|
||||
|
||||
@command
|
||||
def con(*args):
|
||||
"""
|
||||
con -- list available constraints and values
|
||||
con <name> {val} -- constrains and optionally sets one constraint
|
||||
con <name> {val} <name> {val} <name> {val} -- clears and then fully constrains
|
||||
|
||||
Select three constraints using 'con' and 'uncon'. Choose up to one
|
||||
from each of the sample and detector columns and up to three from
|
||||
the sample column.
|
||||
|
||||
Not all constraint combinations are currently available:
|
||||
|
||||
1 x samp: all 80 of 80
|
||||
|
||||
2 x samp and 1 x ref: chi & phi
|
||||
chi & eta
|
||||
chi & mu
|
||||
mu & eta (4 of 6)
|
||||
|
||||
2 x samp and 1 x det: chi & phi
|
||||
mu & eta
|
||||
mu & phi (3 of 6)
|
||||
|
||||
3 x samp: eta, chi & phi (1 of 4)
|
||||
|
||||
See also 'uncon'
|
||||
"""
|
||||
args = list(args)
|
||||
msg = _handle_con(args)
|
||||
if (hklcalc.constraints.is_fully_constrained() and
|
||||
not hklcalc.constraints.is_current_mode_implemented()):
|
||||
msg += ("\n\nWARNING:. The selected constraint combination is valid but "
|
||||
"is not implemented.\n\nType 'help con' to see implemented combinations")
|
||||
|
||||
if msg:
|
||||
print msg
|
||||
|
||||
def _handle_con(args):
|
||||
if not args:
|
||||
return hklcalc.constraints.__str__()
|
||||
|
||||
if len(args) > 6:
|
||||
raise TypeError("Unexpected args: " + str(args))
|
||||
|
||||
cons_value_pairs = []
|
||||
while args:
|
||||
scn_or_str = args.pop(0)
|
||||
name = getNameFromScannableOrString(scn_or_str)
|
||||
if args and isinstance(args[0], (int, long, float)):
|
||||
value = args.pop(0)
|
||||
else:
|
||||
try:
|
||||
value = settings.hardware.get_position_by_name(name)
|
||||
except ValueError:
|
||||
value = None
|
||||
cons_value_pairs.append((name, value))
|
||||
|
||||
if len(cons_value_pairs) == 1:
|
||||
pass
|
||||
elif len(cons_value_pairs) == 3:
|
||||
hklcalc.constraints.clear_constraints()
|
||||
else:
|
||||
raise TypeError("Either one or three constraints must be specified")
|
||||
for name, value in cons_value_pairs:
|
||||
hklcalc.constraints.constrain(name)
|
||||
if value is not None:
|
||||
hklcalc.constraints.set_constraint(name, value)
|
||||
return '\n'.join(hklcalc.constraints.report_constraints_lines())
|
||||
|
||||
|
||||
@command
|
||||
def uncon(scn_or_string):
|
||||
"""uncon <name> -- remove constraint
|
||||
|
||||
See also 'con'
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
hklcalc.constraints.unconstrain(name)
|
||||
print '\n'.join(hklcalc.constraints.report_constraints_lines())
|
||||
|
||||
@command
|
||||
def allhkl(hkl, wavelength=None):
|
||||
"""allhkl [h k l] -- print all hkl solutions ignoring limits
|
||||
|
||||
"""
|
||||
hardware = hklcalc._hardware
|
||||
geometry = hklcalc._geometry
|
||||
if wavelength is None:
|
||||
wavelength = hardware.get_wavelength()
|
||||
h, k, l = hkl
|
||||
pos_virtual_angles_pairs = hklcalc.hkl_to_all_angles(
|
||||
h, k, l, wavelength)
|
||||
cells = []
|
||||
# virtual_angle_names = list(pos_virtual_angles_pairs[0][1].keys())
|
||||
# virtual_angle_names.sort()
|
||||
virtual_angle_names = ['qaz', 'psi', 'naz', 'tau', 'theta', 'alpha', 'beta']
|
||||
header_cells = list(hardware.get_axes_names()) + [' '] + virtual_angle_names
|
||||
cells.append(['%9s' % s for s in header_cells])
|
||||
cells.append([''] * len(header_cells))
|
||||
|
||||
|
||||
for pos, virtual_angles in pos_virtual_angles_pairs:
|
||||
row_cells = []
|
||||
|
||||
|
||||
angle_tuple = geometry.internal_position_to_physical_angles(pos)
|
||||
angle_tuple = hardware.cut_angles(angle_tuple)
|
||||
for val in angle_tuple:
|
||||
row_cells.append('%9.4f' % val)
|
||||
|
||||
row_cells.append('|')
|
||||
|
||||
for name in virtual_angle_names:
|
||||
row_cells.append('%9.4f' % virtual_angles[name])
|
||||
cells.append(row_cells)
|
||||
|
||||
|
||||
column_widths = []
|
||||
for col in range(len(cells[0])):
|
||||
widths = []
|
||||
for row in range(len(cells)):
|
||||
cell = cells[row][col]
|
||||
width = len(cell.strip())
|
||||
widths.append(width)
|
||||
column_widths.append(max(widths))
|
||||
|
||||
lines = []
|
||||
for row_cells in cells:
|
||||
trimmed_row_cells = []
|
||||
for cell, width in zip(row_cells, column_widths):
|
||||
trimmed_cell = cell.strip().rjust(width)
|
||||
trimmed_row_cells.append(trimmed_cell)
|
||||
lines.append(' '.join(trimmed_row_cells))
|
||||
print '\n'.join(lines)
|
||||
|
||||
|
||||
commands_for_help = ['Constraints',
|
||||
con,
|
||||
uncon,
|
||||
'Hkl',
|
||||
allhkl
|
||||
]
|
||||
27
script/__Lib/diffcalc-2.1/diffcalc/log.py
Executable file
27
script/__Lib/diffcalc-2.1/diffcalc/log.py
Executable file
@@ -0,0 +1,27 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
import getpass
|
||||
|
||||
logging.basicConfig(format="%(asctime)s %(levelname)s:%(name)s:%(message)s",
|
||||
datefmt='%m/%d/%Y %I:%M:%S',
|
||||
filename='/tmp/diffcalc_%s.log' % getpass.getuser(),
|
||||
level=logging.DEBUG)
|
||||
24
script/__Lib/diffcalc-2.1/diffcalc/settings.py
Executable file
24
script/__Lib/diffcalc-2.1/diffcalc/settings.py
Executable file
@@ -0,0 +1,24 @@
|
||||
'''
|
||||
Created on Aug 5, 2013
|
||||
|
||||
@author: walton
|
||||
'''
|
||||
import os
|
||||
|
||||
from diffcalc.ub.persistence import UbCalculationNonPersister
|
||||
|
||||
# These should be by the user *before* importing other modules
|
||||
geometry = None
|
||||
hardware = None
|
||||
ubcalc_persister = UbCalculationNonPersister()
|
||||
|
||||
axes_scannable_group = None
|
||||
energy_scannable = None
|
||||
energy_scannable_multiplier_to_get_KeV=1
|
||||
|
||||
|
||||
# These will be set by dcyou, dcvlieg or dcwillmot
|
||||
ubcalc_strategy = None
|
||||
angles_to_hkl_function = None # Used by checkub to avoid coupling it to an hkl module
|
||||
include_sigtau=False
|
||||
include_reference=False
|
||||
0
script/__Lib/diffcalc-2.1/diffcalc/ub/__init__.py
Executable file
0
script/__Lib/diffcalc-2.1/diffcalc/ub/__init__.py
Executable file
854
script/__Lib/diffcalc-2.1/diffcalc/ub/calc.py
Executable file
854
script/__Lib/diffcalc-2.1/diffcalc/ub/calc.py
Executable file
@@ -0,0 +1,854 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.ub.calcstate import decode_ubcalcstate
|
||||
from diffcalc.ub.calcstate import UBCalcState
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.ub.reflections import ReflectionList
|
||||
from diffcalc.ub.persistence import UBCalculationJSONPersister, UBCalculationPersister
|
||||
from diffcalc.util import DiffcalcException, cross3, dot3, bold, xyz_rotation,\
|
||||
bound
|
||||
from math import acos, cos, sin, pi
|
||||
from diffcalc.ub.reference import YouReference
|
||||
from diffcalc.ub.orientations import OrientationList
|
||||
|
||||
try:
|
||||
from numpy import matrix, hstack
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix, hstack
|
||||
from numjy.linalg import norm
|
||||
|
||||
SMALL = 1e-7
|
||||
TODEG = 180 / pi
|
||||
|
||||
WIDTH = 13
|
||||
|
||||
def z(num):
|
||||
"""Round to zero if small. This is useful to get rid of erroneous
|
||||
minus signs resulting from float representation close to zero.
|
||||
"""
|
||||
if abs(num) < SMALL:
|
||||
num = 0
|
||||
return num
|
||||
|
||||
#The UB matrix is used to find or set the orientation of a set of
|
||||
#planes described by an hkl vector. The U matrix can be used to find
|
||||
#or set the orientation of the crystal lattices' y axis. If there is
|
||||
#crystal miscut the crystal lattices y axis is not parallel to the
|
||||
#crystals optical surface normal. For surface diffraction experiments,
|
||||
#where not only the crystal lattice must be oriented appropriately but
|
||||
#so must the crystal's optical surface, two angles tau and sigma are
|
||||
#used to describe the difference between the two. Sigma is (minus) the
|
||||
#ammount of chi axis rotation and tau (minus) the ammount of phi axis
|
||||
#rotation needed to move the surface normal into the direction of the
|
||||
|
||||
|
||||
class PaperSpecificUbCalcStrategy(object):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
"""Calculate hkl in the phi frame in units of 2 * pi / lambda from
|
||||
pos object in radians"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class UBCalculation:
|
||||
"""A UB matrix calculation for an experiment.
|
||||
|
||||
Contains the parameters for the _crystal under test, a list of measured
|
||||
reflections and, if its been calculated, a UB matrix to be used by the rest
|
||||
of the code.
|
||||
"""
|
||||
|
||||
def __init__(self, hardware, diffractometerPluginObject,
|
||||
persister, strategy, include_sigtau=True, include_reference=True):
|
||||
|
||||
# The diffractometer geometry is required to map the internal angles
|
||||
# into those used by this diffractometer (for display only)
|
||||
|
||||
self._hardware = hardware
|
||||
self._geometry = diffractometerPluginObject
|
||||
self._persister = persister
|
||||
self._strategy = strategy
|
||||
self.include_sigtau = include_sigtau
|
||||
self.include_reference = include_reference
|
||||
try:
|
||||
self._ROT = diffractometerPluginObject.beamline_axes_transform
|
||||
except AttributeError:
|
||||
self._ROT = None
|
||||
self._clear()
|
||||
|
||||
def _get_diffractometer_axes_names(self):
|
||||
return self._hardware.get_axes_names()
|
||||
|
||||
def _clear(self, name=None):
|
||||
# NOTE the Diffraction calculator is expecting this object to exist in
|
||||
# the long run. We can't remove this entire object, and recreate it.
|
||||
# It also contains a required link to the angle calculator.
|
||||
reflist = ReflectionList(self._geometry, self._get_diffractometer_axes_names())
|
||||
orientlist = OrientationList()
|
||||
reference = YouReference(self._get_UB)
|
||||
self._state = UBCalcState(name=name, reflist=reflist, orientlist=orientlist, reference=reference)
|
||||
self._U = None
|
||||
self._UB = None
|
||||
self._state.configure_calc_type()
|
||||
|
||||
### State ###
|
||||
def start_new(self, name):
|
||||
"""start_new(name) --- creates a new blank ub calculation"""
|
||||
# Create storage object if name does not exist (TODO)
|
||||
if name in self._persister.list():
|
||||
print ("No UBCalculation started: There is already a calculation "
|
||||
"called: " + name)
|
||||
print "Saved calculations: " + repr(self._persister.list())
|
||||
return
|
||||
self._clear(name)
|
||||
self.save()
|
||||
|
||||
def load(self, name):
|
||||
state = self._persister.load(name)
|
||||
if isinstance(self._persister, UBCalculationJSONPersister):
|
||||
self._state = decode_ubcalcstate(state, self._geometry, self._get_diffractometer_axes_names())
|
||||
self._state.reference.get_UB = self._get_UB
|
||||
elif isinstance(self._persister, UBCalculationPersister):
|
||||
self._state = state
|
||||
else:
|
||||
raise Exception('Unexpected persister type: ' + str(self._persister))
|
||||
if self._state.manual_U is not None:
|
||||
self._U = self._state.manual_U
|
||||
self._UB = self._U * self._state.crystal.B
|
||||
self.save()
|
||||
elif self._state.manual_UB is not None:
|
||||
self._UB = self._state.manual_UB
|
||||
self.save()
|
||||
elif self._state.or0 is not None:
|
||||
if self._state.or1 is None:
|
||||
self.calculate_UB_from_primary_only()
|
||||
else:
|
||||
if self._state.reflist:
|
||||
self.calculate_UB()
|
||||
elif self._state.orientlist:
|
||||
self.calculate_UB_from_orientation()
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
self.saveas(self._state.name)
|
||||
|
||||
def saveas(self, name):
|
||||
self._state.name = name
|
||||
self._persister.save(self._state, name)
|
||||
|
||||
def listub(self):
|
||||
return self._persister.list()
|
||||
|
||||
def listub_metadata(self):
|
||||
return self._persister.list_metadata()
|
||||
|
||||
def remove(self, name):
|
||||
self._persister.remove(name)
|
||||
if self._state == name:
|
||||
self._clear(name)
|
||||
|
||||
def getState(self):
|
||||
return self._state.getState()
|
||||
|
||||
def __str__(self):
|
||||
|
||||
if self._state.name is None:
|
||||
return "<<< No UB calculation started >>>"
|
||||
lines = []
|
||||
lines.append(bold("UBCALC"))
|
||||
lines.append("")
|
||||
lines.append(
|
||||
" name:".ljust(WIDTH) + self._state.name.rjust(9))
|
||||
|
||||
if self.include_sigtau:
|
||||
lines.append("")
|
||||
lines.append(
|
||||
" sigma:".ljust(WIDTH) + ("% 9.5f" % self._state.sigma).rjust(9))
|
||||
lines.append(
|
||||
" tau:".ljust(WIDTH) + ("% 9.5f" % self._state.tau).rjust(9))
|
||||
|
||||
if self.include_reference:
|
||||
lines.append("")
|
||||
ub_calculated = self._UB is not None
|
||||
lines.extend(self._state.reference.repr_lines(ub_calculated, WIDTH, self._ROT))
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("CRYSTAL"))
|
||||
lines.append("")
|
||||
|
||||
if self._state.crystal is None:
|
||||
lines.append(" <<< none specified >>>")
|
||||
else:
|
||||
lines.extend(self._state.crystal.str_lines())
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("UB MATRIX"))
|
||||
lines.append("")
|
||||
|
||||
if self._UB is None:
|
||||
lines.append(" <<< none calculated >>>")
|
||||
else:
|
||||
lines.extend(self.str_lines_u())
|
||||
lines.append("")
|
||||
lines.extend(self.str_lines_u_angle_and_axis())
|
||||
lines.append("")
|
||||
lines.extend(self.str_lines_ub())
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("REFLECTIONS"))
|
||||
lines.append("")
|
||||
|
||||
lines.extend(self._state.reflist.str_lines())
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("CRYSTAL ORIENTATIONS"))
|
||||
lines.append("")
|
||||
|
||||
lines.extend(self._state.orientlist.str_lines(R=self._ROT))
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def str_lines_u(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
try:
|
||||
U = self._ROT.I * self.U * self._ROT
|
||||
except AttributeError:
|
||||
U = self.U
|
||||
lines.append(" U matrix:".ljust(WIDTH) +
|
||||
fmt % (z(U[0, 0]), z(U[0, 1]), z(U[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(U[1, 0]), z(U[1, 1]), z(U[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(U[2, 0]), z(U[2, 1]), z(U[2, 2])))
|
||||
return lines
|
||||
|
||||
def str_lines_u_angle_and_axis(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
y = matrix('0; 0; 1')
|
||||
try:
|
||||
rotation_axis = cross3(self._ROT * y, self._ROT * self.U * y)
|
||||
except TypeError:
|
||||
rotation_axis = cross3(y, self.U * y)
|
||||
if abs(norm(rotation_axis)) < SMALL:
|
||||
lines.append(" miscut angle:".ljust(WIDTH) + " 0")
|
||||
else:
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
cos_rotation_angle = dot3(y, self.U * y)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
|
||||
lines.append(" miscut:")
|
||||
lines.append(" angle:".ljust(WIDTH) + "% 9.5f" % (rotation_angle * TODEG))
|
||||
lines.append(" axis:".ljust(WIDTH) + fmt % tuple((rotation_axis.T).tolist()[0]))
|
||||
|
||||
return lines
|
||||
|
||||
def str_lines_ub(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
try:
|
||||
RI = self._ROT.I
|
||||
B = self._state.crystal.B
|
||||
UB = RI * self.UB * B.I * self._ROT * B
|
||||
except AttributeError:
|
||||
UB = self.UB
|
||||
lines.append(" UB matrix:".ljust(WIDTH) +
|
||||
fmt % (z(UB[0, 0]), z(UB[0, 1]), z(UB[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(UB[1, 0]), z(UB[1, 1]), z(UB[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(UB[2, 0]), z(UB[2, 1]), z(UB[2, 2])))
|
||||
return lines
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._state.name
|
||||
### Lattice ###
|
||||
|
||||
def set_lattice(self, name, *shortform):
|
||||
"""
|
||||
Converts a list shortform crystal parameter specification to a six-long
|
||||
tuple returned as . Returns None if wrong number of input args. See
|
||||
set_lattice() for a description of the shortforms supported.
|
||||
|
||||
shortformLattice -- a tuple as follows:
|
||||
[a] - assumes cubic
|
||||
[a,b]) - assumes tetragonal
|
||||
[a,b,c]) - assumes ortho
|
||||
[a,b,c,gam]) - assumes mon/hex gam different from 90.
|
||||
[a,b,c,alp,bet,gam]) - for arbitrary
|
||||
where all measurements in angstroms and angles in degrees
|
||||
"""
|
||||
self._set_lattice_without_saving(name, *shortform)
|
||||
self.save()
|
||||
|
||||
def _set_lattice_without_saving(self, name, *shortform):
|
||||
sf = shortform
|
||||
if len(sf) == 1:
|
||||
fullform = (sf[0], sf[0], sf[0], 90., 90., 90.) # cubic
|
||||
elif len(sf) == 2:
|
||||
fullform = (sf[0], sf[0], sf[1], 90., 90., 90.) # tetragonal
|
||||
elif len(sf) == 3:
|
||||
fullform = (sf[0], sf[1], sf[2], 90., 90., 90.) # ortho
|
||||
elif len(sf) == 4:
|
||||
fullform = (sf[0], sf[1], sf[2], 90., 90., sf[3]) # mon/hex gam
|
||||
# not 90
|
||||
elif len(sf) == 5:
|
||||
raise ValueError("wrong length input to set_lattice")
|
||||
elif len(sf) == 6:
|
||||
fullform = sf # triclinic/arbitrary
|
||||
else:
|
||||
raise ValueError("wrong length input to set_lattice")
|
||||
self._set_lattice(name, *fullform)
|
||||
|
||||
def _set_lattice(self, name, a, b, c, alpha, beta, gamma):
|
||||
"""set lattice parameters in degrees"""
|
||||
if self._state.name is None:
|
||||
raise DiffcalcException(
|
||||
"Cannot set lattice until a UBCalcaluation has been started "
|
||||
"with newubcalc")
|
||||
self._state.crystal = CrystalUnderTest(name, a, b, c, alpha, beta, gamma)
|
||||
# Clear U and UB if these exist
|
||||
if self._U is not None: # (UB will also exist)
|
||||
print "Warning: the old UB calculation has been cleared."
|
||||
print " Use 'calcub' to recalculate with old reflections or"
|
||||
print " 'orientub' to recalculate with old orientations."
|
||||
|
||||
### Surface normal stuff ###
|
||||
|
||||
def _gettau(self):
|
||||
"""
|
||||
Returns tau (in degrees): the (minus) ammount of phi axis rotation ,
|
||||
that together with some chi axis rotation (minus sigma) brings the
|
||||
optical surface normal parallel to the omega axis.
|
||||
"""
|
||||
return self._state.tau
|
||||
|
||||
def _settau(self, tau):
|
||||
self._state.tau = tau
|
||||
self.save()
|
||||
|
||||
tau = property(_gettau, _settau)
|
||||
|
||||
def _getsigma(self):
|
||||
"""
|
||||
Returns sigma (in degrees): the (minus) ammount of phi axis rotation ,
|
||||
that together with some phi axis rotation (minus tau) brings the
|
||||
optical surface normal parallel to the omega axis.
|
||||
"""
|
||||
return self._state.sigma
|
||||
|
||||
def _setsigma(self, sigma):
|
||||
self.state._sigma = sigma
|
||||
self.save()
|
||||
|
||||
sigma = property(_getsigma, _setsigma)
|
||||
|
||||
|
||||
### Reference vector ###
|
||||
|
||||
def _get_n_phi(self):
|
||||
return self._state.reference.n_phi
|
||||
|
||||
n_phi = property(_get_n_phi)
|
||||
|
||||
def set_n_phi_configured(self, n_phi):
|
||||
try:
|
||||
self._state.reference.n_phi_configured = self._ROT.I * n_phi
|
||||
except AttributeError:
|
||||
self._state.reference.n_phi_configured = n_phi
|
||||
self.save()
|
||||
|
||||
def set_n_hkl_configured(self, n_hkl):
|
||||
self._state.reference.n_hkl_configured = n_hkl
|
||||
self.save()
|
||||
|
||||
def print_reference(self):
|
||||
print '\n'.join(self._state.reference.repr_lines(self.is_ub_calculated(), R=self._ROT))
|
||||
|
||||
### Reflections ###
|
||||
|
||||
def add_reflection(self, h, k, l, position, energy, tag, time):
|
||||
"""add_reflection(h, k, l, position, tag=None) -- adds a reflection
|
||||
|
||||
position is in degrees and in the systems internal representation.
|
||||
"""
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
self._state.reflist.add_reflection(h, k, l, position, energy, tag, time)
|
||||
self.save() # incase autocalculateUbAndReport fails
|
||||
|
||||
# If second reflection has just been added then calculateUB
|
||||
if len(self._state.reflist) == 2:
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def edit_reflection(self, num, h, k, l, position, energy, tag, time):
|
||||
"""
|
||||
edit_reflection(num, h, k, l, position, tag=None) -- adds a reflection
|
||||
|
||||
position is in degrees and in the systems internal representation.
|
||||
"""
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
self._state.reflist.edit_reflection(num, h, k, l, position, energy, tag, time)
|
||||
|
||||
# If first or second reflection has been changed and there are at least
|
||||
# two reflections then recalculate UB
|
||||
if (num == 1 or num == 2) and len(self._state.reflist) >= 2:
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def get_reflection(self, num):
|
||||
"""--> ( [h, k, l], position, energy, tag, time
|
||||
num starts at 1, position in degrees"""
|
||||
return self._state.reflist.getReflection(num)
|
||||
|
||||
def get_reflection_in_external_angles(self, num):
|
||||
"""--> ( [h, k, l], position, energy, tag, time
|
||||
num starts at 1, position in degrees"""
|
||||
return self._state.reflist.get_reflection_in_external_angles(num)
|
||||
|
||||
def get_number_reflections(self):
|
||||
return 0 if self._state.reflist is None else len(self._state.reflist)
|
||||
|
||||
def del_reflection(self, reflectionNumber):
|
||||
self._state.reflist.removeReflection(reflectionNumber)
|
||||
if ((reflectionNumber == 1 or reflectionNumber == 2) and
|
||||
(self._U is not None)):
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def swap_reflections(self, num1, num2):
|
||||
self._state.reflist.swap_reflections(num1, num2)
|
||||
if ((num1 == 1 or num1 == 2 or num2 == 1 or num2 == 2) and
|
||||
(self._U is not None)):
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def _autocalculateUbAndReport(self):
|
||||
if len(self._state.reflist) < 2:
|
||||
pass
|
||||
elif self._state.crystal is None:
|
||||
print ("Not calculating UB matrix as no lattice parameters have "
|
||||
"been specified.")
|
||||
elif not self._state.is_okay_to_autocalculate_ub:
|
||||
print ("Not calculating UB matrix as it has been manually set. "
|
||||
"Use 'calcub' to explicitly recalculate it.")
|
||||
else: # okay to autocalculate
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix."
|
||||
else:
|
||||
print "Recalculating UB matrix."
|
||||
self.calculate_UB()
|
||||
|
||||
### Orientations ###
|
||||
|
||||
def add_orientation(self, h, k, l, x, y, z, tag, time):
|
||||
"""add_reflection(h, k, l, x, y, z, tag=None) -- adds a crystal orientation
|
||||
"""
|
||||
if self._state.orientlist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
try:
|
||||
xyz_rot = self._ROT * matrix([[x],[y],[z]])
|
||||
xr, yr, zr = xyz_rot.T.tolist()[0]
|
||||
self._state.orientlist.add_orientation(h, k, l, xr, yr, zr, tag, time)
|
||||
except TypeError:
|
||||
self._state.orientlist.add_orientation(h, k, l, x, y, z, tag, time)
|
||||
self.save() # incase autocalculateUbAndReport fails
|
||||
|
||||
# If second reflection has just been added then calculateUB
|
||||
if len(self._state.orientlist) == 2:
|
||||
self._autocalculateOrientationUbAndReport()
|
||||
self.save()
|
||||
|
||||
def edit_orientation(self, num, h, k, l, x, y, z, tag, time):
|
||||
"""
|
||||
edit_orientation(num, h, k, l, x, y, z, tag=None) -- edit a crystal reflection """
|
||||
if self._state.orientlist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
try:
|
||||
xyz_rot = self._ROT * matrix([[x],[y],[z]])
|
||||
xr, yr, zr = xyz_rot.T.tolist()[0]
|
||||
self._state.orientlist.edit_orientation(num, h, k, l, xr, yr, zr, tag, time)
|
||||
except TypeError:
|
||||
self._state.orientlist.edit_orientation(num, h, k, l, x, y, z, tag, time)
|
||||
|
||||
# If first or second orientation has been changed and there are
|
||||
# two orientations then recalculate UB
|
||||
if (num == 1 or num == 2) and len(self._state.orientlist) == 2:
|
||||
self._autocalculateOrientationUbAndReport()
|
||||
self.save()
|
||||
|
||||
def get_orientation(self, num):
|
||||
"""--> ( [h, k, l], [x, y, z], tag, time )
|
||||
num starts at 1"""
|
||||
try:
|
||||
hkl, xyz, tg, tm = self._state.orientlist.getOrientation(num)
|
||||
xyz_rot = self._ROT.I * matrix([[xyz[0]],[xyz[1]],[xyz[2]]])
|
||||
xyz_lst = xyz_rot.T.tolist()[0]
|
||||
return hkl, xyz_lst, tg, tm
|
||||
except AttributeError:
|
||||
return self._state.orientlist.getOrientation(num)
|
||||
|
||||
|
||||
def get_number_orientations(self):
|
||||
return 0 if self._state.orientlist is None else len(self._state.reflist)
|
||||
|
||||
def del_orientation(self, orientationNumber):
|
||||
self._state.orientlist.removeOrientation(orientationNumber)
|
||||
if ((orientationNumber == 2) and (self._U is not None)):
|
||||
self._autocalculateOrientationUbAndReport()
|
||||
self.save()
|
||||
|
||||
def swap_orientations(self, num1, num2):
|
||||
self._state.orientlist.swap_orientations(num1, num2)
|
||||
if ((num1 == 2 or num2 == 2) and
|
||||
(self._U is not None)):
|
||||
self._autocalculateOrientationUbAndReport()
|
||||
self.save()
|
||||
|
||||
def _autocalculateOrientationUbAndReport(self):
|
||||
if len(self._state.orientlist) < 2:
|
||||
pass
|
||||
elif self._state.crystal is None:
|
||||
print ("Not calculating UB matrix as no lattice parameters have "
|
||||
"been specified.")
|
||||
elif not self._state.is_okay_to_autocalculate_ub:
|
||||
print ("Not calculating UB matrix as it has been manually set. "
|
||||
"Use 'orientub' to explicitly recalculate it.")
|
||||
else: # okay to autocalculate
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix."
|
||||
else:
|
||||
print "Recalculating UB matrix."
|
||||
self.calculate_UB_from_orientation()
|
||||
|
||||
# @property
|
||||
# def reflist(self):
|
||||
# return self._state.reflist
|
||||
### Calculations ###
|
||||
|
||||
def set_U_manually(self, m):
|
||||
"""Manually sets U. matrix must be 3*3 Jama or python matrix.
|
||||
Turns off aution UB calcualtion."""
|
||||
|
||||
# Check matrix is a 3*3 Jama matrix
|
||||
if m.__class__ != matrix:
|
||||
m = matrix(m) # assume its a python matrix
|
||||
if m.shape[0] != 3 or m.shape[1] != 3:
|
||||
raise ValueError("Expects 3*3 matrix")
|
||||
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix."
|
||||
else:
|
||||
print "Recalculating UB matrix."
|
||||
|
||||
if self._ROT is not None:
|
||||
self._U = self._ROT * m * self._ROT.I
|
||||
else:
|
||||
self._U = m
|
||||
self._state.configure_calc_type(manual_U=self._U)
|
||||
if self._state.crystal is None:
|
||||
raise DiffcalcException(
|
||||
"A crystal must be specified before manually setting U")
|
||||
self._UB = self._U * self._state.crystal.B
|
||||
print ("NOTE: A new UB matrix will not be automatically calculated "
|
||||
"when the orientation reflections are modified.")
|
||||
self.save()
|
||||
|
||||
def set_UB_manually(self, m):
|
||||
"""Manually sets UB. matrix must be 3*3 Jama or python matrix.
|
||||
Turns off aution UB calcualtion."""
|
||||
|
||||
# Check matrix is a 3*3 Jama matrix
|
||||
if m.__class__ != matrix:
|
||||
m = matrix(m) # assume its a python matrix
|
||||
if m.shape[0] != 3 or m.shape[1] != 3:
|
||||
raise ValueError("Expects 3*3 matrix")
|
||||
|
||||
if self._ROT is not None:
|
||||
self._UB = self._ROT * m
|
||||
else:
|
||||
self._UB = m
|
||||
self._state.configure_calc_type(manual_UB=self._UB)
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def U(self):
|
||||
if self._U is None:
|
||||
raise DiffcalcException(
|
||||
"No U matrix has been calculated during this ub calculation")
|
||||
return self._U
|
||||
|
||||
@property
|
||||
def UB(self):
|
||||
return self._get_UB()
|
||||
|
||||
def is_ub_calculated(self):
|
||||
return self._UB is not None
|
||||
|
||||
def _get_UB(self):
|
||||
if not self.is_ub_calculated():
|
||||
raise DiffcalcException(
|
||||
"No UB matrix has been calculated during this ub calculation")
|
||||
else:
|
||||
return self._UB
|
||||
|
||||
def _calc_UB(self, h1, h2, u1p, u2p):
|
||||
B = self._state.crystal.B
|
||||
h1c = B * h1
|
||||
h2c = B * h2
|
||||
|
||||
# Create modified unit vectors t1, t2 and t3 in crystal and phi systems
|
||||
t1c = h1c
|
||||
t3c = cross3(h1c, h2c)
|
||||
t2c = cross3(t3c, t1c)
|
||||
|
||||
t1p = u1p # FIXED from h1c 9July08
|
||||
t3p = cross3(u1p, u2p)
|
||||
t2p = cross3(t3p, t1p)
|
||||
|
||||
# ...and nornmalise and check that the reflections used are appropriate
|
||||
SMALL = 1e-4 # Taken from Vlieg's code
|
||||
e = DiffcalcException("Invalid orientation reflection(s)")
|
||||
|
||||
def normalise(m):
|
||||
d = norm(m)
|
||||
if d < SMALL:
|
||||
raise e
|
||||
return m / d
|
||||
|
||||
t1c = normalise(t1c)
|
||||
t2c = normalise(t2c)
|
||||
t3c = normalise(t3c)
|
||||
|
||||
t1p = normalise(t1p)
|
||||
t2p = normalise(t2p)
|
||||
t3p = normalise(t3p)
|
||||
|
||||
Tc = hstack([t1c, t2c, t3c])
|
||||
Tp = hstack([t1p, t2p, t3p])
|
||||
self._state.configure_calc_type(or0=1, or1=2)
|
||||
self._U = Tp * Tc.I
|
||||
self._UB = self._U * B
|
||||
self.save()
|
||||
|
||||
def calculate_UB(self):
|
||||
"""
|
||||
Calculate orientation matrix. Uses first two orientation reflections
|
||||
as in Busang and Levy, but for the diffractometer in Lohmeier and
|
||||
Vlieg.
|
||||
"""
|
||||
|
||||
# Major variables:
|
||||
# h1, h2: user input reciprical lattice vectors of the two reflections
|
||||
# h1c, h2c: user input vectors in cartesian crystal plane
|
||||
# pos1, pos2: measured diffractometer positions of the two reflections
|
||||
# u1a, u2a: measured reflection vectors in alpha frame
|
||||
# u1p, u2p: measured reflection vectors in phi frame
|
||||
|
||||
|
||||
# Get hkl and angle values for the first two refelctions
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("Cannot calculate a U matrix until a "
|
||||
"UBCalculation has been started with "
|
||||
"'newub'")
|
||||
try:
|
||||
(h1, pos1, _, _, _) = self._state.reflist.getReflection(1)
|
||||
(h2, pos2, _, _, _) = self._state.reflist.getReflection(2)
|
||||
except IndexError:
|
||||
raise DiffcalcException(
|
||||
"Two reflections are required to calculate a U matrix")
|
||||
h1 = matrix([h1]).T # row->column
|
||||
h2 = matrix([h2]).T
|
||||
pos1.changeToRadians()
|
||||
pos2.changeToRadians()
|
||||
|
||||
# Compute the two reflections' reciprical lattice vectors in the
|
||||
# cartesian crystal frame
|
||||
u1p = self._strategy.calculate_q_phi(pos1)
|
||||
u2p = self._strategy.calculate_q_phi(pos2)
|
||||
|
||||
self._calc_UB(h1, h2, u1p, u2p)
|
||||
|
||||
def calculate_UB_from_orientation(self):
|
||||
"""
|
||||
Calculate orientation matrix. Uses first two crystal orientations.
|
||||
"""
|
||||
|
||||
# Major variables:
|
||||
# h1, h2: user input reciprical lattice vectors of the two reflections
|
||||
# h1c, h2c: user input vectors in cartesian crystal plane
|
||||
# pos1, pos2: measured diffractometer positions of the two reflections
|
||||
# u1a, u2a: measured reflection vectors in alpha frame
|
||||
# u1p, u2p: measured reflection vectors in phi frame
|
||||
|
||||
|
||||
# Get hkl and angle values for the first two crystal orientations
|
||||
if self._state.orientlist is None:
|
||||
raise DiffcalcException("Cannot calculate a U matrix until a "
|
||||
"UBCalculation has been started with "
|
||||
"'newub'")
|
||||
try:
|
||||
(h1, x1, _, _) = self._state.orientlist.getOrientation(1)
|
||||
(h2, x2, _, _) = self._state.orientlist.getOrientation(2)
|
||||
except IndexError:
|
||||
raise DiffcalcException(
|
||||
"Two crystal orientations are required to calculate a U matrix")
|
||||
h1 = matrix([h1]).T # row->column
|
||||
h2 = matrix([h2]).T
|
||||
u1p = matrix([x1]).T
|
||||
u2p = matrix([x2]).T
|
||||
|
||||
self._calc_UB(h1, h2, u1p, u2p)
|
||||
|
||||
def calculate_UB_from_primary_only(self):
|
||||
"""
|
||||
Calculate orientation matrix with the shortest absolute angle change.
|
||||
Uses first orientation reflection
|
||||
"""
|
||||
|
||||
# Algorithm from http://www.j3d.org/matrix_faq/matrfaq_latest.html
|
||||
|
||||
# Get hkl and angle values for the first two refelctions
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException(
|
||||
"Cannot calculate a u matrix until a UBCalcaluation has been "
|
||||
"started with newub")
|
||||
try:
|
||||
(h, pos, _, _, _) = self._state.reflist.getReflection(1)
|
||||
except IndexError:
|
||||
raise DiffcalcException(
|
||||
"One reflection is required to calculate a u matrix")
|
||||
|
||||
h = matrix([h]).T # row->column
|
||||
pos.changeToRadians()
|
||||
B = self._state.crystal.B
|
||||
h_crystal = B * h
|
||||
h_crystal = h_crystal * (1 / norm(h_crystal))
|
||||
|
||||
q_measured_phi = self._strategy.calculate_q_phi(pos)
|
||||
q_measured_phi = q_measured_phi * (1 / norm(q_measured_phi))
|
||||
|
||||
rotation_axis = cross3(h_crystal, q_measured_phi)
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
|
||||
cos_rotation_angle = dot3(h_crystal, q_measured_phi)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
|
||||
uvw = rotation_axis.T.tolist()[0] # TODO: cleanup
|
||||
print "resulting U angle: %.5f deg" % (rotation_angle * TODEG)
|
||||
u_repr = (', '.join(['% .5f' % el for el in uvw]))
|
||||
print "resulting U axis direction: [%s]" % u_repr
|
||||
|
||||
u, v, w = uvw
|
||||
rcos = cos(rotation_angle)
|
||||
rsin = sin(rotation_angle)
|
||||
m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] # TODO: tidy
|
||||
m[0][0] = rcos + u * u * (1 - rcos)
|
||||
m[1][0] = w * rsin + v * u * (1 - rcos)
|
||||
m[2][0] = -v * rsin + w * u * (1 - rcos)
|
||||
m[0][1] = -w * rsin + u * v * (1 - rcos)
|
||||
m[1][1] = rcos + v * v * (1 - rcos)
|
||||
m[2][1] = u * rsin + w * v * (1 - rcos)
|
||||
m[0][2] = v * rsin + u * w * (1 - rcos)
|
||||
m[1][2] = -u * rsin + v * w * (1 - rcos)
|
||||
m[2][2] = rcos + w * w * (1 - rcos)
|
||||
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix from the first reflection only."
|
||||
else:
|
||||
print "Recalculating UB matrix from the first reflection only."
|
||||
print ("NOTE: A new UB matrix will not be automatically calculated "
|
||||
"when the orientation reflections are modified.")
|
||||
|
||||
self._state.configure_calc_type(or0=1)
|
||||
|
||||
self._U = matrix(m)
|
||||
self._UB = self._U * B
|
||||
|
||||
self.save()
|
||||
|
||||
def set_miscut(self, xyz, angle, add_miscut=False):
|
||||
"""Calculate U matrix using a miscut axis and an angle"""
|
||||
if xyz is None:
|
||||
rot_matrix = xyz_rotation([0, 1, 0], angle)
|
||||
if self.is_ub_calculated() and add_miscut:
|
||||
self._U = rot_matrix * self._U
|
||||
else:
|
||||
self._U = rot_matrix
|
||||
else:
|
||||
rot_matrix = xyz_rotation(xyz, angle)
|
||||
try:
|
||||
rot_matrix = self._ROT * rot_matrix * self._ROT.I
|
||||
except TypeError:
|
||||
pass
|
||||
if self.is_ub_calculated() and add_miscut:
|
||||
self._U = rot_matrix * self._U
|
||||
else:
|
||||
self._U = rot_matrix
|
||||
self._state.configure_calc_type(manual_U=self._U)
|
||||
self._UB = self._U * self._state.crystal.B
|
||||
self.print_reference()
|
||||
self.save()
|
||||
|
||||
def get_hkl_plane_distance(self, hkl):
|
||||
"""Calculates and returns the distance between planes"""
|
||||
return self._state.crystal.get_hkl_plane_distance(hkl)
|
||||
|
||||
def get_hkl_plane_angle(self, hkl1, hkl2):
|
||||
"""Calculates and returns the angle between planes"""
|
||||
return self._state.crystal.get_hkl_plane_angle(hkl1, hkl2)
|
||||
|
||||
def rescale_unit_cell(self, h, k, l, pos):
|
||||
"""
|
||||
Calculate unit cell scaling parameter that matches
|
||||
given hkl position and diffractometer angles
|
||||
"""
|
||||
q_vec = self._strategy.calculate_q_phi(pos)
|
||||
q_hkl = norm(q_vec) / self._hardware.get_wavelength()
|
||||
d_hkl = self._state.crystal.get_hkl_plane_distance([h, k, l])
|
||||
sc = 1/ (q_hkl * d_hkl)
|
||||
name, a1, a2, a3, alpha1, alpha2, alpha3 = self._state.crystal.getLattice()
|
||||
if abs(sc - 1.) < SMALL:
|
||||
return None, None
|
||||
return sc, (name, sc * a1, sc* a2, sc * a3, alpha1, alpha2, alpha3)
|
||||
|
||||
def calc_miscut(self, h, k, l, pos):
|
||||
"""
|
||||
Calculate miscut angle and axis that matches
|
||||
given hkl position and diffractometer angles
|
||||
"""
|
||||
q_vec = self._strategy.calculate_q_phi(pos)
|
||||
hkl_nphi = self._UB * matrix([[h], [k], [l]])
|
||||
try:
|
||||
axis = cross3(self._ROT.I * q_vec, self._ROT.I * hkl_nphi)
|
||||
except AttributeError:
|
||||
axis = cross3(q_vec, hkl_nphi)
|
||||
norm_axis = norm(axis)
|
||||
if norm_axis < SMALL:
|
||||
return None, None
|
||||
axis = axis / norm(axis)
|
||||
try:
|
||||
miscut = acos(bound(dot3(q_vec, hkl_nphi) / (norm(q_vec) * norm(hkl_nphi)))) * TODEG
|
||||
except AssertionError:
|
||||
return None, None
|
||||
return miscut, axis.T.tolist()[0]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user