490 likes | 655 Views
Introductory concepts: PERL for AIMPRO users. Jon Goss. Outline. What is PERL? Why do you need to know? What common uses are there? The actual stuff through case studies: Data file format conversion: o2x, x2o, RescaleOTB Filters to unix/linux commands: E.g. qsub, q
E N D
Introductory concepts:PERL for AIMPRO users Jon Goss MMG Skills Lecture Series
Outline • What is PERL? • Why do you need to know? • What common uses are there? • The actual stuff through case studies: • Data file format conversion: • o2x, x2o, RescaleOTB • Filters to unix/linux commands: • E.g. qsub, q • AIMPRO data analysis: • E.g. gres, ETOT, FORCES, CHAINS, SandD MMG Skills Lecture Series
What is PERL? • Perl is a scripting programming language: • Interpreted rather than compiled (c.f. fortran and C++) • Can be object oriented • Sometimes linked to web systems • Very “c-like” in structure, and similar to unix/linux shell environments • Easy to do simple things MMG Skills Lecture Series
Why should you care? • As your studies are almost entirely based on computer generated, ASCII data files, especially those produced from AIMPRO, learning a little about how to manage the numbers will be essential. • Spending a little time early on to develop some skills in data analysis will save you time in the long run. MMG Skills Lecture Series
Why perl rather than something else? • I use perl • Perl is designed with text-file manipulation in mind: c.f. C and Fortran. • Especially regular expression matching (coming later) • If you use a compiled language (c, c++, fortran…) you are more dependent on the compiler and libraries (non-standards, compability…). • However, if you need to do some real number crunching, then you are probably better off using something else. • (Note, you can use perl to do these things.) MMG Skills Lecture Series
Common uses • I use perl on a daily basis, writing scripts of a few lines to do something simple, and throwing it away: • generating a number of similar files where only the lattice constants of the systems change (Zn3P2). • converting general basis vectors into spherical polars • Less frequently I write longer programs to do more sophisticated things that I expect to do again: • converting hyperfine tensor output from AIMPRO to a postscript graphics file, or a POVray input file. • gres (general aimpro output interigator) • batch queue summary • FORCES, CHAINS, SandD, … MMG Skills Lecture Series
My “permanent” scripts on Rhodes: AB2exp ABC-AlpBetGam_to_abcdef AddKFPARAM AddNorm aim2res analysis AnglularDeviation available AverageOTB AverageOTBpoint b B B2P2 bandst2ps bun CentreNEB centre_super_cell CHAINS ChangeProcs CHECK CND CountDown crit DoS dsub echerr ETOT ETOT3 F FE2plot FORCES GetHGHOptions GetLatticeRatios GetPSOptions gres HarvestCharges HFi2POV HFi2ps Homer iter LastMod latest latex2ps LOADS.EXE MakeFakeDDRESTART MakeGroupRun MakeHGH makesphere Monkey neb2xyz NEBSaddlePoints2xyz new nsub o2x PlotBasisParams plt2ps Provec q qme qsub RandomizeOTB RandomizeXYZ Recentre RecentreXYZ Redistribute RedistributeHGH Redistributelib res2neb res2nebxyz RES2ROMP Rescale RESvEGY rsub SandD SCFTIMES StateEq SwapUsage table2sortedlist TETOT TidyNEB TIME tofin x2o XYZrotator XYZTransformation MMG Skills Lecture Series
Case studies: Rescale, o2x and x2o • In AIMPRO data files, we use a standard format to describe the (relative) positions of the atoms in the simulation cells. This is what is sometimes referred to as “otb”: MMG Skills Lecture Series
Case studies: Rescale, o2x and x2o • The atom number and the lists of four neighbours are only information, and do not affect the calculation • The atomic species is a number corresponding to a chemical species listed elsewhere in the data file. • The (x, y, z) may be in a variety of units, but we’ll assume that they’re atomic (1a.u.≈0.529Å). MMG Skills Lecture Series
Case studies: Rescale, o2x and x2o • However, this is not a well known standard • More common is “xyz”, and this is one format supported by molecular structure plotting software (e.g. minimol, rasmol, jmol, xmol, etc.) • The simplest form of xyz format is as in the following example: 216 Structure data (comment line) C 0.587548 1.276483 29.385792 C 3.098373 1.239844 28.981111 … MMG Skills Lecture Series
Case studies: Rescale, o2x and x2o • We therefore commonly want to convert between the data format you have to pass to AIMPRO, and a form you can visualise using minimol – this is prime perl-script territory. • In order to write such a script we need to know some basics… MMG Skills Lecture Series
Case studies: Rescale, o2x and x2oPerl basics • A scalar variable in a perl script (a number, string etc) is stored as a term such as “$a” • The dollar sign in this context indicates a scalar variable. • An array (lets say a vector) is stored as “@a”. • There are default scalars and vectors: $_ and @_, which are set when a perl script function returns a value or vector that is not specified. These must be looked after! • Command line values are stored in a vector “@ARGV”, and the name of the script (as invoked) is stored in “$0”. MMG Skills Lecture Series
Case studies: Rescale, o2x and x2oPerl basics • To look at the contents of a file you need to open it, or pass it as “standard input”: • open INPUT, “<data.file” or die “I could not open data.file\n”;; • $a=<INPUT>; • or for standard input: • $a=<>; • Each example is reads a single line. MMG Skills Lecture Series
Case studies: Rescale, o2x and x2oPerl basics • Perl has a number of mechanisms for forming a “loop”. • while • foreach (aka for) • The while command checks a logical condition and ends to loop when a false is returned. • The foreach operates on an array or list. • For following script we’ll be using the both case. MMG Skills Lecture Series
Case studies: Rescale #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } MMG Skills Lecture Series
YIKES MMG Skills Lecture Series
I’ve introduced several more ideas here… #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… Note the use of braces and semicolons. #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… The computer needs to be told how to interpret the script, and this line tells it two things: Perl lives in /usr/bin The “-w” flag tells it to write out warnings to the shell where the script is being run (this is very important when you’re debugging). #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… split is a perl function that takes a string and “splits” it into its constituent parts. Perl has lots of such useful functions As invoked it looks at “$_” and splits it into the parts separated by “white space”, returning the output to @_; More generally: @b=split(“xxxx”,$a) #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… “for(a..b)” means all integer values between a and b, inclusive. In this case we have 6..8 which means 6, 7, 8. Because there is no variable stated, the values are assigned to $_. We could have written for $x (6..8) #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… For an array, @a, we can ask for a particular value in this way. $a[0] is the first element, $a[1] the second and so on. In this case we have The index of the final element can be determined using the (scalar) $#a. #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… This is a shorthand for “multiply yourself by the value in $f. This is not a mathematical expression! It is the same as $_[$_]=($_[$_]*$f) #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… This is actually a compound of two new functions. #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… “join” is a function which joins together the elements of an array and returns a scalar. The first argument is the “glue”, in this case a space. The rest is a list of items, in this case the contents of @_ and this “\n” object, which is a “newline” character (there are several special string characters like this all with “\”). #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
I’ve introduced several more ideas here… “print” means pass to the standard output (by default the shell window) #!/usr/bin/perl -w $f=0.5; while(<>){ split; for(6..8){$_[$_]*=$f} print(join” ”,@_,”\n”); } Case studies: Rescale MMG Skills Lecture Series
Case studies: Rescale • This is a pretty basic, and fundamentally flawed way to do this (although with some care it will work). • You are assuming that the “standard input” is correctly formatted otb. • The scaling factor is “hard-wired”. MMG Skills Lecture Series
Case studies: Rescale #!/usr/bin/perl -w $f=$ARGV[0]; $file=$ARGV[1]; open INPUT, “<$file” or die “I cannot open $file\n”; while(<INPUT>){ @a=(split); if($#a!=8){die “Wrong number of elements detected on line $.\n”} foreach $b (6..8){$a[$b]*=$f} print(join” ”,@a,”\n”); } close(INPUT); MMG Skills Lecture Series
Case studies: Rescale #!/usr/bin/perl -w if($#ARGV!=1){die “Wrong number of arguments used\n”} $f=$ARGV[0]; $file=$ARGV[1]; if(-e $file){ open INPUT, “<$file” or die “I cannot open $file\n”; }else{ die “file ‘$file’ does not exist”; } while(<INPUT>){ @a=(split); if($#a!=8){die “Wrong number of elements detected on line $.\n”} for $b (6..8){$a[$b]*=$f} print(join” ”,@a,”\n”); } close(INPUT); MMG Skills Lecture Series
Case studies: Rescale #!/usr/bin/perl -w if($#ARGV!=1){die “Wrong number of arguments used\n”} $f=$ARGV[0]; if($f!~/^(\d*\.?\d+|\d+)$/){ die “scaling factor not a number\n”; } $file=$ARGV[1]; if(-e $file){ open INPUT, “<$file” or die “I cannot open $file\n”; }else{ die “file ‘$file’ does not exist”; } while(<INPUT>){ @a=(split); if($#a!=8){die “Wrong number of elements detected on line $.\n”} for $b (6..8){$a[$b]*=$f} print(join” ”,@a,”\n”); } close(INPUT); MMG Skills Lecture Series
Case studies: o2x and x2oAudience Participation • What are the differences in the operation of these two converters relative to • Rescale? • each other? • Sketch out the script for x2o… 1 1 0 0 0 0 0.0000000000 0.0000000000 0.0000000000 2 1 39 29 0 0 6.5000000000 0.0000000000 6.5000000000 3 1 38 33 0 0 6.5000000000 6.5000000000 0.0000000000 4 1 35 30 0 0 0.0000000000 6.5000000000 6.5000000000 5 1 27 26 25 28 3.2500000000 3.2500000000 3.2500000000 OTB 56 #Set no. 1 (Final) (Initial) Fe 0.00000000000 0.00000000000 0.00000000000 Fe 3.43965211850 0.00000000000 3.43965211850 Fe 3.43965211850 3.43965211850 0.00000000000 Fe 0.00000000000 3.43965211850 3.43965211850 Fe 1.71982605925 1.71982605925 1.71982605925 XYZ MMG Skills Lecture Series
Case studies: linux command filter • We can also open a file-handle on a linux/unix command rather than a file: • e.g. open Q, “ls -l|” or die • This example would execute the list files command “ls –l” and pass the standard output to the file-handle “Q”. • Actually there are better, perl function based methods to look at the contents of a directory, but never mind MMG Skills Lecture Series
Case studies: linux command filter • The example wasn’t very obviously useful, but there are often instances of standard output from a shell command being unhelpful because • there’s too much and some disappears off the screen • the width means that text is wrapped and difficult to interpret • there’s lots of irrelevant information and you really only want a small part of it. • Sometimes we sort this out with an “alias” in the shell (e.g. “alias ll ‘ls –l’ ”). • More complicated manipulation may be performed with the use of perl… MMG Skills Lecture Series
The standard way to examine the contents of the batch queue on Verity would be something along the lines of “qstat”, the output from which is not very helpful: job-ID prior name user state submit/start at queue slots ja-task-ID ----------------------------------------------------------------------------------------------------------------- 15621 0.60500 aim2.3.0b2 a6909644 r 09/21/2008 22:47:50 master.q@verity.ncl.ac.uk 3 15638 0.50500 aim2.3.0b2 a6912698 r 09/22/2008 16:41:22 master.q@verity.ncl.ac.uk 2 15642 0.50500 aim2.3.0b1 n1101440 r 09/22/2008 21:21:37 master.q@verity.ncl.ac.uk 2 15645 0.50500 aim2.3.0b1 n1101440 r 09/23/2008 01:44:29 master.q@verity.ncl.ac.uk 2 15646 0.50500 aim2.3.0b1 n1101440 r 09/23/2008 12:55:25 master.q@verity.ncl.ac.uk 2 15650 0.50500 aim2.3.0b2 a6909644 r 09/24/2008 14:11:32 master.q@verity.ncl.ac.uk 2 15652 0.60500 aim2.3.0b2 a6909644 r 09/23/2008 12:33:01 master.q@verity.ncl.ac.uk 3 15653 0.60500 aim2.3.0b2 a6909644 r 09/23/2008 13:21:17 master.q@verity.ncl.ac.uk 3 15655 0.50500 aim2.3.0b2 a6912698 r 09/24/2008 14:12:07 master.q@verity.ncl.ac.uk 2 15668 0.60500 aim2.3.0b2 a6909644 r 09/23/2008 20:50:21 master.q@verity.ncl.ac.uk 3 15670 0.60500 aim2.3.0b2 a6909644 r 09/24/2008 04:33:40 master.q@verity.ncl.ac.uk 3 15671 0.60500 aim2.3.0b2 a6918314 qw 09/24/2008 11:25:00 3 15672 0.60500 aim2.3.0b2 a6918314 qw 09/24/2008 11:47:04 3 15680 0.60500 aim2.3.0b2 a6909644 qw 09/24/2008 13:57:30 3 15656 0.50500 aim2.3.0b2 a6912698 qw 09/23/2008 12:04:20 2 15657 0.50500 aim2.3.0b2 a6909644 qw 09/23/2008 12:22:55 2 15658 0.50500 aim2.3.0b2 a6909644 qw 09/23/2008 12:23:22 2 15659 0.50500 aim2.3.0b1 n1101440 qw 09/23/2008 12:55:16 2 15662 0.50500 aim2.3.0b2 a6912698 qw 09/23/2008 14:16:17 2 15663 0.50500 aim2.3.0b2 a6912698 qw 09/23/2008 14:16:57 2 15664 0.50500 aim2.3.0b2 a6912698 qw 09/23/2008 14:19:15 2 15665 0.50500 aim2.3.0b2 a6912698 qw 09/23/2008 15:02:51 2 15666 0.50500 aim2.3.0b2 a6912698 qw 09/23/2008 15:03:51 2 15667 0.50500 aim2.3.0b2 a6912698 qw 09/23/2008 15:04:46 2 15674 0.50500 aim2.3.0b1 n8156276 qw 09/24/2008 12:21:53 2 15675 0.50500 aim2.3.0b1 n8156276 qw 09/24/2008 12:21:54 2 15676 0.50500 aim2.3.0b1 n8156276 qw 09/24/2008 12:21:55 2 15677 0.50500 aim2.3.0b1 n8156276 qw 09/24/2008 12:21:57 2 15678 0.50500 aim2.3.0b1 n8156276 qw 09/24/2008 12:21:58 2 15679 0.50500 aim2.3.0b1 n8156276 qw 09/24/2008 12:22:00 2 Case studies: linux command filter“q” on Verity MMG Skills Lecture Series
The perl script “q” takes output from qstat (in various ways) and turns it into something (at least I find) useful: Queue data: ===== ========= ====== == == =================================================== JobID user time #n ST dir ===== ========= ====== == == =================================================== 15621 Abdusalam 2.8d 2 r 15638 Mariam 2.0d 1 r 15642 Richard 1.8d 1 r 15645 Richard 1.7d 1 r 15652 Abdusalam 1.2d 2 r 15646 Richard 1.2d 1 r 15653 Abdusalam 1.2d 2 r 15668 Abdusalam 20.5h 2 r 15670 Abdusalam 12.8h 2 r 15650 Abdusalam 3.2h 1 r 15655 Mariam 3.2h 1 r ===== ========= ====== == == =================================================== 15671 Khaled 5.9h 2 qw 15672 Khaled 5.6h 2 qw 15680 Abdusalam 3.4h 2 qw 15656 Mariam 1.2d 1 qw 15657 Abdusalam 1.2d 1 qw 15658 Abdusalam 1.2d 1 qw 15659 Richard 1.2d 1 qw 15662 Mariam 1.1d 1 qw 15663 Mariam 1.1d 1 qw 15664 Mariam 1.1d 1 qw 15665 Mariam 1.1d 1 qw 15666 Mariam 1.1d 1 qw 15667 Mariam 1.1d 1 qw 15674 Rob 5.0h 1 qw 15675 Rob 5.0h 1 qw 15676 Rob 5.0h 1 qw 15677 Rob 5.0h 1 qw 15678 Rob 5.0h 1 qw 15679 Rob 5.0h 1 qw ===== ========= ====== == == =================================================== ************************* *** 24 nodes *** *** 0 nodes TNA *** *** 10 nodes dsbld *** *** -2 nodes free *** *** 22 nodes queued *** ************************* *** my R nodes: 0 *** *** my Q nodes: 0 *** ************************* Case studies: linux command filter“q” on Verity MMG Skills Lecture Series
Case studies: linux command filter“q” on Verity Queue data: ===== ========= ====== == == =================================================== JobID user time #n ST dir ===== ========= ====== == == =================================================== 15642 Richard 1.8d 1 r /scratch/n1101440/T3 15645 Richard 1.7d 1 r /scratch/n1101440/T4 15646 Richard 1.2d 1 r /scratch/n1101440/T5 ===== ========= ====== == == =================================================== 15659 Richard 1.2d 1 qw /scratch/n1101440/T1/T2/T2_1 ===== ========= ====== == == =================================================== ************************* *** 24 nodes *** *** 0 nodes TNA *** *** 10 nodes dsbld *** *** -2 nodes free *** *** 21 nodes queued *** ************************* *** my R nodes: 3 *** *** my Q nodes: 1 *** ************************* MMG Skills Lecture Series
Case studies: linux command filter“q” on Verity • How is this done? • We will not look at the gory details, but here’s the script… MMG Skills Lecture Series
#!/usr/bin/perl # Initialise variables: &SetDefaults; #Check the command-line options: &CommandLine; #For each jobid, get the relevant data: &GetJobData; &GetJOBIDOrder; &QueueUsage; #Do some output if($Settings{"PrintQueue"}){&PrintQueue} if($Settings{"QSummary"}){&PrintQueueSummary} if($Settings{"NodeSummary"}){&PrintNodeSummary} if($Settings{"UserSummary"}){&PrintUserSummary} Case studies: linux command filter“q” on Verity This is clearly not a very complicated script: in fact, does it do anything at all? MMG Skills Lecture Series
Case studies: linux command filter“q” on Verity • Of course it does, but the guts are structured in a series of functions or subroutines, which are then called using the syntax such as • &DoSomething(a list of arguments) • We’ve also now seen a new data structure called a hash. This is a bit like an array, but the index is not necessarily a number: • $name{first}=“Jonathan”; • $name{last}=“Goss”; • A hash is denoted by a percent: %name; • These structures can be very useful in organising data which is linked in some complex way. • You can interrogate a hash using the “keys” function: • “keys %name” returns a list of the elements of the hash, in this case (“first”, “last”). • Returning to “q”, we’ll look at one subroutine as an illustration… MMG Skills Lecture Series
sub GetJobData{ open IN, "qstat -r -f -ne |" or die; my $comp=0; while(<IN>){ my @stuff=split; #Get the number of nodes: if($stuff[0] eq "Requested"){ if($jobid){${$data{$jobid}}{"Nodes"}=$stuff[3]-1} else{die "Error - no job id"} }elsif(/parallel\.q\@comp(..)/){ $comp=$1; } Case studies: linux command filter“q” on Verity MMG Skills Lecture Series
Case studies: linux command filter“q” on Verity (it goes on…) elsif(/^\s*\d+\s+/){ $jobid=$stuff[0]; if(${$data{$jobid}}{"user"}){ #For the slaves,gather which nodes they're running on: ${$data{$stuff[0]}}{"Comp"}.=" $comp"; $nodes++; #Once for each job: }else{ ${$data{"users"}}{$stuff[3]}++; if($stuff[4]eq"r"||$stuff[4]eq"t"){${$data{$stuff[3]}}{"jobs running"}++} else{${$data{$stuff[3]}}{"jobs queued"}++} ${$data{$jobid}}{"user"}=$stuff[3]; ${$data{$jobid}}{"state"}=$stuff[4]; ${$data{$jobid}}{"time"}=&dt(@stuff[5..6]); ${$data{$jobid}}{"CWD"}=""; if( (${$data{$jobid}}{"state"} eq "r") || (${$data{$jobid}}{"state"} eq "t") ){ push @{$data{"PreserveQstatOrderRunning"}},$jobid; }else{ push @{$data{"PreserveQstatOrderQueued"}},$jobid; } if($Settings{"user"} eq $stuff[3]||$Settings{"AllUsers"}){push @{$data{"MyJobs"}},$jobid} } } } close(IN); #For the relevant user, get some additional data: for(@{$data{"MyJobs"}}){GetJobDir($_)} } MMG Skills Lecture Series
Case studies: linux command filter“q” on Verity • So what should you expect to “take home” from the past two slides? • Certainly not the details. • You should have a feel for the scope of the use of perl scripts to do useful things… • And know that there are plenty of working examples from which you can copy parts and learn how to adapt them for your own purposes… MMG Skills Lecture Series
Case studies: linux command filter“qsub” on Verity • Another example is the batch queue submission procedure. • The submission of a job to the batch queue potentially commits a substantial fraction of our computation resources to do your bidding. • An error may result in wasted resources or the job failing for a trivial reason. • It is therefore important that the chances of it doing something useful are high • Hence the “qsub” script that I use (I do not require you to do the same, but why not?). MMG Skills Lecture Series
Case studies: linux command filter“qsub” on Verity • Again, the script is written as a header listing a number of calls to subroutines: #!/usr/bin/perl -w &Defaults; &CommandLine(@ARGV); &CheckOptions; if(!$Switches{'nochange'}){ &ParseDATAfile; &ModifyDATAfile; } if(!$Switches{'tidyonly'}){&Submit} exit; MMG Skills Lecture Series
Case studies: linux command filter“qsub” on Verity: more of a hash ###################################################################### # Set default values: ###################################################################### sub Defaults{ # These three hashes should be the only global parameters: %Settings=( "exec" => "/users/njpg/bin/AIM", "invokation" => $0, "nodes" => 0 ); # %Strings=( parameters=> "", filespace => "filespace{/scratch/njpg/DUMP-FILES}\n", rsb => "parameter{use_real_space_build}\n!parameter{gvec_cutoff=30}\n" ); # %Switches=( 'normalize' => 0, 'override' => 0, 'tidyonly' => 0, 'nochange' => 0, 'rsb' => 0, 'kpar' => 0, 'gga' => 0 ); } ###################################################################### MMG Skills Lecture Series
AIMPRO Filters:FORCES (audience participation, handout) • This (along with many others) is an example of a script that couples AIMPRO data with a graphics representation. • When a structure is being relaxed, AIMPRO outputs information regarding the changes in total energies and the forces on each atom. • FORCES digests this data, prepares summary, plottable, temporary data files, and a gnuplot script. • Look through the script and identify what you do not understand… MMG Skills Lecture Series
AIMPRO Filters:FORCES – what you see MMG Skills Lecture Series
Resources • Cannibalise existing scripts • Books • The web: • http://www.comp.leeds.ac.uk/Perl/ • http://www.tizag.com/perlT/ • http://www.perl.com/pub/a/2000/10/begperl1.html MMG Skills Lecture Series
Exercise • The best way I fund to learn programming is not seeing, but doing: • You should each identify a simple problem of data analysis or production that is a real need in your research. • Write the code and see if it works. • Use existing scripts as source materials. • Get together to discuss your scripts and identify better solutions. MMG Skills Lecture Series