In the following you find a template for a
general scan module. It has a mandatory
data structure %GS::h
and some mandatory
functions.
Let's start with the hash %GS::h
, a string-indexed array.
All data that control a scan are stored here. This
data structure is displayed, if the user selects Module-Info.
The key a1 has the value MOT1 in this example.
It is used by the functions get_position() and
set_position(). It is a possible value
of the $axis
. a1
can be assigned to a motor name,
a virtual motor name, dummy1
or energy
.
The same applies to a2 and a3. But they
don't have to be supplied for 1D scans.
For 2D scans we need also a2 and for 3D scan
a3 has to be defined.
The key description is also mandatory.
The other keys of the hash are arbitrary. The have no meaning for Online. Putting them into this hash has the advantage that they can be displayed by selecting the menu option Info.
This is the list of the functions:
That's all. The general scan widget creates a framework for
executing repeated measurements. It defines a minimal
interface. Basically the name, the limits and some
action buttons. All the rest is left to the user. Anything
can be done in the before
, during
and after
macros.
#!/usr/bin/perl -w use strict; package GS; # # An example for a General Scan Module # # The following symbols are defined by Online, they # may be used in this module # # $Spectra::SYM{ scan_name} # $Spectra::SYM{ np_total} # $Spectra::SYM{ sample_time} may change from point to point # $Spectra::SYM{ scan_offset_c1} # $Spectra::SYM{ scan_offset_c...} # $Spectra::SYM{ start} start, stop and delta are unknown, # $Spectra::SYM{ stop} if the positions are specified as # $Spectra::SYM{ delta} commands. # use vars qw( %h); %h = ( a1 => "MOT1", a2 => "MOT2", a3 => "MOT3", counters => [ qw( c3 c4 c5 c8)], timer => "t1", samples => { s1 => 12, s2 => 13}, description => "General Scan Demo Module", ); 1; # # set/get position # sub set_position { my ( $axis, $new_pos) = @_; my $status = 0; if( ref( $new_pos) eq "CODE") { $status = &$new_pos; } else { $status = Spectra::move( $h{ $axis} => $new_pos); } finish: return $status; } sub get_position { my ( $axis) = @_; # 'a1', 'a2' or 'a3' return Spectra::gmup( $h{ $axis}); } # # this function is called once when the scan starts # sub exec_before { my $status = 0; Spectra::delete(); Spectra::cls(); my $scan_name = $Spectra::SYM{ scan_name}; my $np_total = $Spectra::SYM{ np_total}; # # the preparation: copy the offsets to %h, # thereby checking whether they exist # $h{ sample_time} = $Spectra::SYM{ sample_time}; foreach my $c ( @{ $h{ counters}}) { $h{ "offset_${c}"} = $Spectra::SYM{ "scan_offset_$c"}; if( !defined $h{ "offset_${c}"}) { Spectra::error( "before: failed to find scan_offset_${c}"); goto finish; } } $h{ start_time} = Spectra::date_and_time(); $h{ start_position} = GS::get_position( "a1"); $h{ np_total} = $np_total; TEXT->create( name => 0, string => "T1 Scan ($scan_name) started at $h{ start_time}", y => 1.12, x => 1.0, v_aling => 'top', h_align => 'right'); TEXT->create( name => 0, string => $h{ a2} . " at " . Spectra::gmup( $h{a2}) , y => 1.05, x => 1.0, v_aling => 'top', h_align => 'right'); # # it is important to create a SCAN named scan_name because # it helps Online to keeps track of the scan numbers # $h{ scan_name} = SCAN->create( name => $scan_name, np => $np_total); # # allocate space for the counter readings # foreach my $c ( @{ $h{ counters}}) { $h{ $c} = SCAN->create( name => $scan_name . "_" . $c, title => $c, colour => 'blue', np => $np_total); } # # allocate space for the sample time # $h{ st} = SCAN-> create( name => $scan_name . "_sample_time", title => "Sample Time", colour => 'blue', np => $np_total); $h{ scan_name}->deactivate(); Spectra::display( vp => 1); $status = 1; finish: return $status; } # # this function is called for each stop # sub exec_during { my ( $index) = @_; my $status = 0; repeat: # # get the current position ... # my $pos = GS::get_position( "a1"); # # ... and store it # $h{ scan_name}->{ x}[ $index] = $pos; $h{ sample_time} = $Spectra::SYM{ sample_time}; if( $h{ sample_time} <= 0.) { Spectra::error( "exec-during: sample time: $h{ sample_time}"); goto finish; } Spectra::reset_all_counters(); if( $Util::db_h{ flag_automatic_beamshutter}) { my $t = $Util::db_h{ timer_scan}; $Util::db_h{ timer_scan} = $h{ timer}; $status = Util::was_injection(); $Util::db_h{ timer_scan} = $t; if( !$status) { goto finish; } } else { if( !Spectra::start_and_wait_for_timer( $h{ timer}, $h{ sample_time})) { goto finish; } } # # loop over the counters # foreach my $c ( @{ $h{ counters}}) { $h{ $c}->{ x}[ $index] = $pos; $h{ $c}->{ y}[ $index] = Spectra::rc( $c)/$h{ sample_time} - $h{ "offset_$c"}; } # # store the sample time # $h{ st}->{x}[ $index] = $pos; $h{ st}->{y}[ $index] = $h{ sample_time}; Spectra::autoscale(); Spectra::display(); $status = 1; # # the after file needs to know the final scan position # $h{ stop_position} = GS::get_position( "a1"); finish: return $status; } # # this function is called once after the scan # sub exec_after { my $status; my $scan_name = $h{ scan_name}->get( "name"); # # prepare the command lines # $h{ scan_name}->set( com_1 => $h{ a1} . "-Scan started at " . $h{ start_time} . ", ended " . Spectra::time()); $h{ scan_name}->set( com_2 => "Name: $scan_name from " . $h{ start_position} . " to " . $h{ stop_position} . ", sampling " . $h{ sample_time} . "s"); $h{ scan_name}->set( com_3 => $h{ a2} . " at " . GS::get_position( "a2") . ", " . $h{ a3} . " at " . GS::get_position( "a3")); $h{ scan_name}->set( com_4 => "Counter reading are offset corrected, the offsets are"); my $line = ""; foreach my $c ( @{ $h{ counters}}) { $line .= "$c " . $Spectra::SYM{ "scan_offset_$c"} . " "; } $h{ scan_name}->set( com_5 => $line); $status = Spectra::gra_command( "write/fio/scan/motors $Spectra::SYM{ scan_name}"); # # create log file # open( FH, ">${scan_name}.log"); print FH " Scan name ${scan_name}\n"; print FH " User $ENV{ USER} \n"; print FH " Start $Spectra::SYM{ start}\n"; print FH " Step $Spectra::SYM{ delta} \n"; print FH " Stop $Spectra::SYM{ stop} \n"; print FH " Sample time $Spectra::SYM{ sample_time} \n"; print FH " Started " . $Util::res_h{ start_time} . "\n"; print FH " Ended " . Spectra::date_and_time() . "\n"; print FH " Offset C3 " . $Spectra::SYM{ scan_offset_c3} . "\n"; print FH " Offset C4 " . $Spectra::SYM{ scan_offset_c4} . "\n"; print FH " Offset C5 " . $Spectra::SYM{ scan_offset_c5} . "\n"; print FH " Offset C8 " . $Spectra::SYM{ scan_offset_c8} . "\n"; if( defined( $Scan::menu_h{ w_comment})) { print FH " Comment " . $Scan::menu_h{ w_comment}->get() . "\n"; } close( FH); return $status; }