#!/usr/bin/perl -w # Usage: # make_magsynop_batch.pl batchfile machine1 machine2 ... machineN # # batchfile contains entries like: # 1909 1220.26 1247.49 # 1910 1247.49 1274.71 # 1911 1274.71 1301.92 # # where the first column is CR, the second is the MDI day of the start of the CR, # and the third column in the MDI day of the end of the CR # # example: make_magsynop_batch.pl make_magsynop_batchfile.txt n00 n01 suncat # There are two types of ranges used by this script. An O_RANGE has the form -. # The complete range of MDI days used to create a synoptic chart for a given CR is an # O_RANGE. An N-RANGE also has the form -, but it is created by starting with # an O_RANGE and removing the MDI days that also exist in an earlier O_RANGE. Whereas # O_RANGES overlap, N_RANGES do not. $ORANGEAUG = 5; $DELETEFILES = "yes"; $TMPLOG = "/tmp20/mmblog"; my($aidx) = 0; my($arg); my($cmd); my($batchfile); my(@machNames); $machine = 0; my(%machinesInUseRemap); my(%machinesInUseSynop); $guid = 0; $nFH = 10; $fh = 0; my(@fhNames); my(%fhOpen); my(@oRangesAll); # all O_RANGEs to process my(@oRangesRemap); # O_RANGEs completely remapped my(@oRangesSynop); # O_RANGEs from which a synoptic chart has been generated my(@crAll); my(%dayRefcount); # Maps MDI day to number of O_RANGES that are currently using # that day. # Starts off with no day defined. When remapping of a day starts # refcount gets set to 1. Subsequent attempts to remap a day # whose refcount is defined will be prevented (to avoid # duplication) and instead the day's refcount will be incremented # # A day's recount will be decremented whenever a synoptic chart # using that day is complete. # # If a day's refcount is defined with any value, it has been # or is, being remapped. There should be no further remapping # of such days. # # A refcount greater than zero indicates that the day's remapped # images are still being used to create a synoptic chart. Those # images should not be deleted until the refcount becomes 0. my($cr); my($from); my($to); my($doneSched); my($nCmds); my($parentpid); my($pid); my(@range); # 2-d array my(@rangeW); my($oRange); my($nRange); my($resp); my($lowDay); my($hiDay); my($nCharts) = 0; my($nMachines) = 0; my($cmdln); my($ofh); # save default output filehandle when using perl's select() $v2helioexe = "v2helio"; $fdradialexe = "fdradial"; $rootdir = "/synoptic/carrot"; $MAGDIR = "$rootdir/fd_M_96m_01d"; $RADIALDIR = "$rootdir/fd_M_radial_96m_01d"; # Non-differential-rotatation-adjusted images $REMAPDIR = "$rootdir/fd_M_remap_96m_01d"; # Differential-rotatation-adjusted images $DREMAPDIR = "$rootdir/fd_M_dremap_96m_01d"; $ENV{'mdi'} = "wd:$rootdir/{series}/{series}.{#%06d#series}"; system("mkdir -p $MAGDIR"); system("mkdir -p $RADIALDIR"); system("mkdir -p $REMAPDIR"); system("mkdir -p $DREMAPDIR"); $| = 1; # autoflush STDOUT (the default output filehandle); don't # worry about STDERR - buffering is okay for that. while ($arg = shift(@ARGV)) { if ($aidx == 0) { $batchfile = $arg; } else { push(@machNames, $arg); $nMachines++; } $aidx++; } $parentpid = $$; open(BATCHFILE, $batchfile); $doneSched = "no"; $nCmds = 0; # no machine is busy to begin with foreach $machine (@machNames) { $machinesInUseRemap{$machine} = "no"; $machinesInUseSynop{$machine} = "no"; } while (defined($cmd = )) { chomp($cmd); if ($cmd =~ /(\d+\.?\d*)\s+(\d+\.?\d*)\s+(\d+\.?\d*)\s*/) { $cr = sprintf("%d", $1); $from = sprintf("%d", $2); $to = sprintf("%d", $3); $oRange = $from . '-' . $to; push(@oRangesAll, $oRange); push(@crAll, $cr); } } $nCharts = scalar(@oRangesAll); if ($nCharts == 0) { print STDOUT "no synoptic charts specified; nothing to do\n"; $doneSched = "yes"; } else { print STDOUT "generating $nCharts synoptic charts on $nMachines machines\n"; } # schedule cr's onto available machines # # O_RANGES start in @oRangesAll and move to @oRangesRemap then to @oRangesSynop # then they are popped into oblivion. While a child is processing an O_RANGE, # it will not be in any of these arrays. During processing, $nCmds is incremented, # so the total number of not completed O_RANGES equals the number in "All" plus # "Remap" plus "Synop" plus $nCmds # WARNING: when sending data between processing using pipes, use only calls that # flush the write buffer (eg., syswrite and sysread, or set $! = 1, which causes # the output stream to autoflush. while (@oRangesAll > 0 || @oRangesRemap > 0 || @oRangesSynop > 0 || $nCmds > 0) { if ($doneSched ne "yes") { foreach $machine (@machNames) { if ($machinesInUseRemap{$machine} eq "no") { # create remapped images for one CR $oRange = shift(@oRangesAll); $cr = shift(@crAll); if (defined($oRange) && defined($cr)) { $guid = $machine . "_" . $nFH; pipe *{$guid},FH; push(@fhNames, $guid); $fhOpen{$guid} = "yes"; $nFH++; # must augment oRanges for off-center synop charts @range = RangeStrToArr($oRange); @rangeW = AugmentORange(@range); @range = CalcNRange(@rangeW); # refcount each day in this oRange IncRefcount(@rangeW); # save stdout # open($ofh, ">&STDOUT"); unless ($pid = fork()) { # child close($guid); # close read end # perl's pipe() causes stdout, stderr, and stdin to be # shared with the parent, which can cause problems, like # output missing in stdout when redirecting this script's # output to a file using ">&". So, always close these # filehandles, and reopen them if necessary. close(STDOUT); close(STDERR); close(STDIN); # reopen # open(STDOUT, ">&", $ofh); # force autoflush to FH $ofh = select(FH); $| = 1; select($ofh); # redirect stdout to FH open(STDOUT, ">&FH"); Remap($cr, $machine, $nFH - 1, @range); print FH "Done remap $cr $oRange\n"; exit(0); } # parent close(FH); # close write end $machinesInUseRemap{$machine} = "yes"; $nCmds++; } else { $doneSched = "yes"; print STDOUT "finished scheduling jobs\n"; last; } } } } # if any O_RANGEs have been remapped, create synoptic charts for those ranges if (scalar(@oRangesRemap) > 0) { foreach $machine (@machNames) { if ($machinesInUseSynop{$machine} eq "no") { # create a synoptic chart for one CR $oRange = shift(@oRangesRemap); $cr = shift(@crRemap); if (defined($oRange) && defined($cr)) { $guid = $machine . "_" . $nFH; pipe *{$guid},FH; push(@fhNames, $guid); $fhOpen{$guid} = "yes"; $nFH++; # save stdout # open($ofh, ">&STDOUT"); @range = RangeStrToArr($oRange); unless ($pid = fork()) { # child close($guid); # close read end # perl's pipe() causes stdout, stderr, and stdin to be # shared with the parent, which can cause problems, like # output missing in stdout when redirecting this script's # output to a file using ">&". So, always close these # filehandles, and reopen them if necessary. close(STDERR); close(STDIN); close(STDOUT); # reopen stdout # open(STDOUT, ">&", $ofh); # force autoflush to FH $ofh = select(FH); $| = 1; select($ofh); # redirect stdout to FH open(STDOUT, ">&FH"); Synop($cr, $machine, $nFH - 1, @range); print FH "Done synop $cr $oRange\n"; exit(0); } # parent close(FH); # close write end $machinesInUseSynop{$machine} = "yes"; $nCmds++; } } } } if (scalar(@oRangesSynop) > 0) { $oRange = shift(@oRangesSynop); @range = RangeStrToArr($oRange); DecRefcount(@range); # delete remapped images (and their precursors) if they are no longer being used if ($oRange =~ /(.+)-(.+)/) { $lowDay = $1; $hiDay = $2; } for ($day = $lowDay; $day <= $hiDay; $day++) { if ($dayRefcount{$day} == 0) { # delete $day # print STDOUT "synop $oRange done; removing remap for day $day\n"; if ($DELETEFILES eq "yes") { system("rm -r $RADIALDIR/fd_M_radial_96m_01d.00$day/*"); system("rm -r $REMAPDIR/fd_M_remap_96m_01d.00$day/*"); system("rm -r $DREMAPDIR/fd_M_dremap_96m_01d.00$day/*"); } } } } if ($nCmds > 0) { foreach $fh (@fhNames) { if ($fh =~ /(.+)_.*/) { $machine = $1; } else { print STDERR "ERROR - invalid file handle\n"; exit(-1); } if ($fhOpen{$fh} eq "yes") { $rin = ""; $win = ""; vec($rin, fileno(*{$fh}), 1) = 1; $ein = $rin; if (select($rin, $win, $ein, 0)) { sysread($fh, $resp, 128); # find out who returned if ($resp !~ /Done/) { print STDOUT $resp; } else { if ($resp =~ /^([\s\S]+)\nDone/) { print STDOUT $1 . "\n"; } if ($resp =~ /Done\s+remap\s+(\d+)\s+(.+)\s*/) { $cr = $1; $oRange = $2; push(@oRangesRemap, $oRange); push(@crRemap, $cr); print STDOUT "created remaps for CR $cr\n"; $machinesInUseRemap{$machine} = "no"; $fhOpen{$fh} = "no"; close $fh; $nCmds--; } elsif ($resp =~ /Done\s+synop\s+(\d+)\s+(.+)\s*/) { $cr = $1; $oRange = $2; push(@oRangesSynop, $oRange); print STDOUT "created synop for CR $cr\n"; $machinesInUseSynop{$machine} = "no"; $fhOpen{$fh} = "no"; close $fh; $nCmds--; } else { print STDOUT "ERROR - invalid response $resp\n"; } } } } } } } # all done print STDOUT "exiting make_magsynop_batch\n"; exit(0); sub RangeStrToArr { my($rstr) = @_; my(@rarr); if ($rstr =~ /(.+)-(.+)/) { $rarr[0] = $1; $rarr[1] = $2; } return @rarr; } # Okay to increment refcount of 0 - day may have been used, then deleted sub IncRefcount { my(@rangein) = @_; my($lowin); my($hiin); my($day); $lowin = $rangein[0]; $hiin = $rangein[1]; for ($day = $lowin; $day <= $hiin; $day++) { if (!defined($dayRefcount{$day})) { $dayRefcount{$day} = 1; } else { $dayRefcount{$day} = $dayRefcount{$day} + 1; } } } sub DecRefcount { my(@rangein) = @_; my($lowin); my($hiin); my($day); $lowin = $rangein[0]; $hiin = $rangein[1]; for ($day = $lowin; $day <= $hiin; $day++) { if (!defined($dayRefcount{$day})) { print STDOUT "ERROR - can't decrement refcount for day $day; count not defined\n"; } elsif ($dayRefcount{$day} > 0) { $dayRefcount{$day} = $dayRefcount{$day} - 1; } else { print STDOUT "ERROR - can't decrement refcount for day $day; count is zero\n"; } } } sub AugmentORange { my(@rangein) = @_; my(@rangeout); $rangeout[0] = $rangein[0] - $ORANGEAUG; $rangeout[1] = $rangein[1] + $ORANGEAUG; return @rangeout; } # Reduce the size of the range to include only that # which does not lie in any range in the pending ranges list. sub CalcNRange { my(@rangein) = @_; my(@rangeout); my($lowin); my($hiin); my($day); my($lowout); my($hiout); $lowin = $rangein[0]; $hiin = $rangein[1]; for ($day = $lowin; $day <= $hiin; $day++) { if (!defined($dayRefcount{$day}) || $dayRefcount{$day} == 0) { if (!defined($lowout)) { $lowout = $day; } else { $hiout = $day; } } } $rangeout[0] = $lowout; $rangeout[1] = $hiout; return @rangeout; } sub Remap { my($cr, $machine, $nFH, @rangein) = @_; my($lowin); my($hiin); my($day); my($line) = ""; my($nChar); print FH "remapping cr $cr on $machine\n"; for ($day = $rangein[0]; $day <= $rangein[1]; $day++) { system("mkdir -p $RADIALDIR/fd_M_radial_96m_01d.00$day"); system("mkdir -p $REMAPDIR/fd_M_remap_96m_01d.00$day"); system("mkdir -p $DREMAPDIR/fd_M_dremap_96m_01d.00$day"); system("/bin/cp -r /mag/fd_M_96m_01d.00$day $MAGDIR"); # Do radial conversion $cmdln = "ssh $machine \"setenv mdi 'wd:$rootdir/{series}/{series}.{#%06d#series}';$fdradialexe RADIALCORR=1 in=prog:mdi,level:lev1.8,series:fd_M_96m_01d\\[$day\\] out=prog:mdi,level:lev1.8,series:fd_M_radial_96m_01d\\[$day\\] >& $TMPLOG.$nFH.txt\""; print FH $cmdln . "\n"; system($cmdln); open(REMAPFH, "$TMPLOG.$nFH.txt"); while (defined($line = )) { print FH $line; } close(REMAPFH); # Don't adjust for differential rotation $cmdln = "ssh $machine \"setenv mdi 'wd:$rootdir/{series}/{series}.{#%06d#series}';$v2helioexe z=1 MOFFSET=0 MCORLEV=0 VCORLEV=0 MAPRMAX=0.994 MAPLGMAX=90 MAPLGMIN=-90 MAPBMAX=90 LGSHIFT=2 MAPMMAX=1800 SINBDIVS=540 CARRSTRETCH=0 in=prog:mdi,level:lev1.8,series:fd_M_radial_96m_01d\\[$day\\] out=prog:mdi,level:lev1.8,series:fd_M_remap_96m_01d\\[$day\\] >& $TMPLOG.$nFH.txt\""; print FH $cmdln . "\n"; system($cmdln); open(REMAPFH, "$TMPLOG.$nFH.txt"); while (defined($line = )) { print FH $line; } close(REMAPFH); # Adjust for differential rotation $cmdln = "ssh $machine \"setenv mdi 'wd:$rootdir/{series}/{series}.{#%06d#series}';$v2helioexe z=1 MOFFSET=0 MCORLEV=0 VCORLEV=0 MAPRMAX=0.994 MAPLGMAX=90 MAPLGMIN=-90 MAPBMAX=90 LGSHIFT=2 MAPMMAX=1800 SINBDIVS=540 CARRSTRETCH=1 in=prog:mdi,level:lev1.8,series:fd_M_radial_96m_01d\\[$day\\] out=prog:mdi,level:lev1.8,series:fd_M_dremap_96m_01d\\[$day\\] >& $TMPLOG.$nFH.txt\""; print FH $cmdln . "\n"; system($cmdln); open(REMAPFH, "$TMPLOG.$nFH.txt"); while (defined($line = )) { print FH $line; } close(REMAPFH); system("rm $TMPLOG.$nFH.txt"); system("rm -r $MAGDIR/fd_M_96m_01d.00$day"); } } sub Synop { my($cr, $machine, $nFH, @rangein) = @_; my($nChar); my($resp); $cmdln = "ssh $machine \"/synoptic/new_scripts/make_magsynop.pl $cr $rangein[0] $rangein[1] -s >& $TMPLOG.$nFH.txt\""; print FH "running \'$cmdln\' on machine $machine\n"; system($cmdln); open(SYNOPFH, "$TMPLOG.$nFH.txt"); while (defined($line = )) { print FH $line; } close(SYNOPFH); system("rm $TMPLOG.$nFH.txt"); }