Changeset 254

Show
Ignore:
Timestamp:
08/14/09 09:20:29
Author:
dan
Message:

--

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • scout/trunk/ftpSamosData.pl

    r252 r254  
    88use netcdfFuncs; 
    99 
    10 #do 'samos_moving_point.pl'; 
     10do 'samos_moving_point.pl'; 
    1111 
    1212 
     
    3232} 
    3333$destDir = $destDir->string_value(); 
     34#print( "destDir: $destDir\n" ); 
    3435 
    3536my $fetchLogDir = $XMLObj->findnodes('//ftpInfo/fetchLogDir'); 
     
    3940} 
    4041$fetchLogDir = $fetchLogDir->string_value(); 
     42#print( "fetchLogDir: $fetchLogDir\n" ); 
    4143 
    4244 
     
    5153if( length( $obsKMLDir ) == 0 ) 
    5254{ 
    53   die( "No value given for the baseURL: <ftpInfo><outputs><obsKMLDir> entry in $strURLControlFile\n"); 
     55  die( "No value given for the obsKML output directory: <ftpInfo><outputs><obsKMLDir> entry in $strURLControlFile\n"); 
    5456} 
    5557$obsKMLDir = $obsKMLDir->string_value(); 
     58 
    5659my $zipFiles = 0; 
    5760foreach my $id ($XMLObj->findnodes('//ftpInfo/idList/id')) 
     
    134137  } 
    135138} 
    136  
    137 use constant USE_DEBUG_PRINTS => 1; 
    138  
    139 sub samos_moving_point 
    140 { 
    141   # top timestamp 
    142   my( $ncFilename, $strObsKMLFilePath,$iLastNTimeStamps ) = @_; 
    143  
    144   # Turn off fatal error aborts.  We need to allow some attributes to error out w/o crashing. 
    145   NetCDF::opts(VERBOSE) ; 
    146    
    147   # 
    148   # Open the netCDF file 
    149  
    150   my $ncid = NetCDF::open($ncFilename, 0); 
    151   if($ncid < 0) 
    152   { 
    153     die "ABORT!  Cannot open netCDF file.\n"; 
    154   } 
    155  
    156   # 
    157   # General file query 
    158   my( $ndims,$nvars,$natts,$recdim ); 
    159   my $inquire = NetCDF::inquire($ncid,$ndims,$nvars,$natts,$recdim); 
    160   if( $inquire < 0 ) 
    161   { 
    162     die "ABORT!  Cannot query netCDF file.\n"; 
    163   } 
    164  
    165    
    166   my $bWriteobsKMLFile = 0; 
    167   if( length($strObsKMLFilePath) > 0 ) 
    168   { 
    169    $bWriteobsKMLFile = 1; 
    170   } 
    171  
    172   #The XML file that has our obsKML units conversion. WE use it here to convert the units string names from the netcdf 
    173   #file into the strings we use in the obsKML and then in our database. 
    174   my $strUnitsXMLFilename; 
    175   $strUnitsXMLFilename = './UnitsConversion.xml'; 
    176   my $XMLControlFile = XML::LibXML->new->parse_file("$strUnitsXMLFilename"); 
    177    
    178   #Create the platform handle 
    179   my $id='None'; 
    180   my $attget = NetCDF::attget($ncid,NetCDF::GLOBAL,'ID',\$id); 
    181   if( $attget < 0 ) 
    182   { 
    183     print( "No ID provided in file.\n" ); 
    184   } 
    185   #my $strPlatformID = "samos.$id.ship"; 
    186   my $strPlatformID = $id; 
    187    
    188   my $institution_url_value = 'http://samos.coaps.fsu.edu/html/data.php'; 
    189    
    190   my @KMLTimeStamp; 
    191   my ( $rTime, $rLong, $rLat ); 
    192   my @vars; 
    193   my @varIgnoreList = ( "platform heading", 
    194                         "platform course", 
    195                         "platform relative wind direction", 
    196                         "platform speed over ground", 
    197                         "platform relative wind speed", 
    198                         "calender date", 
    199                         "time of day", 
    200                         "file history information" 
    201                        ); 
    202    
    203   my $this_var_name; 
    204   my $timeCnt = 0; 
    205   for (my $i = 0; $i < $nvars; $i++)  
    206   { 
    207     my $this_var_type; 
    208     my $this_var_dims; 
    209     my @this_var_dimid = (); 
    210     my $this_var_natts; 
    211     my $this_standard_name = ''; 
    212     my $varinq = NetCDF::varinq($ncid,  
    213                                 $i,  
    214                                 \$this_var_name,  
    215                                 \$this_var_type,  
    216                                 \$this_var_dims,  
    217                                 \@this_var_dimid,  
    218                                 \$this_var_natts); 
    219     if ($varinq < 0)  
    220     { 
    221       die "ABORT!  Cannot get to variables.\n"; 
    222     } 
    223     my $attget = NetCDF::attget($ncid, $i, 'long_name', \$this_standard_name); 
    224     if (substr($this_standard_name,length($this_standard_name)-1) eq chr(0))    
    225     { 
    226       chop($this_standard_name); 
    227     } 
    228     if( isInIgnoreList( \@varIgnoreList, $this_standard_name ) == 0 ) 
    229     { 
    230       if ($attget >= 0)  
    231       { 
    232         if( $this_var_dims <= 0 )  
    233         { 
    234           die( "ABORT! $this_standard_name has no dimensions.\n" ); 
    235         } 
    236         my $refArrayVarData; 
    237         #print( "this_var_name: $this_var_name this_standard_name: $this_standard_name\n" ); 
    238          
    239         my %VariableHash; 
    240         netcdfFuncs::ncSetupVariableInfo( $this_standard_name,  
    241                             $this_var_name,  
    242                             \%VariableHash,  
    243                             $i,  
    244                             $this_var_dims,  
    245                             \@this_var_dimid,  
    246                             $this_var_natts,  
    247                             $ncid, 
    248                             $XMLControlFile ); 
    249         netcdfFuncs::ncGetData( $this_standard_name,  
    250                   $this_var_name,  
    251                   \%VariableHash,  
    252                   $ncid ); 
    253         #Save the slot for the time. 
    254         if( $this_standard_name =~ /^time$/)  
    255         { 
    256           $rTime = \%VariableHash; 
    257            
    258           $timeCnt = %$rTime->{'var_name'}{$this_var_name}{'dim_name'}{'time'}{'dim_size'}; 
    259           my $strUnits = %$rTime->{'var_name'}{$this_var_name}{'units'};          
    260           my @Data = %$rTime->{'var_name'}{$this_var_name}{'data'}; 
    261           my $iDataSize = @{$Data[0]}; 
    262           if( $timeCnt != $iDataSize ) 
    263           { 
    264             die( "ABORT! Time Dimension: $timeCnt does not match the data count: $iDataSize!\n"); 
    265           } 
    266         } 
    267         elsif ($this_standard_name =~ /^latitude$/)  
    268         { 
    269           #Save a reference to the longitude hash for easy access. 
    270           $rLat = \%VariableHash; 
    271         } 
    272         elsif ($this_standard_name =~ /^longitude$/)  
    273         { 
    274           $rLong = \%VariableHash; 
    275         } 
    276         else 
    277         { 
    278           %VariableHash->{'var_name'}{$this_standard_name}{'process_function'} = \&ProcessSamosVar;         
    279           push( @vars, {%VariableHash} ); 
    280         }                           
    281       } 
    282     } 
    283   } 
    284   my $iStartingNdx = 0; 
    285   if( $iLastNTimeStamps > 0 ) 
    286   { 
    287     #If we have more entries in the time_values array, let's set the starting index at the spot in the array which    
    288     #will get us to the first of the N time stamps. 
    289     print( "iTimeCnt: $timeCnt iLastNTimeStamps: $iLastNTimeStamps\n" ); 
    290     if( $timeCnt > $iLastNTimeStamps ) 
    291     { 
    292       $iStartingNdx = $timeCnt - $iLastNTimeStamps; 
    293       if( USE_DEBUG_PRINTS ) 
    294       { 
    295         print( "moving_point()::Printing Last: $iLastNTimeStamps out of $timeCnt entries. Starting Index: $iStartingNdx. $ncid\n" ); 
    296       } 
    297     } 
    298     elsif( $iLastNTimeStamps > $timeCnt ) 
    299     { 
    300       print( "moving_point()::iLastNTimeStamps: $iLastNTimeStamps is greater than total number of times in file. Resetting to iLastNTimeStamps to $timeCnt\n" ); 
    301       $iLastNTimeStamps = $timeCnt; 
    302     } 
    303   } 
    304   my %ObsHash; 
    305   # write data to file(s) 
    306   my $iVarCnt = @vars; 
    307   if( $bWriteobsKMLFile ) 
    308   {      
    309     #TIme is always the outer loop. Each measurement is taken at a specific time.  
    310     my $iTimeNdx = $iStartingNdx; 
    311     for( ; $iTimeNdx < $timeCnt; $iTimeNdx++ ) 
    312     { 
    313       my $strTimeVal = getDateTimeFromEpoch( $rTime, $iTimeNdx ); 
    314       my( $LatVal, $LonVal ); 
    315       netcdfFuncs::ncGetLatLong( $rLat, $rLong, $iTimeNdx, \$LatVal, \$LonVal ); 
    316       if( $LonVal > 180 ) 
    317       { 
    318         $LonVal = -1 * (360.0 - $LonVal); 
    319       } 
    320       #Fix precision  
    321       $LatVal = sprintf( '%.5f', $LatVal );  
    322       $LonVal = sprintf( '%.5f', $LonVal );  
    323       obsKMLSubRoutines::KMLAddPlatformHashEntry( $strPlatformID,  
    324                                                   $institution_url_value,  
    325                                                   $LatVal,  
    326                                                   $LonVal,  
    327                                                   \%ObsHash, 
    328                                                   $strTimeVal ); 
    329        
    330       for( my $iVar = 0; $iVar < $iVarCnt; $iVar++ ) 
    331       { 
    332         my $refVarData = $vars[$iVar]; 
    333         foreach my $strVarName ( sort keys %{$refVarData->{'var_name'}} ) 
    334         { 
    335           #print( "Var: $strVarName\n" ); 
    336           if( defined $refVarData->{'var_name'}{$strVarName}{'process_function'} ) 
    337           { 
    338             my $ProcFunc = $refVarData->{'var_name'}{$strVarName}{'process_function'}; 
    339             &$ProcFunc( $strPlatformID,  
    340                         $strVarName,  
    341                         $refVarData,  
    342                         $strTimeVal, 
    343                         $iTimeNdx,  
    344                         $LatVal,  
    345                         $LonVal,  
    346                         \%ObsHash, 
    347                         \@vars ); 
    348           } 
    349         } 
    350       } 
    351     } 
    352     my $iCnt = keys( %ObsHash ); 
    353     #print( "Cnt: $iCnt\n" ); 
    354     if( $iCnt ) 
    355     { 
    356        
    357       my $strXMLPath;  
    358       my @aSrcFileParts = split( /\//, $ncFilename ); 
    359       my $strSrcFileName = @aSrcFileParts[-1]; 
    360       #Break the filename and extension apart. 
    361       my $iPos = rindex( $strSrcFileName, '.' ); 
    362       my $strFileName = $strSrcFileName; 
    363       if( $iPos != -1 ) 
    364       { 
    365         $strFileName = substr( $strSrcFileName, 0, $iPos ); 
    366       } 
    367       #Use the source netcdf filename. 
    368       #Add the $strDate which gives us a unique file name. Some providers don't uniquely name the netcdf files, so to prevent overwritting of my 
    369       #kml, I add the time. 
    370       $strXMLPath = $strObsKMLFilePath . $strFileName . '.kml'; 
    371       print( "XMLFilePath: $strXMLPath\n" ); 
    372       obsKMLSubRoutines::BuildKMLFile( \%ObsHash, $strXMLPath ); 
    373     }     
    374   } 
    375 } 
    376  
    377 ####################################################################################################################### 
    378 # ProcessVariable 
    379 ####################################################################################################################### 
    380 sub ProcessSamosVar #() 
    381 { 
    382   my( $strPlatformID, $strVarName, $refVarData, $strTimeVal, $iTimeNdx, $LatVal, $LonVal, $rObsHash ) = @_; 
    383    
    384   #We don't want to add the flags as a obs into the kml. 
    385   if( $strVarName eq "quality control flags" ) 
    386   { 
    387     return; 
    388   } 
    389   #For fixed ADCP we have dimensions of time and z. Time is fixed per measurement, and the z count 
    390   #tells us how man data points we need to read for a given time. 
    391   my $iDataNdx = $iTimeNdx; 
    392   my $DimCnt = 0; 
    393   my $iDataCnt = 0; 
    394    
    395   foreach my $strDimName ( sort keys %{$refVarData->{'var_name'}{$strVarName}{'dim_name'}} ) 
    396   { 
    397     $DimCnt += 1; 
    398     #If the dimension is time, let's get the time data for the current slot. 
    399     #WE get the converted time data instead of using the UTC that is in the time field in the netcdf file. 
    400   #  if( $strDimName =~ 'time' ) 
    401   #  {  
    402   #    $TimeVal = $strTimeVal; 
    403   #  } 
    404   #  elsif( $strDimName =~ 'z' ) 
    405   #  { 
    406   #    $iZDimCnt = $refVarData->{'var_name'}{$strVarName}{'dim_name'}{$strDimName}{'dim_size'}; 
    407   #  }             
    408   } 
    409   #Calc the data index if the variable has a Z dim. For instance we have a variable with a Z dim size of 
    410   #19. First pass $iTimeNdx = 0 and Z dim = 19, so our array offset in the data is iTimeNdx * Z DimSize = 0; 
    411   #Next time through iTimeNdx = 1 so 1 * 19 = 19, we will pull data starting at slot 19 for the data variable. 
    412   #If we have a Z dimension for the variable, we need to adjust our array index.         
    413   #if( $iZDimCnt ) 
    414   #{ 
    415   #  $iDataNdx *= $iZDimCnt; 
    416   #  $iDataCnt = $iZDimCnt; 
    417   #} 
    418   #No Z/height dimension, so we only have point data. 
    419   #else 
    420   #{ 
    421   #  $iDataCnt = 1; 
    422   #} 
    423   $iDataCnt = 1; 
    424   my @Data = $refVarData->{'var_name'}{$strVarName}{'data'};  
    425   #Get "missing value" value. 
    426   my $missingVal = $refVarData->{'var_name'}{$strVarName}{'missing_value'}; 
    427    
    428   my $iStartNdx = $iDataNdx; 
    429   my $iNdx;           
    430   for( $iNdx = 0; $iNdx < $iDataCnt; $iNdx++ ) 
    431   { 
    432     my $Val = @{$Data[0]}[$iStartNdx];       
    433     if(  $Val != $missingVal ) 
    434     { 
    435       $Val = sprintf( '%.3f', $Val ); 
    436     } 
    437     #$Val is missing, so we reset it to NULL. 
    438     else 
    439     { 
    440       $Val = 'NULL'; 
    441     } 
    442     my $iSOrder = 1; 
    443     my $obsName = convertToXeniaObsName( $strVarName ); 
    444     netcdfFuncs::ncOutputData( $strPlatformID, 
    445                 $obsName,  
    446                 $Val, 
    447                 $refVarData->{'var_name'}{$strVarName}{'units'}, 
    448                 $iSOrder, 
    449                 0,                
    450                 $strTimeVal,  
    451                 $LatVal,  
    452                 $LonVal, 
    453                 $rObsHash ); 
    454     $iStartNdx++; 
    455   }       
    456 } 
    457  
    458 sub isInIgnoreList#(/@ignoreList, $varName) 
    459 { 
    460   my( $ignoreList, $varName ) = @_; 
    461   foreach my $var ( @$ignoreList ) 
    462   { 
    463     if( $var eq $varName ) 
    464     { 
    465       return(1); 
    466     } 
    467   } 
    468   return(0); 
    469 } 
    470 sub convertToXeniaObsName#(obsName) 
    471 { 
    472   my( $obsName ) = @_; 
    473   my $xeniaName = $obsName; 
    474   if( $obsName eq "sea temperature"  ) 
    475   { 
    476     $xeniaName = 'water_temperature'; 
    477   } 
    478   elsif( $obsName eq 'relative humidity') 
    479   { 
    480     return( 'relative_humidity' ); 
    481   } 
    482   elsif( $obsName eq 'air temperature') 
    483   { 
    484     return( 'air_temperature' ); 
    485   } 
    486   elsif( $obsName eq 'atmospheric pressure') 
    487   { 
    488     return( 'air_pressure' ); 
    489   } 
    490   elsif( $obsName eq 'atmospheric pressure') 
    491   { 
    492     return( 'air_pressure' ); 
    493   } 
    494   elsif( $obsName eq 'earth relative wind speed') 
    495   { 
    496     return( 'wind_speed' ); 
    497   } 
    498   elsif( $obsName eq 'earth relative wind direction') 
    499   { 
    500     return( 'wind_from_direction' ); 
    501   }   
    502   return( $xeniaName ); 
    503 } 
    504  
    505 sub getDateTimeFromEpoch#( ) 
    506 { 
    507   my ( $TimeRef, $Ndx ) = @_; 
    508    
    509   my $strUnits = %$TimeRef->{'var_name'}{'time'}{'units'};          
    510   my @Data = %$TimeRef->{'var_name'}{'time'}{'data'}; 
    511   #COnvert the utc time into the format we use for the database and KML files. 
    512   my $secsOffset = 315532800; #This is to deal with the fact PCs use a utc from 1980-1-1 instead of the unix 1970-1-1 
    513   my $Date = @{$Data[0]}[$Ndx]; 
    514   my $dateString = strftime( '%Y-%m-%dT%H:%M:%S', gmtime((($Date*60)+$secsOffset)) ); 
    515   return( $dateString ); 
    516 } 
    517139sub zipKMLFiles #() 
    518140{