LADCP_w_postproc
author A.M. Thurnherr <athurnherr@yahoo.com>
Mon, 04 Jan 2016 11:19:09 +0000
changeset 33 866c881b3a4a
parent 32 6041a20feb39
child 34 e550db661c17
permissions -rwxr-xr-x
V1.1

#!/usr/bin/perl
#======================================================================
#                    L A D C P _ W _ P O S T P R O C 
#                    doc: Fri Apr 24 17:15:59 2015
#                    dlm: Tue Oct 13 10:51:31 2015
#                    (c) 2015 A.M. Thurnherr
#                    uE-Info: 50 0 NIL 0 0 72 2 2 4 NIL ofnI
#======================================================================

$antsSummary = 'edit and re-grid LADCP vertical-velocity samples';

# HISTORY:
#	Apr 24, 2015: - created
#	Apr 25, 2015: - maded gridding work
#	Apr 26, 2015: - made editing work
#	Apr 27, 2015: - added -p
#	May  5, 2015: - modified Editfile syntax to use parens()
#	May  7, 2015: - allow leading whitespace before Editfile labels
#	May 17, 2015: - removed warning about missing ./Editfile
#	May 18, 2015: - added important %PARAMs for dual-head data
#				  - updated to libV6.1
#	May 19, 2015: - added hab to output
#				  - allow setting %PARAMS in Editfile
#	May 20, 2015: - Editfile => EditParams
#	Jun 18, 2015: - added -i
#				  - implemented default output on -t stdout
#				  - changed to libGMT.pl
#				  - removed dead -d option
#	Jul 26, 2015: - adapted for %outgrid_*
#	Jul 27, 2015: - B-t)rack <wprof>
#	Sep 21, 2015: - added valid_bins()
#				  - replaced -t by -b
#				  - BUG: -k default was wrong
#				  - added error message output to EditParams
#	Sep 22, 2015: - added output_resolution()
#	Sep 24, 2015: - BUG: -k did not work any more
#				  - BUG: some plot commands were exectuted even without -p
#				  - BUG: wprof plot did not respect -k
#				  - BUG: typo in mad output
#	Sep 26, 2015: - allow $ID as alias for $STN and $PROF
#	Sep 27, 2015: - adapted to 'unknown' %water_depth
#	Oct 12, 2015: - improved EditParams handling
#				  - BUG: single-profile plot did not work any more
#				  - BUG: wrong single-profile bin size warning produced
#				  - BUG: -o /-k code was wrong
#				  - BUG: plot was in landscape mode
#			      - added run-label(s) to plot
#                 - require ANTSlibs V6.2 for release
#   Oct 13, 2015: - adapted to [version.pl]

($ANTS)  = (`which ANTSlib` =~ m{^(.*)/[^/]*$});
($WCALC) = ($0              =~ m{^(.*)/[^/]*$});
$WCALC = '.' if ($WCALC eq '');

die("$0: ANTSlib required but not found (bad \$PATH?)\n")
	unless ($ANTS ne '');

require "$WCALC/version.pl";
require "$ANTS/ants.pl";
require "$ANTS/libstats.pl";
require "$ANTS/libGMT.pl";

&antsUsage('b:i:k:o:p:',1,
	'[profile -i)d <id>]',
	'[-o)utput bin <resolution>] [-k) require <min> samples]',
	'[-p)lot <[%03d_wprof.eps]> [-b)t <wprof>]]',
	'<.wsamp file> [.wsamp file]');

$dual_head = (@ARGV==1);

if (defined($opt_o)) {
	$opt_o_override = 1;
	&antsCardOpt($opt_o);
} else {
	$opt_o = &antsRequireParam('outgrid_dz');
}

if (defined($opt_k)) {
	$opt_k_override = 1;
	&antsCardOpt($opt_k);
} else {
	$opt_k = &antsRequireParam('outgrid_minsamp');
	$opt_k *= 2 if ($dual_head);
}
	
#----------------------------------------------------------------------
# Redirect STDOUT to %.wprof & create %_wprof.ps if STDOUT is a tty
#----------------------------------------------------------------------

