Using Inline::SLang with CIAO
The following code and examples can be found in the Inline::SLang distribution available from CPAN. The output was created using version 1.00 of the module, using the PDL support, together with the S-Lang library from CIAO 3.2.
What is CIAO?
The CIAO software system is designed to help Astronomers analyse X-ray data from space-based telescopes such as Chandra and XMM-Newton. It includes support for scripting by emedding the S-Lang programming language, as highlighted in the S-Lang threads section. The most-obvious place where this is seen in the system is with Sherpa, CIAO's modelling and fitting tool. If you would like to take advantage of this increased flexibility but using Perl - rather than S-Lang - then this page is for you!
The following examples show how you can use the S-Lang modules from CIAO from Perl using Inline::SLang. See the main page for more examples of embedding S-Lang code into your Perl scripts.
Using the CALDB module
The CALDB library is one of the CIAO libraries that have been made available to S-Lang. To access the functionality all you have to do is add an require("caldb"); statement to your S-Lang script.
Well, now you can access it from Perl too:
use Inline 'SLang' => 'require("caldb");'; # Set up the CALDB query my $infile = "/data/dburke2/data/Chandra/CIAO/code/perl-slang/evt2_3.fits"; my $cal = calCreateInfo($infile); calSetExpression( $cal, "cti_corr.eq.yes" ); calSetData( $cal, "FEF_PHA" ); # See what's in the $cal structure print "The contents of the $cal object are:\n"; calPrintInfo($cal); print "\n"; # Now find the file matching the CALDB query my $file = calFindFile( $cal ) or die "Error: unable to find the FEF_PHA file\n"; print "The FEF_PHA file (with CTI_CORR=yes) is\n$file\n\n";
which, when run, produces
The contents of the Caldb_Type object are: Telescope: CHANDRA Instrument: ACIS Detector: ACIS-01236 Filter: - Start-Date: 2000-02-27T03:25:15 Start-Time: 03:25:15 Expression: cti_corr.eq.yes Data: FEF_PHA The FEF_PHA file (with CTI_CORR=yes) is /soft/ciao/CALDB/data/chandra/acis/cpf/fefs/acisD2000-01-29fef_pha_ctiN0004.fits[FUNCTION]
Note that the Inline::SLang module knows nothing about the CALDB module other than it was told to load it into S-Lang. Everything just happens "magically".
Using the REGION module
The following is very similar to the previous example; this time we take advantage of the S-Lang interface to the CIAO region library. We also define our own function, in part to show an alternative way of defining S-Lang code using the __SLang__ marker.
# Since no code is specified on the 'use Inline' line we look for # the __SLang__ block at the end of the file # use strict; use Inline 'SLang'; # regParse() in S-Lang returns a S-Lang variable with a type of Reg_Type. # This value is automatically converted into a Perl object of class Reg_Type. # my $reg = regParse("circle(100,200,50)"); print "S-Lang's regParse() returned [$reg]\n"; print "which is a " . ref($reg) . " object\n"; print "and whose area is " . regArea($reg) . "\n"; print " (pi * 50^2 is " . 4.0*atan2(1.0,1.0)*50*50 . ")\n"; does_slang_agree($reg); __END__ __SLang__ % Anything after the __SLang__ marker is S-Lang code % load in the region routines require("region"); % and define a somewhat pointless routine define does_slang_agree(in) { if ( typeof(in) != Region_Type ) verror( "Error!" ); vmessage( "S-Lang was sent a Region_Type variable with an area of %.11f", regArea(in) ); }
which outputs
S-Lang's regParse() returned [Region_Type] which is a Region_Type object and whose area is 7853.98163397447 (pi * 50^2 is 7853.98163397448) S-Lang was sent a Region_Type variable with an area of 7853.98163397447
The Region_Type object returned to Perl (i.e. the thingy stored in the $reg variable) is something that has been defined by the region module. Since there is no way for Inline::SLang to know what the contents of such a variable are, all you can do is call S-Lang functions with it as an argument (as shown in the calls to regArea and does_slang_agree). Fortunately that is all that you need to do with it.
Sherpa: using S-Lang
In this example we use S-Lang to set up the data, model, and perform the fit. The only time we use Perl is to read the best-fit parameter results - via get_par() - and then display them. This apporach should be compared to that used in the next example.
# # Set up everything in S-Lang code and execute it from Perl # use strict; use Inline 'SLang'; # access the fit results from Perl # print "Now in perl\n"; my $res = get_par ("ptest"); print "Fit results:\n"; foreach my $par ( @{$res} ) { printf " parameter: %-15s ", $$par{name}; if ( $$par{frozen} ) { printf "[frozen at %g]\n", $$par{value}; } else { printf "value = %g\n", $$par{value}; } } __END__ __SLang__ require ("sherpa"); % The sin(x) term is just to make sure the values % do not exactly match a polynomial. % print ("Setting up a model"); variable x = [1:80:2] * 0.1; variable y = -10.5 - 2.5 * x + 4 * x^2 + sin(x); variable e = abs (y) * 0.1; () = set_axes (1,x); () = set_data (1,y); () = set_errors (1,e); print ("Setting up a model"); () = create_model ("polynom1d","ptest"); () = set_par ("ptest.c0", "thawed", 1); () = set_par ("ptest.c1", "thawed", 1); () = set_par ("ptest.c2", "thawed", 1); () = set_source_expr (1, "ptest"); print ("Fitting the model"); () = run_fit (1);
which, when run, produces
Abundances set to Anders & Grevesse Setting up a model Setting up a model Fitting the model Now in perl Fit results: parameter: ptest.c0 value = -10.0887 parameter: ptest.c1 value = -1.89079 parameter: ptest.c2 value = 3.82745 parameter: ptest.c3 [frozen at 0] parameter: ptest.c4 [frozen at 0] parameter: ptest.c5 [frozen at 0] parameter: ptest.c6 [frozen at 0] parameter: ptest.c7 [frozen at 0] parameter: ptest.c8 [frozen at 0] parameter: ptest.offset [frozen at 0]
Sherpa: using Perl
In this example we load the Sherpa module but then use it directly from Perl. This apporach should be compared to that used in the preceeding example, which did most of the work in the S-Lang code.
# # Do everything from Perl (requires PDL) # use strict; use PDL; use Inline SLang => 'require ("sherpa");'; print "Now in perl\n"; # The sin(x) term is just to make sure the values # do not exactly match a polynomial. # print "Setting up a model\n"; my $x = 0.1 * (1+2*sequence(40)); my $y = -10.5 - 2.5 * $x + 4 * $x**2 + sin($x); my $e = abs($y) * 0.1; set_axes (1,$x); set_data (1,$y); set_errors (1,$e); print "Setting up a model\n"; create_model ("polynom1d","ptest"); set_par ("ptest.c0", "thawed", 1); set_par ("ptest.c1", "thawed", 1); set_par ("ptest.c2", "thawed", 1); set_source_expr (1, "ptest"); print "Fitting the model\n"; run_fit (1); my $res = get_par ("ptest"); print "Fit results:\n"; foreach my $par ( @{$res} ) { printf " parameter: %-15s ", $$par{name}; if ( $$par{frozen} ) { printf "[frozen at %g]\n", $$par{value}; } else { printf "value = %g\n", $$par{value}; } }
which, when run, produces
Abundances set to Anders & Grevesse Now in perl Setting up a model Setting up a model Fitting the model Fit results: parameter: ptest.c0 value = -10.0887 parameter: ptest.c1 value = -1.89079 parameter: ptest.c2 value = 3.82745 parameter: ptest.c3 [frozen at 0] parameter: ptest.c4 [frozen at 0] parameter: ptest.c5 [frozen at 0] parameter: ptest.c6 [frozen at 0] parameter: ptest.c7 [frozen at 0] parameter: ptest.c8 [frozen at 0] parameter: ptest.offset [frozen at 0]