Friday, February 28, 2014

IDL experience accumulated

1. Output device
1) SET_PLOT : specify the output device.
    Normally it's 'X' that is screen, however, you can specify other devices such as PostScript.
    Normal screen is black background. PostScript is white background.
2) DEVICE : access or control abilities a device provides.

2. Variables have be defined somewhere, whether it's in procedure/function or it's in the main program. What it mean by "defined" is that a variable needs to be assigned with a value.
You can feed less parameters to a procedure/function than what the procedure/function expects as long as you don't refer to these missing variables in your code.
eg:
  PRO proc1,  i1, i2, o1, o2
    o1=i1 + i2   ; o1 and o2 are defined within proc1
    o2=i1 * i2  
  END

  i1=1       ; i1 and i2 are defined within main.
  i2=2 
  proc1 i1, i2, o1   ; you don't feed o2 when calling proc1
  print o1              ;  and that's okay to miss o2 as long as you don't refer o2
  print o2              ; This is an error because you refer to o2.
                            ;  to correct the issue, you need to define o2 either in main or in proc1.


3. multiple statements can be joined together using "&"
eg:
    if deyong eq 1 then print, 1 &  print , 2 & print, 3
is the same as :
    if deyong eq 1 then begin
        print, 1
        print, 2
        print, 3
    endif


4. summary about "SIZE" function: return type info of a variable
  t1 = size(deyong, /type)
  print , "t1 is " , t1          ;  undefined
  deyong=3L
  t1 = size(deyong, /type)
  print , "t1 is " , t1          ;  3 -> long int
  deyong=4.5          
  t1 = size(deyong, /type)
  print , "t1 is " , t1           ; 4   -> float

5 "POSITION"
Allows direct specification of the plot window.
POSITION is a 4-element vector giving, in order, the coordinates [(X 0 , Y 0 ), (X 1 , Y 1 )], of the lower left and upper right corners of the data window. Coordinates are expressed in normalized units ranging from 0.0 to 1.0, unless the DEVICE keyword is present, in which case they are in actual device units. The value of POSITION is never specified in data units, even if the DATA keyword is present.
   Y /\ 
 1.0 |
       |
0.0  |________________\    X
      0.0                      1.0  /

6. PLOT
PLOT, [X,] Y
X :  A vector argument. If X is not specified, Y is plotted as a function of point number (starting at zero). If both arguments are provided, Y is plotted as a function of X .
Y :  A vector argument.

7. !PATH.MULTI
In IDL, the !P.Multi system variable can be used to create multiple plots in a display window. !P.Multi is a five element vector defined as follows:


!P.Multi(0) Contains the number of plots remaining on the page. Start with this as 0 to clear the page.
!P.Multi(1) The number of plot columns on the page.
!P.Multi(2) The number of plot rows on the page.
!P.Multi(3) The number of plots stacked in the Z direction.
!P.Multi(4) If 0, plots are displayed from left to right and top to bottom, i.e., the plots are displayed in rows. If 1, plots are displayed from top to bottom and from left to right, (i.e., the plots are displayed in columns).

To display four plots on a page in two columns and two rows, and the plots should appear in columns, the !P.Multi array should look like:
IDL> !P.Multi = [0, 2, 2, 0, 1]
8. COMMON block 
Common blocks are useful (a) when there are variables that need to be accessed by several IDL procedures or (b) when the value of a variable within a procedure must be preserved across calls.

Variables in a common statement have a global scope within procedures defining the same common block. Unlike local variables, variables in common blocks are not destroyed when a procedure is exited.

There are two types of common block statements:
    1. definition statements
          common block_name, v1, v2
    2. reference statements.      
          dxu: duplicates the COMMON block and variable names from a previous definition.
          common block_name            ; same as   common block_name, v1, v2

Variables in IDL COMMON blocks do not actually have names.

The number of variables appearing in the common block cannot change after the common block has been defined. ( Fixed once defined:  )


The "first program unit" (the one which gets compiled first : main program, function, or procedure, NOT order who gets executed ) to define the common block sets the number of included variables;
eg:
    common block_a , v1, v2, v3       ; there are 3 vars in block.



Other program units can reference the common block with any number of variables up to the number originally specified.
eg:
    common block_a , v1, v2         ; number could be less than the original number.

Different program units can give the variables different names.
eg:
    common block_a ,  M1, M2    ; name is NOT important, position IS.  so M1 = v1, M2=v2.

9. Array assignment. 
a=make_array(2,3, /integer, value=100)
b=make_array(2,3, /integer, value=200)
a) slice operation 
   b(0,0:1) = a(0, 0:1)   ; copy first two element in row 0
  b(0:1, 0) = a(0:1, 0)   ; copy first two element in column 0 
b) copy 1 row or 1 column
    b(*,1) = a(*,1)         ; copy column 1
   b(1,*) = a(1,*)          ; copy row 1
c) copy entire array
   b(*,*) = a(*,*)          ; copy all the rows / copy all the columns
   b = a                           ; same as above