$id = defined($opt_i) ? $opt_i : &antsParam('profile_id');
croak("$0: no profile_id in first file => -i required\n")
	unless defined($id);
	
if (-t STDOUT) {
	$opt_p = '%03d_wprof.ps' unless defined($opt_p);
	$outfile = sprintf('%03d.wprof',$id);
	open(STDOUT,">$outfile") || die("$outfile: $!\n");
}

croak("$0: -b only makes sense when a plot is produced\n")
	if $opt_b && !defined($opt_p);

#----------------------------------------------------------------------
# EditParams Library
#
#	output_resolution(dz)								output_resolution(40)
#	bad_range[_dc|_uc](field,min_val,max_val)			bad_range_uc('depth',3500,3600)
#	good_bins(first_good,last_good)						good_bins(2,'*')
#	
#----------------------------------------------------------------------

my(@brFnr,@brMin,@brMax,@brDUc);
my(@gbFirst,@gbLast);

sub output_resolution($)
{
	my($dz) = @_;
	$opt_o = $dz;
	$opt_o_override = 1;
}

sub bad_range($$$)
{
	push(@brFnr,&fnr(shift));
	push(@brMin,shift); push(@brMax,shift);
	$brMin[$#brMin] = -9e99 if ($brMin[$#brMin] eq '*');
	$brMax[$#brMax] =  9e99 if ($brMax[$#brMax] eq '*');
	push(@brDUc,2);
}
	
sub bad_range_dc($$$)
{
	push(@brFnr,&fnr(shift));
	push(@brMin,shift); push(@brMax,shift);
	$brMin[$#brMin] = -9e99 if ($brMin[$#brMin] eq '*');
	$brMax[$#brMax] =  9e99 if ($brMax[$#brMax] eq '*');
	push(@brDUc,1);
}
	
sub bad_range_uc($$$)
{
	push(@brFnr,&fnr(shift));
	push(@brMin,shift); push(@brMax,shift);
	$brMin[$#brMin] = -9e99 if ($brMin[$#brMin] eq '*');
	$brMax[$#brMax] =  9e99 if ($brMax[$#brMax] eq '*');
	push(@brDUc,0);
}
	
sub good_bins($$)
{
	push(@gbFirst,shift); push(@gbLast,shift);
	$gbFirst[$#gbFirst] = 1    if ($gbFirst[$#gbFirst] eq '*');
	$gbLast[$#gbLast]   = 9e99 if ($gbLast[$#gbLast] eq '*');
}	
	
	

sub isBad()
{
	for (my($f)=0; $f<$antsBufNFields; $f++) {
		for (my($i)=0; $i<@gbFirst; $i++) {								# good bin range
			return 1 if ($ants_[0][$bF] < $gbFirst[$i] ||
			             $ants_[0][$bF] > $gbLast[$i]);
		}

		for (my($i)=0; $i<@brFnr; $i++) {								# bad ranges
			next unless ($brFnr[$i] == $f);
			next unless ($brDUc[$i]==2 || $brDUc[$i]==$ants_[0][$dcF]);
			return 1 if ($ants_[0][$f] >= $brMin[$i] &&
						 $ants_[0][$f] <= $brMax[$i]);
		}
	}
	return 0;
}

#----------------------------------------------------------------------
# Edit Data
#----------------------------------------------------------------------

$wF = &fnr('w');
$eF = &fnr('elapsed');
$dF = &fnr('depth');
$bF = &fnr('bin');
$dcF = &fnr('downcast');

$first_label 	= &antsRequireParam('run_label');
$bin_length 	= &antsRequireParam('ADCP_bin_length');
$pulse_length   = &antsRequireParam('ADCP_pulse_length');
$blanking_dist  = &antsRequireParam('ADCP_blanking_distance');
($dayNoP,$dn) = &antsFindParam('dn\d\d');
croak("$0: cannot determine day number\n")
	unless defined($dayNoP);

my($R,$R2);
if ($opt_p) {												# begin plot
	$xmin = -0.1; $x2min = -200;
	$xmax = 0.35; $x2max =	200;
	$ymin =  0;
	$ymax = antsParam('water_depth');
	$ymax = antsRequireParam('max_depth') unless numberp($ymax);
	$plotsize = 13;
	$R	= "-R$xmin/$xmax/$ymin/$ymax";
	$R2 = "-R$x2min/$x2max/$ymin/$ymax";
	GMT_begin(sprintf($opt_p,$id),"-JX$plotsize/-$plotsize",$R,'-P -X6 -Y4');
	GMT_psxy('-W1');
	print(GMT "0 $ymin\n0 $ymax");
	GMT_psxy('-L -G200');
	print(GMT "0.07 $ymin\n0.07 $ymax\n0.18 $ymax\n0.18 $ymin\n");
	GMT_setR($R2);
	GMT_psxy('-M -W1');
	print(GMT ">\n50 $ymin\n50 $ymax\n");
	print(GMT ">\n100 $ymin\n100 $ymax\n");
	print(GMT ">\n150 $ymin\n150 $ymax\n");
	GMT_setR($R);

	if (defined($opt_b)) {
		open(BT,$opt_b) || croak("$opt_b: $!\n");
		@BTL = &antsFileLayout(BT);
		my($BTwf,$BTdf,$BTmf,$BTnf);
		for (my($f)=0; $f<=$#BTL; $f++) {
			$BTdf = $f if ($BTL[$f] eq 'depth');
			$BTwf = $f if ($BTL[$f] eq 'BT_w');
			$BTmf = $f if ($BTL[$f] eq 'BT_w.mad');
			$BTnf = $f if ($BTL[$f] eq 'BT_w.nsamp');
		}
		croak("$opt_b: file-layout error\n")
			unless defined($BTdf) && defined($BTwf) &&
				   defined($BTmf) && defined($BTnf);
		GMT_psxy('-W6');
		while (@BT = &antsFileIn(BT)) {
			next unless numberp($BT[$BTwf]);
			printf(GMT "%f %f\n",$BT[$BTwf],$BT[$BTdf]);
		}
	}
}

$min_depth =  9e99;										# sentinels
$max_depth = -9e99;

$curF = '';												# current input file (sentinel)
$filt = 0;
for (my($curF),$r=0; &antsIn(); $r++) {
	if ($P{PATHNAME} ne $curF) {						# new file
		$curF = $P{PATHNAME};

		&antsInfo("WARNING: inconsistent %%outgrid_dz in input files")
			if (defined($P{outgrid_dz}) && $P{outgrid_dz}!=$opt_o &&!$opt_o_override);
		&antsInfo("WARNING: inconsistent %%outgrid_minsamp in input files")
			if defined($P{outgrid_minsamp}) && !$opt_k_override &&
					(( $dual_head && $P{outgrid_minsamp}*2!=$opt_k) ||
					 (!$dual_head && $P{outgrid_minsamp}!=$opt_k));
		
		$bin_length = sprintf('%d & %d',round($bin_length),($P{ADCP_bin_length}))
			unless (round($bin_length) == round($P{ADCP_bin_length}));
		$pulse_length = sprintf('%d & %d',round($pulse_length),round($P{ADCP_pulse_length}))
			unless (round($pulse_length) == round($P{ADCP_pulse_length}));
		$blanking_dist = sprintf('%d & %d',round($blanking_dist),($P{ADCP_blanking_distance}))
			unless (round($blanking_dist) == round($P{ADCP_blanking_distance}));

		$PROF = $STN = $ID = $id; $RUN = antsRequireParam('run_label');
		undef(@rngMin); undef(@rngMax); undef(@bins);
		unless ($return = do "./EditParams") {					# man perlfunc
			croak("./EditParams: $@\n") if ($@);
#	        croak("do ./EditParams: $!\n") unless defined($return);		# happens when EditParams does not exist
#	        croak("couldn't run ./EditParams\n") unless $return;		# happens when EditParams does not exist
		}

		if ($opt_p && @dcw1) {									# 2nd file in dual-head profile => plot 1st
			GMT_psxy('-W2,255/127/80,-');
			for (my($bi)=0; $bi<=$#dcw1; $bi++) {
				printf(GMT "%f %f\n",median(@{$dcw1[$bi]}),($bi+0.5)*$opt_o);
			}
			GMT_psxy('-W2,46/139/87,-');
			for (my($bi)=0; $bi<=$#ucw1; $bi++) {
				printf(GMT "%f %f\n",median(@{$ucw1[$bi]}),($bi+0.5)*$opt_o);
			}
			undef(@dcw1); undef(@ucw1);
		}
	}
	next if ($ants_[0][$bF]<$P{outgrid_firstbin}-1 || $ants_[0][$bF]>$P{outgrid_lastbin}-1);
	$filt++,next if &isBad();
	$min_depth = $ants_[0][$dF] if ($ants_[0][$dF] < $min_depth);
	$max_depth = $ants_[0][$dF] if ($ants_[0][$dF] > $max_depth);
	my($bi) = $ants_[0][$dF]/$opt_o;
	if ($ants_[0][$dcF]) {										# downcast
		push(@{$dcw[$bi]},$ants_[0][$wF]);						# vertical velocity
		push(@{$dcw1[$bi]},$ants_[0][$wF]) if ($dual_head);
		push(@{$dce[$bi]},$ants_[0][$eF]);	 					# elapsed time
	} else {								 					# upcast
		push(@{$ucw[$bi]},$ants_[0][$wF]);
		push(@{$ucw1[$bi]},$ants_[0][$wF]) if ($dual_head);
		push(@{$uce[$bi]},$ants_[0][$eF]);
	}
}

if ($opt_p && @dcw1) {											# 2nd file in dual-head profile in buffer => plot it
	GMT_psxy('-W2,255/127/80,.');
	for (my($bi)=0; $bi<=$#dcw1; $bi++) {
		printf(GMT "%f %f\n",median(@{$dcw1[$bi]}),($bi+0.5)*$opt_o);
	}
	GMT_psxy('-W2,46/139/87,.');
	for (my($bi)=0; $bi<=$#ucw1; $bi++) {
		printf(GMT "%f %f\n",median(@{$ucw1[$bi]}),($bi+0.5)*$opt_o);
	}
}

&antsInfo("%d measurements edited (%d%% of total)",$filt,round(100*$filt/$r))
	if ($filt > 0);

#----------------------------------------------------------------------
# Average and Output Profile, Add to Plot
#----------------------------------------------------------------------

@antsNewLayout = ('depth','hab',
				  'dc_elapsed','dc_w','dc_w.mad','dc_w.nsamp',
				  'uc_elapsed','uc_w','uc_w.mad','uc_w.nsamp');
				  		  
if ($dual_head) {										# selected %PARAMs only
	&antsAddParams('profile_id',$id,'lat',$P{lat},'lon',$P{lon});
	&antsAddParams($dayNoP,$dn,'run_label',"$first_label & $P{run_label}");
	&antsAddParams('outgrid_dz',$opt_o,'outgrid_minsamp',$opt_k);
	&antsAddParams('outgrid_firstbin',$P{outgrid_firstbin},'outgrid_lastbin',$P{outgrid_lastbin});
	&antsAddParams('ADCP_bin_length',round($bin_length),'ADCP_pulse_length',round($pulse_length))
	&antsAddParams('ADCP_blanking_distance',round($blanking_dist));
	&antsAddParams('min_depth',round($min_depth),'max_depth',round($max_depth));
	&antsAddParams('water_depth',$P{water_depth},'water_depth.sig',$P{water_depth.sig});
	undef($antsOldHeaders);
}

&antsInfo("WARNING: unknown water depth (no height-above-bottom)")
	unless numberp($P{water_depth});

my(@dcwm,@ucwm,@dcns,@ucns,@dcwmad,@ucwmad);
for (my($bi)=0; $bi<=max($#dcw,$#ucw); $bi++) {
	$dcwm[$bi] = median(@{$dcw[$bi]}); 
	$ucwm[$bi] = median(@{$ucw[$bi]});
	$dcns[$bi] = @{$dcw[$bi]};
	$ucns[$bi] = @{$ucw[$bi]};
	$dcwmad[$bi] = mad2($dcwm[$bi],@{$dcw[$bi]});
	$ucwmad[$bi] = mad2($ucwm[$bi],@{$ucw[$bi]});
	push(@{$out[$bi]},
			 ($bi+0.5)*$opt_o,
			 (numberp($P{water_depth}) ? $P{water_depth}-($bi+0.5)*$opt_o : nan),
			 avg(@{$dce[$bi]}),
			 (($dcns[$bi]>=$opt_k)?$dcwm[$bi]:nan),(($dcns[$bi]>=$opt_k)?$dcwmad[$bi]:nan),
			 scalar(@{$dcw[$bi]}),
			 avg(@{$uce[$bi]}),
			 (($ucns[$bi]>=$opt_k)?$ucwm[$bi]:nan),(($ucns[$bi]>=$opt_k)?$ucwmad[$bi]:nan),
			 scalar(@{$ucw[$bi]}));
	&antsOut(@{$out[$bi]});				 
}

if ($opt_p) {																		# complete plot
	GMT_setR($R);

	GMT_psxy('-W4,255/127/80');														# median profiles
	for (my($bi)=0; $bi<=$#dcw; $bi++) {
		printf(GMT "%f %f\n",(($dcns[$bi]>=$opt_k)?$dcwm[$bi]:nan),($bi+0.5)*$opt_o);
	}
	GMT_psxy('-W4,46/139/87');
	for (my($bi)=0; $bi<=$#ucw; $bi++) {
		printf(GMT "%f %f\n",(($ucns[$bi]>=$opt_k)?$ucwm[$bi]:nan),($bi+0.5)*$opt_o);
	}

	GMT_psxy('-Sc0.1 -G255/127/80');												# m.a.d. profiles
	for (my($bi)=0; $bi<=$#dcw; $bi++) {
		printf(GMT "%f %f\n",(($dcns[$bi]>=$opt_k)?$dcwmad[$bi]:nan),($bi+0.5)*$opt_o);
	}
	GMT_psxy('-Sc0.1 -G46/139/87');
	for (my($bi)=0; $bi<=$#ucw; $bi++) {
		printf(GMT "%f %f\n",(($ucns[$bi]>=$opt_k)?$ucwmad[$bi]:nan),($bi+0.5)*$opt_o);
	}

	GMT_setR($R2);
	GMT_psxy('-Mn -W1,255/127/80');
	for (my($bi)=0; $bi<=$#dcw; $bi++) {											# number of samples
		printf(GMT "%f %f\n",$dcns[$bi],($bi+0.5)*$opt_o);
	}
	GMT_psxy('-Mn -W1,46/139/87');
	for (my($bi)=0; $bi<=$#dcw; $bi++) {
		printf(GMT "%f %f\n",$ucns[$bi],($bi+0.5)*$opt_o);
	}

	GMT_psbasemap('-Bf10a1000-950:"                                     # of Samples":N');
	GMT_psbasemap('-Ba1000-900N'); GMT_psbasemap('-Ba1000-850N');

	$depth_tics = ($ymax-$ymin< 1000) ? 'f10a100' : 'f100a500';
	GMT_setR($R);
	GMT_psbasemap('-Bf0.01a10-10.05:"Vertical Velocity [m/s]                               ":/' .
						$depth_tics . ':"Depth [m]":WeS');
	GMT_psbasemap('-Ba10-9.95S'); GMT_psbasemap('-Ba10-9.85S');

	GMT_setR('-R0/1/0/1');
	GMT_pstext('-Gblue -N');
	if (defined($outfile)) { print(GMT "0.01 -0.06 14 0 0 TL $outfile [$P{run_label}]\n"); }
	else { printf(GMT "0.01 -0.06 14 0 0 TL %03d\n [$P{run_label}]",$id); }
	GMT_pstext();
	print(GMT '0.62 0.98 12 0 0 MR m.a.d.');
	GMT_end();
}

&antsExit(0);