Jscript Tutorial
Jscript Tutorial
I Introduction 4
1 What is JScript? 5
6 Programming in JScript 15
6.1 Data Types and Type Conversion . . . . . . . . . . . . . . . . . . . . . . . . . 15
6.2 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6.2.1 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.3 Program Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.3.1 if..else-statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.3.2 for-Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6.3.3 for..in-Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.3.4 while-Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.4 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1
7.5 DoasCore.Spectra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.5.1 DoasCore.Spectra.ISpectrum . . . . . . . . . . . . . . . . . . . . . . . 29
7.5.2 DoasCore.Spectra.Specbar . . . . . . . . . . . . . . . . . . . . . . . . . 29
7.6 DoasCore.Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
7.7 DoasCore.HMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
7.7.1 Progress Bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
7.8 System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
7.9 System.Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
7.10 System.Windows.Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
7.11 System.IO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
7.12 System.Threading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
11 Evaluating spectra 55
11.1 Offset and Dark Current Correction . . . . . . . . . . . . . . . . . . . . . . . 55
11.2 Offset and Dark Current Correction with a “JScript project file” . . . . . . . 56
11.2.1 Preparation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
11.2.2 The “project file“ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
11.2.3 The file variables.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
11.2.4 The file functions.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
11.2.5 The file maincorrect.js . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
11.3 Fitting with JScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
11.4 Modifying a fit scenario with JScript . . . . . . . . . . . . . . . . . . . . . . . 59
11.5 Save the residual of the fit result . . . . . . . . . . . . . . . . . . . . . . . . . 62
2
12 Advanced JScripts 65
12.1 Write spectrum data to an Excel-Sheet . . . . . . . . . . . . . . . . . . . . . . 65
12.1.1 A word on ActiveXObjects . . . . . . . . . . . . . . . . . . . . . . . . 66
12.2 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
12.3 Evaluate data with a fit scenario file . . . . . . . . . . . . . . . . . . . . . . . 69
12.4 Automatized scanning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
12.5 Threading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
12.6 Controlling Mini-MAX-DOAS (MiniDOAS) instruments with JScript . . . . . 73
12.6.1 Structure of the program . . . . . . . . . . . . . . . . . . . . . . . . . 73
12.6.2 Description of the tasks . . . . . . . . . . . . . . . . . . . . . . . . . . 74
12.6.3 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
12.6.4 Remarks: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
13 Literature 85
Index 86
3
Part I
Introduction
4
Chapter 1
What is JScript?
JScript is a script language which can be used within an application. In DOASIS, this makes
possible to automatize measuring and evaluating data. For example, let’s say you want to
record a huge number of spectra, and you want to adjust the parameters (e.g. the angle)
after each measurement. Since you don’t want to start a new measurement every 5 minutes,
you can use a script which tells DOASIS what measurements to make.
A script language is a programming language, but you are not able to write executable
programs with them. Instead, the scripts are started from the program for which the script
was written. Scripts are not compiled, but interpreted. That means, the script is not at
once translated to machine language and then executed, but read and executed line by line.
Resources that your script makes use of (namespaces, objects) are precompiled.
In DOASIS, everything that you need concerning scripts can be found in the Console-
Window. More precisely, there are four tabs: the Output-, the Script-, the Mini Scrips- and
the Quick Script-Tab.
A script can be started from the Script-Tab in the Console-Window (by specifying the file
in which the script is stored) or by entering a script in the Mini-Script-Tab. The output
that is generated by the Script can be viewed in the Output-Tab.
5
Figure 1.1: The main application window of the graphical user interface part DoasUI.
6
Chapter 2
If you are fairly good at programming and you know Java or JavaScript, this is not for you.
In fact, JScript could also be called the ”Mircosoft JavaScript”. There quite a lot similarities,
although Microsoft emphasizes that the technology behind JScript is very different from the
JavaScript by Netscape.
But if you are a poor programmer, or even never learned programming, but still want to
use all the great possibilities of DOASIS-JScript without bothering too much on aspects of
programming in general, then this is written for you! Here you will learn just what you need
to write JScripts in DOASIS.
Maybe you have experience with other script languages like VBA (”Visual Basic for Ap-
plications”). But this will be little help, since JScript has a different syntax, orientated at
C/C++. I would recommend to read this anyhow, since there is a lot DOASIS-specific to
learn about.
7
Chapter 3
The Tutorial is split into two parts. In part II, the basic features of JScript and its use
in DOASIS are explained. This is more a general overview and interesting for people, who
have non or only very little programming experience. If you already have a general idea
about programming it is recommended to skip Part II and continue directly with Part III.
Part III consists of a selection of practical source code examples, which have been or are
still in use by different working groups which use DOASIS for measurement and evaluation
purposes. The code examples are explained in a way which can be easily understood and
the important commands are commented out.
The code examples can be ”copy-pasted” directly from your pdf-Reader program (e.g.
Adobe Acrobat Reader) to a text editor, then saved with the suffix ”.js” and opened within
DOASIS in the sheet ”Script” of the ”Console window”. If the programs are very short,
than it might be more convenient to ”copy-paste” them directly into the ”Mini Scripts”
sheet of the console window and press ”Start”. (See as well 5.3)
To get fast access to the commands you are looking for, take advantage of the Index,
that will guide you to the requested sections.
8
Chapter 4
Save this file for example under C:\startscript.bat. By double clicking on the batch file
9
the DoasConsole of DOASIS is started by C:\Programme\DOASIS\DoasConsole.exe and
jscript1.js (stored in C:\scripttest\jscript1.js) is executed. The command >>C:\logfile1.txt
is optional. It stores the output of the program, which is usually displayed in the Output-
Tab of DOASIS in the file C:\logfile1.txt. In case the output is stored in a file, it is not
shown while the program is executed. The suffix “.bat” is the identifier for the “batch”-file.
A batch file contains DOS commands which are executed successively.
Warning:
Make sure that the path name does not contain blanks since DOS does not support them.
Several JScript can be successively run simply by adding more lines to the batch file:
10
Part II
11
Chapter 5
import System;
System.Console.WriteLine("Hello World!");
If you switch to the Output-Window, you’ll see the result. Congratulation to your first
JScript! But how did it work? There are some remarks I want to make here:
• First of all, we ”imported” the ”System”. This just means that we will make use of
certain functions made available by a ”namespace” (a kind of library) by that name.
Later on, we will import other namespaces, which will be then specific to DOASIS.
How else should the interpreter know how to deal with DOASIS-specific commands?!?
• In both commands, we had to finish the line with a semicolon. This is important,
because this tells the interpreter when a command ends. You could put the whole code
into one line, and the interpreter would still get it right because of the semicolons. But
never forget the semicolons, because this most certainly will produce an error!
12
need to mention all the names because there could be a WriteLine-method as part of another
object with different name. The interpreter wouldn’t find the method otherwise. This is all
about object-orientation so far. Wasn’t that difficult, right?
import System;
import DoasCore.Spectra;
var Filename;
Filename = Specbar.CurrentSpectrum.Name;
System.Console.WriteLine(Filename);
Then save it as a ”filename.js”. Notice that ”.js” is the file extension for JScript. Now
you need to specify the file (with the whole path) at the Script-Tab. Alternatively you can
browse the file. Before you start the script, open your favorite spectrum in DOASIS. Now
please start the script. As you can see in the Output-Tab, the script returns the name of
your spectrum. So let us learn some new things from the script:
• This time, we not only imported the System, but also the DoasCore.Spectra names-
pace. In this namespace all the objects and methods are defined that deal with spectra.
• Then we defined a variable. In other program languages, you need to worry a lot
about different types of variables, not so in JScript!!! In the declaration of a variable,
no difference is made between integers or floats or strings. All you need to do is to
tell that you want to declare a variable. This is done by the var command. In our
script, we declared the variable ”Filename”, which is an arbitrary name and you could
have used (almost) anything else. Unfortunately, sometimes you need to worry about
types nevertheless. Once a variable contains data of a certain type (we assigned a
string to ”Filename”), you can only use it as a different type later on if a so-called
type-conversion is possible. We will come back to this point later on.
• Look what we did next: we assigned a value to our new defined variable, more precisely
the name of the current spectrum in the Specbar, i.e. the spectrum that you just
opened before starting the script. Assigning a value to a variable is pretty simple: just
use a =. The right side is then assigned to the left side. The left side therefore always
has to be a variable, the right side can also be a constant, an explicit expression (like
a number) or a more complicated algebraic expression, a string, or an array. We will
see other examples later on.
• Last, we just wrote the value of our variable in the output. And indeed, it is the name
of your spectrum, as it should.
Hint: Scripts can also be started from the sheet ”Mini Scripts” of the
”console window”. Advantage: this is faster.
13
5.4 The syntax
So far, we have already learned that every command has to be completed with a semicolon.
There are other syntax rules, i.e. rules that specify how a script should be written in order
to be understood by the interpreter. We will discuss them by looking at the next example:
import System;
import DoasCore.Spectra;
var ABCDEFGH;
var abcdefgh;
var aBcDeFgH;
var A123;
/* the text between the stars
will be ignored */
Filename = Specbar.CurrentSpectrum.Name;
System.Console.WriteLine(Filename)
• The script starts with a so-called comment, something that the interpreter will ignore
since it appears after the comment-symbol ”//”. Comments that shall extend over
several lines, are put between ”/*” and ”*/”.
• It is important that all import-commands are put at the beginning of the script.
14
Chapter 6
Programming in JScript
This part of the introduction into the more general aspects of programming in JScript,
concerning data types, operators, loops, for-blocks, if-blocks, and more, aims to give you
a basic idea of the structure of typical JScripts. Most of the commands are identical to
the Java or C/C++ language. If you never came in touch with one of those programming
languages, you might also want to consult other learning materials as given in the literature
below to learn about details which can not be covered here. Here, you will find the essentials
that enable you to write powerful JScripts.
In short, data types are specifications of how to handle variables. The interpreter needs to
know how much memory he shall reserve for the data, and what can be done with these.
For example, the data type integer is of size 32 bit, and you can add, subtract, multiply
and divide (with rest) integers. By doing so, another integer is produced. Different data
types differ in memory, in how they are interpreted, and in what can be done with them.
As another example, strings cannot be added like numbers, but linked, which is also done
by the +. Here is a list of data types available in JScript:
To understand the difference between typed and untyped variables, let’s compare the fol-
lowing scripts:
import System;
var s = 3;
s=s+5;
Console.WriteLine(s);
s = "I’m not an integer!";
Console.WriteLine(s);
15
Data Type Description Example
char a single character, var c: char = ’a’;
enclosed in single quotation marks
String a sequence of characters, var s: String = "Hello";
enclosed in double quotation marks
int a 32-bit integer value, ranging var i: int = 1;
from -2.147.483.648 to 2.147.483.647
uint a unsigned 32-bit integer, var i: uint = 1;
ranging from 0 to 4.294.967.295
boolean a boolean value that is var b: boolean = false;
either true or false
double floating point number of var d: double = 0.123;
double precision (about 15 digits)
Date object representing var date: Date =
a date and time definition "10/08/2003 15:45";
import System;
var s: int = 3;
s = s + 5;
Console.WriteLine(s);
s = "I’m not an integer!";
Console.WriteLine(s);
The first script will work perfectly, whereas the second script will produce the error ”Type
mismatch”.
Why then should it be useful to use typed variables if they just produce more errors? The
answer is: typed variables are less confusing and protect you against misuse. Look at these
examples:
import System;
var s = 5;
s = "I’m a string!";
s = s + 3;
Console.WriteLine(s);
16
import System;
var s: int = 5;
s= "I’m a string!";
s = s + 3;
Console.WriteLine(s);
import System;
var i;
Console.WriteLine( "Value of i: " + i);
Console.WriteLine( "Value of 2*i: " + 2*i);
6.2 Operators
You already know mathematical operators such as +,-,*,/. In a programming language,
they can indeed be used to add/multiply numbers (such as integer, double), but there are
also other usages. As we have already seen, you can also connect two string variables to one
string with the +. But there are some more operators that we have to learn about.
17
Here is a list of the available operators:
Operator Description
. [] () member access, array access, function call
++ – - ! unary operators
typeof new void specify return type, object instantiation, undefined value
*/% multiplication, division, modulo-division
+-+ addition, subtraction, string concatenation
<< >> >>> bit-shift
< <= > >= smaller as, smaller or equal, greater as, greater or equal
== != equality, inequality
&& logical AND
|| logical OR
& bit-wise AND
^ bit-wise XOR
| bit-wise OR
?: conditions
= += -= *= /= assignment (also with operators)
, multiple evaluation
import System;
Output:
”a And b = false”
”a OR b = true”
6.3.1 if..else-statements
The if..else statement is used to split the flow of your program in two or more branches.
Usually, the value of a variable is compared to a certain constant value, and depending on if
the comparison holds or not, different code is executed. Let’s start with a simple example:
18
import System;
var i=Math.random();
if (i<0.5) Console.WriteLine("This number " + i + " is smaller than 0.5");
else Console.WriteLine("This number " + i + " is larger than or equals 0.5");
Here, the code following the if-condition is executed if the condition is true, and the code
following the else-statement is executed if the statement is false. This is what you should
notice:
• the if-clause here only consists of one command. It has to be closed by a semicolon
• the else-clause also only consists of one command and has to be closed by a semicolon
What if we have more than two cases? Here another example that illustrates this point:
import System;
var i=Math.random();
if (i<0.5) Console.WriteLine("This number " + i + " is smaller than 0.5");
else if (i>0.5) Console.WriteLine("This number " + i + " is larger than 0.5");
else Console.WriteLine("This number " + i + " equals 0.5");
What if you have more than one command that you want to execute in an if- or else-block?
Simply put them between braces as the next example illustrates. This can also be done in
other contexts, for example in loops, as we will see later.
import System;
var i=Math.random();
if (i==0.5) {
Console.WriteLine("This number " + i + " equals 0.5");
Console.WriteLine("Isn’t that a nice result?");
}
else {
Console.WriteLine("This number " + i + " is not equal to 0.5");
Console.WriteLine("Sorry, can’t tell you if < 0.5 or > 0.5.");
}
19
Warning: Always remember that equality-comparisons are done by ”==”,
not ”=”. If you use ”=”, there will not be an error as long as the right-hand
side can be assigned to the left-hand side. So you have to be careful.
6.3.2 for-Loops
The for-loops allow to repeat a command or block of code for a certain time. Usually, a
counter is counted up until a certain condition does not hold any more. Here is an example:
import System;
var i;
for (i=1;i<10;i++) Console.WriteLine("This is the " + i + ". line.");
• After the for-command, which opens the for-loop, there is a loop-header consisting of
three statements, which are separated by semicolons.
• The first statement in the parenthesis is the initializing command. It is executed only
once, just before the loop is entered. Usually, the loop variable (here: i) is set to a
certain value.
• The second statement is a boolean expression. The loop is (re)entered only if the
boolean expression is true. Usually, the loop variable is compared to a certain value
which it shall not exceed.
• The third statement is a command that is executed every time the loop was swept.
Usually, the loop variable is incremented here.
• The loop itself, the command that is executed several times, follows the loop-header.
If you use more than one command, make a block with braces.
20
6.3.3 for..in-Loops
import System;
6.3.4 while-Loops
The while-loops are similar to the for-loops, but the header of the while loop has no section
for initializing and no section for incrementation, but just the section for a comparison,
the while-condition. This of course only makes sense if the while-condition changes during
sweeping the while-loop. Here is an example:
import System;
6.4 Functions
In JScript it is possible to declare classes functions. A function is a piece of code that
is encapsulated and can be executed by calling the command under which the function is
defined. This has the advantage that code which is used in several places of the script has
only to be written once. For the declaration of classes see section 12.5.
Here is an example that calculates the factorial n! of the number n.
21
import System;
function factorial(n)
{
var i;
var f=1;
for (i=1;i<=n;i++) f=f*i;
return f;
}
Console.WriteLine(factorial(8));
The types of the parameters and the return parameter are not specified in the declaration
of the function (contrary to C/C++/C#). If your function shall not return anything, just
omit the return line. If your function takes no parameters, leave the brackets empty, but do
not forget the empty brackets ().
22
Chapter 7
Important DOASIS-namespaces
and their usage
7.1 Overview
All the DOASIS functionality is entailed in the DoasCore. There are six namespaces of inter-
est, which need to be imported in order do use its classes (i.e. objects and methods). These
are DoasCore.Math, DoasCore.Device, DoasCore.IO, DoasCore.Spectra, DoasCore.Script
and DoasCore.HMI. (compare Fig. 7.2).
We will also discuss some namespaces and classes that are offered by the .NET frame-
work, such as the System.Console that we already know from making outputs, the Sys-
tem.Windows.Forms which is useful to design forms like message boxes or dialogs (e.g. to
enter paramters), and the System.IO namespace that is used for file handling (compare Fig.
7.1). A complete list of all namespaces can be found here:
http://msdn2.microsoft.com/de-de/library/ms306608(vs.80).aspx
System
Windows IO Threading
Forms
Sp2File
Figure 7.1: The System namespaces and its classes (incomplete - only most common classes
listed)
23
DoasCore
JulianDateTime
Figure 7.2: The Doasis namespaces and its classes (incomplete - only most common classes
listed)
24
7.2 DoasCore.Math
In this namespace you will find all kinds of mathematical operations provided by Doasis.
The classes that you can make use of are:
7.2.1 DoasCore.Math.SpecMath
The first step in the evaluation of a recorded spectrum is to correct it: Offset and Dark
current have to be subtracted. This can be done at once to a great number of spectra by
using a JScript. Here, we are just interested in the method that is used to do the correction,
so for simplicity we suppose that the spectrum that shall be corrected and the offset- and
dark current-spectrum are loaded into the specbar.
import DoasCore.Spectra;
import DoasCore.Math;
SpecMath.CorrectOffset(Meas,Offset);
SpecMath.CorrectDarkCurrent(Meas,Dunkel);
In this example, ”Offset” and ”Dunkelstrom” are the object keys of the spectra by which
they can be identified. The methods CorrectOffset and CorrrectDarkCurrent are member
of the SpecMath class. To see more examples, read the glossary of the Doasis Tutorial.
25
function CalcSZA(Spectr)
{
var Julian = new JulianDateTime();
Julian = new JulianDateTime(Spectr.StartDateAndTime);
if (S.CalculateSZA()) return(S.SZA);
}
7.2.3 DoasCore.Math.DoasFit
With the class DoasCore.Math.DoasFit one is able to construct fit-scenarios and start fit
procedures. Here is an example of how to do fit-scenarios (how to evaluate data with fit
scenarios in JScript is shown in section 12.3).
26
import DoasCore;
import DoasCore.Spectra;
import DoasCore.Math;
import DoasCore.IO;
Frauenhofer.Open(Path + FrauenhoferFile);
Ring.Open(Path + RingFile);
O3223.Open(Path + "Ozon\\Ozon223Gefaltet.sp2");
O3246.Open(Path + "Ozon\\Ozon246Gefaltet.sp2");
Warning: If you want to describe the path of a file in JScipt you have to
use two ”backslashes” instead of one.
e.g. ”C:\\Fitszenarios\\Ozon\\Ozon223Gefaltet.sp2”
7.3 DoasCore.Device
The DoasCore.Device namespace contains classes for each of the supported devices, and
general interfaces. The most common are:
27
• DoasCore.Device.Acton: another spectrograph often used
Here is an example how to perform one scan with the Ocean Optics Spectrograph:
import DoasCore;
import DoasCore.Spectra;
import DoasCore.Device;
var NScan = 1000; var ExpTime = 1; var MiniDoas : OceanOptics = new OceanOptics();
var Spec1 : ISpectrum = Specbar.GetSpectrum("Offset1");
MiniDoas.Scan(Spec1,NScan,ExpTime);
Note that the Scan method is not only a member of the OceanOptics class in the Doas-
Core.Device namepace, but also of the Acton class and the interface class ISpectograph,
from which all specific spectographs inherit members. The parameters of the Scan method
are the name of the spectrum in which the measuremen shall be stored, the number of scans
that shall be performed, and the exposure time for each scan. The Properties NumScans
and ExposureTime are also members of all devices.
Hint: Using the generic class Spectrograph allows to scan without the
need to know the exact hardware used.
7.4 DoasCore.IO
The DoasCore.IO namespace is used for handling the input and output of Doas-specific data,
most importantly spectra.
7.5 DoasCore.Spectra
This namespace is used to manage a set of spectra. The important classes are:
28
7.5.1 DoasCore.Spectra.ISpectrum
The most important object here is the ISpectrum object. For example, one can modify the
current spectrum with it. Here is an example of a function that searches the peak of a
spectrum:
import System;
import DoasCore.Spectra;
function SetMarkerToPeak()
{
Spec.Marker = Spec.MinChannel;
while(Spec.MarkerValue < Spec.Max) Spec.Marker++;
System.Console.WriteLine("Peak bei Kanal : " + Spec.Marker);
}
SetMarkerToPeak();
There are quite a lot members in the ISpectrum object: Marker, MinChannel, MaxChannel,
MarkerValue, and many more (ObjectKey, FileName, StartTime, StopTime, AzimuthAngle,...)
To each property in the property tab of a spectrum there is a member in the ISpectrum
class that can be used in a JScript. A complete list can be found in the Programming
Documentation in the ”help”-menu of DOASIS. Just search for ”ISpectrum”!
7.5.2 DoasCore.Spectra.Specbar
The specbar contains the object Specbar.CurrentSpectrum. This allows to access data of
the current spectrum (the one that is displayed in the main window). Here is an example
that sets the coefficients of the calibration polynomial (which assigns wavelength info to the
channels):
import Doas.Core;
import DoasCore.Spectra;
Spec1.CalibPolynomialOrder = 2;
Spec1.CalibPolynomial[0]= 297.51431;
Spec1.CalibPolynomial[1]= 0.12086;
Spec1.CalibPolynomial[2]= -9.60429e-6;
Spec1.SaveAs("modified");
Spec2.ExposureTime= 10000;
Spec2.SaveAs("modified2");
Specbar.CloseAllSpectra();
29
The Spectrum-class also contains methods to open and save (used above) the spectrum
directly without the need to use the DoasCore.IO.SpectrumFile class.
7.6 DoasCore.Script
The DoasCore.Script-namespaces helps to handle scripts. Especially important is the prop-
erty StopScript and StopAllScripts, which signalize when a script was stopped by the user,
and the methods SuspendScript() and ResumeScript(). They are illustrated in the script be-
low, which optimizes the exposure time according to the counts given by the range between
MinCount and MaxCount.
import System;
import DoasCore;
import DoasCore.Spectra;
import DoasCore.Math;
import DoasCore.Device;
import DoasCore.IO;
import DoasCore.Script;
while(!Script.StopAllScripts) {
MiniDoas.Scan(OptSpec,1,ETime);
var Faktor : Double = OptSpec.Max/MaxCounts;
//******************* too few counts ***********************
while( (OptSpec.Max< MinCounts || OptSpec.Max > MaxCounts)
&& !Script.StopAllScripts) {
ETime = parseInt(ETime/Faktor);
if (ETime > 60000) {
ETime = 60000;
}
Console.WriteLine("Exposure Time = " +ETime );
Console.WriteLine("Maximimum = " + OptSpec.Max);
MiniDoas.Scan(OptSpec,1,ETime);
Faktor = OptSpec.Max/MaxCounts;
}
Console.WriteLine("Optimization finished. Exposure Time = " + ETime);
Console.WriteLine("Maximum : " + OptSpec.Max);
}
30
7.7 DoasCore.HMI
The DoasCore.HMI namespaces (Human Machine Interface) can be used to simplify the
interaction between your JScript and the user. The most common used classes are:
import System;
import DoasCore;
import DoasCore.HMI;
var i;
for (i=0;i<100;i++)
{
doCalculation();
Bar.Value++;
}
The function doCalculation() is not defined here, but can be considered a calculation that
has to be done a couple of times.
7.8 System
The System namespace and all its subnamespaces are provided by the .NET Framework.
All its classes are also available in programing C++ or C# in the Visual .NET Framework.
Since they are not part of Doasis, I will just give a few examples and refer you to the very
extensive guide to the .NET framework on the web (see last chapter for addresses).
7.9 System.Console
We already used the WriteLine() method a lot. But there is more functionality of the
System.Console namespace.
You can also input data from the console:
31
import System;
Due to the concept of untyped variables, you can use the same command to read integers
or real numbers.
7.10 System.Windows.Forms
The most important and easiest form is the message box:
import System.Windows.Forms;
But there are plenty of other opportunities to design very personal forms including buttons
and check boxes and much more.
7.11 System.IO
The System.IO namespace contains classes that provide all kinds of input and output rou-
tines, such as serialization (which helps storing data of instants of classes). As an example
we will consider the TextWriter class, which can be helpful to save evaluation data of spectra
in plain text to files:
using System;
using System.IO;
StreamWriter sr = File.CreateText(filename);
sr.WriteLine ("I am the text in this file.");
sr.Close();
7.12 System.Threading
In the System.Threading namespace, the class thread allows to start more than one threads
to execute a portion of your program. A thread is a sequence of instructions. Multiple
threads allow parallel computing, comparable to multitasking of programs. For example
32
you could create two threads, one to measure data, another to do simple math like offset
corrections, etc. on all recorded spectra. A sample script about threading is explained in
section 12.5
33
Part III
Collection of JScript
applications
34
Chapter 8
Simple JScripts
The following programs are a collection of fairly simple JScripts, that build the basis for any
bigger program.
// The namespace "System" provides the most basic functions and should
// always be imported
import System;
import System;
35
The output will then be:
The type of the variable (integer, string,...) doesn’t necessarily have to be declared in
JScript. See section 8.11 Remarks.
var i;
Remarks
Alternatively, a “wait” function can be implemented in the following way:
import System;
import DoasCore.HMI;
36
8.4 Display message boxes
When conducting measurements it can be useful not only to display parameters in the Out-
put window but also to let appear message boxes, if something extraordinary happened. The
following example counts from zero to ten and displays the numbers in the Output window.
After each count there is a break of 300ms. After number 5 and number 10 a message box
appears.
import System;
// This namespace provides the "OldUI"-class which includes the message boxes
import DoasCore.HMI;
var i;
Remarks
• In that case, the “wait”-function of the “OldUI()”-class was chosen (see section 8.3)
since this class is used to display the message boxes as well.
• The “OldUI()”-class provides many more message boxes. Information about message
boxes can be found in the Programming Documentation of DOASIS (Help menu -
Programming Documentation) by searching for “OldUI”. See as well the script in
section 12.2.
37
import System;
// The namespace "System.IO" must be imported because it includes the class
// "Directory" which is needed to create a directory.
import System.IO;
Remarks
The class “Directory” of the“System.IO” namespace includes many more methods, e.g.
-“Directory.Delete()” to delete the path given in the brackets or
-“Directory.Exists()” which returns “true” if the path specified in brackets exists and “false”
in case it doesn’t.
var textfile
// create an object which enables to create a textfile
var dispFileSystem = new ActiveXObject("Scripting.FileSystemObject");
Remarks
• In this case no namespace has to be imported.
• For a quick description on ActiveXObjects, see section 12.1.1.
38
• The method dispFileSystem.OpenTextFile takes three arguments.
The first one is the path and the name of the text file, here "C:\text.dat"
The second one is a number, here “2”.
“2” means, that the file is for writing.
“1”: file is for reading only.
“8”: data is appended to file.
The third argument, here “true” means, that a new file is created, if the specified file
name does not exist. If “false” is used, the file is not created.
• In case you want to open the created file with the program “Origin”, the file should be
of the type “.dat”. With “\t”, a new column is started, with “\n”, a new line begins.
In “Origin”, it is very important that each line has the same number of columns.
39
// the System namespace provides access to date and time
import System;
// display CurrentDateTime
Console.WriteLine("Date and Time: "+CurrentDateTime);
Remarks
The program “Origin” only recognizes time data in the format hh:mm:ss. So make use of
this example if you want to store the time in a result file, which you later want to edit with
“Origin”.
40
import System;
var x = 123456789.123456789;
Remarks
The recommended option is:
x.ToString("g5")
It generally choses the best way of representing the number. The “5” does represent the
number of digits, but the “numbers” altogether.
For example: 4.3 has two “numbers”, 13.45 has four, 14.567 has seven, 1.23e+05 has 3 etc.
41
import System;
// The class "Spectra" of the namespace "DoasCore" is necessary to handle spectra
import DoasCore.Spectra;
// open an empty spectrum sheet with the name "Spectrum" and store it
// in the variable "Spec"
var Spec: ISpectrum = Specbar.GetSpectrum("Spectrum");
// load the spectrum "oldspec.sp2" in the empty sheet
Spec.Open("c:\\scripttest\\oldspec.sp2");
// save it as a new name
Spec.SaveAs("C:\\scripttest\\newspec.sp2");
Remarks
• If you handle spectra with JScript, they will always be of the type “ISpectrum”. It
will not be correct in the sense of informatics, but imagine it this way:
A whole number is of the type “integer”, a spectrum is of the type “ISpectrum”.
• The Programming Documentation in the Help menu of DOASIS shows all the mem-
bers, that are connected with the type “ISpectrum”. Many following examples will
make this clearer!
• In most cases we will deal with automatized opening and saving of large numbers of
spectra. Therefore we will make use of the class “AutoFileName()”.
42
import System;
import DoasCore.Spectra;
// IO stands for input/output operations
// AutoFileName is a class of the DoasCore.IO namespace
import DoasCore.IO;
– The method “Save” saves a Spectrum and then increases the “CurrentFileNum-
ber” counter by one.
43
that opens a single spectrum. The spectrum number is asked for in the Output window.
The demanded spectrum will be opened and some details of the spectrum like “Current-
FileNumber”, “ExposureTime” and “AzimuthAngle” are displayed in the Output window.
The spectra have to be stored in the folder C:\scripttest\S0000000. The spectra themselves
must have names like S0000000.sp2, S0000001.sp2, S0000002,.... This is the same structure
as how they are stored, when automatic measurements are taken.
import System;
import DoasCore.Spectra;
import DoasCore.IO;
var SpectrumNumber;
var Spec: ISpectrum;
// see section 8.10.1 for "AutoFileName"-class
var afn : AutoFileName = new AutoFileName();
afn.BasePath = "C:\\scripttest\\";
afn.Prefix = "S";
afn.Suffix = ".sp2";
afn.NumberOfDigits = 7;
afn.FilesPerFolder = 100;
// ask for the spectrum number in the Output window
Console.WriteLine("Open spectrum with the number:");
// store the number that is typed in the variable "SpectrumNumber"
SpectrumNumber = Console.ReadLine();
// add a new empty spectrum sheet to the "Specbar"
// the name of the spectrum is the spectrum number, that was specified before
Spec = Specbar.GetSpectrum(SpectrumNumber);
// the property "CurrentFileNumber" of the "AutoFileName" class
// is set to "SpectrumNumber"
afn.CurrentFileNumber = SpectrumNumber;
// open the spectrum with the demanded spectrum number into the empty
// Spectrum "Spec"
afn.Open(Spec);
// display some properties of the opened spectrum in the Output window
Console.WriteLine(
" Spectrum: "+SpectrumNumber+
" ExposureTime: "+Spec.ExposureTime+
" AzimuthAngle: "+Spec.AzimuthAngle);
Remarks
• Referring to the line
var Spec: ISpectrum;:
It would be enough as well to write
var Spec;
only. In JScript, the type of the variable doesn’t have to be declared most of the
times. But sometimes, it is useful to declare the type of the variable explicitly. See
8.14, where the variable “time” has to be of the type “System.DateTime”.
44
• If the script doesn’t open any spectrum when calling the line
afn.Open();
the problem often is a mistake in the declaration of the “AutoFileName” properties
(e.g. “BasePath”,“ Prefix”,...) and it is worth checking those very carefully.
In order to proof, if the problem is actually caused by the “afn.Open()” method, dis-
play the return value of this method in the Output window. The following command
can be placed in the script:
Console.WriteLine(afn.Open(Spec));
“True” is displayed if the file could be opened and “false” if not.
import System;
import DoasCore.Spectra;
// The spectrum in the active spectrum sheet is stored in the variable "MeasSpec"
var MeasSpec = Specbar.CurrentSpectrum;
Remarks
Other spectrum properties like StartDate, StartTime, ExposureTime, NumScans etc. can
be accessed in the same way. For a list of all spectrum properties search for “ISpectrum” in
the Programming Documentation of DOASIS (Help - Programming Documentation).
45
Figure 8.1: The property window of the spectrum.
import System;
import DoasCore.Spectra;
import DoasCore.IO;
// the method "FindFirstIndex()" returns the number of the first existing file
afn.CurrentFileNumber = afn.FindFirstIndex();
// open the first spectrum and increase the "CurrentFileNumber" by one
afn.Open(Spectrum1);
// open the next spectrum
afn.Open(Spectrum2);
// display the date and time, when the spectra were recorded
Console.WriteLine("Spectrum1: "+Spectrum1.StartDateAndTime);
Console.WriteLine("Spectrum2: "+Spectrum2.StartDateAndTime);
// check which spectrum has been recorded first
if (DateTime.Compare(Spectrum1.StartDateAndTime, Spectrum2.StartDateAndTime) > 0)
Console.WriteLine("Spectrum1 was recorded later than Spectrum2.")
else if (DateTime.Compare(Spectrum1.StartDateAndTime, Spectrum2.StartDateAndTime) == 0)
Console.WriteLine("Spectrum1 was recorded at the same time as Spectrum2.")
46
else
Console.WriteLine("Spectrum1 was recorded before Spectrum2.")
The output can look like this:
import System;
import DoasCore.Spectra;
import DoasCore.Math;
Remarks
• When “JulianDateTime” is called, it has to be made clear, that the argument time is
of the type “System.DateTime”, because another type would call a different routine.
In this case, “StartDateAndTime” of the spectrum is stored in the variable “time”,
then “time” is specified to be of the type “System.DateTime” and then delivered to
the class “JulianDateTime”, that afterwards returns the julian date.
47
8.14.1 A word on the class ScanGeometry
• This class offers calculations of solar and lunar zenith angle (sza, lza) and solar and
lunar azimuth angle (saz, laz).
• You can find the whole functionality of the class, if you search for ScanGeometry in
the Help menu of the Programming Documentation of DOASIS
λ = c0 + c1 · x + c2 · x2
import DoasCore.Spectra;
48
Chapter 9
Using JScript Project Files (jsp-files) to structure JScripts is very recommendable as it saves
a lot of work. Variables and functions are declared once in a separate JScript file and can be
used later on by simply calling these files in the JScript Project before the “main” JScript,
in which the actual task is defined.
A typical project file would look like this:
C:\\scripttest\\generally\\variables.js
C:\\scripttest\\generally\\functions.js
C:\\scripttest\\correct\\maincorrect.js
49
A specific example can be looked up in section 11.2
Remarks
• Old JScripts
If you use old JScripts for DOASIS that were programmed for an older version of
DOASIS, it might happen that the script won’t run if they use the dispTools-, dispIO
or other disp-Objects. These objects are not supported and replaced by equivalent
functions in newer DOASIS-Versions.
However, if you want to use these old scripts nevertheless, you can create a project file
referencing the ”system.js” and the old script. Then, also old scripts will run without
problems. But there is no guarantee.
50
Chapter 10
51
import System;
// namespace to access the serial port
import System.IO.Ports;
// namespace to abort the script by pressing the "Stop" button
import DoasCore.Script;
var signal;
// specify the properties of the port and the data transfer
var serial = new SerialPort();
serial.PortName = "COM5";
serial.BaudRate = 57600;
serial.DataBits = 8;
serial.Handshake = Handshake.None;
serial.Parity = Parity.None;
serial.StopBits = StopBits.One;
Remarks
• The output of the GPS used here consisted of a sequences of 6, which are continuously
produced:
GPRMC,135257.000,V,4925.0709,N,00840.4109,E,0.00,0.00,120608,,,N*78
GPGGA,135257.000,4925.0709,N,00840.4109,E,0,00,99.9,249.6,M,48.0,M,,0000*62
GPGSA,A,1,,,,,,,,,,,,,99.9,99.9,99.9*09
GPGSV,2,1,08,10,39,197,,27,15,070,,07,06,069,,18,09,324,*7B
GPGSV,2,2,08,15,53,298,,09,03,253,,19,07,027,,08,42,063,*7F
The first line starting with GPRMC provides information about time (13h 52min
57s UTC), latitude 49◦ 25.0709′ and longitude 8◦ 40.4109′ . For more information
search the internet for the NMEA (National Marine Electronics Association) standard
protocol.
• To extract specific characters out the lines, the command signal.Substring(x,y) can
be used. It provides part of the string “signal” which starts at a specified character
position x and has a specified length y.
52
Figure 10.1: Scan button (marked red) to record a spectrum manually.
import System;
import DoasCore.Spectra;
// the namespace "Device" enables the usage of external devices
import DoasCore.Device;
53
Remarks
• A new spectrograph object could be created as well like this:
var Spectrograph : OceanOptics = new OceanOptics();
The only difference to
var Spectrograph = new OceanOptics();
is that the “type” of the object is declared after the colon. However, creating the
object this way sometimes caused problems when trying to access the properties of the
measured spectrum. E.g. the measurement temperature of an Ocean Optics QE65000
spectrograph could not be retrieved.
1. Each of the two instances of DOASIS is connected to one of the spectrographs. So,
in each of these instances, choose the proper JScript for controlling the connected
spectrograph.
2. Make sure that these JScripts address the spectrographs by using the ”OceanOptics”
class (see example of section 10.2). In the JScript, create an object of this class and
assign to it the serial number of the connected spectrograph.
3. Now, you should be able to operate both spectrographs with the two JScripts at the
same time.
54
Chapter 11
Evaluating spectra
import Systme;
import DoasCore.Spectra;
import DoasCore.Math;
Remarks
• The offset correction will be done by subtracting the offset spectrum scan weighted.
The dark current correction will be done by subtracting the dark current spectrum
scan time weighted.
What is actually done in mathematical sense when calling the correction routines is
explained in detail in the DOASIS Tutorial, section 8.1.2: Spectrum Operations.
• Make sure that the dark current spectrum you use has already been offset corrected!
55
11.2 Offset and Dark Current Correction with a “JScript
project file”
In 9 it was strongly recommended to structure JScript programs by using so called JScript
project files. A concrete example will be given here. The functionality will be exactly the
same as 11.1.
11.2.1 Preparation
Create the three folders C:\scripttest\generally, C:\scripttest\correct and C:\scripttest\darkspectra.
In C:\scripttest\darkspectra, save a dark current spectrum as darkcur.sp2 and an offset
spectrum as offset.sp2.
C:\\scripttest\\generally\\variables.js
C:\\scripttest\\generally\\functions.js
C:\\scripttest\\correct\\maincorrect.js
import System;
import DoasCore.Spectra;
import DoasCore.Math;
As mentioned already in 8.11, the declaration of the type “ISpectrum” is not absolutely
necessary.
Save variables.js as C:\scripttest\generally\variables.js.
56
11.2.4 The file functions.js
All common functions are defined in the file functions.js. Offset and Dark Current Correc-
tion are one of the most frequent functions and will therefore be specified here.
function CorrectOffset(Spectr)
{
SpecMath.CorrectOffset(Spectr,Offset);
}
function CorrectDC(Spectr)
{
SpecMath.CorrectDarkCurrent(Spectr,DC);
}
Meas = Specbar.CurrentSpectrum;
Offset = Specbar.GetSpectrum("Offset");
DC = Specbar.GetSpectrum("Darkcurrent");
Offset.Open(darkpath+OffsetName);
DC.Open(darkpath+DarkCurrentName);
CorrectOffset(Meas);
CorrectDC(Meas);
In the lines
CorrectOffset(Meas);
CorrectDC(Meas);
the functions from the file functions.js are called. The argument, which is passed, is a spec-
trum, in this case, the spectrum “Meas”.
57
11.3 Fitting with JScript
This example does the same, as if you opened a spectrum and a fit scenario in DOASIS and
then executed the fit. All properties of the fit, like fit range and reference spectra are stored
in the fit scenario. So all you need to run the script is to open a spectrum manually in
DOASIS and make it the active spectrum (see Fig. 1.1). This will be the spectrum against
which will be fitted. Make sure that it is offset and dark current corrected (see section 11.1)
and that the logarithm has been taken. Apart from that, a fit scenario file has to be stored
as c:\scripttest\fitscenario.fs.
The program runs the fit, shows the fit result and displays the fit coefficient of the first
spectrum in the fit scenario in the Output window. Another example for fitting is presented
in section 7.2.3.
import System;
import DoasCore.Spectra;
// necessary for the DoasFit class
import DoasCore.Math;
// execute the fit, DoFit returns "true" if the fit was succesfull
if(fit.DoFit(MeasSpec))
{
// display message for successful fit
Console.WriteLine("Fit successful!");
// display the fit result windows in the spectrum "ResultSpec"
fit.PrepareFitResultSpectrum(ResultSpec);
// display the fit results an the active spectrum sheet
Specbar.CurrentSpectrum = ResultSpec;
// display the fit coefficient of the first reference spectrum
Console.WriteLine("Fit Coefficient: "+fit.ReferencesInfo[0].FitCoefficient)
// write fit results into file
fit.AppendResultToFile("c:\\scripttest\\result.dat");
}
else
{
System.Console.WriteLine("Error while fitting!");
}
58
Remarks:
• Each time the fit is executed the fit results will be appended to the file result.dat. If
result.dat doesn’t exist yet it will be created.
• Each fit result (fit coefficient, shift, squeeze, chi square...) can be individually accessed.
The approach is similar to displaying the fit coefficient in the example above. For more
information about fit results of the different reference spectra search for “DoasFitRefer-
enceInfo” in the Programming Documentation of DOASIS (Help menu - Programming
Documentation). For properties of the fit itself (like fit range, polynomial...) search
for “DoasFit”.
• If you want to display e.g. the shift value of the second spectrum of the fit scenario
the command would be:
var shift;
shift = fit.ReferencesInfo[1].Shift;
Console.WriteLine(shift);
The entry “0” of the fit.ReferencesInfo-Array refers to the first spectrum from the top,
the entry “1” to the second...
Examples for other properties:
– Squeeze:
fit.ReferencesInfo[1].Squeeze;
– Fit coefficient error:
fit.ReferencesInfo[1].FitCoefficientError;
– Chi Square:
fit.ChiSquare;
• If you don’t want to fit against the active spectrum but instead load a spectrum from
a file and fit against that spectrum, make use of the commands described in section
8.9.
59
Figure 11.1: Fitting window of DOASIS. By ticking the boxes (marked by the red circle)
reference spectra can be activated and deactivated for the fit. This is not possible with
JScript.
Figure 11.2: Fit reference properties window. It can be activated by double clicking on
the reference spectrum in the Fitting window. The marked parameters are set within the
JScript. The default value of the shift parameter has to be in between the limit parameters.
It constitutes the starting value of the numerical calculations for the shift within the given
boundaries.
60
with 3 being the default value. See Fig. 11.2. The fit range is set from 300 to 600 channels.
Finally the fit scenario is saved as C:\scripttest\newfitscenario.fs. Before running
the script make sure that a fit scenario with at least one reference spectrum exists under
C:\scripttest\fitscenario.fs and a spectrum is available from C:\scripttest\testspec.sp2.
import System;
import DoasCore.Spectra;
import DoasCore.Math;
After the script is executed the modified fit scenario can be opened in DOASIS from
C:\scripttest\newfitscenario.fs and the newly implemented spectrum will appear to-
61
gether with the other spectra of the fit scenario in the Specbar and the limits for the shift
are visible in the Fitting window.
Remarks
• By loading a new spectrum into the fit scenario, only the spectrum itself, meaning
the channel/wavelength-intensity plot and the file name is changed. The “ObjectKey”
property however does not change and, if required, must be changed separately by
using the command:
fit.ReferencesInfo[0].ObjectKey = "..."
• When limiting the shift it is important that the default value of the shift is in between
the low limit and the high limit.
• The “squeeze” of each reference spectrum can be limited in a similar way. Just sub-
stitute
DoasFitReferenceInfo.Coefficients.Shift
by
DoasFitReferenceInfo.Coefficients.Squeeze
• Spectra can only be implemented in a fit scenario with JScript, if the were opened
within the same JScript before. Hence it is not possible to include a spectrum which
was opened manually beforehand and the using the the command:
MeasSpec = Specbar.CurrentSpectrum;
In this case
fit.ReferencesInfo[0].ReferenceSpectrum = MeasSpec;
will not work.
• For setting the low limit of the fit range the command:
fit.FitRanges[0].LimitLow = 300;
is used. FitRanges[] is an array thus several fit ranges can be defined if required.
The value “0” here represents the first fit range. It can be useful to define several fit
ranges though if e.g. broken pixels or strong absorption lines of interfering absorbers
should be excluded.
• For more information to modify the settings of the different reference spectra search
for “DoasFitReferenceInfo” in the Programming Documentation of DOASIS (Help
menu - Programming Documentation). For properties of the fit itself (like fit range,
polynomial...) search for “DoasFit”.
• Sometimes it is useful to fix the fit coefficient of certain reference spectra (see Fig. 11.2
“Fix Parameter”. For setting the parameters of the fit coefficient the Tab “Coefficient”
instead of “Shift” has to be chosen). However it does not work with JScript using the
SetCoefficientFixed() command. No solution is known by now.
62
here in detail. Fitting is done as in 11.3, for saving the spectrum see 8.9.
import System;
import DoasCore.Spectra;
import DoasCore.Math;
if(fit.DoFit(MeasSpec)){
// get a vector, containing wavelength info from target spectrum
var wavelength = fit.TargetSpectrum.Wavelength.ToVector();
Remarks
• ResultSpectrum is a function that you can actually see after fitting manually in the
Fit Result window. For a good fit, it should be similar to the “TargetSpectrum”.
“TargetSpectrum” is the spectrum in the Active Spectrum Sheet, that we want to fit.
By subtracting the ResultSpectrum from the TargetSpectrum we get the residual.
• Don´t create the variable fit by writing var fit: DoasFit = new DoasFit(), be-
cause then, TargetSpectrum does not support the function GetValues.
But: If you want to get access to the properties of fit.ReferencesInfo like FitCoefficient
or ObjectKey, you have to create the variable fit in that way! In case you want to get
63
the Residual and get access to fit.ReferencesInfo use two different variables fit1 and
fit2, where you create each in a different way.
• We created three vectors here: targetSpec, resultSpec and wavelength. All vectors
have as many entries, as the number of channels of the spectrum that we want to
fit (TargetSpectrum). In the vector wavelength, each entry consists of a wavelength
corresponding to the specific channel. The other two vectors contain intensity values.
Make sure to take the logarithm of the spectrum you want to fit either by pressing
“Logarithm” in the “Math” menu of DOASIS, or by activating the “Log. spectrum”
control box in the fitting sheet of the console window.
• Is it possible to extract the fit functions of the reference spectra as well? No. At least
not very easily.
64
Chapter 12
Advanced JScripts
The JScripts provided in this chapter are longer and therefore not commented out in great
detail anymore. It needs some experience to understand them. Nevertheless, with the gained
knowledge of the preceding chapters it shoud be possible to understand and use them.
65
import System;
import DoasCore.Spectra;
Console.WriteLine("Ready.");
• WinDoasMotor.DoasMotor
• WinDoasMath.DoasMath
66
12.2 Exception handling
ßindextry..catch..finally JScript provides the possibility to handle exceptions by putting
commands which might cause errors in the “try”-block of a so called try/catch/finally en-
vironment. If any command of the code enclosed in the “try”-block causes an error, the
entire block will be skipped and instead the content of the “catch”-block is executed. If
no error occurs in the “try”-block, the “catch” block will not be executed. The content of
the “finally” block is executed no matter whether an error occurred in the “try”-block or
even in the “catch”-block or not. In the following example, the type of the error is displayed
in a pop up window. By pressing “yes” or “no”, the user can either accept the error and
continue the script or abort it.
67
import System;
import DoasCore.Spectra;
// This namespace provides the class "OldUI"
import DoasCore.HMI;
function main()
{
// In the "try"-block, a spectrum should be loaded into the empty spectrum
// "Spec". If the file "C:\Spectrum.sp2" exists, the spectrum will be
// opened and the message "Spectrum opened!" is displayed. If the file
// does not exist, the entire "try"-block is skipped and the "catch"-block
// is executed.
try
{
Spec.Open("C:\\Spectrum.sp2");
Console.WriteLine("Spectrum opened!");
}
catch(e)
{
// Show a pop up window including a "yes/no" button with the title
// "An error occurred!" and displaying the reason for
// the error (e). If "yes" is pressed the method returns "true", if "no"
// is pressed it returns "false"
answer = checkbox.MessageBoxYesNo(e+" Continue?","An error occurred!");
// If "answer = true", then continue, else exit the "main()"-function
// and thus the entire script
if(answer)
{
Console.WriteLine("Script is continued!");
}
else
{
Console.WriteLine("Script is aborted!");
// Exit the "main()"-function
return;
}
}
finally
{
Console.WriteLine("Always execute this part!");
}
Console.WriteLine("End of script!");
}
68
Remarks
• For the first time in this manual a function is declared here. Making use of functions is
a very common and convenient style of programming. The program itself only starts
in the last line:
main();
calling the function “main()” which has been declared in the beginning. In this script
the function “main()” was used in order to be able to quit the script by leaving the
“main()”-function, if the user clicks on “no” when the checkbox appears.
• The “finally”-block is executed even though “no” is pressed in the checkbox and thus
the “return” command is called. However the command
Console.WriteLine("End of script!")
is not executed in that case.
• It is advisable to be very careful with the usage of the “try/catch” routine. If the error
message is not displayed, the program might pretend to work well even though it only
jumped over parts of the code.
/* EvaluateExample.js\\
Note: To run the example its necessary to have already some spectra
saved as
C:\scanTest
and that you have an existing fit scenario file
C:\scanTest\EvaluateExample.fs
69
var afnFile = new AutoFileName();
afnFile.BasePath = "C:\\scanTest";
afnFile.Prefix = "a";
afnFile.Suffix = ".std";
afnFile.FilesPerFolder = 100,
afnFile.NumberOfDigits = 5;
// create the spectrum object that will receive the scanned data
var specEval = Specbar.GetSpectrum("Eval");
// repeat until the stop button was pressed and a file could be loaded
while(!Script.StopAllScripts && afnFile.Open(specEval))
{
// set the target spectrum for fitting
fit.TargetSpectrum = specEval;
System.Console.WriteLine("Evaluate stopped.");
/* ScanExample.js
This example script gives an example about how to scan using the default spectrograph
and saves the measured spectra one after another using the AutoFileName scheme.
70
import DoasCore.Script; // use the Script namespace
import DoasCore.Spectra; // use the Spectra namespace
// look for the last existing file and set the file counter to the successor
afnFile.FindLastIndex();
// create the spectrum object that will receive the scanned data
var specScan = Specbar.GetSpectrum("Scan");
afnFile.Save(specScan);
System.Console.WriteLine("Saved spectrum " +
afnFile.CurrentFileNumber.ToString() + "!");
}
System.Console.WriteLine("Scanning stopped.");
12.5 Threading
This example shows how to create multiple thread that run at once. Each thread can be
supplied with a different information. Also the usage of classes and object is shown.
71
// The content of ’objectInfoForThread’ is set when the object is created.
// The example function that actually runs in a separate thread can access this
// additional information.
class ThreadTest
{
// an internal variable used to store the additional
// information for the thread
private var objectInfoForThread;
// This variable will store the thread object. Using this object
// we can control the thread (Start, Stop, Pause, ...)
private var threadWorker : Thread;
// This is the function that will run in a separarte thread as soon as the
// ’StartThread’ function is called. The thread will run until this function
// exits or you terminate the thread using the ’threadWorker’ object.
function RunWorker()
{
// just do something inside the thread
var i : int = 0;
while(i < 100)
{
// print the additional information supplied
72
// on creation of the object including the loop counter
System.Console.WriteLine(objectInfoForThread.ToString() + ": " + i.ToString());
i++;
}
}
}; // end of class
2. The main()-function.
73
further JScripts.
The main()-function only takes about one page out of the ten pages of the entire code. In
the main()-function the different functions declared towards the end of script are called.
The basic tasks of the Script can already understood by reading the main()-function only,
since all the other functions reveal their functionality more or less by their name. It is very
important that the main()-function itself is called at the end of the script.
• It calculates the solar zenith angle (SZA) (see function aurinko())for each measure-
ment for two reasons:
1. To interrupt the “normal” measurement mode after sunset and from that time
onwards only measure offset and dark current in a fixed position.
2. To save the SZA in the properties of the spectrum for later evaluation purposes.
• The function TakeSpectrum() automatically adapts the integration time to the cur-
rent light conditions by running several test scans and prolonging or shortening the
integration time according to the saturation of the spectrum.
12.6.3 Prerequisites
In the script several “ActiveXObjects” are used:
• WinDoasIO.FileIO
• WinDoasMath.DoasMath
• WinDoasTools.DoasTools
• Scripting.FileSystemObject
• HMTUSB.PDZControl
These can be understood a separate “programs” (such as Microsoft Excel, see section 12.1.1)
which can be accessed via JScript by ActiveXObjects. Therefore different drivers and pro-
grams must be installed. It showed in the past that as well the order of installation is
important. Here a list of the required drivers in the right order:
3. InstallerHMTActiveXControll
4. DOASIS
6. VNC
74
Of course the different file and path names mentioned in the script have to be adapted
accordingly.
import System;
import DoasCore;
import DoasCore.IO;
import DoasCore.Spectra;
import DoasCore.Math;
import DoasCore.Device;
75
var ttotal = 100000; // total integration time
var sOS = 10000; // number of offset scans
var tOS = 3; // offset integration time in ms
var tDC = 20000; // dark current integration time
var sat = 3000; // saturation level(max 4095)
var tNap = 600000; // break between two offset mesurements(ms)
var waitscan = 150; // break after scan
var waitmotor = 500;
function main()
{
dispIO.Silent = true;
WriteToLog(AdcLog,"UBatt [V]; USteuer [mV];
TCold [C]; TWarm [C]; TSet [C]; IPelt [A]; ");
// initialise the Hoffmann controllers
InitHMTUSB();
// check if script was aborted by pressing the stop button in the Script window
StopCheck();
// MakeSpec() creates empty spectra in the Specbar
offset0 = MakeSpec("OOoffset0");
offset1 = MakeSpec("OOoffset1");
offset2 = MakeSpec("OOoffset2");
dark1 = MakeSpec("OOdark1");
dark2 = MakeSpec("OOdark2");
dispTools.CurrentSpectrum = offset0;
for (j=0;j<AngleSeries.length;j++)
76
{
straylight[j] = MakeSpec(AngleSeries[j].toString());
}
while (!window.CheckStop())
{
// calculate the solar zenith angle
SolarValues = aurinko(Latitude,SZALongitude);
StopCheck();
// only measure during day time
if (SolarValues.SZA < SZAnight)
{
WriteToLog(DoasLog, "Started MAX routine");
MotorMoveHome();
StopCheck();
for (j=0;j<AngleSeries.length;j++)
{
StopCheck();
for (k=0;k<AngleTimes[j];k++)
{
StopCheck();
{
StopCheck();
SolarValues = aurinko(Latitude,SZALongitude);
WriteToLog(DoasLog, "SZA = "
+parseInt(SolarValues.SZA*1000)/1000+"◦ "
+"SAA = "+parseInt(SolarValues.SAZ*1000)/1000+"◦ ");
// calculate integration time and measure spectrum
TakeSpectrum(AngleSeries[j])
}
}
}
}
// during night time record offset and dark current
else if (SolarValues.SZA > SZAnight)
{
MotorMoveToPos(MotorOSDCPosition);
WriteToLog(DoasLog, "Started Offset and DC routine");
TakeOffsetDarkCurrent();
StopCheck();
}
}
WriteToLog(DoasLog, "Stopped");
}
// ********* Declare the individual functions called in the main() routine ******
// Initialize device
function InitHMTUSB()
{
window.Status = "Initializing USB device " + serialHMT + "/"
+serialUSBHMT + " ...";
77
dispHMTUSB.SetSerial(serialHMT + "/" + serialUSBHMT);
if (!dispHMTUSB.IsDevicePresent())
{
WriteToLog(DoasLog, "Device not found - sleep 1 min.");
window.Sleep(60000);
StopCheck();
}
else window.Status = "Device found!";
dispHMTUSB.UndervoltageDetection == false;
if(!(dispHMTUSB.UndervoltageDetection))
window.Status = "Low battery warning is turned off!";
else
{
WriteToLog(DoasLog, "Low battery warning could not be turned off");
return;
}
dispHMTUSB.SetMotorMode(1, 2); // half step mode
dispHMTUSB.SetMotorFreq(1, MotorFrequency); // frequency
MotorMoveHome();
78
function aurinko(lat,lon)
{
time = new Date();
var y = time.getFullYear();
var m = time.getMonth()+1; //Bug!!
var d = time.getDate();
var h = time.getHours();
var min = time.getMinutes();
var s = time.getSeconds();
var tz = time.getTimezoneOffset();
if (tz != 0) tz /= 60;
var juliantime;
juliantime = dispMath.MakeJulianDate(y,m,d,h+tz,min,s);
SolarValues = dispMath.GetSZA(juliantime,lat,lon);
return(SolarValues);
}
dispTools.CurrentSpectrum = offset0;
if (offset0.Average < 100)
specOOI.Scan(offset0,100,3); // measure offset spectrum
window.Sleep(waitscan);
dispTools.CurrentSpectrum = measspec;
specOOI.Scan(measspec,1,t); // measure test spectrum
window.Sleep(waitscan);
79
dispMath.Correctoffset(measspec,offset0) // correct measspec for offset
// determine integration time
while (measspec.Max > sat)
{
StopCheck();
t = (parseInt(0.8 * t));
window.Status = "IT= "+t;
if (t < 3)
{
t = 3;
break;
}
specOOI.Scan(measspec,1,t);
window.Sleep(waitscan);
dispMath.Correctoffset(measspec,offset0)
}
specOOI.Scan(measspec,1,t);
window.Sleep(waitscan);
while (measspec.Max < (0.8*sat))
{
StopCheck();
t = (parseInt((1.2 * t)+0.5));
window.Status = "IT= "+t;
if (t > tmax)
{
t = tmax;
break;
}
// the integration time has been determined with t
// the number of scans still has to be calculated
specOOI.Scan(measspec,1,t);
window.Sleep(waitscan);
dispMath.Correctoffset(measspec,offset0)
}
// calculate the number of scans s
s = parseInt(ttotal/t);
if (s>smax)
{
s=smax;
}
if (s < 1)
{
s=smin;
}
// now s has been determined
dispIO.PathSplitting(1,specPath,100);
dispIO.AutoFileNumber( 1,CampInit,6,1);
i = dispIO.AutoFileNumberFindLastIndex() + 1;
window.Status = "Taking spectrum #" + i + " " + s + "x" + t +"ms @ "+angle+"◦ ";
// the actual spectrum, which will be used for evaluation later is recorded now!
specOOI.Scan(measspec,s,t);
window.Sleep(waitscan);
//
StoreADCValues(measspec);
80
measspec.CalibPolynomialOrder = 2;
measspec.CalibPolynomial[0] = CalZero;
measspec.CalibPolynomial[1] = CalFirst;
measspec.CalibPolynomial[2] = CalSecond;
measspec.Site = MeasSite;
// the spectrum is now saved!!!!!!!!
dispIO.Save(measspec);
// check if the file of the spectrum exists
if (CheckFileSize(measspec.FileName))
WriteToLog(DoasLog, measspec.FileName+" looks ok - IT was " + s
+ " scans at" + t + " ms");
// modify integration for next spectrum if spectrum was over- or undersaturated
if ((measspec.Max/s) > sat)
{ t = parseInt(0.8 * t) }
if ((measspec.Max/s) < (0.8*sat))
{
t = parseInt(1.2 * t);
}
// checks, if stored spectrum shows signal
CheckIfSpecOk(measspec);
i++;
}
function TakeOffsetDarkCurrent()
{
StopCheck();
specPath=OSDCPath;
window.Status = "Offset spectrum 1: " + sOS + " x " + tOS + " ms";
// measure offset or dark current depending on given parameters (see function below)
OSDC(offset1,100,sOS,tOS);
window.Status = "Offset spectrum 2: " + sOS + " x " + tOS + " ms";
OSDC(offset2,100,sOS,tOS);
window.Status = "Dark current spectrum 1: 1 x " + tDC + " ms";
OSDC(dark1,200,1,tDC);
window.Status = "Dark current spectrum 2: 1 x " + tDC + " ms";
OSDC(dark2,200,1,tDC);
window.Status = "Went for a nap - " + tNap/60000 + " min ... See you soon!!!";
window.Sleep(tNap);
StopCheck();
}
81
if (CheckFileSize(spec.FileName))
WriteToLog(DoasLog, spec.FileName+" looks ok");
o++
StopCheck();
}
function MotorMoveToPos(angle_L)
{
var pos = parseInt(angle_L/90*MotorStep90) + MotorHorizontalPosition;
dispHMTUSB.MoveToPos(1,pos);
window.Sleep(waitmotor);
var Position = dispHMTUSB.GetMotorPosition(1);
window.Sleep(waitmotor);
if (Position == pos)
WriteToLog(DoasLog, "Motor position "+pos+" ("+angle_L+"◦ ) reached");
else
WriteToLog(DoasLog, "Motor position "+pos+" not reached. Motor responds "+Position);
}
function MotorMoveHome()
{
dispHMTUSB.MoveHome(1);
window.Sleep(waitmotor);
if (dispHMTUSB.GetMotorStatus(1)==3)
WriteToLog(DoasLog, "Home Position reached");
else
82
{
WriteToLog(DoasLog, "Home Position not reached");
return;
}
window.Sleep(waitmotor);
if (dispHMTUSB.GetMotorPosition(1)==0)
WriteToLog(DoasLog, "Home Position set to 0");
else
{
WriteToLog(DoasLog, "Home Position not 0");
return;
}
StopCheck();
}
function WriteToLog(file,message)
{
window.Status = "log> " + message;
var out=file.OpenAsTextStream(8);
out.WriteLine(UTCDate() + " ; " + message);
out.Close();
}
83
WriteToLog(DoasLog, "No Spectrum taken, intensity is
zero due to an error! New initialisation of HMT device");
window.Sleep(1000);
InitHMT()
}
}
main();
12.6.4 Remarks:
• The motor status checked by the command
dispHMTUSB.GetMotorStatus()
can have the values:
– 0: motor stopped
– 1: motor is moving
– 2: positive end reached
– 3: negative end (homing position) reached
84
Chapter 13
Literature
JScript Textbooks
85
Index
ActiveXObject, 38, 66, 74 decimal numbers, see digits
AND, 18 Device, 27, 54
AppendResultToFile, 58 digits
AutoFileName, 28, 42 control, 40
errors related to, 45 directory
Open, 43 create, 37
Save, 43 DoasCore, 23
automatic start of JScript, 10 IO, 28
automized measurements, 70 DoasCore.Spectra, 13
DoasFit, 26, 59
backslash, 27 DoasFitReferenceInfo, 59
batch file, 9 driver, 74
baud rate, 52
boolean, 18 else if, 19
break, 36 equals, 20
Excel
CalcSZA, 26 ActiveXObject, 66
calculate create worksheet, 65
integration time, 30 write data into sheet, 65
calibration exception handling, 67
polynomial, 48
wavelength, 48 factorial, 21
calibration polynomial, 29 false, 18
catch, 67 FileSystemObject, 38
check box, 32, 69 find peak of spectrum, 29
ChiSquare FindLastIndex, 43
display, 59 fit, 26, 58, 69
class, 71 access properties, 63
colon, 20 fit coefficient
comments, 14 display, 58
Console, 31 fit range, 61
correct fit result
offset and dark current, 25, 55 show, 58
CorrectDarkCurrent, 55 fit scenario, 26, 58
CorrectOffset, 55 active/deactivate spectra, 59
crash modify, 59
avoid, 10 number of spectra, 59
CurrentFileNumber, 44 replace spectrum, 59
set fit range, 61
data transfer, 10 FitCoefficientError
data types, 15 display, 59
conversion, 15 fix parameter, 62
lost of, 16 for loop, 20
date for..in-loop, 21
get, 39 Forms, 32
DateTime, 45
86
functions, 21, 57 ObjectKey, 25, 45, 62
Ocean Optics, 53
g5, 41 control two, 54
GetSpectrum, 25 OldUI, 36
google, 85 OpenTextFile, 39
GPS, 51 operators, 17
list of, 17
handshake, 52 logical, 18
hardware OR, 18
communication with, 51 Origin, 39
Hello World, 12, 35
HMI, 31, 36 parity, 52
plus, 17
if..else, 18 port, 52
import, 14 PrepareFitResultSpectrum, 58
input, 32 Progress Bar, 31
input/output, 28 Project file, 9
InstallerHMTActiveXControll, 74 project files, see JScript project file
InstallerHMTUSBDriver, 74
internet, 85 question mark, 20
IO, 38
ISpectrum, 29, 42, 45 ReadLine, 32
members, 29 ReferencesInfo, 61
residual
JScript project file, 9, 49, 56 save, 62
jsp, see JScript project file ResultSpectrum, 63
Julian, 47 run several JScripts, 9
JulianDateTime, 25, 47
SaveAs, 29
LAZ, see lunar azimuth angle SAZ, see solar azimuth angle
LimitHard, 61 Scan
link parameter, 62 OceanOptics, 28, 53
lunar azimuth angle, 48 ScanGeometry, 25, 47
lunar zenith angle, 48 scanning
LZA, see lunar zenith angle automized, 70
Script, 30
main function, 74 semicolon, 12
marker, 29 serial port
Math, 25 communication with, 51
message box, 32, 37 SetCoefficientDefault, 61
MinChannel, 29 SetCoefficientHighLimit, 61
Mini Scripts, 13 SetCoefficientLowLimit, 61
MiniDOAS SetCoefficientLowMode, 61
control, 54 shift
MiniDoas, 73 display, 59
minus, 17 limit parameter, 61
sleep, 36, 84
namespace, 12
solar azimuth angle, 48
namespaces
solar zenith angle, 25
overview, 23
calculate, 47
NaN, 17
Specbar, 13, 29
notation
SpecMath, 25
scientific, 41
Spectra, 28
object orientation, 12, 57 spectrograph
control, 53
87
control two, 54
serial number, 53
spectrum
file name, 59
measure, 53
modify, 29
name, 13
open, 41
optimize, 30
properties, 45
save, 41
Squeeze
display, 59
limit, 62
start JScript, 5
Stop button, 31
StopAllScripts, 30
stopbits, 52
String, 12
syntax, 14
System, 12, 31, 35
IO, 32
SZA, 25, see solar zenith angle
TargetSpectrum, 63
text file, 32
create, 38
textbooks, 85
Threading, 32, 36, 71
time
compare, 45
get, 39
TimeSpan, 45
true, 18
type mismatch, 17
variable
case sensitive, 14
conversion, 15
declare, 13
initialize, 17
type, 44
types, 13
variables
display, 35
vectors, 64
wait, 36, 84
while loop, 21
WriteLine, 12, 35
88