d) shriek array
   a = a (*, 0:1)          ; array shrieked to first two columns.
e) Playing an array is easy.eg: 
   a = a + a     ; doubling all the elements in an array
   a = 3* a      ; tripling all the elements in an array
   a= a * 3      ; same as above
   a= a / 3       ; divide elements by 3
   a= a ^ 3      ; square elements

 f) print, a                     ; column-base: print column1 , then print column2, so on.
 g) raise initial value of array to 1-base
eg:
   a = INDGEN(3)+1
   print, a
output: 
   1       2       3

10. Index variable used in for-statement will still incremented/decremented one more time after for-statement exits.
eg:
   for i=2, 1, -1 do begin
      j=i    &   print, i , j
   endfor
   print, i , j

result: 
       2       2     ; i, j
       1       1     ; i, j
             1     ; i, j    , note : i will be decremented one more time after for-statement.

11. Conversion to string
Use strtrim or string:  str
eg:
a=strtrim("  34  ", 2)    ; 2nd parameter 2 means removal of both leading and trailing spaces.
help ,a
a=strtrim(23, 2)            ;  convert int to string
help ,a
a=string(23.234, format='(f5.2)')      ; convert float to string,
help ,a                                                ; f5.2 : 5 digits in total including dot with 2 digits after dot.
a=string(232.232)                 
help ,a
output:
A               STRING    = '34'
A               STRING    = '23'
A               STRING    = '23.23'
A               STRING    = '      232.232'

12. Catch message from IDL code when running IDL code from bash.
eg:
runIDL.sh 
#!/bin/bash
idl <<EOF
   .run  ${mainCode}
   7
   1
EOF

$ ./runIDL.sh   >log  2>> log2
Note:   a) Normal prints from IDL commands go to log.
            b) Messages from compiling IDL code go to log2.
$ tf log       # to monitor the process of IDL code. 

13. Logical/Mathematical operations involving array 
Basically it applies an operation to each element of an array and generates a new array. 
eg: 
a=indgen(5)
b=a>2          ; max value (mathematical operation)
c=a ge 2       ; logical operation.
print, a
print, b
print, c
       0       1       2       3       4
       2       2       2       3       4
      0   0   1   1   1

14. Device must close at the end of  plotting, otherwise, missing data could happen because these data are not flushed into the graphics if Device is not closed.
So remember to do "DEVICE, /CLOSE" explicitly when needed.

15. Make font better in PS output
aspect_ratio=1.5  ; rectangle shape
xsize=9
ysize=xsize/aspect_ratio
set_plot, 'ps'
!p.font=0
device, filename='fig_better.eps', encapsulated=1, /helvetica
device, xsize=xsize, ysize=ysize
plot, a, b, xtitle='X Title', ytitle='Y Title'
device, /close
set_plot, 'x'
!p.font=-1
 
16. where 
If "where" doesn't find any match, then what "where" returns is -1L, not an long array. 
In this case, using the filter return from "where" actually will copy the last 
element of input array to the new array. 
eg: 
var.a=[1,2,3,4] 
fil=where(var.a gt 4)
help, fil
print, "filter " , fil, n_elements(fil)
a.a = var.a(fil) 
print , a.a
 
output: 

FIL             LONG      =           -1
filter           -1           1
       4       4       4       4

This action could be used as a trick to initialize an array with the last element 
of an input array. 
 
eg: 
a = indgen(10) + 1 
b = make_array(10, /int, value=-999) 
filt = where ( a GT 3 ) 
help, b
print, b 
b = a(filt) ;; What this does is to copy data that satisfies the condition 
            ;; to beginning of array b and truncate tail of b off. 
help, b
print, b
 
Output:  
B               INT       = Array[10]
    -999    -999    -999    -999    -999    -999    -999    -999    -999    -999
B               INT       = Array[7]
       4       5       6       7       8       9      10
 
  
16. Create array as 1-based, or 2-based, etc. 
Eg: 
  a = INDGEN(10) + 1  ; 1-based array of 10 elements.   
  a = INDGEN(10) + 2  ; 2-based array of 10 elements
 
17. Read a line as string. 
   ; Either way, it works to read a line as string. 
   READF, iu, a
   ;READF, iu, form='(a0)',  a
   b=strsplit(a,/extract) ; /extract to return sub-string, w/o it it returns 
                          ; an array of the position of the substrings is returned.
   print, b(-1)    ; -1: print last element of an array
 
18. [] operator 
   ; This is so wrong. Here is the reason why.
   ; [1, nPos] is 2-element array
   ; [bias(*,iChan,0), bias(*,iChan,0)] is 60-element array.
   ; because * represents 30 scan positions.
   ; What happens is it gets the two values from the first
   ; two scan positions. I don't know what the initial intent is for.
   ; but this doesn't seem to do whatever the intent is for.
   ;;; PLOTS,[1, nPos], [bias(*,iChan,0), bias(*,iChan,0)]
   ; Change to below to connect first and last
