source: specdomain/trunk/src/specdomain/comparison/auto.mac @ 1019

Last change on this file since 1019 was 1019, checked in by jemian, 10 years ago

refs #11, fold back in additional changes from author

File size: 49.7 KB
Line 
1"""
2Summary
3=======
4This macro provides a set of definitions which allow for automatic filter
5transmission and exposure time adjustments during experiments.
6
7Description
8===========
9After each count command, the obtained counts are evaluated and checked for
10over-/under-exposure. In case of unsatisfactory count levels, filter
11transmissions and optionally exposure times are adjusted and exposures are
12repeated until a valid exposure is obtained.
13
14Exposure optimization modes
15---------------------------
16Two different modes of operation are available to optimize the count levels
17for each exposure:
18
19- Post-exposure adjustments: Each new exposures is taken with settings that
20  are based on the feedback obtained from the previous one. This mode is
21  based on the assumption that the measured intensity profiles are only
22  gradually changing, and that a satisfactory prediction of the change in
23  the count levels can be obtained in most cases to yield a good exposure.
24  In those cases where the predictions fail and the new exposure falls
25  outside the acceptable limits, the settings are adjusted and the exposure
26  is retaken immediately.
27- Pilot exposure: Each exposure is preceeded by a short pilot exposure,
28  which is used to establish the count levels at the current positions.
29
30Both modes have their relative merits and drawbacks. Post-exposure
31adjustments are riskier in terms of overexposing a detector, since the
32feedback is obtained only after potentially very long exposures. On the
33other hand, they are more efficient in terms of dead-time, especially when
34scanning signals that change only gradually. In this case, it is very
35seldomly necessary to repeat exposures. The pilot exposure mode, in
36contrast, is safer, since it detects potentially harmfully strong signals
37much faster. This comes at the cost of significantly increased dead-times,
38particularly for detectors with longer arming or readout times.
39
40Exposure optimization scheme
41----------------------------
42The filter and exposure time adjustments principles are based on the
43following criteria to formulate an adjustment strategy.  Firstly, it is
44important to note that there are two separate effects which may cause an
45over-exposure of the detector:
46
47#. Paralizing the counter as a result of a count RATE which exceeds the
48   ability of the detector to separate individual photons in time (only for
49   single-photon-counting devices, does not apply to charge-integrating).
50#. Saturating the counter as a result of exceeding the maximum NUMBER OF
51   COUNTS that can be stored in the counter.
52
53The incident photon RATE (case 1) can only be adjusted through the use of
54filters (attenuators), while the integrated NUMBER OF COUNTS is affected
55both by the filter transmission and the integration duration (count time).
56In this implementation, ensuring a valid photon RATE always takes
57precedence over any other adjustment. Once the rate has been optimized
58(keeping it within a given band below the saturation threshold), the
59exposure times may be adjusted. See the next sections below for details.
60
61Filter tramsmission adjustments (RATE)
62----------------------------------------
63The filter adjustment assures a high incident photon rate within a band
64just below the rate limit of the detector. The width of the band is
65defined by the step size in transmission, defined in AUTO_FILTER_FACTOR,
66which is used for each correction. If the count rate is higher than
67AUTO_RATE_LIMIT, the transmission is immediately reduced by
68AUTO_FILTER_FACTOR and the exposure is retaken. If the count rate is
69lower than AUTO_RATE_LIMIT/(2*AUTO_FILTER_FACTOR), the change in
70transmission required to reach a count rate of 0.75*AUTO_RATE_LIMIT is
71calculated, the transmission increased by that factor and the exposure is
72retaken immediately. If the measured count rate falls between these limits,
73no change is applied to the filters. The following scheme illustrates
74this behavior::
75
76  Threshold levels           Actions
77  ----------------           -------
78
79                             - decrease trasmission by AUTO_FILTER_FACTOR
80                             - retake exposure immediately
81  AUTO_RATE_LIMIT---------------------------------------------------------
82   /\
83   || 2*AUTO_FILTER_FACTOR   - leave filters as they are
84   \/
85  ------------------------------------------------------------------------
86                             - calculate change in transmission required to
87                               reach 0.75*AUTO_RATE_LIMIT
88                             - increase trasmission by this factor
89                             - retake exposure immediately
90
91
92Exposure time adjustments (integrated NUMBER OF COUNTS)
93---------------------------------------------------------
94Exposure time adjustments are designed with maximum efficiency in mind.
95The general idea is to attempt to maintain the integrated count level as
96close as possible to the user-defined AUTO_COUNT_TARGET, but to minimize
97the number of re-exposures by accepting exposures which fall into an
98"acceptable" count range, which is defined as any count level between
99the detectors saturation count AUTO_COUNT_HIGH and a user-defined
100lower count level AUTO_COUNT_LOW. If the exposure is within this
101acceptable band, a new count time to reach the target level is
102calculated based on the current exposure, but only applied to the next
103exposure in an attempt to predict a change in the right direction. If the
104current exposure falls outside the acceptable count range, the expsoure
105time is adjusted and the exposure is retaken immediately. Note that
106chosing a small acceptable range will thus result in retaking many
107exposures, hence increasing scan times.
108Count times will be adjusted between user-defined limits AUTO_EXP_LOW and
109AUTO_EXP_HIGH and rounded to a user-defined precision AUTO_COUNT_PREC.
110
111The diagram below outlines the measures taken when the registered maximum
112NUMBER OF COUNTS falls into the various defined ranges::
113
114  Threshold levels           Actions
115  ----------------           -------
116
117                             - reduce exposure time (if > minimum time)
118                             - retake exposure immediately
119  AUTO_COUNT_HIGH---------------------------------------------------------
120                             - reduce exposure time (if > minimum time)
121                             - apply only to next exposure
122  AUTO_COUNT_TARGET-------------------------------------------------------
123                             - increase exposure time (if < maximum time)
124                             - apply only to next exposure
125  AUTO_COUNT_LOW----------------------------------------------------------
126                             - increase exposure time (if < maximum time)
127                             - retake exposure immediately
128
129
130Configuration
131=============
132
133No special configuration is needed to run these macros. Simply load the macro
134file and run :spec:def:`auto_setup`::
135
136  > qdo auto.mac
137  > auto_setup
138
139Dependencies
140------------
141
142Dependencies on other macros:
143
144* ``filter.mac`` (used to control the attenuators):
145
146  - :spec:def:`filter_trans`
147  - :spec:def:`filter_get_trans()`
148  - :spec:def:`filter_get_trans_up()`
149  - :spec:def:`filter_get_mask()`
150  - :spec:def:`filter_max()`
151
152* :spec:def:`recount` (modified count command used to retake an exposure)
153
154Impact
155------
156The following chained macro definitions are affected by this macro:
157
158* :spec:def:`user_prescan_head`
159* :spec:def:`user_chk_counts` (from our modified :spec:def:`count` command)
160* :spec:def:`user_precount`
161
162File information
163================
164
165Authors
166-------
167* C.M. Schlepuetz (CS, cschlep),
168  Argonne National Laboratory, cschlep@aps.anl.gov
169* Y. Yang (YY, ysyang),
170  University of Michigan, ysyang@umich.edu
171
172Creation date
173-------------
1742011/02/25
175
176Copyright
177---------
178Copyright 2010 by the above authors (see AUTHOR/AUTHORS)
179
180This program is free software: you can redistribute it and/or modify
181it under the terms of the GNU General Public License as published by
182the Free Software Foundation, either version 3 of the License, or
183(at your option) any later version.
184
185This program is distributed in the hope that it will be useful,
186but WITHOUT ANY WARRANTY; without even the implied warranty of
187MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
188GNU General Public License for more details.
189
190You should have received a copy of the GNU General Public License
191along with this program.  If not, see http://www.gnu.org/licenses/.
192
193Version
194-------
195::
196
197  $Date: 2011-04-11 13:17:13 -0400 (Mon, 11 Apr 2011) $
198  $Author: cschlep $
199  $URL: file:///data/svn/software/spec/trunk/common/auto.mac $
200  $Revision: 25 $
201
202
203Change log
204----------
2052011/02/25 (CS, YY):
206
207- completely reworked previous versions of ``auto.mac`` to produce this new
208  version:
209
210  * improved efficiency
211  * simplified code
212  * new method of scaling the count times (see description above)
213
2142011/04/04 (CS):
215
216- cleaned up code further
217- added and updated documentation
218- added ``auto_setup`` macro
219- added AUTO_AREADETECTOR_VERSION global to track which version of
220  areaDetector is used in ``auto_init_analysis``.
221- added ``auto_on`` and ``auto_off``
222- changed all macro names to lower case and underscore naming convention
223- changed all calls to macros from ``filter.mac`` to lower case and underscore
224  naming conventions.
225
2262011/04/11 (CS):
227
228- changed ``auto_prescan_header``: if AUTO_LEVEL > 1, set the exposure times to
229  the minimum exposure time to start with.
230
2312012/03/29 (CS):
232
233- modified code documentation to be compatible with the ROBODoc
234  documentation generation software.
235- monitor a configurable SPEC counter rather than an EPICS channel for the
236  adjustments. This allows for the monitoring of any arbitrary counter in
237  SPEC, but requires that whatever signal is to be monitored is captured in
238  a SPEC counter during the count process.
239- reworked the setup routines for easier use.
240- removed unnecessary ``auto_init_analysis``
241- removed unnecessary AUTO_AREADETECTOR_VERSION global variable
242- renamed many variables for improved consistency
243
2442012/04/23 (CS):
245
246- fixed a bug where long exposures with valid rate but saturating the
247  counter would result in an infinite loop.
248
2492012/07/06 (CS):
250
251- changed code documentation to be compatible with the new SPEC domain for the
252  SPHINX code documentation suite.
253
2542012/07/13 (CS):
255
256- renamed some private macros to start with underscores::
257
258    auto_precount        --> _auto_precount
259    auto_prescan_head    --> _auto_prescan_head
260    auto_user_chk_counts --> _auto_user_chk_counts
261
262- moved the macro definitions for the above macros out of the
263  :spec:def:`auto_set_level` macro to avoid unnecessary nested definitions.
264
265
266TO DO
267-----
268
269- Extensive testing of the pilot exposure mode
270- complete documentation
271- insert hyperlinks into documentation
272
273"""
274
275###############################################################################
276# Global variable definitions
277###############################################################################
278
279  global AUTO_MAC                 #: Save the name of this macro file
280  global AUTO_LEVEL               #: Type of adjustments {0,1,2}
281  global AUTO_MODE                #: Adjustment mode (pilot vs. post-exp) {0,1}
282  global AUTO_COUNTER             #: Counter to monitor
283  global AUTO_COUNT_RBV           #: Counter read back value (measured counts)
284  global AUTO_RETRY_MAX           #: Maximum number of retries
285  global AUTO_EXP_LOW             #: Low exposure time limit
286  global AUTO_EXP_HIGH            #: High exposure time limit
287  global AUTO_PILOT_EXPTIME       #: Exposure time for pilot exposures
288  global AUTO_RATE_LIMIT          #: High rate limit
289  global AUTO_COUNT_HIGH          #: High count limit
290  global AUTO_COUNT_TARGET        #: Target count level
291  global AUTO_COUNT_LOW           #: Low count limit
292  global AUTO_FILTER_FACTOR       #: Filter transmission factor for adjustments
293  global AUTO_COUNT_PREC          #: Count time precision (rounding)
294  global AUTO_FILTER_LOCK         #: Lock if rate-limited
295  global AUTO_SET_PILOT           #: Set pilot exposure time in user_precount
296  global AUTO_ORIG_EXPTIME        #: Save the original requested count time
297  global AUTO_DEBUG               #: Debug flag
298
299  # set default values for global variables
300  AUTO_MAC = DOFILE
301  AUTO_COUNTER = det
302  AUTO_LEVEL = 0
303  AUTO_MODE = 0
304  AUTO_RETRY_MAX = 20
305  AUTO_COUNT_HIGH = 5e5
306  AUTO_RATE_LIMIT =2e5
307  AUTO_COUNT_RBV = 1e6
308  AUTO_COUNT_TARGET = 1e4
309  AUTO_COUNT_LOW = 0.5 * AUTO_COUNT_TARGET
310  AUTO_PILOT_EXPTIME = 0.05
311  AUTO_EXP_LOW = 1
312  AUTO_EXP_HIGH = 10
313  AUTO_FILTER_FACTOR = 5
314  AUTO_COUNT_PREC = 0.01
315  AUTO_FILTER_LOCK = 0
316  AUTO_SET_PILOT = 1
317  AUTO_DEBUG = 0
318
319
320###############################################################################
321# Macro command definitions
322###############################################################################
323
324#------------------------------------------------------------------------------
325# allow for misspelled help commands
326#def autohelp '{auto_help}'
327
328def auto_help '{
329  """
330  Displays the auto help text.
331
332  Usage::
333
334     > auto_help
335
336  .. note:: The help text is generated by simply displaying the text file
337     ``auto_mac.txt``, which should reside in the same directory as
338     ``auto.mac``. If the file does not exist, a generic help text defined in
339     ``auto_help`` is shown.
340  """
341
342  unix (sprintf ("dirname %s", AUTO_MAC), _1)
343  ll = length (_1)
344  if (substr (_1, ll, 1) == "\n") _1 = substr (_1, 1, (ll - 1))
345  file = sprintf ("%s/auto_mac.txt", _1)
346  if (file_info (file, "-e")) {
347    unix (sprintf ("cat %s", file))
348  } else {
349    printf("\nMacros available in file auto.mac ($Revision: 25 $):\n")
350    printf("                           ========"\n)
351    printf("\n")
352    printf("  auto_help          - creates this help text\n")
353    printf("  auto_setup         - setup automatic exposure control\n")
354    printf("  auto_set_mode      - set the auto-adjustment mode\n")
355    printf("  auto_set_level     - activate or deactivate automatic filter\n")
356    printf("                       and exposure setting\n")
357    printf("  auto_on            - turn auto exposure control ON (dialog)\n")
358    printf("  auto_off           - turn auto exposure control OFF\n")
359    printf("  auto_set_exposure  - define the shortest and longest exposure\n")
360    printf("                       time used in case of automatic exposure\n")
361    printf("                       setting\n")
362    printf("  auto_show          - display current auto exposure settings\n")
363    printf("  auto_show_exposure - display current exposure time settings\n")
364  }
365}'
366
367
368#------------------------------------------------------------------------------
369def auto_setup '{
370  """
371  Set up the control parameters for the automatic filter and exposure
372  adjustments.
373
374  Description:
375
376    The following parameters can be adjusted to fit the particular needs of an
377    experiment or detector type (global variables holding these parameters and
378    default values are given in brackets):
379
380    * Auto level: the level of automatic adjustments to be performed. Three
381      levels are currently available [AUTO_LEVEL = 0]:
382
383        ===== =================================================================
384        Level Description
385        ===== =================================================================
386        0     No automatic adjustments are made
387        1     Only filters are adjusted, no exposure time adjustments
388        2     Both filters and exposure times are automatically adjusted
389        ===== =================================================================
390
391    * Auto mode: the mode used to calculate/apply the adjustments. Two modes
392      are available [AUTO_MODE = 0]:
393
394        ==== ==================================================================
395        Mode Description
396        ==== ==================================================================
397        0    Post-exposure analysis: exposures are taken at normal settings and
398             analyzed in retrospect. The exposure is only retaken if it is
399             deemed unacceptable. Otherwise, the calculated adjustments are
400             applied only to the next exposure. This mode is faster, but
401             riskier in terms of over-exposing the detector for potentially
402             much longer times.
403        1    Pilot exposure mode: A short pilot exposure is taken before each
404             exposure to determine the correct filter and exposure time
405             settings. This is safer in terms of identifying over-exposures
406             quickly and provides optimized settings for each exposure, but
407             comes at a considerable cost in additional dead time. The pilot
408             exposure time is specified in AUTO_PILOT_EXPTIME.
409        ==== ==================================================================
410
411    * Counter to monitor: the SPEC counter mnemonic or number of the counter
412      used to assess the validity of the exposure. Note that when using area
413      detectors, it is necessary to monitor the count levels per pixel, as this
414      the saturation conditions. In this case, there needs to be a counter
415      configured that is monitoring the maximum count rate of all pixels within
416      the relevant region of interest. [AUTO_COUNTER = det]
417
418    * Count RATE high limit: the maximum count rate (counts per second) on
419      the detector that is acceptable for the experiment. If the measured count
420      rate is higher than this limit, filters will be inserted to lower the
421      rate. [AUTO_RATE_LIMIT = 2.0e5]
422
423    * Target count level: the desired count level for a "perfect" exposure.
424      All adjustments applied to filter and/or count times aim to achieve this
425      level. [AUTO_COUNT_TARGET = 1.0e4]
426
427    * Count level low limit: The lower count limit for an acceptable exposure.
428      If the measured level is below this, filters and exposure times will be
429      adjusted (if possible) and the exposure retaken.
430      [AUTO_COUNT_LOW = 5000]
431
432    * Counter saturation limit: The upper count limit for an acceptable
433      exposure. This should be chosen below the actual saturation level of the
434      detector. If the measured level exceeds the saturation limit, filters and
435      exposure times will be adjusted (if possible) and the exposure is
436      repeated.
437      [AUTO_COUNT_HIGH = 5.0e5]
438
439    * Transmission step: The step in filter transmission to be taken when
440      adjusting the filters. The specified step must be larger than the
441      largest available incremet in transmission values of the experimental
442      setup to ensure that the adjustments can be successful. Ideally, this
443      number is chosen anywhere between 2 and 10, but may need to be higher
444      depending on the available filters. [AUTO_FILTER_FACTOR = 5]
445
446    * Minimum exposure time: Minimum allowable exposure time to be used whith
447      automatic exposure time adjustments. [AUTO_EXP_LOW = 1]
448
449    * Maximum exposure time: Maximum allowable exposure time to be used whith
450      automatic exposure time adjustments. [AUTO_EXP_HIGH = 10]
451
452    * Pilot exposure time: Exposure time for the pilot exposure used in pilot
453      mode. [AUTO_PILOT_EXPTIME = 0.05]
454
455    * Count time precision: Automatically calculated count times will be
456      rounded to this precision. Typically, a value of 0.01 or 0.001 seconds is
457      recommended. [AUTO_COUNT_PREC = 0.01]
458
459    * Maximum number of retries: The maximum number of retries to adjust
460      exposure and filter settings before giving up. This avoids infinite loops
461      due to inconsistent choices of control parameters. [AUTO_RETRY_MAX = 20]
462
463  Usage::
464
465    > auto_setup
466        then answer the questions
467
468  """
469
470  local _setup_numitems, _setup_option, _tmp_option, _str1
471
472  # total number of setup items
473  _setup_numitems = 13
474
475  _clear_screen
476
477  _setup_option = 0
478  _tmp_option = -1
479  while (_tmp_option) {
480      _tmp_option = -1
481      while (_tmp_option < 0 || _tmp_option > _setup_numitems){
482          _auto_print_setup
483          _str1 = sprintf("Enter 1-%d to change the parameters, 0 to quit",\
484            _setup_numitems)
485          _tmp_option = getval(_str1, _setup_option)
486          if(index(_tmp_option, "q") == 1 || index(_tmp_option, "Q") == 1){
487            _tmp_option = 0
488          }
489      }
490      _setup_option = _tmp_option
491      if (_setup_option != 0){
492          _auto_set_option _setup_option
493      }
494      _setup_option = (_tmp_option + 1)%(_setup_numitems + 1)
495  }
496
497  _auto_check_levels
498  _auto_check_exposure
499
500}'
501
502
503#------------------------------------------------------------------------------
504def auto_off '{
505  """
506  Turn off any automatic filter and exposure adjustments.
507
508  USAGE::
509
510    > auto_off
511
512  NOTE:
513    This command is equivalent to ``auto_set_level 0``
514
515  SEE ALSO:
516     :spec:def:`auto_set_level`,
517     :spec:def:`auto_on`
518
519  """
520
521  auto_set_level 0
522
523}'
524
525
526#------------------------------------------------------------------------------
527def auto_on '{
528  """
529  Turn on automatic filter and exposure adjustments.
530
531  This macro is identical to :spec:def:`auto_set_level`. Please refer to the
532  :spec:def:`auto_set_level` documentation for more details.
533  """
534
535auto_set_level $*
536
537}'
538
539#------------------------------------------------------------------------------
540def auto_set_level '{
541  """
542  Set the level of automatic filter and exposure adjustments.
543
544  USAGE::
545
546    > auto_set_level [<level>]
547    > auto_on [<level>]
548
549  If now arguement is given, the user is prompted for input. The argument
550  ``<level>`` can be one of the following:
551
552      =====  =================================================================
553      Level  Description
554      =====  =================================================================
555      ``0``  No automatic adjustments are made
556      ``1``  Only filters are adjusted, no exposure time adjustments
557      ``2``  Both filters and exposure times are automatically adjusted
558      =====  =================================================================
559
560  EXAMPLES::
561
562    > auto_set_level
563        then answer the questions in the dialogue
564
565    > auto_on 1
566        turns on automatic filter adjustments (level 1)
567
568  NOTE:
569     :spec:def:`auto_set_level` and :spec:def:`auto_on` are equivalent to
570     each other.
571
572  SEE ALSO:
573     :spec:def:`auto_off`
574
575  """
576
577  if ($#>1){
578    eprint "Wrong number or illegal arguments in \'auto_set_level\'"
579    eprint "Usage:"
580    eprint "  auto_set_level <level>"
581    eprint ""
582    eprint "<level> can be:"
583    eprint "0 - OFF"
584    eprint "1 - only automatic filter ON, automatic exposure OFF"
585    eprint "2 - automatic filter and exposure ON"
586    eprint ""
587    exit
588  } else if ($#>0){
589    AUTO_LEVEL = $1
590  } else {
591    printf("Choose auto level:\n")
592    printf("  0 - automatic filter and exposure OFF\n")
593    printf("  1 - only automatic filter ON, automatic exposure OFF\n")
594    printf("  2 - automatic filter and exposure ON\n")
595    AUTO_LEVEL = getval("Auto level", AUTO_LEVEL)
596  }
597
598  # check validity of AUTO_LEVEL
599  if (!((AUTO_LEVEL==0) || (AUTO_LEVEL==1) || (AUTO_LEVEL==2))){
600    eprint "Illegal auto level in \'auto_set_level\'"
601    eprint "Valid levels are:"
602    eprint "  0 - OFF"
603    eprint "  1 - only automatic filter ON, automatic exposure OFF"
604    eprint "  2 - automatic filter and exposure ON"
605    eprint ""
606  }
607
608  #--------------------------------------------
609  # include necessary chained macro definitions
610  # depending on the current auto-level
611
612  if (AUTO_LEVEL > 0){
613
614    #: add _auto_prescan_head to user_prescan_head
615    cdef("user_prescan_head", "{_auto_prescan_head}; ", \
616         "auto_prescan_head_key", 0x10)
617
618    #: add _auto_user_chk_counts to user_chk_counts
619    cdef("user_chk_counts", "{_auto_user_chk_counts}; ", \
620         "auto_user_chk_counts_key")
621
622    #: add _auto_precount to user_precount
623    cdef("user_precount", "{_auto_precount}; ", "auto_precount_key", 0x10)
624
625    #: add _auto_cleanup to the end of user_scan_tail
626    cdef("user_scan_tail","{_auto_cleanup}; ", \
627         "auto_user_scan_tail_key",0x20)
628  }
629
630  #---------------------------------------------
631  # remove unnecessary chained macro definitions
632  # depending on the current auto-level
633
634  # Note: chained macro definitions which are not currently defined
635  #       can be deleted without producing an error.
636
637  if (AUTO_LEVEL < 1) {
638
639    #: remove _auto_prescan_head from user_prescan_head
640    cdef("user_prescan_head", "", "auto_prescan_head_key", "delete")
641
642    #: remove _auto_user_chk_counts from user_chk_counts
643    cdef("user_chk_counts", "", "auto_user_chk_counts_key", "delete")
644
645    #: remove _auto_precount from user_precount
646    cdef("user_precount", "", "auto_precount_key", "delete")
647
648    #: remove _auto_cleanup from user_scan_tail
649    cdef("user_scan_tail", "", "auto_user_scan_tail_key", "delete")
650    #: remove _auto_cleanup from cleanup_once
651    cdef("cleanup_once", "", "auto_cleanup_once_key", "delete")
652  }
653
654  auto_show
655
656}'
657
658#------------------------------------------------------------------------------
659def auto_set_mode '{
660  """
661  Set the acquisition mode to be used for the automatic filter and
662  exposure time adjustments.
663
664  DESCRIPTION:
665    Need some more details here...
666
667  USAGE::
668
669    > auto_set_mode [<mode>]
670        where <mode> must be one of the following:
671          0 - post-exposure analysis
672          1 - pilot exposure mode
673        when called with no arguments, the user is prompted
674
675  EXAMPLE::
676
677    > auto_set_mode 1
678        use the pilot exposure mode for automatic adjustments.
679
680  SEE ALSO:
681    :spec:def:`auto_setup`
682
683  """
684
685  local _mode
686
687  if ( ($# != 1) && ($# != 0 )) {
688    eprint "Wrong number or illegal arguments in \'auto_set_mode\'"
689    eprint "Usage:"
690    eprint "  auto_set_mode <mode>"
691    exit
692  } else if ($# == 1){
693    _mode = $1
694  } else {
695    _mode = getval("Enter the new auto mode", AUTO_MODE)
696  }
697
698  # check validity of mode
699  if((AUTO_MODE != 0) & (AUTO_MODE !=1)){
700    eprint "ERROR: Illegal value for auto mode (%g)!"
701    printf("  Auto mode is still %d\n", AUTO_MODE)
702    exit
703  } else {
704    AUTO_MODE = _mode
705  }
706
707  auto_show
708
709}'
710
711
712#------------------------------------------------------------------------------
713def auto_set_exposure '{
714  """
715  Set the maximum and minimum exposure times used for automatic exposure
716  adjustments.
717
718  USAGE::
719
720    > auto_set_exposure [<min> <max>]
721        where <min> is the minimum and <max> the maximum exposure time [s]
722        when called with no arguments, the user is prompted
723
724  EXAMPLE::
725
726      > auto_set_exposure 1 10
727          set the minimum exposure time to 1 sec and the maximum to 10 sec
728
729  """
730
731  if ( ($# != 2) && ($# != 0 )) {
732    eprint "Wrong number or illegal arguments in \'auto_set_exposure\'"
733    eprint "Usage:"
734    eprint "auto_set_exposure [<min> <max>]"
735    eprint "defines the minimum and maximum exposure times in seconds"
736    eprint "(used if auto-level is set to 2  with \'auto_set_level\')"
737  } else if ($# == 2){
738    AUTO_EXP_LOW = $1
739    AUTO_EXP_HIGH = $2
740  } else {
741    AUTO_EXP_LOW = getval("Minimum exposure time [s]", AUTO_EXP_LOW)
742    AUTO_EXP_HIGH = getval("Maximum exposure time [s]", AUTO_EXP_HIGH)
743  }
744
745  _auto_check_exposure
746  auto_show_exposure
747
748}'
749
750
751#------------------------------------------------------------------------------
752def auto_show '{
753  """
754  Display the current auto settings.
755
756  USAGE::
757
758    > auto_show
759
760  """
761
762  if (AUTO_LEVEL == 0) {
763    printf("Auto-level has been set to %d.\n", AUTO_LEVEL)
764    printf("Automatic filter setting is OFF.\n")
765    printf("Automatic exposure setting is OFF.\n")
766  } else if (AUTO_LEVEL == 1) {
767    printf("Auto-level has been set to %d.\n", AUTO_LEVEL)
768    printf("Automatic filter setting is ON.\n")
769    printf("Automatic exposure setting is OFF.\n")
770  } else  if (AUTO_LEVEL == 2) {
771    printf("Auto-level has been set to %d.\n", AUTO_LEVEL)
772    printf("Automatic filter setting is ON.\n")
773    printf("Automatic exposure setting is ON.\n")
774  } else {
775    AUTO_LEVEL = 0
776    printf("ERROR: Unknown auto-level - resetting to %d", AUTO_LEVEL)
777    printf("Automatic filter setting is OFF.\n")
778    printf("Automatic exposure setting is OFF.\n")
779  }
780
781  if(AUTO_MODE == 0){
782    printf("Auto mode is 0 (post-exposure adjustments)\n")
783  } else if (AUTO_MODE == 1){
784    printf("Auto mode is 1 (pilot exposure)\n")
785  } else {
786    AUTO_MODE = 0
787    printf("ERROR: Unknown auto mode - resetting to %d", AUTO_MODE)
788  }
789
790  if(AUTO_LEVEL>1){
791    auto_show_exposure
792  }
793
794}'
795
796
797#------------------------------------------------------------------------------
798def auto_show_exposure '{
799  """
800  Display the current auto-level exposure settings.
801
802  USAGE::
803
804    > auto_show_exposure
805
806  """
807
808  printf("Exposure times: minimum = %g s, maximum = %g s\n",\
809         AUTO_EXP_LOW, AUTO_EXP_HIGH)
810
811}'
812
813
814###############################################################################
815# Internal macros
816###############################################################################
817
818#------------------------------------------------------------------------------
819def _auto_cleanup '{
820  """
821  Cleanup routine for automatic filter/exposure control
822  """
823
824  # drop in filters after finishing, since we do not know where we end up
825  # (center of a peak for dscan?)
826  AUTO_SET_PILOT = 1
827  AUTO_FILTER_LOCK = 0
828  if(AUTO_LEVEL > 0){
829    filter_trans 1e-10
830  }
831  #: remove _auto_cleanup_once from cleanup_once
832  cdef("cleanup_once", "", "auto_cleanup_once_key", "delete")
833}'
834
835
836#------------------------------------------------------------------------------
837def _auto_prescan_head '{
838  """
839  Prepare for automatic filter/exposure control before the start of a scan
840
841  This inserts filters with a transmission of 1e-10, sets some values in
842  the global variables and adds a cleanup routine to ``cleanup_once``.
843  """
844
845  # if automatic filter setting is active start scan with very low
846  # filter transmission
847  if(AUTO_LEVEL > 0){
848    AUTO_ORIG_EXPTIME = COUNT_TIME
849    filter_trans 1e-10
850    if(AUTO_LEVEL > 1){
851      # start with low exposure times
852      COUNT_TIME = AUTO_EXP_LOW
853      _ctime = COUNT_TIME
854    }
855  }
856  #: add _auto_cleanup to cleanup_once
857  cdef("cleanup_once","{_auto_cleanup}; ", "auto_cleanup_once_key",0x20)
858}'
859
860
861#------------------------------------------------------------------------------
862def _auto_user_chk_counts '{
863  """
864  Check if counts are valid and retake exposure if necessary.
865  """
866
867  if(AUTO_LEVEL > 0){
868    # automatic filter and exposure setting (if activated)
869    success = _auto_adjust_redo()
870  }
871}'
872
873
874#------------------------------------------------------------------------------
875def _auto_precount '{
876  """
877  Prepare for automatic filter/exposure control at beginning of count command.
878  """
879
880  if(AUTO_LEVEL > 0){
881    if(AUTO_MODE == 1 & AUTO_SET_PILOT == 1){
882      # remember the original exposure time
883      AUTO_ORIG_EXPTIME = COUNT_TIME
884      # set the pilot exposure time
885      COUNT_TIME = AUTO_PILOT_EXPTIME
886      _ctime = COUNT_TIME
887      AUTO_SET_PILOT = 0
888    }
889  }
890}'
891
892
893#------------------------------------------------------------------------------
894def _auto_print_setup '{
895  """
896  Print the configuration options and current values to screen
897
898  NOTE:
899     The option numbers must be kept in sync between
900     :spec:def:`_auto_set_option` and
901     :spec:def:`_auto_print_setup`.
902  """
903
904  tty_cntl("ho")  # home cursor on left upper corner of screen
905  tty_cntl("cd")  # clear the rest of the screen
906
907  tty_cntl("so")  # highlight font
908  printf("Auto setup:\n")
909  tty_cntl("se")  # turn off font highlighting
910
911  printf("\n 1)  %40s: %s", "Auto level {0,1,2}", AUTO_LEVEL)
912  if(AUTO_LEVEL == 0) printf(" (no automatic adjustments)")
913  if(AUTO_LEVEL == 1) printf(" (automatic filter adjustments)")
914  if(AUTO_LEVEL == 2) printf(" (automatic filter and exptime adjustments)")
915  printf("\n 2)  %40s: %s", "Auto mode {0,1}", AUTO_MODE)
916  if(AUTO_MODE == 0) printf(" (post-exposure adjustments)")
917  if(AUTO_MODE == 1) printf(" (pilot pre-exposure)")
918  printf("\n 3)  %40s: %s", "Counter to monitor", AUTO_COUNTER)
919  printf("\n 4)  %40s: %s", "Count RATE high limit [cts/s]", AUTO_RATE_LIMIT)
920  printf("\n 5)  %40s: %s", "Target count level [cts]", AUTO_COUNT_TARGET)
921  printf("\n 6)  %40s: %s", "Count level low limit [cts]", AUTO_COUNT_LOW)
922  printf("\n 7)  %40s: %s", "Counter saturation (high) limit [cts]", \
923    AUTO_COUNT_HIGH)
924  printf("\n 8)  %40s: %s", "Transmission step", AUTO_FILTER_FACTOR)
925  printf("\n 9)  %40s: %s", "Minimum exposure time [s]", AUTO_EXP_LOW)
926  printf("\n 10) %40s: %s", "Maximum exposure time [s]", AUTO_EXP_HIGH)
927  printf("\n 11) %40s: %s", "Pilot exposure time [s]", AUTO_PILOT_EXPTIME)
928  printf("\n 12) %40s: %s", "Count time precision [s]", AUTO_COUNT_PREC)
929  printf("\n 13) %40s: %s", "Maximum number of retries", AUTO_RETRY_MAX)
930  printf("\n\n")
931}'
932
933
934#------------------------------------------------------------------------------
935def _auto_set_option '{
936  """
937  Sets a new value for a given option.
938
939  DESCRIPTION:
940    Sets a new value for a given option from the options menu that was created
941    with the :spec:def:`_auto_print_setup` command.
942
943  NOTE:
944    The option numbers must be kept in sync between
945    :spec:def:`_auto_set_option` and
946    :spec:def:`_auto_print_setup`.
947
948  """
949
950  local _input, _dummy, _valid, _numitems
951
952  #----------
953  if ($1==1){
954    auto_set_level
955
956  #----------------
957  } else if ($1==2){
958    auto_set_mode
959
960  #----------------
961  } else if ($1==3){
962
963    show_counters()
964
965    _valid = 0
966    while(!(_valid)){
967      _input = getval("Pleae enter the counter to monitor", AUTO_COUNTER)
968      if(cnt_num(_input)<0){
969        printf("ERROR: Invalid counter (%s)\n", _input)
970      } else {
971        AUTO_COUNTER = cnt_num(_input)
972        _valid = 1
973      }
974    }
975
976  #----------------
977  } else if ($1==4){
978    _valid = 0
979    while(!(_valid)){
980      _input= getval("Upper limit for the counte RATE [cts/sec]", \
981        AUTO_RATE_LIMIT)
982      _numitems = sscanf(_input, "%f", _input)
983      if(_numitems == 1){
984        if(_input > 0) {
985          AUTO_RATE_LIMIT = _input
986          _valid = 1
987        }
988      }
989      if(!(_valid)){
990        printf("ERROR: Invalid input for rate limit (%s)\n", _input)
991      }
992    }
993
994  #----------------
995  } else if ($1==5){
996    _valid = 0
997    while(!(_valid)){
998      _input= getval("Target count level [cts]", AUTO_COUNT_TARGET)
999      _numitems = sscanf(_input, "%f", _input)
1000      if(_numitems == 1){
1001        if(_input > 0) {
1002          AUTO_COUNT_TARGET = _input
1003          _valid = 1
1004        }
1005      }
1006      if(!(_valid)){
1007        printf("ERROR: Invalid target count level (%s)\n", _input)
1008      }
1009    }
1010
1011  #----------------
1012  } else if ($1==6){
1013    _valid = 0
1014    while(!(_valid)){
1015      _input= getval("Count level low limit [cts]", AUTO_COUNT_LOW)
1016      _numitems = sscanf(_input, "%f", _input)
1017      if(_numitems == 1){
1018        if(_input > 0) {
1019          AUTO_COUNT_LOW = _input
1020          _valid = 1
1021        }
1022      }
1023      if(!(_valid)){
1024        printf("ERROR: Invalid count level low limit (%s)\n", _input)
1025      }
1026    }
1027
1028  #----------------
1029  } else if ($1==7){
1030    _valid = 0
1031    while(!(_valid)){
1032      _input= getval("Counter saturation (high) limit [cts]", AUTO_COUNT_HIGH)
1033      _numitems = sscanf(_input, "%f", _input)
1034      if(_numitems == 1){
1035        if(_input > 0) {
1036          AUTO_COUNT_HIGH = _input
1037          _valid = 1
1038        }
1039      }
1040      if(!(_valid)){
1041        printf("ERROR: Invalid counter saturation limit (%s)\n", _input)
1042      }
1043    }
1044
1045  #----------------
1046  } else if ($1==8){
1047    _valid = 0
1048    while(!(_valid)){
1049      _input= getval("Transmission step used to adjust filters", \
1050        AUTO_FILTER_FACTOR)
1051      _numitems = sscanf(_input, "%f", _input)
1052      if(_numitems == 1){
1053        if(AUTO_FILTER_FACTOR <= 1.2){
1054          printf("Error: Transmission step factor must be >1.2 !\n")
1055          printf("  (recommended: 4 - 100, must match available filters)\n")
1056        } else if (AUTO_FILTER_FACTOR >= AUTO_RATE_LIMIT){
1057          printf("Error: Transmission step factor must be smaller than\n")
1058          printf("  the maximum count rate (%g)\n", AUTO_RATE_LIMIT)
1059        } else if (AUTO_FILTER_FACTOR >= AUTO_COUNT_HIGH){
1060          printf("Error: Transmission step factor must be smaller than\n")
1061          printf("  the counter saturation limit (%g)\n", AUTO_COUNT_HIGH)
1062        } else {
1063          AUTO_FILTER_FACTOR = _input
1064          _valid = 1
1065        }
1066      }
1067      if(!(_valid)){
1068        printf("ERROR: Invalid transmission step (%s)\n", _input)
1069      }
1070    }
1071
1072  #----------------
1073  } else if ($1==9){
1074    _valid = 0
1075    while(!(_valid)){
1076      _input= getval("Minimum exposure time [s]", AUTO_EXP_LOW)
1077      _numitems = sscanf(_input, "%f", _input)
1078      if(_numitems == 1){
1079        if(_input > 0) {
1080          AUTO_EXP_LOW = _input
1081          _valid = 1
1082        }
1083      }
1084      if(!(_valid)){
1085        printf("ERROR: Invalid minimum exposure time (%s)\n", _input)
1086      }
1087    }
1088
1089  #-----------------
1090  } else if ($1==10){
1091    _valid = 0
1092    while(!(_valid)){
1093      _input= getval("Maximum exposure time [s]", AUTO_EXP_HIGH)
1094      _numitems = sscanf(_input, "%f", _input)
1095      if(_numitems == 1){
1096        if(_input > 0) {
1097          AUTO_EXP_HIGH = _input
1098          _valid = 1
1099        }
1100      }
1101      if(!(_valid)){
1102        printf("ERROR: Invalid maximum exposure time (%s)\n", _input)
1103      }
1104    }
1105
1106
1107  #-----------------
1108  } else if ($1==11){
1109    _valid = 0
1110    while(!(_valid)){
1111      _input= getval("Pilot exposure time [s]", AUTO_PILOT_EXPTIME)
1112      _numitems = sscanf(_input, "%f", _input)
1113      if(_numitems == 1){
1114        if(_input > 0) {
1115          AUTO_PILOT_EXPTIME = _input
1116          _valid = 1
1117        }
1118      }
1119      if(!(_valid)){
1120        printf("ERROR: Invalid pilot exposure time (%s)\n", _input)
1121      }
1122    }
1123
1124  #-----------------
1125  } else if ($1==12){
1126    local _str
1127
1128    _valid = 0
1129    while(!(_valid)){
1130      _str = "Count time rounding precision [s] (e.g.: 0.01; 0=no rounding)"
1131      _input= getval(_str, AUTO_COUNT_PREC)
1132      _numitems = sscanf(_input, "%f", _input)
1133      if(_numitems == 1){
1134        if(_input < 0) {
1135          printf("Count time precision must be >=0 \n")
1136        } else if(_input > 10){
1137          printf("Count time precision must be smaller than 10 sec\n")
1138        } else {
1139          AUTO_COUNT_PREC = _input
1140          _valid = 1
1141        }
1142      }
1143      if(!(_valid)){
1144        printf("ERROR: Invalid count time precision (%s)\n", _input)
1145      }
1146    }
1147
1148  #-----------------
1149  } else if ($1==13){
1150    _valid = 0
1151    while(!(_valid)){
1152      _input= getval("Maximum number of retries", AUTO_RETRY_MAX)
1153      _numitems = sscanf(_input, "%d", _input)
1154      if(_numitems == 1){
1155        if(_input > 100) {
1156          printf("Maximum number of retries must be < 100 !\n")
1157          printf("  (recommended: <30 and >10)\n")
1158        } else if(_input <2) {
1159          printf("Maximum number of retries must be > 2 !\n")
1160          printf("  (recommended: <30 and >10)\n")
1161        } else {
1162          AUTO_RETRY_MAX = int(_input)
1163          _valid = 1
1164        }
1165      }
1166      if(!(_valid)){
1167        printf("ERROR: Invalid pilot exposure time (%s)\n", _input)
1168      }
1169    }
1170  }
1171}'
1172
1173
1174
1175#------------------------------------------------------------------------------
1176def _auto_analyze_exposure '{
1177  """
1178  Analyze the previous exposure
1179
1180  DESCRIPTION:
1181    This macro retrieves the necessary information to analyze the last exposure
1182    and to initiate adjustments, if necessary. Usually, this step consists only
1183    of retrieving the count value from the monitored SPEC counter, but for more
1184    sophisticated experimental setups, this definition could be overwritten to
1185    include non-standard procedures, such as retrieving counts from EPICS PVs,
1186    etc.
1187
1188  USAGE::
1189
1190    > _auto_analyze_exposure
1191
1192  """
1193
1194  AUTO_COUNT_RBV = S[AUTO_COUNTER]
1195
1196}'
1197
1198
1199#------------------------------------------------------------------------------
1200def _auto_adjust() '{
1201  """
1202  Calculate and apply necessary exposure time and filter adjustments.
1203
1204  DESCRIPTION:
1205
1206    The function returns 1 if transmission or exposure time have been changed,
1207    0 otherwise.
1208
1209  USAGE::
1210    > changed = _auto_adjust()
1211
1212  """
1213
1214  local _auto_adjusted, _count_time, _factor, _transm, _transm_up, _new_transm
1215
1216  # do nothing when auto-level is zero
1217  if (AUTO_LEVEL < 1) {
1218    return(0)
1219  }
1220
1221  # set exposure times to default if they are not defined yet
1222  if (AUTO_EXP_LOW < 0.0000001) {
1223    AUTO_EXP_LOW  =  1
1224  }
1225  if (AUTO_EXP_HIGH < 0.0000001) {
1226    AUTO_EXP_HIGH = 10
1227  }
1228
1229  _auto_adjusted = 0
1230
1231  # record last count time
1232  _count_time = COUNT_TIME
1233
1234  # analyze the exposure in terms of the threshold values
1235  _auto_analyze_exposure
1236
1237  if(AUTO_DEBUG && 0x1){
1238    printf("\n%s\n", date())
1239    printf("Analyzing exposure with exposure time %f s\n", COUNT_TIME)
1240    printf("Obtained count RATE: %f cts/s (saturation limit = %f cts/s)\n",\
1241            AUTO_COUNT_RBV/_count_time, AUTO_RATE_LIMIT)
1242    printf("Obtained count level: %f counts\n", AUTO_COUNT_RBV)
1243    printf("(Target = %f, Hi limit = %f, low limit = %f\n", \
1244            AUTO_COUNT_TARGET, AUTO_COUNT_HIGH, AUTO_COUNT_LOW)
1245  }
1246
1247  #-----------------------------------------
1248  # 1.) filter adjustments if AUTO_LEVEL > 0
1249
1250  if(AUTO_DEBUG && 0x1){
1251    printf("Filter lock is: %d\n", AUTO_FILTER_LOCK)
1252  }
1253
1254  # check if filters are already locked (rate has been adjusted)
1255  if (!(AUTO_FILTER_LOCK)){
1256
1257    # reduce filter transmission if rate is too high
1258    if ( ((AUTO_COUNT_RBV/_count_time) > AUTO_RATE_LIMIT) &\
1259         (filter_get_mask() < filter_max()) ){
1260
1261      if(AUTO_DEBUG && 0x1){
1262        printf("Rate is too high: %f > %f\n", AUTO_COUNT_RBV/_count_time,\
1263                AUTO_RATE_LIMIT)
1264      }
1265
1266      _new_transm = filter_get_trans()/ AUTO_FILTER_FACTOR
1267      filter_trans _new_transm
1268      _auto_adjusted = 1
1269      return(_auto_adjusted)
1270    }
1271
1272    # increase filter transmission if rate is too low
1273    if (((AUTO_COUNT_RBV/_count_time) < \
1274          0.5*AUTO_RATE_LIMIT/AUTO_FILTER_FACTOR) & \
1275          (filter_get_mask() > 0) ){
1276
1277      if(AUTO_DEBUG && 0x1){
1278        printf("Rate is too low: %f < %f\n", AUTO_COUNT_RBV/_count_time, \
1279                0.5*AUTO_RATE_LIMIT/AUTO_FILTER_FACTOR)
1280      }
1281
1282      _transm = filter_get_trans()
1283      if (AUTO_COUNT_RBV > 0){
1284        _factor = (0.75 * AUTO_RATE_LIMIT) / (AUTO_COUNT_RBV/_count_time)
1285      } else {
1286        _factor = (0.75 * AUTO_RATE_LIMIT)
1287      }
1288      # make sure that there is actually a better filter setting available for
1289      # the requested new transmission
1290      _transm_up = filter_get_trans_up()
1291      if(_factor > (_transm_up/_transm)){
1292        _new_transm = _transm * _factor
1293        if(_new_transm > 1){
1294          _new_transm = 1
1295        }
1296        filter_trans _new_transm
1297        _auto_adjusted = 1
1298        return(_auto_adjusted)
1299      } else {
1300        # there is nothing we can do with the filters
1301        AUTO_FILTER_LOCK = 1
1302          if(AUTO_DEBUG && 0x1){
1303            printf("No filter adjustments possible\n")
1304          }
1305      }
1306    }
1307  }
1308
1309  # avoid counter saturation of the detector if AUTO_LEVEL < 2 or the exposure
1310  # time is at AUTO_EXP_LOW
1311  if((AUTO_LEVEL) < 2 | (_count_time <= AUTO_EXP_LOW+1e-7)){
1312    if((AUTO_COUNT_RBV > AUTO_COUNT_HIGH) & \
1313        (filter_get_mask() < filter_max())){
1314
1315      if(AUTO_DEBUG && 0x1){
1316        printf("Rate is ok (%f), but counter is saturating (%f > %f)\n",\
1317                AUTO_COUNT_RBV/_count_time, AUTO_COUNT_RBV, AUTO_COUNT_HIGH)
1318      }
1319
1320      _new_transm = filter_get_trans()/ AUTO_FILTER_FACTOR
1321      filter_trans _new_transm
1322      AUTO_FILTER_LOCK = 1
1323      _auto_adjusted = 1
1324      return(_auto_adjusted)
1325    }
1326  }
1327
1328
1329  #-------------------------------------------------------------------------
1330  # 2.) take real exposure with requested exposure time after pilot exposure
1331  #     if in pilot mode
1332
1333  if(AUTO_LEVEL == 1 && AUTO_MODE == 1){
1334    if(_count_time != AUTO_ORIG_EXPTIME){
1335      if(AUTO_DEBUG && 0x1){
1336        printf("Setting exposure time to %f s\n", AUTO_ORIG_EXPTIME)
1337      }
1338
1339      # set exposure time to requested exposure time to retake the exposure after
1340      # the pilot exposures
1341      AUTO_FILTER_LOCK = 1
1342      COUNT_TIME = AUTO_ORIG_EXPTIME
1343      _ctime = COUNT_TIME
1344      _auto_adjusted = 1
1345      return(_auto_adjusted)
1346    }
1347  }
1348
1349  #-----------------------------------------
1350  # 3.) count time scaling if AUTO_LEVEL > 1
1351
1352  if(AUTO_LEVEL > 1){
1353
1354    # calculate exposure time for next exposure
1355    if (AUTO_COUNT_RBV > 0){
1356      _factor = AUTO_COUNT_TARGET / AUTO_COUNT_RBV
1357    } else {
1358      _factor = 1e3
1359    }
1360    COUNT_TIME = _auto_calc_exposure(_count_time * _factor)
1361    _ctime = COUNT_TIME
1362
1363    if(AUTO_DEBUG && 0x1){
1364        printf("Adjusting exposure time from %f to %f sec\n", _count_time, \
1365                COUNT_TIME)
1366    }
1367
1368    # recount immediately if last exposure time was not within allowed limits
1369    if((_count_time < AUTO_EXP_LOW) | (_count_time > AUTO_EXP_HIGH)){
1370      if(AUTO_DEBUG && 0x1){
1371        printf("Previous exposure outside limits: retake immediately\n")
1372      }
1373      _auto_adjusted = 1
1374      return(_auto_adjusted)
1375    }
1376
1377    # recount immediately if we are saturated or under-exposed
1378    # and count times can still be changed
1379    if((AUTO_COUNT_RBV > AUTO_COUNT_HIGH) & \
1380       (_count_time > AUTO_EXP_LOW)){
1381
1382      if(AUTO_DEBUG && 0x1){
1383        printf("Overexposure: retaking exposure immediately\n")
1384      }
1385      _auto_adjusted = 1
1386      return(_auto_adjusted)
1387    }
1388    if((AUTO_COUNT_RBV < AUTO_COUNT_LOW) & \
1389       (_count_time < AUTO_EXP_HIGH)){
1390
1391      if(AUTO_DEBUG && 0x1){
1392        printf("Underexposure: retaking exposure immediately\n")
1393      }
1394      _auto_adjusted = 1
1395      return(_auto_adjusted)
1396    }
1397
1398    # decrease filter transmission if we are saturated and decreasing the
1399    # exposure time is not possible. Recount immediately
1400    if((AUTO_COUNT_RBV > AUTO_COUNT_HIGH) & \
1401        (_count_time <= AUTO_EXP_LOW+1e-7) & \
1402        (filter_get_mask() < filter_max())){
1403
1404      if(AUTO_DEBUG && 0x1){
1405        printf("Overexposure but cannot decrease exposure time")
1406        printf(" -> reducing filter transmission\n")
1407      }
1408
1409      _new_transm = filter_get_trans()/ AUTO_FILTER_FACTOR
1410      filter_trans _new_transm
1411      _auto_adjusted = 1
1412      return(_auto_adjusted)
1413      AUTO_FILTER_LOCK = 1
1414    }
1415  }
1416
1417  return(_auto_adjusted)
1418}'
1419
1420
1421#------------------------------------------------------------------------------
1422def _auto_check_exposure '{
1423  """
1424  Make sure the user-entered exposure times are consistent
1425
1426  USAGE::
1427
1428    > _auto_check_exposure
1429
1430  """
1431
1432  if (AUTO_EXP_LOW >= AUTO_EXP_HIGH) {
1433    AUTO_EXP_LOW  =  1
1434    AUTO_EXP_HIGH = 10
1435    eprint "ERROR: Invalid exposure time values!"
1436    printf("  Minimum (%f) must be less than maximum (%f) exposure time\n",\
1437      AUTO_EXP_LOW, AUTO_EXP_HIGH)
1438    printf("  Setting exposure times to default values:\n")
1439  }
1440}'
1441
1442
1443#------------------------------------------------------------------------------
1444def _auto_check_levels '{
1445  """
1446  Make sure the user-entered count levels are consistent
1447
1448  USAGE::
1449
1450    > _auto_check_levels
1451
1452  """
1453
1454  if(AUTO_COUNT_TARGET >= AUTO_COUNT_HIGH){
1455    eprint "ERROR: Invalid count target!"
1456    printf("The count target (%f) must be smaller than ", AUTO_COUNT_TARGET)
1457    printf("the counter saturation limit (%f).\n", AUTO_COUNT_HIGH)
1458    printf("Setting count target to %d counts.\n\n", int(AUTO_COUNT_HIGH/10))
1459    AUTO_COUNT_TARGET = int(AUTO_COUNT_HIGH/10)
1460  }
1461  if(AUTO_COUNT_LOW >= AUTO_COUNT_TARGET) {
1462    eprint "ERROR: Invalid low count limit!"
1463    printf("Low count limit (%f) must be smaller than count target (%f).\n", \
1464      AUTO_COUNT_LOW, AUTO_COUNT_TARGET)
1465    printf("Setting low count limit to %d counts.\n\n", \
1466      int(AUTO_COUNT_TARGET/10))
1467    AUTO_COUNT_LOW = int(AUTO_COUNT_TARGET/10)
1468  }
1469}'
1470
1471
1472#------------------------------------------------------------------------------
1473def _auto_calc_exposure(t) '{
1474  """
1475  Make sure the requested exposure time is between the min and max values and
1476  round it to the given count time precision.
1477
1478  USAGE::
1479
1480    > adjusted_time = _auto_calc_exposure(requested_time)
1481
1482  """
1483
1484  # round to given precision
1485  if (AUTO_COUNT_PREC>1e-7){
1486    t = (int(t/AUTO_COUNT_PREC))*AUTO_COUNT_PREC
1487  }
1488
1489  # check if we are inside the limits
1490  if(t > AUTO_EXP_HIGH){
1491    t = AUTO_EXP_HIGH
1492  } else if (t < AUTO_EXP_LOW){
1493    t = AUTO_EXP_LOW
1494  }
1495
1496  return(t)
1497}'
1498
1499
1500#------------------------------------------------------------------------------
1501def _auto_adjust_redo() '{
1502  """
1503  Determines whether the auto-adjusting has been successful.
1504
1505  DESCRIPTION:
1506
1507    If the current exposure does not meet the required criteria, counting
1508    is repeated until the best possible filter and exposure settings have been
1509    obtained, or a maximum number of retry counts has been reached.
1510    The function returns 1 in case of success, 0 otherwise.
1511
1512  USAGE::
1513
1514    > success = _auto_adjust_redo()
1515
1516  NOTE:
1517    This macro makes use of the :spec:def:`recount` macro, which has to be
1518    added to SPEC during the startup procedure.
1519
1520  """
1521
1522  local retryCount
1523  local redo
1524  local _success
1525
1526  _success = 1
1527  AUTO_SET_PILOT = 0
1528
1529  if (AUTO_LEVEL < 1) {
1530    return(_success)
1531  } else {
1532    retryCount = 0
1533    redo = 1
1534    while (redo != 0) {
1535      redo = 0
1536      retryCount++
1537      if (_auto_adjust() != 0) {
1538        if (retryCount <  AUTO_RETRY_MAX) {
1539          redo = 1
1540        } else {
1541          eprint " >> Couldn\'t optimize filter and exposure settings. <<"
1542        }
1543      }
1544      if (redo != 0) {
1545        # repeat exposure
1546        recount COUNT_TIME
1547      } else {
1548        _success = 1
1549        redo = 0
1550      }
1551    }
1552    AUTO_SET_PILOT = 1
1553    AUTO_FILTER_LOCK = 0
1554    return (_success)
1555  }
1556}'
1557
1558#------------------------------------------------------------------------------
1559# define this only if there is no _clear_screen function available yet
1560if (!(whatis("_clear_screen") & 0x2)){
1561  def _clear_screen '{
1562    """
1563    Clears the terminal screen
1564
1565    DESCRIPTION:
1566      Clears the screen without losing the screen history or messing up the
1567      scrolling capabilities (this has been a problem for certain terminals)
1568      by blanking out the entire height of the screen with newlines and
1569      returning the cursor to the top left corner.
1570
1571    USAGE::
1572
1573      > _clear_screen
1574
1575    """
1576
1577    # update the ROWS and COLS variables in case the terminal has been resized
1578    tty_cntl("resized?")
1579
1580    # print as many newlines as there are ROWS in terminal
1581    cl_text = ""
1582    for (i=0;i<ROWS;i++){
1583      cl_text = cl_text "\n"
1584    }
1585    printf(cl_text)
1586
1587    # move back to the top of the screen and clear to end of the screen
1588    tty_move(0,0)
1589    tty_cntl("cd")
1590
1591  }'
1592}
1593
1594###############################################################################
1595# End of $Id: $
1596###############################################################################
Note: See TracBrowser for help on using the repository browser.