Index: trunk/cleanup_aira.php
===================================================================
--- trunk/cleanup_aira.php	(revision 7)
+++ trunk/cleanup_aira.php	(revision 7)
@@ -0,0 +1,844 @@
+<?php
+/*
+ * cleanup_aira.php
+ *
+ * functions relating to copying results and cleaning up the gfac DB
+ *  where the job used an Airavata interface.
+ *
+ */
+
+$us3bin = exec( "ls -d ~us3/bin" );
+include_once "$us3bin/listen-config.php";
+include "/srv/www/htdocs/common/class/experiment_status.php";
+include "/srv/www/htdocs/common/class/experiment_errors.php";
+$me              = 'cleanup_aira.php';
+$email_address   = '';
+$queuestatus     = '';
+$jobtype         = '';
+$db              = '';
+$editXMLFilename = '';
+$status          = '';
+
+function aira_cleanup( $us3_db, $reqID, $gfac_link )
+{
+   global $dbhost;
+   global $user;
+   global $passwd;
+   global $db;
+   global $guser;
+   global $gpasswd;
+   global $gDB;
+   global $me;
+   global $work;
+   global $email_address;
+   global $queuestatus;
+   global $jobtype;
+   global $editXMLFilename;
+   global $submittime;
+   global $status;
+   global $stderr;
+   global $stdout;
+   global $tarfile;
+   global $requestID;
+   global $submit_dir;
+   $me        = 'cleanup_aira.php';
+
+   $requestID = $reqID;
+   $db = $us3_db;
+   write_log( "$me: debug db=$db; requestID=$requestID" );
+
+   $us3_link = mysql_connect( $dbhost, $user, $passwd );
+
+   if ( ! $us3_link )
+   {
+      write_log( "$me: could not connect: $dbhost, $user, $passwd" );
+      mail_to_user( "fail", "Internal Error $requestID\nCould not connect to DB" );
+      return( -1 );
+   }
+
+   $result = mysql_select_db( $db, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: could not select DB $db" );
+      mail_to_user( "fail", "Internal Error $requestID\n$could not select DB $db" );
+      return( -1 );
+   }
+
+   // First get basic info for email messages
+   $query  = "SELECT email, investigatorGUID, editXMLFilename FROM HPCAnalysisRequest " .
+             "WHERE HPCAnalysisRequestID=$requestID";
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query: $query" );
+      mail_to_user( "fail", "Internal Error $requestID\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+
+   list( $email_address, $investigatorGUID, $editXMLFilename ) =  mysql_fetch_array( $result );
+
+   $query  = "SELECT personID FROM people " .
+             "WHERE personGUID='$investigatorGUID'";
+   $result = mysql_query( $query, $us3_link );
+
+   list( $personID ) = mysql_fetch_array( $result );
+
+   $query  = "SELECT clusterName, submitTime, queueStatus, method "              .
+             "FROM HPCAnalysisRequest h, HPCAnalysisResult r "                   .
+             "WHERE h.HPCAnalysisRequestID=$requestID "                          .
+             "AND h.HPCAnalysisRequestID=r.HPCAnalysisRequestID";
+
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+
+   if ( mysql_num_rows( $result ) == 0 )
+   {
+      write_log( "$me: US3 Table error - No records for requestID: $requestID" );
+      return( -1 );
+   }
+
+   list( $cluster, $submittime, $queuestatus, $jobtype ) = mysql_fetch_array( $result );
+
+   // Get the GFAC ID
+   $query = "SELECT HPCAnalysisResultID, gfacID FROM HPCAnalysisResult " .
+            "WHERE HPCAnalysisRequestID=$requestID";
+
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query: $query" );
+      mail_to_user( "fail", "Internal Error $requestID\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+
+   list( $HPCAnalysisResultID, $gfacID ) = mysql_fetch_array( $result ); 
+
+   // Get data from global GFAC DB then insert it into US3 DB
+
+   $result = mysql_select_db( $gDB, $gfac_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Could not connect to DB $gDB" );
+      mail_to_user( "fail", "Internal Error $requestID\nCould not connect to DB $gDB" );
+      return( -1 );
+   }
+
+   $query = "SELECT status, cluster, id FROM analysis " .
+            "WHERE gfacID='$gfacID'";
+
+   $result = mysql_query( $query, $gfac_link );
+   if ( ! $result )
+   {
+      write_log( "$me: Could not select GFAC status for $gfacID" );
+      mail_to_user( "fail", "Could not select GFAC status for $gfacID" );
+      return( -1 );
+   }
+   
+   list( $status, $cluster, $id ) = mysql_fetch_array( $result );
+
+   if ( $cluster == 'bcf-local'  || $cluster == 'alamo-local' )
+   {
+         $clushost = $cluster;
+         $clushost = preg_replace( "/\-local/", "", $clushost );
+         get_local_files( $gfac_link, $clushost, $requestID, $id, $gfacID );
+   }
+
+
+   $query = "SELECT id FROM analysis " .
+            "WHERE gfacID='$gfacID'";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+      mail_to_user( "fail", "Internal error " . mysql_error( $gfac_link ) );
+      return( -1 );
+   }
+
+   list( $analysisID ) = mysql_fetch_array( $result );
+
+   // Get the request guid (LIMS submit dir name)
+   $query  = "SELECT HPCAnalysisRequestGUID FROM HPCAnalysisRequest " .
+             "WHERE HPCAnalysisRequestID = $requestID ";
+   $result = mysql_query( $query, $us3_link );
+   
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+   }
+
+   list( $requestGUID ) = mysql_fetch_array( $result );
+   $output_dir = "$submit_dir/$requestGUID";
+
+   // Get stderr,stdout,tarfile from work directory
+   if ( ! is_dir( "$output_dir" ) ) mkdir( "$output_dir", 0770 );
+   chdir( "$output_dir" );
+//write_log( "$me: gfacID=$gfacID" );
+//write_log( "$me: submit_dir=$submit_dir" );
+//write_log( "$me: requestGUID=$requestGUID" );
+write_log( "$me: output_dir=$output_dir" );
+
+   $stderr     = "";
+   $stdout     = "";
+   $tarfile    = "";
+   $fn_stderr  = "Ultrascan.stderr";
+   $fn_stdout  = "Ultrascan.stdout";
+   $fn_tarfile = "analysis-results.tar";
+   $num_try    = 0;
+   while ( ! file_exists( $fn_tarfile ) && $num_try < 3 )
+   {
+      sleep( 10 );
+      $num_try++;
+   }
+
+   $ofiles     = scandir( $output_dir );
+   foreach ( $ofiles as $ofile )
+   {
+      if ( preg_match( "/^" . $gfacID . ".*stderr$/", $ofile ) )
+         $fn_stderr  = $ofile;
+      if ( preg_match( "/^" . $gfacID . ".*stdout$/", $ofile ) )
+         $fn_stdout  = $ofile;
+//write_log( "$me:    ofile=$ofile" );
+   }
+write_log( "$me: fn_stderr=$fn_stderr" );
+write_log( "$me: fn_stdout=$fn_stdout" );
+if (file_exists($fn_tarfile)) write_log( "$me: fn_tarfile=$fn_tarfile" );
+else                          write_log( "$me: NOT FOUND: $fn_tarfile" );
+
+   if ( file_exists( $fn_stderr  ) ) $stderr   = file_get_contents( $fn_stderr  );
+   if ( file_exists( $fn_stdout  ) ) $stdout   = file_get_contents( $fn_stdout  );
+   if ( file_exists( $fn_tarfile ) ) $tarfile  = file_get_contents( $fn_tarfile );
+
+   if ( $cluster == 'alamo'  || $cluster == 'alamo-local' )
+   {  // Filter "ipath_userinit" lines out of alamo stdout lines
+      $prefln = strlen( $stdout );
+      $output = array();
+      exec( "grep -v 'ipath_userinit' $fn_stdout 2>&1", $output, $err );
+      $stdout = implode( "\n", $output );
+      $posfln = strlen( $stdout );
+write_log( "$me: fn_stdout : filtered. Length $prefln -> $posfln ." );
+   }
+
+   // Save queue messages for post-mortem analysis
+   $query = "SELECT message, time FROM queue_messages " .
+            "WHERE analysisID = $analysisID " .
+            "ORDER BY time ";
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      // Just log it and continue
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+   }
+
+   $now = date( 'Y-m-d H:i:s' );
+   $message_log = "US3 DB: $db\n" .
+                  "RequestID: $requestID\n" .
+                  "GFAC ID: $gfacID\n" .
+                  "Processed: $now\n\n" .
+                  "Queue Messages\n\n" ;
+   if ( mysql_num_rows( $result ) > 0 )
+   {
+      while ( list( $message, $time ) = mysql_fetch_array( $result ) )
+         $message_log .= "$time $message\n";
+   }
+
+   $query = "DELETE FROM queue_messages " .
+            "WHERE analysisID = $analysisID ";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      // Just log it and continue
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+   }
+
+   $query = "SELECT queue_msg FROM analysis " .
+            "WHERE gfacID='$gfacID' ";
+
+   $result = mysql_query( $query, $gfac_link );
+   list( $queue_msg ) = mysql_fetch_array( $result );
+
+   // But let's allow for investigation of other large stdout and/or stderr
+   if ( strlen( $stdout ) > 20480000 ||
+        strlen( $stderr ) > 20480000 )
+      write_log( "$me: stdout + stderr larger than 20M - $gfacID\n" );
+
+   $message_log .= "\n\n\nStdout Contents\n\n" .
+                   $stdout .
+                   "\n\n\nStderr Contents\n\n" .
+                   $stderr .
+                   "\n\n\nGFAC Status: $status\n" .
+                   "GFAC message field: $queue_msg\n";
+
+   // Delete data from GFAC DB
+   $query = "DELETE from analysis WHERE gfacID='$gfacID'";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      // Just log it and continue
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+   }
+
+
+   // Try to create it if necessary, and write the file
+   // Let's use FILE_APPEND, in case this is the second time around and the 
+   //  GFAC job status was INSERTed, rather than UPDATEd
+   if ( ! is_dir( $output_dir ) )
+      mkdir( $output_dir, 0775, true );
+   $message_filename = "$output_dir/$db-$requestID-messages.txt";
+   file_put_contents( $message_filename, $message_log, FILE_APPEND );
+  // mysql_close( $gfac_link );
+
+   /////////
+   // Insert data into HPCAnalysis
+
+   $query = "UPDATE HPCAnalysisResult SET "                              .
+            "stderr='" . mysql_real_escape_string( $stderr, $us3_link ) . "', " .
+            "stdout='" . mysql_real_escape_string( $stdout, $us3_link ) . "', " .
+            "queueStatus='completed' " .
+            "WHERE HPCAnalysisResultID=$HPCAnalysisResultID";
+
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+      mail_to_user( "fail", "Bad query:\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+
+   // Delete data from GFAC DB
+   $query = "DELETE from analysis WHERE gfacID='$gfacID'";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      // Just log it and continue
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+   }
+
+   // Expand the tar file
+
+   if ( strlen( $tarfile ) == 0 )
+   {
+      write_log( "$me: No tarfile" );
+      mail_to_user( "fail", "No results" );
+      return( -1 );
+   }
+
+   $tar_out = array();
+   exec( "tar -xf analysis-results.tar 2>&1", $tar_out, $err );
+
+   // Insert the model files and noise files
+   $files      = file( "analysis_files.txt", FILE_IGNORE_NEW_LINES );
+   $noiseIDs   = array();
+   $modelGUIDs = array();
+
+   foreach ( $files as $file )
+   {
+      $split = explode( ";", $file );
+
+      if ( count( $split ) > 1 )
+      {
+         list( $fn, $meniscus, $mc_iteration, $variance ) = explode( ";", $file );
+      
+         list( $other, $mc_iteration ) = explode( "=", $mc_iteration );
+         list( $other, $variance     ) = explode( "=", $variance );
+         list( $other, $meniscus     ) = explode( "=", $meniscus );
+      }
+      else
+         $fn = $file;
+
+      if ( preg_match( "/mdl.tmp$/", $fn ) )
+         continue;
+
+      if ( filesize( $fn ) < 100 )
+      {
+         write_log( "$me:fn is invalid $fn size filesize($fn)" );
+         mail_to_user( "fail", "Internal error\n$fn is invalid" );
+         return( -1 );
+      }
+
+      if ( preg_match( "/^job_statistics\.xml$/", $fn ) ) // Job statistics file
+      {
+         $xml         = file_get_contents( $fn );
+         $statistics  = parse_xml( $xml, 'statistics' );
+//         $ntries      = 0;
+//
+//         while ( $statistics['cpucount'] < 1  &&  $ntries < 3 )
+//         {  // job_statistics file not totally copied, so retry
+//            sleep( 10 );
+//            $xml         = file_get_contents( $fn );
+//            $statistics  = parse_xml( $xml, 'statistics' );
+//            $ntries++;
+//write_log( "$me:jobstats retry $ntries" );
+//         }
+//write_log( "$me:cputime=$statistics['cputime']" );
+
+         $otherdata   = parse_xml( $xml, 'id' );
+
+         $query = "UPDATE HPCAnalysisResult SET "   .
+                  "wallTime = {$statistics['walltime']}, " .
+                  "CPUTime = {$statistics['cputime']}, " .
+                  "CPUCount = {$statistics['cpucount']}, " .
+                  "max_rss = {$statistics['maxmemory']}, " .
+                  "startTime = '{$otherdata['starttime']}', " .
+                  "endTime = '{$otherdata['endtime']}', " .
+                  "mgroupcount = {$otherdata['groupcount']} " .
+                  "WHERE HPCAnalysisResultID=$HPCAnalysisResultID";
+         $result = mysql_query( $query, $us3_link );
+
+         if ( ! $result )
+         {
+            write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+         }
+
+         file_put_contents( "$output_dir/$fn", $xml );    // Copy to submit dir
+
+      }
+
+      else if ( preg_match( "/\.noise/", $fn ) > 0 ) // It's a noise file
+      {
+         $xml        = file_get_contents( $fn );
+         $noise_data = parse_xml( $xml, "noise" );
+         $type       = ( $noise_data[ 'type' ] == "ri" ) ? "ri_noise" : "ti_noise";
+         $desc       = $noise_data[ 'description' ];
+         $modelGUID  = $noise_data[ 'modelGUID' ];
+         $noiseGUID  = $noise_data[ 'noiseGUID' ];
+
+         $query = "INSERT INTO noise SET "  .
+                  "noiseGUID='$noiseGUID'," .
+                  "modelGUID='$modelGUID'," .
+                  "editedDataID=1, "        .
+                  "modelID=1, "             .
+                  "noiseType='$type',"      .
+                  "description='$desc',"    .
+                  "xml='" . mysql_real_escape_string( $xml, $us3_link ) . "'";
+
+         // Add later after all files are processed: editDataID, modelID
+
+         $result = mysql_query( $query, $us3_link );
+
+         if ( ! $result )
+         {
+            write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+            mail_to_user( "fail", "Internal error\n$query\n" . mysql_error( $us3_link ) );
+            return( -1 );
+         }
+
+         $id        = mysql_insert_id( $us3_link );
+         $file_type = "noise";
+         $noiseIDs[] = $id;
+
+         // Keep track of modelGUIDs for later, when we replace them
+         $modelGUIDs[ $id ] = $modelGUID;
+         
+      }
+      else  // It's a model file
+      {
+         $xml         = file_get_contents( $fn );
+         $model_data  = parse_xml( $xml, "model" );
+         $description = $model_data[ 'description' ];
+         $modelGUID   = $model_data[ 'modelGUID' ];
+         $editGUID    = $model_data[ 'editGUID' ];
+
+         if ( $mc_iteration > 1 )
+         {
+            $miter       = sprintf( "_mcN%03d", $mc_iteration );
+            $description = preg_replace( "/_mc[0-9]+/", $miter, $description );
+write_log( "$me:   MODELUpd: O:description=$description" );
+         }
+
+         $query = "INSERT INTO model SET "       .
+                  "modelGUID='$modelGUID',"      .
+                  "editedDataID="                .
+                  "(SELECT editedDataID FROM editedData WHERE editGUID='$editGUID')," .
+                  "description='$description',"  .
+                  "MCIteration='$mc_iteration'," .
+                  "meniscus='$meniscus'," .
+                  "variance='$variance'," .
+                  "xml='" . mysql_real_escape_string( $xml, $us3_link ) . "'";
+
+         $result = mysql_query( $query, $us3_link );
+
+         if ( ! $result )
+         {
+            write_log( "$me: Bad query:\n$query " . mysql_error( $us3_link ) );
+            mail_to_user( "fail", "Internal error\n$query\n" . mysql_error( $us3_link ) );
+            return( -1 );
+         }
+
+         $modelID   = mysql_insert_id( $us3_link );
+         $id        = $modelID;
+         $file_type = "model";
+
+         $query = "INSERT INTO modelPerson SET " .
+                  "modelID=$modelID, personID=$personID";
+         $result = mysql_query( $query, $us3_link );
+      }
+
+      $query = "INSERT INTO HPCAnalysisResultData SET "       .
+               "HPCAnalysisResultID='$HPCAnalysisResultID', " .
+               "HPCAnalysisResultType='$file_type', "         .
+               "resultID=$id";
+
+      $result = mysql_query( $query, $us3_link );
+
+      if ( ! $result )
+      {
+         write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+         mail_to_user( "fail", "Internal error\n$query\n" . mysql_error( $us3_link ) );
+         return( -1 );
+      }
+   }
+
+   // Now fix up noise entries
+   // For noise files, there is, at most two: ti_noise and ri_noise
+   // In this case there will only be one modelID
+
+   foreach ( $noiseIDs as $noiseID )
+   {
+      $modelGUID = $modelGUIDs[ $noiseID ];
+      $query = "UPDATE noise SET "                                                 .
+               "editedDataID="                                                     .
+               "(SELECT editedDataID FROM model WHERE modelGUID='$modelGUID'),"    .
+               "modelID="                                                          .
+               "(SELECT modelID FROM model WHERE modelGUID='$modelGUID')"          .
+               "WHERE noiseID=$noiseID";
+
+      $result = mysql_query( $query, $us3_link );
+
+      if ( ! $result )
+      {
+         write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+         mail_to_user( "fail", "Bad query\n$query\n" . mysql_error( $us3_link ) );
+         return( -1 );
+      }
+   }
+
+   // Copy results to LIMS submit directory (files there are deleted after 7 days)
+   global $submit_dir; // LIMS submit files dir
+   
+   // Get the request guid (LIMS submit dir name)
+   $query  = "SELECT HPCAnalysisRequestGUID FROM HPCAnalysisRequest " .
+             "WHERE HPCAnalysisRequestID = $requestID ";
+   $result = mysql_query( $query, $us3_link );
+   
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+   }
+   
+//   list( $requestGUID ) = mysql_fetch_array( $result );
+//   
+//   chdir( "$submit_dir/$requestGUID" );
+//   $f = fopen( "analysis-results.tar", "w" );
+//   fwrite( $f, $tarfile );
+//   fclose( $f );
+
+   // Clean up
+//   chdir ( $work );
+   // exec( "rm -rf $gfacID" );
+
+   mysql_close( $us3_link );
+
+   /////////
+   // Send email 
+
+   mail_to_user( "success", "" );
+}
+
+function mail_to_user( $type, $msg )
+{
+   // Note to me. Just changed subject line to include a modified $status instead 
+   // of the $type variable passed. More informative than just "fail" or "success." 
+   // See how it works for awhile and then consider removing $type parameter from 
+   // function.
+   global $email_address;
+   global $submittime;
+   global $queuestatus;
+   global $status;
+   global $cluster;
+   global $jobtype;
+   global $org_name;
+   global $admin_email;
+   global $db;
+   global $dbhost;
+   global $requestID;
+   global $gfacID;
+   global $editXMLFilename;
+   global $stdout;
+
+global $me;
+write_log( "$me mail_to_user(): sending email to $email_address for $gfacID" );
+
+   // Get GFAC status and message
+   // function get_gfac_message() also sets global $status
+   $gfac_message = get_gfac_message( $gfacID );
+   if ( $gfac_message === false ) $gfac_message = "Job Finished";
+      
+   // Create a status to put in the subject line
+   switch ( $status )
+   {
+      case "COMPLETE":
+         $subj_status = 'completed';
+         break;
+
+      case "CANCELLED":
+      case "CANCELED":
+         $subj_status = 'canceled';
+         break;
+
+      case "FAILED":
+         $subj_status = 'failed';
+         if ( preg_match( "/^US3-AIRA/i", $gfacID ) )
+         {  // For A/Thrift FAIL, get error message
+            $gfac_message = getExperimentErrors( $gfacID );
+//$gfac_message .= "Test ERROR MESSAGE";
+         }
+         break;
+
+      case "ERROR":
+         $subj_status = 'unknown error';
+         break;
+
+      default:
+         $subj_status = $status;       // For now
+         break;
+
+   }
+
+   $queuestatus = $subj_status;
+   $limshost    = $dbhost;
+   if ( $limshost == 'localhost' )
+      $limshost    = gethostname();
+
+   // Parse the editXMLFilename
+   list( $runID, $editID, $dataType, $cell, $channel, $wl, $ext ) =
+      explode( ".", $editXMLFilename );
+
+   $headers  = "From: $org_name Admin<$admin_email>"     . "\n";
+   $headers .= "Cc: $org_name Admin<$admin_email>"       . "\n";
+
+   // Set the reply address
+   $headers .= "Reply-To: $org_name<$admin_email>"      . "\n";
+   $headers .= "Return-Path: $org_name<$admin_email>"   . "\n";
+
+   // Try to avoid spam filters
+   $now = time();
+   $headers .= "Message-ID: <" . $now . "cleanup@$dbhost>\n";
+   $headers .= "X-Mailer: PHP v" . phpversion()         . "\n";
+   $headers .= "MIME-Version: 1.0"                      . "\n";
+   $headers .= "Content-Transfer-Encoding: 8bit"        . "\n";
+
+   $subject       = "UltraScan Job Notification - $subj_status - " . substr( $gfacID, 0, 16 );
+   $message       = "
+   Your UltraScan job is complete:
+
+   Submission Time : $submittime
+   LIMS Host       : $limshost
+   Analysis ID     : $gfacID
+   Request ID      : $requestID  ( $db )
+   RunID           : $runID
+   EditID          : $editID
+   Data Type       : $dataType
+   Cell/Channel/Wl : $cell / $channel / $wl
+   Status          : $queuestatus
+   Cluster         : $cluster
+   Job Type        : $jobtype
+   GFAC Status     : $status
+   GFAC Message    : $gfac_message
+   Stdout          : $stdout
+   ";
+
+   if ( $type != "success" ) $message .= "Grid Ctrl Error :  $msg\n";
+
+   // Handle the error case where an error occurs before fetching the
+   // user's email address
+   if ( $email_address == "" ) $email_address = $admin_email;
+
+   mail( $email_address, $subject, $message, $headers );
+}
+
+function parse_xml( $xml, $type )
+{
+   $parser = new XMLReader();
+   $parser->xml( $xml );
+
+   $results = array();
+
+   while ( $parser->read() )
+   {
+      if ( $parser->name == $type )
+      {
+         while ( $parser->moveToNextAttribute() ) 
+         {
+            $results[ $parser->name ] = $parser->value;
+         }
+
+         break;
+      }
+   }
+
+   $parser->close();
+   return $results;
+}
+
+// Function to get information about the current job GFAC
+function get_gfac_message( $gfacID )
+{
+  global $serviceURL;
+  global $me;
+
+  $hex = "[0-9a-fA-F]";
+  if ( ! preg_match( "/^US3-Experiment/i", $gfacID ) &&
+       ! preg_match( "/^US3-$hex{8}-$hex{4}-$hex{4}-$hex{4}-$hex{12}$/", $gfacID ) )
+   {
+      // Then it's not a GFAC job
+      return false;
+   }
+
+   $url = "$serviceURL/jobstatus/$gfacID";
+   try
+   {
+      $post = new HttpRequest( $url, HttpRequest::METH_GET );
+      $http = $post->send();
+      $xml  = $post->getResponseBody();      
+   }
+   catch ( HttpException $e )
+   {
+      write_log( "$me: Job status not available - $gfacID" );
+      return false;
+   }
+
+   // Parse the result
+   $gfac_message = parse_message( $xml );
+
+   return $gfac_message;
+}
+
+function parse_message( $xml )
+{
+   global $status;
+   $status       = "";
+   $gfac_message = "";
+
+   $parser = new XMLReader();
+   $parser->xml( $xml );
+
+   $results = array();
+
+   while( $parser->read() )
+   {
+      $type = $parser->nodeType;
+
+      if ( $type == XMLReader::ELEMENT )
+         $name = $parser->name;
+
+      else if ( $type == XMLReader::TEXT )
+      {
+         if ( $name == "status" ) 
+            $status       = $parser->value;
+         else 
+            $gfac_message = $parser->value; 
+      }
+   }
+      
+   $parser->close();
+   return $gfac_message;
+}
+
+function get_local_files( $gfac_link, $cluster, $requestID, $id, $gfacID )
+{
+   global $work;
+   global $work_remote;
+   global $me;
+   global $db;
+   global $status;
+
+   // Figure out local working directory
+   if ( ! is_dir( "$work/$gfacID" ) ) mkdir( "$work/$gfacID", 0770 );
+   $pwd = chdir( "$work/$gfacID" );
+
+   // Figure out remote directory
+   $remoteDir = sprintf( "$work_remote/$db-%06d", $requestID );
+
+   // Get stdout, stderr, output/analysis-results.tar
+   $output = array();
+//   $cmd = "scp us3@$cluster.uthscsa.edu:$remoteDir/stdout . 2>&1";
+//
+//   exec( $cmd, $output, $stat );
+//   if ( $stat != 0 ) 
+//      write_log( "$me: Bad exec:\n$cmd\n" . implode( "\n", $output ) );
+//     
+//   $cmd = "scp us3@$cluster.uthscsa.edu:$remoteDir/stderr . 2>&1";
+//   exec( $cmd, $output, $stat );
+//   if ( $stat != 0 ) 
+//      write_log( "$me: Bad exec:\n$cmd\n" . implode( "\n", $output ) );
+
+   $cmd = "scp us3@$cluster.uthscsa.edu:$remoteDir/output/analysis-results.tar . 2>&1";
+   exec( $cmd, $output, $stat );
+   if ( $stat != 0 ) 
+      write_log( "$me: Bad exec:\n$cmd\n" . implode( "\n", $output ) );
+
+   $cmd = "scp us3@$cluster.uthscsa.edu:$remoteDir/stdout . 2>&1";
+   exec( $cmd, $output, $stat );
+   if ( $stat != 0 ) 
+   {
+      write_log( "$me: Bad exec:\n$cmd\n" . implode( "\n", $output ) );
+      sleep( 10 );
+      write_log( "$me: RETRY" );
+      exec( $cmd, $output, $stat );
+      if ( $stat != 0 ) 
+         write_log( "$me: Bad exec:\n$cmd\n" . implode( "\n", $output ) );
+   }
+     
+   $cmd = "scp us3@$cluster.uthscsa.edu:$remoteDir/stderr . 2>&1";
+   exec( $cmd, $output, $stat );
+   if ( $stat != 0 ) 
+   {
+      write_log( "$me: Bad exec:\n$cmd\n" . implode( "\n", $output ) );
+      sleep( 10 );
+      write_log( "$me: RETRY" );
+      exec( $cmd, $output, $stat );
+      if ( $stat != 0 ) 
+         write_log( "$me: Bad exec:\n$cmd\n" . implode( "\n", $output ) );
+   }
+
+   // Write the files to gfacDB
+
+   if ( file_exists( "stderr" ) ) $stderr  = file_get_contents( "stderr" );
+   if ( file_exists( "stdout" ) ) $stdout  = file_get_contents( "stdout" );
+   if ( file_exists( "analysis-results.tar" ) ) 
+      $tarfile = file_get_contents( "analysis-results.tar" );
+
+   $query = "UPDATE analysis SET " .
+            "stderr='"  . mysql_real_escape_string( $stderr,  $gfac_link ) . "'," .
+            "stdout='"  . mysql_real_escape_string( $stdout,  $gfac_link ) . "'," .
+            "tarfile='" . mysql_real_escape_string( $tarfile, $gfac_link ) . "'";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+      echo "Bad query\n";
+      return( -1 );
+   }
+}
+?>
Index: trunk/cleanup_gfac.php
===================================================================
--- trunk/cleanup_gfac.php	(revision 7)
+++ trunk/cleanup_gfac.php	(revision 7)
@@ -0,0 +1,673 @@
+<?php
+/*
+ * cleanup_gfac.php
+ *
+ * functions relating to copying results and cleaning up the gfac DB
+ *
+ */
+
+$us3bin = exec( "ls -d ~us3/bin" );
+include_once "$us3bin/listen-config.php";
+$me              = 'cleanup_gfac.php';
+$email_address   = '';
+$queuestatus     = '';
+$jobtype         = '';
+$db              = '';
+$editXMLFilename = '';
+$status          = '';
+
+function gfac_cleanup( $us3_db, $reqID, $gfac_link )
+{
+   global $dbhost;
+   global $user;
+   global $passwd;
+   global $db;
+   global $guser;
+   global $gpasswd;
+   global $gDB;
+   global $me;
+   global $work;
+   global $email_address;
+   global $queuestatus;
+   global $jobtype;
+   global $editXMLFilename;
+   global $submittime;
+   global $status;
+   global $stdout;
+   global $requestID;
+
+   $requestID = $reqID;
+   $db = $us3_db;
+   write_log( "$me: debug db=$db; requestID=$requestID" );
+
+   $us3_link = mysql_connect( $dbhost, $user, $passwd );
+
+   if ( ! $us3_link )
+   {
+      write_log( "$me: could not connect: $dbhost, $user, $passwd" );
+      mail_to_user( "fail", "Internal Error $requestID\nCould not connect to DB" );
+      return( -1 );
+   }
+
+   $result = mysql_select_db( $db, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: could not select DB $db" );
+      mail_to_user( "fail", "Internal Error $requestID\n$could not select DB $db" );
+      return( -1 );
+   }
+
+   // First get basic info for email messages
+   $query  = "SELECT email, investigatorGUID, editXMLFilename FROM HPCAnalysisRequest " .
+             "WHERE HPCAnalysisRequestID=$requestID";
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query: $query" );
+      mail_to_user( "fail", "Internal Error $requestID\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+
+   list( $email_address, $investigatorGUID, $editXMLFilename ) =  mysql_fetch_array( $result );
+
+   $query  = "SELECT personID FROM people " .
+             "WHERE personGUID='$investigatorGUID'";
+   $result = mysql_query( $query, $us3_link );
+
+   list( $personID ) = mysql_fetch_array( $result );
+
+   /*
+   $query  = "SELECT clusterName, submitTime, queueStatus, method "              .
+             "FROM HPCAnalysisRequest h LEFT JOIN HPCAnalysisResult "            .
+             "ON h.HPCAnalysisRequestID=HPCAnalysisResult.HPCAnalysisRequestID " .
+             "WHERE h.HPCAnalysisRequestID=$requestID";
+   */
+   $query  = "SELECT clusterName, submitTime, queueStatus, method "              .
+             "FROM HPCAnalysisRequest h, HPCAnalysisResult r "                   .
+             "WHERE h.HPCAnalysisRequestID=$requestID "                          .
+             "AND h.HPCAnalysisRequestID=r.HPCAnalysisRequestID";
+
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+
+   if ( mysql_num_rows( $result ) == 0 )
+   {
+      write_log( "$me: US3 Table error - No records for requestID: $requestID" );
+      return( -1 );
+   }
+
+   list( $cluster, $submittime, $queuestatus, $jobtype ) = mysql_fetch_array( $result );
+
+   // Get the GFAC ID
+   $query = "SELECT HPCAnalysisResultID, gfacID FROM HPCAnalysisResult " .
+            "WHERE HPCAnalysisRequestID=$requestID";
+
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query: $query" );
+      mail_to_user( "fail", "Internal Error $requestID\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+
+   list( $HPCAnalysisResultID, $gfacID ) = mysql_fetch_array( $result ); 
+
+   ////////
+   // Get data from global GFAC DB and insert it into US3 DB
+   // $gfac_link = mysql_connect( $dbhost, $guser, $gpasswd );
+
+   $result = mysql_select_db( $gDB, $gfac_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Could not connect to DB $gDB" );
+      mail_to_user( "fail", "Internal Error $requestID\nCould not connect to DB $gDB" );
+      return( -1 );
+   }
+
+   $query = "SELECT status, cluster, id FROM analysis " .
+            "WHERE gfacID='$gfacID'";
+
+   $result = mysql_query( $query, $gfac_link );
+   if ( ! $result )
+   {
+      write_log( "$me: Could not select GFAC status for $gfacID" );
+      mail_to_user( "fail", "Could not select GFAC status for $gfacID" );
+      return( -1 );
+   }
+
+   $num_rows = mysql_num_rows( $result );
+   if ( $num_rows == 0 )
+   {
+      write_log( "$me: Cleanup analysis query found 0 entries for $gfacID" );
+      return( 0 );
+   }
+//else
+//{
+//write_log( "$me:    db=$db; num_rows=$num_rows; queuestatus=$queuestatus" );
+//}
+
+   list( $status, $cluster, $id ) = mysql_fetch_array( $result );
+//write_log( "$me:     db=$db; requestID=$requestID; status=$status; cluster=$cluster" );
+
+   if ( $cluster == 'bcf-local'  ||  $cluster == 'alamo-local' )
+   {
+      $clushost = $cluster;
+      $clushost = preg_replace( "/\-local/", "", $clushost );
+      get_local_files( $gfac_link, $clushost, $requestID, $id, $gfacID );
+   }
+
+   $query = "SELECT id, stderr, stdout, tarfile FROM analysis " .
+            "WHERE gfacID='$gfacID'";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+      mail_to_user( "fail", "Internal error " . mysql_error( $gfac_link ) );
+      return( -1 );
+   }
+
+   $num_rows = mysql_num_rows( $result );
+   if ( $num_rows == 0 )
+   {
+      write_log( "$me: Cleanup analysis query found 0 entries for $gfacID" );
+      return( 0 );
+   }
+
+   list( $analysisID, $stderr, $stdout, $tarfile ) = mysql_fetch_array( $result );
+
+   if ( strlen( $tarfile ) > 0 )
+   {  // Log success at fetch attempt
+      write_log( "$me: Successful data fetch: $requestID $gfacID" );
+   }
+   else
+   {  // Log failure at fetch attempt
+      write_log( "$me: Failed data fetch: $requestID $gfacID" );
+      if ( $analysisID == '' )
+         $analysisID = '0';
+   }
+
+   // Save queue messages for post-mortem analysis
+   $query = "SELECT message, time FROM queue_messages " .
+            "WHERE analysisID = $analysisID " .
+            "ORDER BY time ";
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      // Just log it and continue
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+   }
+
+   $now = date( 'Y-m-d H:i:s' );
+   $message_log = "US3 DB: $db\n" .
+                  "RequestID: $requestID\n" .
+                  "GFAC ID: $gfacID\n" .
+                  "Processed: $now\n\n" .
+                  "Queue Messages\n\n" ;
+
+   $need_finish = ( $status == 'COMPLETE' );
+
+   if ( mysql_num_rows( $result ) > 0 )
+   {
+      $time_msg = time();
+      while ( list( $message, $time ) = mysql_fetch_array( $result ) )
+      {
+//write_log( "$me: message=$message" );
+         $message_log .= "$time $message\n";
+         if ( preg_match( "/^Finished/i", $message ) )
+            $need_finish = false;
+         $time_msg = strtotime( $time );
+      }
+
+      if ( $need_finish )
+      {  // No 'Finished' yet:  forget if too much time has passed
+         $time_now = time();
+         $tdelta   = $time_now - $time_msg;
+write_log( "$me: no-Finish time: tnow=$time_now, tmsg=$time_msg, tdelt=$tdelta" );
+         if ( $tdelta > 600 )
+            $need_finish = false;
+      }
+//write_log( "$me: no-Finish time: tnow=$time_now, tmsg=$time_msg, tdelt=$tdelta" );
+   }
+   else
+   {
+      write_log( "$me: No messages for analysisID=$analysisID ." );
+      $need_finish = false;
+   }
+
+   if ( $need_finish )
+   {
+      write_log( "$me: Cleanup has not yet found 'Finished' for $gfacID" );
+      return( 0 );
+   }
+
+   $query = "DELETE FROM queue_messages " .
+            "WHERE analysisID = $analysisID ";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      // Just log it and continue
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+   }
+
+   // Save stdout, stderr, etc. for message log
+   $query  = "SELECT stdout, stderr, status, queue_msg FROM analysis " .
+             "WHERE gfacID='$gfacID' ";
+   $result = mysql_query( $query, $gfac_link );
+   try
+   {
+      // What if this is too large?
+      list( $stdout, $stderr, $status, $queue_msg ) = mysql_fetch_array( $result );
+   }
+   catch ( Exception $e )
+   {
+      write_log( "$me: stdout + stderr larger than 128M - $gfacID\n" . mysql_error( $gfac_link ) );
+      // Just go ahead and clean up
+   }
+
+   // But let's allow for investigation of other large stdout and/or stderr
+   if ( strlen( $stdout ) > 20480000 ||
+        strlen( $stderr ) > 20480000 )
+      write_log( "$me: stdout + stderr larger than 20M - $gfacID\n" );
+
+   $message_log .= "\n\n\nStdout Contents\n\n" .
+                   $stdout .
+                   "\n\n\nStderr Contents\n\n" .
+                   $stderr .
+                   "\n\n\nGFAC Status: $status\n" .
+                   "GFAC message field: $queue_msg\n";
+
+   // Delete data from GFAC DB
+   $query = "DELETE from analysis WHERE gfacID='$gfacID'";
+
+   $result = mysql_query( $query, $gfac_link );
+
+   if ( ! $result )
+   {
+      // Just log it and continue
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $gfac_link ) );
+   }
+write_log( "$me: GFAC DB entry deleted" );
+
+   // Copy queue messages to LIMS submit directory (files there are deleted after 7 days)
+   global $submit_dir;
+   
+   // Get the request guid (LIMS submit dir name)
+   $query  = "SELECT HPCAnalysisRequestGUID FROM HPCAnalysisRequest " .
+             "WHERE HPCAnalysisRequestID = $requestID ";
+   $result = mysql_query( $query, $us3_link );
+   
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+   }
+   
+   list( $requestGUID ) = mysql_fetch_array( $result );
+   $output_dir = "$submit_dir/$requestGUID";
+write_log( "$me: Output dir determined: $output_dir" );
+
+   // Try to create it if necessary, and write the file
+   // Let's use FILE_APPEND, in case this is the second time around and the 
+   //  GFAC job status was INSERTed, rather than UPDATEd
+   if ( ! is_dir( $output_dir ) )
+      mkdir( $output_dir, 0775, true );
+   $message_filename = "$output_dir/$db-$requestID-messages.txt";
+   file_put_contents( $message_filename, $message_log, FILE_APPEND );
+  // mysql_close( $gfac_link );
+//write_log( "$me: *messages.txt written" );
+
+   /////////
+   // Insert data into HPCAnalysis
+
+   $query = "UPDATE HPCAnalysisResult SET "                              .
+            "stderr='" . mysql_real_escape_string( $stderr, $us3_link ) . "', " .
+            "stdout='" . mysql_real_escape_string( $stdout, $us3_link ) . "' "  .
+            "WHERE HPCAnalysisResultID=$HPCAnalysisResultID";
+
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+      mail_to_user( "fail", "Bad query:\n$query\n" . mysql_error( $us3_link ) );
+      return( -1 );
+   }
+//write_log( "$me: HPCAnalysisResult stderr,stdout updated" );
+
+   // Save the tarfile and expand it
+
+   if ( strlen( $tarfile ) == 0 )
+   {
+      write_log( "$me: No tarfile" );
+      mail_to_user( "fail", "No results" );
+      return( -1 );
+   }
+
+   // Shouldn't happen
+   if ( ! is_dir( "$work" ) )
+   {
+      write_log( "$me: $work directory does not exist" );
+      mail_to_user( "fail", "$work directory does not exist" );
+      return( -1 );
+   }
+
+   if ( ! is_dir( "$work/$gfacID" ) ) mkdir( "$work/$gfacID", 0770 );
+   chdir( "$work/$gfacID" );
+
+   $f = fopen( "analysis.tar", "w" );
+   fwrite( $f, $tarfile );
+   fclose( $f );
+write_log( "$me: analysis.tar file written to work dir" );
+
+   $tar_out = array();
+   exec( "tar -xf analysis.tar 2>&1", $tar_out, $err );
+
+   if ( $err != 0 )
+   {
+      chdir( $work );
+      exec( "rm -r $gfacID" );
+      $output = implode( "\n", $tar_out );
+
+      write_log( "$me: Bad output tarfile: $output" );
+      mail_to_user( "fail", "Bad output file" );
+      return( -1 );
+   }
+//write_log( "$me: tar files extracted" );
+
+   // Insert the model files and noise files
+   $files      = file( "analysis_files.txt", FILE_IGNORE_NEW_LINES );
+   $noiseIDs   = array();
+   $modelGUIDs = array();
+   $mrecsIDs   = array();
+   $rmodlGUIDs = array();
+
+   foreach ( $files as $file )
+   {
+      $split = explode( ";", $file );
+
+      if ( count( $split ) > 1 )
+      {
+         list( $fn, $meniscus, $mc_iteration, $variance ) = explode( ";", $file );
+      
+         list( $other, $mc_iteration ) = explode( "=", $mc_iteration );
+         list( $other, $variance     ) = explode( "=", $variance );
+         list( $other, $meniscus     ) = explode( "=", $meniscus );
+      }
+      else
+         $fn = $file;
+
+      if ( preg_match( "/mdl.tmp$/", $fn ) )
+         continue;
+
+      if ( filesize( $fn ) < 100 )
+      {
+         write_log( "$me:fn is invalid $fn" );
+         mail_to_user( "fail", "Internal error\n$fn is invalid" );
+         return( -1 );
+      }
+//write_log( "$me:  handling file: $fn" );
+
+      if ( preg_match( "/^job_statistics\.xml$/", $fn ) ) // Job statistics file
+      {
+         $xml         = file_get_contents( $fn );
+         $statistics  = parse_xml( $xml, 'statistics' );
+         $otherdata   = parse_xml( $xml, 'id' );
+
+         $query = "UPDATE HPCAnalysisResult SET "   .
+                  "wallTime = {$statistics['walltime']}, " .
+                  "CPUTime = {$statistics['cputime']}, " .
+                  "CPUCount = {$statistics['cpucount']}, " .
+                  "max_rss = {$statistics['maxmemory']}, " .
+                  "startTime = '{$otherdata['starttime']}', " .
+                  "endTime = '{$otherdata['endtime']}', " .
+                  "mgroupcount = {$otherdata['groupcount']} " .
+                  "WHERE HPCAnalysisResultID=$HPCAnalysisResultID";
+         $result = mysql_query( $query, $us3_link );
+
+         if ( ! $result )
+         {
+            write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+         }
+
+         file_put_contents( "$output_dir/$fn", $xml );    // Copy to submit dir
+         $file_type = "job_stats";
+//write_log( "$me:   job_statistics file updated in Result and written" );
+
+      }
+
+      else if ( preg_match( "/\.noise/", $fn ) > 0 ) // It's a noise file
+      {
+         $xml        = file_get_contents( $fn );
+         $noise_data = parse_xml( $xml, "noise" );
+         $type       = ( $noise_data[ 'type' ] == "ri" ) ? "ri_noise" : "ti_noise";
+         $desc       = $noise_data[ 'description' ];
+         $modelGUID  = $noise_data[ 'modelGUID' ];
+         $noiseGUID  = $noise_data[ 'noiseGUID' ];
+
+         $query = "INSERT INTO noise SET "  .
+                  "noiseGUID='$noiseGUID'," .
+                  "modelGUID='$modelGUID'," .
+                  "editedDataID=1, "        .
+                  "modelID=1, "             .
+                  "noiseType='$type',"      .
+                  "description='$desc',"    .
+                  "xml='" . mysql_real_escape_string( $xml, $us3_link ) . "'";
+
+         // Add later after all files are processed: editDataID, modelID
+
+         $result = mysql_query( $query, $us3_link );
+
+         if ( ! $result )
+         {
+            write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+            mail_to_user( "fail", "Internal error\n$query\n" . mysql_error( $us3_link ) );
+            return( -1 );
+         }
+
+         $id        = mysql_insert_id( $us3_link );
+         $file_type = "noise";
+         $noiseIDs[] = $id;
+
+         // Keep track of modelGUIDs for later, when we replace them
+         $modelGUIDs[ $id ] = $modelGUID;
+//write_log( "$me:   noise file inserted into DB : id=$id" );
+         
+      }
+
+      else if ( preg_match( "/\.mrecs/", $fn ) > 0 )  // It's an mrecs file
+      {
+         $xml         = file_get_contents( $fn );
+         $mrecs_data  = parse_xml( $xml, "modelrecords" );
+         $desc        = $mrecs_data[ 'description' ];
+         $editGUID    = $mrecs_data[ 'editGUID' ];
+write_log( "$me:   mrecs file editGUID=$editGUID" );
+         if ( strlen( $editGUID ) < 36 )
+            $editGUID    = "12345678-0123-5678-0123-567890123456";
+         $mrecGUID    = $mrecs_data[ 'mrecGUID' ];
+         $modelGUID   = $mrecs_data[ 'modelGUID' ];
+
+         $query = "INSERT INTO pcsa_modelrecs SET "  .
+                  "editedDataID="                .
+                  "(SELECT editedDataID FROM editedData WHERE editGUID='$editGUID')," .
+                  "modelID=0, "             .
+                  "mrecsGUID='$mrecGUID'," .
+                  "description='$desc',"    .
+                  "xml='" . mysql_real_escape_string( $xml, $us3_link ) . "'";
+
+         // Add later after all files are processed: editDataID, modelID
+
+         $result = mysql_query( $query, $us3_link );
+
+         if ( ! $result )
+         {
+            write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+            mail_to_user( "fail", "Internal error\n$query\n" . mysql_error( $us3_link ) );
+            return( -1 );
+         }
+
+         $id         = mysql_insert_id( $us3_link );
+         $file_type  = "mrecs";
+         $mrecsIDs[] = $id;
+
+         // Keep track of modelGUIDs for later, when we replace them
+         $rmodlGUIDs[ $id ] = $modelGUID;
+//write_log( "$me:   mrecs file inserted into DB : id=$id" );
+      }
+
+      else                                           // It's a model file
+      {
+         $xml         = file_get_contents( $fn );
+         $model_data  = parse_xml( $xml, "model" );
+         $description = $model_data[ 'description' ];
+         $modelGUID   = $model_data[ 'modelGUID' ];
+         $editGUID    = $model_data[ 'editGUID' ];
+
+         if ( $mc_iteration > 1 )
+         {
+//write_log( "$me:   MODELUpd: mc_iteration=$mc_iteration" );
+            $miter       = sprintf( "_mcN%03d", $mc_iteration );
+//write_log( "$me:   MODELUpd: miter=$miter" );
+//write_log( "$me:   MODELUpd: I:description=$description" );
+            $description = preg_replace( "/_mc[0-9]+/", $miter, $description );
+write_log( "$me:   MODELUpd: O:description=$description" );
+         }
+
+         $query = "INSERT INTO model SET "       .
+                  "modelGUID='$modelGUID',"      .
+                  "editedDataID="                .
+                  "(SELECT editedDataID FROM editedData WHERE editGUID='$editGUID')," .
+                  "description='$description',"  .
+                  "MCIteration='$mc_iteration'," .
+                  "meniscus='$meniscus'," .
+                  "variance='$variance'," .
+                  "xml='" . mysql_real_escape_string( $xml, $us3_link ) . "'";
+
+         $result = mysql_query( $query, $us3_link );
+
+         if ( ! $result )
+         {
+            write_log( "$me: Bad query:\n$query " . mysql_error( $us3_link ) );
+            mail_to_user( "fail", "Internal error\n$query\n" . mysql_error( $us3_link ) );
+            return( -1 );
+         }
+
+         $modelID   = mysql_insert_id( $us3_link );
+         $id        = $modelID;
+         $file_type = "model";
+
+         $query = "INSERT INTO modelPerson SET " .
+                  "modelID=$modelID, personID=$personID";
+         $result = mysql_query( $query, $us3_link );
+//write_log( "$me:   model file inserted into DB : id=$id" );
+      }
+
+      $query = "INSERT INTO HPCAnalysisResultData SET "       .
+               "HPCAnalysisResultID='$HPCAnalysisResultID', " .
+               "HPCAnalysisResultType='$file_type', "         .
+               "resultID=$id";
+
+      $result = mysql_query( $query, $us3_link );
+
+      if ( ! $result )
+      {
+         write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+         mail_to_user( "fail", "Internal error\n$query\n" . mysql_error( $us3_link ) );
+         return( -1 );
+      }
+//write_log( "$me:    ResultData updated : file_type=$file_type" );
+   }
+
+   // Now fix up noise entries
+   // For noise files, there is, at most two: ti_noise and ri_noise
+   // In this case there will only be one modelID
+
+   foreach ( $noiseIDs as $noiseID )
+   {
+      $modelGUID = $modelGUIDs[ $noiseID ];
+      $query = "UPDATE noise SET "                                                 .
+               "editedDataID="                                                     .
+               "(SELECT editedDataID FROM model WHERE modelGUID='$modelGUID')," .
+               "modelID="                                                          .
+               "(SELECT modelID FROM model WHERE modelGUID='$modelGUID')"          .
+               "WHERE noiseID=$noiseID";
+
+      $result = mysql_query( $query, $us3_link );
+
+      if ( ! $result )
+      {
+         write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+         mail_to_user( "fail", "Bad query\n$query\n" . mysql_error( $us3_link ) );
+         return( -1 );
+      }
+//write_log( "$me:     noise entry updated : noiseID=$noiseID" );
+   }
+//write_log( "$me:     noise entries updated" );
+
+   // Now possibly fix up mrecs entries
+
+   foreach ( $mrecsIDs as $mrecsID )
+   {
+      $modelGUID = $rmodlGUIDs[ $mrecsID ];
+      $query = "UPDATE pcsa_modelrecs SET "                                                 .
+               "modelID="                                                          .
+               "(SELECT modelID FROM model WHERE modelGUID='$modelGUID')"          .
+               "WHERE mrecsID=$mrecsID";
+
+      $result = mysql_query( $query, $us3_link );
+
+      if ( ! $result )
+      {
+         write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+         mail_to_user( "fail", "Bad query\n$query\n" . mysql_error( $us3_link ) );
+         return( -1 );
+      }
+//write_log( "$me:     mrecs entry updated : mrecsID=$mrecsID" );
+   }
+//write_log( "$me:     mrecs entries updated" );
+
+   // Copy results to LIMS submit directory (files there are deleted after 7 days)
+   global $submit_dir; // LIMS submit files dir
+
+  // Get the request guid (LIMS submit dir name)
+   $query  = "SELECT HPCAnalysisRequestGUID FROM HPCAnalysisRequest " .
+             "WHERE HPCAnalysisRequestID = $requestID ";
+   $result = mysql_query( $query, $us3_link );
+
+   if ( ! $result )
+   {
+      write_log( "$me: Bad query:\n$query\n" . mysql_error( $us3_link ) );
+   }
+
+   list( $requestGUID ) = mysql_fetch_array( $result );
+
+   chdir( "$submit_dir/$requestGUID" );
+   $f = fopen( "analysis.tar", "w" );
+   fwrite( $f, $tarfile );
+   fclose( $f );
+
+   // Clean up
+   chdir ( $work );
+   // exec( "rm -rf $gfacID" );
+
+   mysql_close( $us3_link );
+
+   /////////
+   // Send email 
+
+   mail_to_user( "success", "" );
+}
+
+?>
Index: trunk/runID_info.php
===================================================================
--- trunk/runID_info.php	(revision 7)
+++ trunk/runID_info.php	(revision 7)
@@ -0,0 +1,805 @@
+<?php
+/*
+ * runID_info.php
+ *
+ * All the linkages for a particular runID
+ *
+ */
+include_once 'checkinstance.php';
+
+if ( ($_SESSION['userlevel'] != 2) &&   // data analyst can see own runID's
+     ($_SESSION['userlevel'] != 3) &&   // admin and super admin can see all
+     ($_SESSION['userlevel'] != 4) &&
+     ($_SESSION['userlevel'] != 5) )
+{
+  header('Location: index.php');
+  exit();
+} 
+
+include 'config.php';
+include 'db.php';
+include 'lib/utility.php';
+include $class_dir . 'experiment_status.php';
+
+// Start displaying page
+$page_title = "Info by Run ID";
+$css = 'css/admin.css';
+include 'header.php';
+
+global $uses_airavata;
+
+?>
+<!-- Begin page content -->
+<div id='content'>
+
+  <h1 class="title">Info by Run ID</h1>
+  <!-- Place page content here -->
+
+<?php
+  if ( isset( $_POST['experimentID'] ) )
+  {
+    $text  = experiment_select( 'experimentID', $_POST['experimentID'] );
+    if ( $_POST['experimentID'] != -1 )               // -1 is Please select...
+       $text .= runID_info( $_POST['experimentID'] );
+  }
+
+  else if ( isset( $_GET['RequestID'] ) )
+    $text = HPCDetail( $_GET['RequestID'] );
+
+  else
+    $text  = experiment_select( 'experimentID' );
+
+  echo $text;
+
+?>
+</div>
+
+<?php
+include 'footer.php';
+exit();
+
+// Function to create a dropdown for available runIDs
+function experiment_select( $select_name, $current_ID = NULL )
+{
+  $myID = $_SESSION['id'];
+
+  $users_clause = ( $_SESSION['userlevel'] > 2 ) ? "" : "AND people.personID = $myID ";
+
+  $query  = "SELECT experimentID, runID, lname " .
+            "FROM experiment, projectPerson, people " .
+            "WHERE experiment.projectID = projectPerson.projectID " .
+            "AND projectPerson.personID = people.personID " .
+            $users_clause .
+            "ORDER BY lname, runID ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) == 0 ) return "";
+
+  $text = "<form action='{$_SERVER['PHP_SELF']}' method='post'>\n" .
+          "  <select name='$select_name' size='1' onchange='form.submit();'>\n" .
+          "    <option value=-1>Please select...</option>\n";
+  while ( list( $experimentID, $runID, $lname ) = mysql_fetch_array( $result ) )
+  {
+    $selected = ( $current_ID == $experimentID ) ? " selected='selected'" : "";
+    $text .= "    <option value='$experimentID'$selected>$lname: $runID</option>\n";
+  }
+
+  $text .= "  </select>\n" .
+           "</form>\n";
+
+  return $text;
+}
+
+// A function to retrieve information about that runID
+function runID_info( $experimentID )
+{
+  $query  = "SELECT people.personID, personGUID, lname, fname, email " .
+            "FROM experiment, projectPerson, people " .
+            "WHERE experiment.experimentID = $experimentID " .
+            "AND experiment.projectID = projectPerson.projectID " .
+            "AND projectPerson.personID = people.personID ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+  list( $ID, $GUID, $lname, $fname, $email ) = mysql_fetch_array( $result );
+
+  $text = <<<HTML
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>Investigator Information</caption>
+  <tr><th>ID:</th>
+      <td>$ID</td></tr>
+
+  <tr><th>GUID:</th>
+      <td>$GUID</td></tr>
+
+  <tr><th>Name:</th>
+      <td>$fname $lname</td></tr>
+
+  <tr><th>Email:</th>
+      <td>$email</td></tr>
+
+  </table>
+HTML;
+
+  $query  = "SELECT experimentGUID, coeff1, coeff2, type, runType " .
+            "FROM experiment, rotorCalibration " .
+            "WHERE experimentID = $experimentID " .
+            "AND experiment.rotorCalibrationID = rotorCalibration.rotorCalibrationID ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+  list( $GUID, $coeff1, $coeff2, $type, $runType ) = mysql_fetch_array( $result );
+  $text .= <<<HTML
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>Run Information</caption>
+  <tr><th>GUID:</th>
+      <td>$GUID</td></tr>
+
+  <tr><th>Rotor stretch coeff 1:</th>
+      <td>$coeff1</td></tr>
+
+  <tr><th>Rotor stretch coeff 2:</th>
+      <td>$coeff2</td></tr>
+
+  <tr><th>Experiment type:</th>
+      <td>$type</td></tr>
+
+  <tr><th>Run Type:</th>
+      <td>$runType</td></tr>
+
+  </table>
+HTML;
+
+  $query  = "SELECT rawDataID, rawDataGUID, filename, solutionID " .
+            "FROM rawData " .
+            "WHERE experimentID = $experimentID " .
+            "ORDER BY filename ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) == 0 )
+    return $text;
+
+  $rawIDs      = array();
+  $solutionIDs = array();
+  $text .= <<<HTML
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>Raw Data</caption>
+  <thead>
+    <tr><th>ID</th>
+        <th>GUID</th>
+        <th>Filename</th>
+        <th>Solution</th>
+    </tr>
+  </thead>
+
+  <tbody>
+HTML;
+
+  while ( list( $ID, $GUID, $filename, $solutionID ) = mysql_fetch_array( $result ) )
+  {
+    $rawIDs[]      = $ID;
+    $solutionIDs[] = $solutionID;
+
+    $text .= <<<HTML
+    <tr><td>$ID</td>
+        <td>$GUID</td>
+        <td>$filename</td>
+        <td>$solutionID</td>
+    </tr>
+
+HTML;
+
+  }
+  
+  $text .= "</tbody>\n\n" .
+           "</table>\n";
+
+  $rawIDs_csv = implode( ", ", $rawIDs );
+  $query  = "SELECT editedDataID, rawDataID, editGUID, filename " .
+            "FROM editedData " .
+            "WHERE rawDataID IN ( $rawIDs_csv ) " .
+            "ORDER BY editedDataID, filename ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) == 0 )
+    return $text;
+
+  $text .= <<<HTML
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>Edit Profiles</caption>
+  <thead>
+    <tr><th>ID</th>
+        <th>GUID</th>
+        <th>Filename</th>
+        <th>Raw ID</th>
+    </tr>
+  </thead>
+
+  <tbody>
+
+HTML;
+
+  $editIDs = array();
+  while ( list ( $editID, $rawID, $GUID, $filename ) = mysql_fetch_array( $result ) )
+  {
+    $editIDs[] = $editID;
+
+    $text .= <<<HTML
+    <tr><td>$editID</td>
+        <td>$GUID</td>
+        <td>$filename</td>
+        <td>$rawID</td>
+    </tr>
+
+HTML;
+  }
+
+  $text .= "</tbody>\n\n" .
+           "</table>\n";
+
+  $editIDs_csv = implode( ", ", $editIDs );
+  $query  = "SELECT model.modelID, editedDataID, modelGUID, variance, meniscus, personID " .
+            "FROM model LEFT JOIN modelPerson " .
+            "ON ( model.modelID = modelPerson.modelID ) " .
+            "WHERE editedDataID IN ( $editIDs_csv ) " .
+            "ORDER BY modelID ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) != 0 )
+  {
+    $text .= <<<HTML
+    <table cellspacing='0' cellpadding='0' class='admin'>
+    <caption>Models</caption>
+    <thead>
+      <tr><th>ID</th>
+          <th>GUID</th>
+          <th>Edit ID</th>
+          <th>Variance</th>
+          <th>Meniscus</th>
+          <th>Owner ID</th>
+      </tr>
+    </thead>
+
+    <tbody>
+
+HTML;
+
+    $modelIDs = array();
+    while ( list ( $modelID, $editID, $GUID, $variance, $meniscus, $personID ) = mysql_fetch_array( $result ) )
+    {
+      $modelIDs[] = $modelID;
+
+      $text .= <<<HTML
+      <tr><td>$modelID</td>
+          <td>$GUID</td>
+          <td>$editID</td>
+          <td>$variance</td>
+          <td>$meniscus</td>
+          <td>$personID</td>
+      </tr>
+
+HTML;
+    }
+
+    $text .= "</tbody>\n\n" .
+             "</table>\n";
+  }
+
+  if ( count( $modelIDs ) > 0 )
+  {
+    $modelIDs_csv = implode( ", ", $modelIDs );
+    $query  = "SELECT noiseID, noiseGUID, editedDataID, modelID, modelGUID, noiseType " .
+              "FROM noise " .
+              "WHERE modelID IN ( $modelIDs_csv ) " .
+              "ORDER BY noiseID ";
+    $result = mysql_query( $query )
+              or die( "Query failed : $query<br />\n" . mysql_error() );
+
+    if ( mysql_num_rows( $result ) != 0 )
+    {
+      $text .= <<<HTML
+      <table cellspacing='0' cellpadding='0' class='admin'>
+      <caption>Noise Linked to Models</caption>
+      <thead>
+        <tr><th>ID</th>
+            <th>GUID</th>
+            <th>Edit ID</th>
+            <th>Model ID</th>
+            <th>Model GUID</th>
+            <th>Type</th>
+        </tr>
+      </thead>
+    
+      <tbody>
+
+HTML;
+
+      while ( list ( $noiseID, $GUID, $editID, $modelID, $modelGUID, $type ) = mysql_fetch_array( $result ) )
+      {
+        $text .= <<<HTML
+        <tr><td>$noiseID</td>
+            <td>$GUID</td>
+            <td>$editID</td>
+            <td>$modelID</td>
+            <td>$modelGUID</td>
+            <td>$type</td>
+        </tr>
+
+HTML;
+      }
+
+      $text .= "</tbody>\n\n" .
+               "</table>\n";
+    }
+  }
+
+  $query  = "SELECT noiseID, noiseGUID, editedDataID, modelID, modelGUID, noiseType " .
+            "FROM noise " .
+            "WHERE editedDataID IN ( $editIDs_csv ) " .
+            "ORDER BY noiseID ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) != 0 )
+  {
+    $text .= <<<HTML
+    <table cellspacing='0' cellpadding='0' class='admin'>
+    <caption>Noise Linked to Edit Profiles</caption>
+    <thead>
+      <tr><th>ID</th>
+          <th>GUID</th>
+          <th>Edit ID</th>
+          <th>Model ID</th>
+          <th>Model GUID</th>
+          <th>Type</th>
+      </tr>
+    </thead>
+  
+    <tbody>
+
+HTML;
+
+    while ( list ( $noiseID, $GUID, $editID, $modelID, $modelGUID, $type ) = mysql_fetch_array( $result ) )
+    {
+      $text .= <<<HTML
+      <tr><td>$noiseID</td>
+          <td>$GUID</td>
+          <td>$editID</td>
+          <td>$modelID</td>
+          <td>$modelGUID</td>
+          <td>$type</td>
+      </tr>
+
+HTML;
+    }
+
+    $text .= "</tbody>\n\n" .
+             "</table>\n";
+  }
+
+  $reportIDs = array();
+  $query  = "SELECT reportID, reportGUID, title " .
+            "FROM report " .
+            "WHERE experimentID = $experimentID " .
+            "ORDER BY reportID ";
+
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) != 0 )
+  {
+    $text .= <<<HTML
+    <table cellspacing='0' cellpadding='0' class='admin'>
+    <caption>Reports Related to This Experiment</caption>
+    <thead>
+      <tr><th>ID</th>
+          <th>GUID</th>
+          <th>Title</th>
+      </tr>
+    </thead>
+  
+    <tbody>
+
+HTML;
+
+    while ( list ( $reportID, $GUID, $title ) = mysql_fetch_array( $result ) )
+    {
+      $reportIDs[] = $reportID;
+      $text .= <<<HTML
+      <tr><td>$reportID</td>
+          <td>$GUID</td>
+          <td>$title</td>
+      </tr>
+
+HTML;
+    }
+
+    $text .= "</tbody>\n\n" .
+             "</table>\n";
+  }
+
+  $reportTripleIDs = array();
+  if ( ! empty( $reportIDs ) )
+  {
+    $reportIDs_csv = implode( ",", $reportIDs );
+    $query  = "SELECT reportTripleID, reportTripleGUID, resultID, triple, dataDescription, reportID " .
+              "FROM reportTriple " .
+              "WHERE reportID IN ( $reportIDs_csv ) " .
+              "ORDER BY reportID, reportTripleID ";
+  
+    $result = mysql_query( $query )
+              or die( "Query failed : $query<br />\n" . mysql_error() );
+
+    if ( mysql_num_rows( $result ) != 0 )
+    {
+      $text .= <<<HTML
+      <table cellspacing='0' cellpadding='0' class='admin'>
+      <caption>Report Triples Related to Reports</caption>
+      <thead>
+        <tr><th>ID</th>
+            <th>GUID</th>
+            <th>Result ID</th>
+            <th>Triple</th>
+            <th>Description</th>
+            <th>Report ID</th>
+        </tr>
+      </thead>
+    
+      <tbody>
+  
+HTML;
+  
+      while ( list ( $reportTripleID, $GUID, $resultID, $triple, $dataDesc, $rptID ) 
+                   = mysql_fetch_array( $result ) )
+      {
+        $reportTripleIDs[] = $reportTripleID;
+        $text .= <<<HTML
+        <tr><td>$reportTripleID</td>
+            <td>$GUID</td>
+            <td>$resultID</td>
+            <td>$triple</td>
+            <td>$dataDesc</td>
+            <td>$rptID</td>
+        </tr>
+  
+HTML;
+      }
+  
+      $text .= "</tbody>\n\n" .
+               "</table>\n";
+    }
+  }
+
+  if ( ! empty( $reportTripleIDs ) )
+  {
+    $reportTripleIDs_csv = implode( ",", $reportTripleIDs );
+    $query  = "SELECT d.reportDocumentID, reportDocumentGUID, editedDataID, label, " .
+              "filename, analysis, subAnalysis, documentType, l.reportTripleID " .
+              "FROM documentLink l, reportDocument d " .
+              "WHERE reportTripleID IN ( $reportTripleIDs_csv ) " .
+              "AND l.reportDocumentID = d.reportDocumentID " .
+              "ORDER BY reportTripleID, reportDocumentID ";
+  
+    $result = mysql_query( $query )
+              or die( "Query failed : $query<br />\n" . mysql_error() );
+
+    if ( mysql_num_rows( $result ) != 0 )
+    {
+      $text .= <<<HTML
+      <table cellspacing='0' cellpadding='0' class='admin'>
+      <caption>Report Documents Related to Triples</caption>
+      <thead>
+        <tr><th>ID</th>
+            <th>GUID</th>
+            <th>Edit ID</th>
+            <th>Label/Filename</th>
+            <th>Anal/Sub/DocType</th>
+            <th>Trip ID</th>
+        </tr>
+      </thead>
+    
+      <tbody>
+  
+HTML;
+  
+      while ( list ( $reportDocumentID, $GUID, $editID, $label, $filename, 
+                     $analysis, $subAnal, $docType, $tripID ) 
+                   = mysql_fetch_array( $result ) )
+      {
+        $text .= <<<HTML
+        <tr><td>$reportDocumentID</td>
+            <td>$GUID</td>
+            <td>$editID</td>
+            <td>$label/$filename</td>
+            <td>$analysis/$subAnal/$docType</td>
+            <td>$tripID</td>
+        </tr>
+  
+HTML;
+      }
+  
+      $text .= "</tbody>\n\n" .
+               "</table>\n";
+    }
+  }
+
+  $query  = "SELECT HPCAnalysisRequestID, HPCAnalysisRequestGUID, editXMLFilename, " .
+            "submitTime, clusterName, method " .
+            "FROM HPCAnalysisRequest " .
+            "WHERE experimentID = $experimentID " .
+            "ORDER BY HPCAnalysisRequestID ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) == 0 )
+    return $text;
+
+  $requestIDs = array();
+  $text .= <<<HTML
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>HPC Requests</caption>
+  <thead>
+    <tr><th>ID</th>
+        <th>GUID</th>
+        <th>XML Filename</th>
+        <th>Submit</th>
+        <th>Cluster</th>
+        <th>Method</th>
+    </tr>
+  </thead>
+
+  <tbody>
+HTML;
+
+  while ( list( $ID, $GUID, $filename, $submit, $cluster, $method ) = mysql_fetch_array( $result ) )
+  {
+    $requestIDs[]  = $ID;
+
+    $text .= <<<HTML
+    <tr><td><a href='{$_SERVER['PHP_SELF']}?RequestID=$ID'>$ID</a></td>
+        <td>$GUID</td>
+        <td>$filename</td>
+        <td>$submit</td>
+        <td>$cluster</td>
+        <td>$method</td>
+    </tr>
+
+HTML;
+
+  }
+  
+  $text .= "</tbody>\n\n" .
+           "</table>\n";
+
+  $requestIDs_csv = implode( ", ", $requestIDs );
+  $query  = "SELECT HPCAnalysisResultID, HPCAnalysisRequestID, gfacID, queueStatus, updateTime " .
+            "FROM HPCAnalysisResult " .
+            "WHERE HPCAnalysisRequestID IN ( $requestIDs_csv ) " .
+            "ORDER BY HPCAnalysisResultID ";
+  $result = mysql_query( $query )
+            or die( "Query failed : $query<br />\n" . mysql_error() );
+
+  if ( mysql_num_rows( $result ) != 0 )
+  {
+    $text .= <<<HTML
+    <table cellspacing='0' cellpadding='0' class='admin'>
+    <caption>HPC Results</caption>
+    <thead>
+      <tr><th>ID</th>
+          <th>Request ID</th>
+          <th>gfac ID</th>
+          <th>Status</th>
+          <th>Updated</th>
+      </tr>
+    </thead>
+
+    <tbody>
+HTML;
+
+    $incomplete = array();
+    while ( list( $ID, $requestID, $gfacID, $status, $updated ) = mysql_fetch_array( $result ) )
+    {
+      if ( $status != 'completed' )
+        $incomplete[] = $gfacID;
+
+      $text .= <<<HTML
+      <tr><td>$ID</td>
+          <td>$requestID</td>
+          <td>$gfacID</td>
+          <td>$status</td>
+          <td>$updated</td>
+      </tr>
+
+HTML;
+
+    }
+  
+  $text .= "</tbody>\n\n" .
+           "</table>\n";
+
+  }
+
+  if ( empty( $incomplete ) )
+    return $text;
+
+  // Now switch over to the global db
+  global $globaldbhost, $globaldbuser, $globaldbpasswd, $globaldbname;
+
+  $globaldb = mysql_connect( $globaldbhost, $globaldbuser, $globaldbpasswd );
+
+  if ( ! $globaldb )
+  {
+    $text .= "<p>Cannot open global database on $globaldbhost</p>\n";
+    return $text;
+  }
+
+  if ( ! mysql_select_db( $globaldbname, $globaldb ) ) 
+  {
+    $text .= "<p>Cannot change to global database $globaldbname</p>\n";
+    return $text;
+  }
+
+  $text .= <<<HTML
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>GFAC Status</caption>
+  <thead>
+    <tr><th>gfacID</th>
+        <th>Cluster</th>
+        <th>DB</th>
+        <th>Status</th>
+        <th>Message</th>
+        <th>Updated</th>
+    </tr>
+  </thead>
+
+  <tbody>
+HTML;
+
+  $in_queue = 0;
+  foreach ( $incomplete as $gfacID )
+  {
+    
+    $query  = "SELECT cluster, us3_db, status, queue_msg, time " .
+              "FROM analysis " .
+              "WHERE gfacID = '$gfacID' ";
+    $result = mysql_query( $query )
+              or die( "Query failed : $query<br />\n" . mysql_error() );
+  
+    if ( mysql_num_rows( $result ) == 1 )
+    {
+      $in_queue++;
+      list( $cluster, $db, $status, $msg, $time ) = mysql_fetch_array( $result );
+      $text .= <<<HTML
+      <tr><td>$gfacID</td>
+          <td>$cluster</td>
+          <td>$db</td>
+          <td>$status</td>
+          <td>$msg</td>
+          <td>$time</td>
+      </tr>
+
+HTML;
+    }
+  }
+  
+  if ( $in_queue == 0 )
+     $text .= "<tr><td colspan='6'>No local jobs currently in the queue</td></tr>\n";
+
+  $text .= "</tbody>\n\n" .
+           "</table>\n";
+
+  mysql_close( $globaldb );
+
+  return $text;
+}
+
+function HPCDetail( $requestID )
+{
+  $query = "SELECT * FROM HPCAnalysisRequest WHERE HPCAnalysisRequestID=$requestID";
+  $result = mysql_query( $query )
+           or die( "Query failed : $query<br />\n" . mysql_error());
+  $row = mysql_fetch_assoc( $result );
+  $row['requestXMLFile'] = '<pre>' . htmlentities( $row['requestXMLFile'] ) . '</pre>';
+
+  // Save for later
+  $requestGUID  = $row['HPCAnalysisRequestGUID'];
+  $cluster = $row['clusterName'];
+  #var_dump($cluster); 
+ $text = <<<HTML
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>HPC Request Detail</caption>
+
+HTML;
+
+  foreach ($row as $key => $value)
+  {
+    $text .= "  <tr><th>$key</th><td>$value</td></tr>\n";
+  }
+
+  $text .= "</table>\n";
+  
+  $query = "SELECT * FROM HPCAnalysisResult WHERE HPCAnalysisRequestID=$requestID";
+  $result = mysql_query( $query )
+           or die( "Query failed : $query<br />\n" . mysql_error());
+  $row = mysql_fetch_assoc( $result );
+  $row['jobfile'] = '<pre>' . htmlentities( $row['jobfile'] ) . '</pre>';
+
+  // Get GFAC job status
+  global $uses_airavata;
+
+  if ( $uses_airavata === true && $cluster != 'juropa.fz-juelich.de' )
+  {
+    $row['gfacStatus'] = nl2br( getExperimentStatus( $row['gfacID'] ) );
+  }
+  else
+  {
+    $row['gfacStatus'] = nl2br( getJobstatus( $row['gfacID'] ) );
+  }
+
+  // Get queue messages from disk directory, if it still exists
+  global $submit_dir;
+  global $dbname;
+
+  $msg_filename = "$submit_dir$requestGUID/$dbname-$requestID-messages.txt";
+  $queue_msgs = false;
+  if ( file_exists( $msg_filename ) )
+  {
+    $queue_msgs   = file_get_contents( $msg_filename );
+    $len_msgs     = strlen( $queue_msgs );
+    $queue_msgs   = '<pre>' . $queue_msgs . '</pre>';
+  }
+
+  // Get resulting model and noise information
+  if ( ! empty( $resultID ) )
+  {
+    $resultID = $row['HPCAnalysisResultID'];
+    $models   = array();
+    $noise    = array();
+    $query  = "SELECT resultID FROM HPCAnalysisResultData " .
+              "WHERE HPCAnalysisResultID = $resultID " .
+              "AND HPCAnalysisResultType = 'model' ";
+    $result = mysql_query( $query )
+             or die( "Query failed : $query<br />\n" . mysql_error());
+    $models = mysql_fetch_row( $result );         // An array with all of them
+    if ( $models !== false )
+      $row['modelIDs'] = implode( ", ", $models );
+
+    $query  = "SELECT resultID FROM HPCAnalysisResultData " .
+              "WHERE HPCAnalysisResultID = $resultID " .
+              "AND HPCAnalysisResultType = 'noise' ";
+    $result = mysql_query( $query )
+             or die( "Query failed : $query<br />\n" . mysql_error());
+    $noise  = mysql_fetch_row( $result );         // An array with all of them
+    if ( $noise !== false )
+      $row['noiseIDs'] = implode( ", ", $noise );
+  }
+
+  $text .= <<<HTML
+  <a name='runDetail'></a>
+  <table cellspacing='0' cellpadding='0' class='admin'>
+  <caption>HPC Result Detail</caption>
+
+HTML;
+
+  foreach ($row as $key => $value)
+  {
+    $text .= "  <tr><th>$key</th><td>$value</td></tr>\n";
+  }
+
+  if ( $queue_msgs !== false )
+  {
+    $linkmsg = "<a href='{$_SERVER[ 'PHP_SELF' ]}?RequestID=$requestID&msgs=t#runDetail'>Length Messages</a>";
+
+    $text .= "  <tr><th>$linkmsg</th><td>$len_msgs</td></tr>\n";
+    if ( isset( $_GET[ 'msgs' ] ) ) 
+      $text .= "  <tr><th>Queue Messages</th><td>$queue_msgs</td></tr>\n";
+  }
+
+  $text .= "</table>\n";
+
+  return $text;
+}
+
+?>
Index: trunk/save-jobstats.sh
===================================================================
--- trunk/save-jobstats.sh	(revision 7)
+++ trunk/save-jobstats.sh	(revision 7)
@@ -0,0 +1,67 @@
+#!/bin/sh
+#	save-jobstats.sh  --  save uslims3_data job_statistics.xml files
+
+BASEDIR=/srv/www/htdocs/uslims3/uslims3_data
+SAVEDIR=/srv/www/htdocs/uslims3/job_stats
+STATFILE=job_statistics.xml
+if [ ! -d ${SAVEDIR} ]; then
+  mkdir ${SAVEDIR}
+fi
+HOSTNAME=`uname -n`
+echo "HOSTNAME=${HOSTNAME}"
+
+##JSTIME=`stat ${SAVEDIR} -c %Y`
+JSTIME=`date +%s`
+##echo "JSTIME=${JSTIME}"
+NCFILE=0
+NMFILE=0
+ONEDAY=86400    # 24-hours worth of seconds
+
+#  Get uslims3_data subdirectories
+cd ${BASEDIR}
+DATADIRS=`ls -rtF|tail -500|grep '/'`
+##DATADIRS=`ls -rtF|tail -200|grep '/'`
+
+for D in $DATADIRS ; do
+  # Change to job subdirectory
+  JDTIME=`stat ${D} -c %Y`
+  AGE=`expr ${JSTIME} - ${JDTIME}`
+##echo "D=${D}"
+##echo "  JDTIME=${JDTIME}"
+##echo "  AGE=${AGE}"
+
+  # Only process directories less than a day old
+  if [ ${AGE} -lt ${ONEDAY} ]; then
+    JDDATE=`stat ${D} -c %y | cut -d: -f1-2 | sed -e 's/ /-/' -e 's/://g'`
+    cd ${BASEDIR}/${D}
+##echo "   +++Less than 1 day old+++"
+
+    if [ -f ${STATFILE} ]; then
+      # Build job stats if job_statistics.xml exists
+      PART1A=`grep cluster= ${STATFILE}|sed -e 's/^.*cluster=\"//'|cut -d'"' -f1`
+      PART1A=`echo ${PART1A} | sed -e 's@-@_@'`
+      PART1B=`echo ${D} | cut -d'-' -f1`
+      PART1=${PART1A}-${PART1B}
+      PART2=`grep submittime= ${STATFILE}|sed -e 's/^.*submittime=\"//'|cut -d' ' -f1`
+      PART2=`echo ${PART2}|sed -e 's/\-//g'`
+      SOUTFILE=${SAVEDIR}/${PART1}-${PART2}-${STATFILE}
+##echo "we can build:  ${SOUTFILE}"
+      if [ ! -f ${SOUTFILE} ]; then
+        echo "cp -p ${STATFILE} ${SOUTFILE}"
+        cp -p ${STATFILE} ${SOUTFILE}
+        NCFILE=`expr ${NCFILE} + 1`
+      fi
+    else
+      CLUST=`grep shortname ${BASEDIR}/${D}hpcr*xml|cut -d'"' -f4`
+      echo "job_statistics.xml in ${D} [ ${JDDATE} ${CLUST} ] does not exist!"
+      NMFILE=`expr ${NMFILE} + 1`
+    fi
+  fi
+
+  # Change back to ./uslims3_data
+  cd ${BASEDIR}
+done
+
+echo "job_stats+++ Files Created:  ${NCFILE}"
+echo "jobxml/stats Files Missing:  ${NMFILE}  (aborted,running jobs?)"
+ 
Index: trunk/update_notice.php
===================================================================
--- trunk/update_notice.php	(revision 7)
+++ trunk/update_notice.php	(revision 7)
@@ -0,0 +1,198 @@
+<?php
+
+$us3bin = exec( "ls -d ~us3/bin" );
+$us3etc = exec( "ls -d ~us3/etc" );
+include_once "$us3bin/listen-config.php";
+
+// Get the US3 system release string
+$s_url1 = "//bcf2.uthscsa.edu/ultrascan3/trunk/utils";
+$s_url2 = "//bcf2.uthscsa.edu/ultrascan3/trunk/programs/us";
+
+$s_cmd1 = "/usr/bin/svn info svn:$s_url1|grep Revision|cut -d ' ' -f2";
+$s_cmd2 = "/usr/bin/svn info svn:$s_url1|grep Revision|cut -d ' ' -f2";
+
+$s_rev1 = exec( $s_cmd1 );
+$s_rev2 = exec( $s_cmd2 );
+
+$sysrev = $s_rev2;
+if ( $s_rev1 > $s_rev2 )
+  $sysrev = $s_rev1;
+$sysrev = "3.3." . $sysrev;
+
+// Global variables
+$notice_db  = "us3_notice";
+$dbhost     = "localhost";
+$dbuser     = "root";
+//$dbpassw    = exec( "cat ~us3/.sec/.pwsq" );
+$dbpassw    = exec( "cat ~/.sec/.pwsq" );
+
+// Produce some output temporarily, so cron will send me message
+$now = time();
+echo "Time started: " . date( 'Y-m-d H:i:s', $now ) . "\n";
+
+// Read and parse the local notice file
+
+$n_fname  = "$us3etc/us3-notice.xml";
+$fh       = fopen( $n_fname, "r" );
+$xml      = fread( $fh, filesize( $n_fname ) );
+
+$parser = new XMLReader();
+$parser->xml( $xml );
+
+$notices  = array();
+$keys     = array();
+
+echo "=====START of PARSE LOOP===== \n";
+while( $parser->read() )
+{
+   $n_type = $parser->nodeType;
+//echo "n_type=$n_type \n";
+      
+   if ( $n_type == XMLReader::ELEMENT )
+   {
+      $name = $parser->name;
+//echo "name=$name \n";
+
+      if ( $name == "notice" )
+      {
+         $type   = $parser->getAttribute( "type" );
+//echo " type=$type \n";
+         $parser->moveToAttribute( "revision" );
+         $rev    = $parser->value;
+//echo " rev=$rev \n";
+         if ( $rev == "latest" )
+            $rev    = $sysrev;
+//echo " rev=$rev \n";
+
+         $key    = $type . $rev;
+         $notices[ $key ] = array();
+//echo "  key=$key \n";
+      }
+   }
+      
+   else if ( $n_type == XMLReader::TEXT )
+   {
+      $msg      = $parser->readString();
+//echo " msg=+++$msg+++ \n";
+      $len      = strlen( $msg );
+
+      if ( $len > 0 )
+      {  // Only add if not an empty message
+         $msg      = preg_replace( "/\@revision/", $rev, $msg );
+         $msg      = preg_replace( "/'/", "\\'", $msg );
+         $notices[ $key ][ 'type' ] = $type;
+         $notices[ $key ][ 'rev'  ] = $rev;
+         $notices[ $key ][ 'msg'  ] = $msg;
+         $notices[ $key ][ 'act'  ] = 'add';
+         $notices[ $key ][ 'id'   ] = '0';
+
+         $keys[]  = $key;
+      }
+   }
+}
+
+$parser->close();
+echo "=====END of PARSE LOOP===== \n";
+
+// Get data from notice DB. Update the action field to
+//  reflect which action is required on each entry:
+//   "add"  - is only present in file (add to DB);
+//   "del"  - is only present in DB (delete from DB);
+//   "upd"  - present in both, but messages differ (update in DB);
+//   "none" - present in both and messages identical (no DB update).
+
+$noteLink = mysql_connect( $dbhost, $dbuser, $dbpassw );
+
+if ( ! mysql_select_db( $notice_db, $noteLink ) )
+{
+   echo "Could not select DB $notice_db - " . mysql_error() . "\n";
+   exit();
+}
+   
+$query = "SELECT id, type, revision, message FROM notice";
+
+$result = mysql_query( $query, $noteLink )
+   or die( "Query failed : $query<br />" . mysql_error() );
+
+echo "=====START of DB QUERY LOOP===== \n";
+$num_rows = mysql_num_rows( $result );
+
+echo "   numrows = $num_rows \n";
+while ( list( $id, $type, $rev, $msg ) = mysql_fetch_array( $result ) )
+{
+   $key    = $type . $rev;
+   $msgf   = $notices[ $key ][ 'msg'  ];
+
+   if ( in_array( $key, $keys ) )
+   {  // Entry is in both file and DB
+      $notices[ $key ][ 'id'   ] = $id;
+      $notices[ $key ][ 'type' ] = $type;
+      $notices[ $key ][ 'rev'  ] = $rev;
+
+      if ( strcmp( $msg, $msgf ) == 0 )
+      {  // Messages match, so no update is needed
+         $notices[ $key ][ 'act'  ] = 'none';
+      }
+      else
+      {  // Messages differ, so DB entry must be updated
+         $notices[ $key ][ 'act'  ] = 'upd';
+         $notices[ $key ][ 'msg'  ] = $msgf;
+echo "   msg  = ++$msg++\n";
+echo "   msgf = ++$msgf++\n";
+      }
+   }
+
+   else
+   {  // Entry is only in DB, so a delete is needed
+      $notices[ $key ] = array();
+      $notices[ $key ][ 'id'   ] = $id;
+      $notices[ $key ][ 'type' ] = $type;
+      $notices[ $key ][ 'rev'  ] = $rev;
+      $notices[ $key ][ 'act'  ] = 'del';
+      $notices[ $key ][ 'msg'  ] = $msg;
+      $keys[]  = $key;
+   }
+}
+echo "=====END of DB QUERY LOOP===== \n";
+
+echo "=====START of DB Update LOOP===== \n";
+foreach ( $keys as $key )
+{
+   $type  = $notices[ $key ][ 'type' ];
+   $rev   = $notices[ $key ][ 'rev'  ];
+   $act   = $notices[ $key ][ 'act'  ];
+   $id    = $notices[ $key ][ 'id'   ];
+   $msg   = $notices[ $key ][ 'msg'  ];
+   $len   = strlen( $msg );
+   echo "-- key=$key --\n";
+   echo "    type:  $type \n";
+   echo "    rev:   $rev  \n";
+   echo "    act:   $act  \n";
+   echo "    id:    $id   \n";
+//   echo "    msg:   $msg  \n";
+   echo "    msg:   ( $len characters ) \n";
+
+   if ( $act == "add" )
+   {  // Must add the entry to the database
+      $query = "INSERT INTO notice " .
+               "SET type='$type', revision='$rev', message='$msg'";
+   }
+   else if ( $act == "del" )
+   {  // Must delete the entry from the database
+      $query = "DELETE FROM notice WHERE id='$id'";
+   }
+   else if ( $act == "upd" )
+   {  // Must update an existing entry in the database
+      $query = "UPDATE notice " .
+               "SET message='$msg' " .
+               "WHERE id='$id'";
+   }
+   echo "      query: [ $query ]  \n";
+
+   $result = mysql_query( $query, $noteLink )
+      or die( "Query failed : $query<br />" . mysql_error() );
+
+}
+echo "=====END of DB Update LOOP===== \n";
+
+?>
Index: trunk/us3-listen
===================================================================
--- trunk/us3-listen	(revision 7)
+++ trunk/us3-listen	(revision 7)
@@ -0,0 +1,47 @@
+#!/bin/sh
+########################################################################
+# Begin $rc_base/init.d/
+#
+# Description : gridctl us3-listen daemons (listen, manage-us3-pipe)
+#
+# Authors     : Gary Gorbet
+#
+# Version     : 01.01
+#
+# Notes       : Goes in /etc/rc.d/init.d
+#
+########################################################################
+
+. /etc/init.d/functions
+
+case "${1}" in
+   start)
+      echo -n "Starting us3-listen daemons ..."
+      /usr/bin/php ~us3/bin/listen.php &
+      echo ""
+      sleep 1
+      ${0} status
+      ;;
+
+   stop)
+      echo -n "Stopping us3-listen daemons ..."
+      killproc /usr/bin/php
+      ;;
+
+   restart)
+      ${0} stop
+      sleep 1
+      ${0} start
+      ;;
+
+   status)
+      ps -aef|grep -v grep|egrep 'listen.php|us3-pipe'
+      ;;
+
+   *)
+      echo "Usage: ${0} {start|stop|restart|status}"
+      exit 1
+      ;;
+esac
+
+# End $rc_base/init.d/
Index: trunk/us3-notice.php
===================================================================
--- trunk/us3-notice.php	(revision 7)
+++ trunk/us3-notice.php	(revision 7)
@@ -0,0 +1,4 @@
+$us3bin = exec( "ls -d ~us3/bin" );
+include_once "$us3bin/listen-config.php";
+include "$us3bin/cleanup_aira.php";
+include "$us3bin/cleanup_gfac.php";