;     PLOTS,[1, nPos], [bias(0,iChan,0), bias(nPos-1,iChan,0)]
 
19. if-else 
Doing so to simplify complicated if_else_statement. 
if (3 gt 4 ) then    $
    print, 'big '    $           ; concatenation is NOT allowed 
else                 $
    print, 'small' & $           ; concatenation IS allowed in else-statement
    print, 'small' & $
    print, 'small' & $
    print, 'small'
 
20. CD command 
The CD procedure is used to set and/or change the current working directory.  
CD, new_dir, CURRENT=old_dir   ; save current directory inot var old_dir 
CD, 'data'
 
; how to get the current working directory info 

IDL> cd , current=old          
IDL> print, old
/data/home001/dxu/graphic

IDL> CD, CURRENT=c & PRINT, c    ; do it in one line

IDL> cd, 'graphic'     ; take relative path
IDL> cd , '../../'          ; take relative path


IDL> cd , '/data/home001/dxu  '                ; Do NOT have whitespace in the directory string.
% CD: Unable to change current directory to /data/home001/dxu .
  No such file or directory
% Execution halted at: $MAIN$
IDL> cd , '/data/home001/dxu'       ; Only work when there is NO white-space.

21. Plot map with data 
eg: 
LOADCT, 39
MAP_SET, 0,0, charsize=1,  /label, latlab=-180, lonlab = -90, latdel=30, londel=60
for i =0, num-1 do begin
   OPLOT, [x(i)], [y(i)], psym=2, symsize = 5, color=y[i]
endfor
MAP_CONTINENTS, /hires, fill_continents=0,  MLINESTYLE=0, MLINETHICK=1, color=210

22. index in where. 
a=indgen(30)+1
print, a
print,'---------------'

ff=where(a ge 20)    ; ff is index of a.
b= a(ff)
print, ff
print,'====='
print, b
print,'---------------'

ff2 = where (b ge 25)  ; ff2 is index of new array b
c= b(ff2)
print, ff2
print,'====='
print, c


23. Set IDL path 
Rather than having to type that !path statement every time you start IDL, you can put it in your .idlstartup file.

$ vi   ~/.idl/.idlstartup

Just add:
!PATH=!PATH+':'+Expand_Path('./src/idl/coyote/')

$ cd  ~/.idl/itt/pref-10-idl_8_0-unix/idl.pref
$ vi     idl.pref

You add:
IDL_STARTUP : ~/.idl/.idlstartup

Maybe there's an easier way to do it, but at least you don't have to assign !PATH every time you start IDL.

If you want to access coyote from other IDL instances, then just replace that path with the absolute path.

24. Here is another way thread about setting up IDL path

Adding Programs to Your IDL Path

IDL looks for programs (*.pro  or *.sav) in a list of directories called a "path". If a program is in a folder that is in your path then IDL knows to look for it when you try to call it in your program or from the command line. By default your present working directory (pwd a.k.a. ./) are in your path as well as some default IDL folders. I suggest that you create a folder called "idl" to keep all your programs in to keep it organized. You then need to add that folder to your path in one of the ways described below.

dxu: Note that this is only to specify the location where IDL can fine a IDL code (*.pro or *.sav). It has nothing to do with a specific subroutine/function within an IDL file.
For example, if you are calling a subroutine called "generateOutput", which is in a.pro file,  then you still need to include @a.pro in your main IDL code, so the module "generateOutput" is available to your main code to use. When IDL looks for "a.pro" file, it will go through a list of directories called a '!path' to find it.
1) So to make a module (function/subroutine) available to your main code, you need to use "@" statement to include a IDL code (eg: a.pro)  that contains the module. 
2) To let IDL find that specific file (eg: a.pro) , you need to specify the location where that file is located in !path, which is used by IDL to find all the IDL code (*.pro and *.sav)

The easiest way to do add a folder to the path that is independent of architecture is the following:
1) Make an IDL startup file. If you have already done this then skip to step 2. You can make an IDL startup file by
     a) creating a file called .idlstartup  in /path/to folder.
     b) within IDL type:
     IDL> pref_set, 'IDL_STARTUP', '/path/to/.idlstartup',/commit
         where you replace '/path/to/.idlstartup' with the path to the file you created for step 1a

2) Now edit your .idlstartup file to include the following lines to include a folder which for example is located in ~/example/
           !PATH=!PATH+':'+Expand_Path('~/example/')
If I wanted to include all sub-directories I would add the following line instead (notice the + sign in front):
     !PATH=!PATH+':'+Expand_Path('+~/example/')

You can also do the same actions in your bash or csh profiles without the use of the .idlstartup file as follows:
bash:
      export IDL_PATH=$IDL_PATH:+'~/example/'
csh:
     setenv IDL_PATH +$IDL_PATH:~/examples

where you can again include all subdirectores by leading the name with a + sign



No comments:

Post a Comment