Jump to: main text

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]