/**---------------------------------------------------------------------------
 ** 
 ** avg_.c -- 
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/31 21:18:42
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/09/21 12:14:02
 ** Update Count    : 11
 ** Directory       : /pcdata1/jaccard/codas3c/gfi/src/apps/nbr/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    Undocumented.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

/* ##################################################################

	-Introduction:

	Utilities used during averaging of NB ADCP aw data. This file should be
	included in the main processing programme.

	##################################################################
*/

#ifndef avg__C_code_already_included
#define avg__C_code_already_included

#include "avg_.h"

/* ------------------------------------------------------------------ 
   --Check Average Time:
   
   This function check the time of current ensemble relative to the previous
   one and the time controls defined in the control file. The [[AVERAGE_FLAG]]
   is updated, unless it is NULL, in which case it is assumed that this
   function was called when an end of file occured. It checks then just if
   currently averaged data should be kept or not.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int check_avg_time(AVG_NPT_TYPE *npt, PROCESS_CONTROL_TYPE *cnt,
									 FLAG_LIST_TYPE *fl)
#else
int check_avg_time(npt, cnt, fl)
#endif
{

	/* Check time if EOF */
	if(!fl){
		if( (int) (npt->prev.time.hun - npt->start.time.hun) < cnt->avg_min )
			return(ABORT_AVERAGE_CODE);
		else
			return(LAST_AVERAGE_CODE);
	}
		
	/* Check for a long time gap since previous ensemble */
	if( (int) (npt->curr.time.hun - npt->prev.time.hun) > cnt->max_gap){

    /*
    printf("%ld %ld %ld %d %d %d\n", npt->curr.time.hun, npt->prev.time.hun,
           npt->start.time.hun, cnt->max_gap, cnt->avg_min,
           (int) (npt->curr.time.hun - npt->prev.time.hun));
    */

		/* Check if current average can be kept */
		if( (int) (npt->prev.time.hun - npt->start.time.hun) < cnt->avg_min ){
			set_flag(fl, AVERAGE_FLAG, 0, ABORT_AVERAGE_CODE);
			return(ABORT_AVERAGE_CODE);
		}
		else{
			set_flag(fl, AVERAGE_FLAG, 0, FORCE_AVERAGE_CODE);
			return(FORCE_AVERAGE_CODE);
		}
	}
	else
		set_flag(fl, AVERAGE_FLAG, 0, 0);

	return(0);
}

/* ------------------------------------------------------------------
   --Set Average Time:
   	
  This function fills the [[AVG_NUM_POS_TIME_TYPE]] structures, according to
  the value of code. If [[scan_nav]] input is required is taken from the
  [[scan_nav]] file, since these data are assumed to have the correct time. If
  [[scan_nav]] input is not required, then the time is taken from the
  [[NBR_ENSEMBLE_TYPE]] structure.
  
  The options from the control file determine if time and position are taken
  at the start or the end of current ensemble. The values of [[code]]
  determine which of the structure must be filled. In case of
  [[CURRENT_NPT_CODE]], the structure [[curr]] is filled with ensemble
  data. For other values, the corresponding structure is filled with the
  values from the [[curr]] structure.
  
  WARNING: Ensemble stop values are copied from the [[prev]] structure.  
	------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int set_avg_npt(AVG_NPT_TYPE *npt, LOAD_NBR_TYPE *rec, 
                      int year_base, int code)
#else
int set_avg_npt(npt, rec, year_base, code)
#endif
{

	char func[]="set_avg_npt";
	
	switch(code){
	case CURRENT_NPT_CODE:
		/* Check for scan_nav input data */
		if(option_bits & USE_SCAN_NAV_BIT){
			/* Fill ensemble _number */
			npt->curr.number = rec->nav.number;
			/* Fill position and time according to options */
		   if(option_bits & POS_TIME_START_BIT){
		   	/* Reference taken at start of ensemble */
		   	npt->curr.time.yd = rec->nav.time.start;
				npt->curr.time.hun = (ULONG) (npt->curr.time.yd * 8640000.0);
				npt->curr.pos.lat = rec->nav.pos.start.lat;
				npt->curr.pos.lon = rec->nav.pos.start.lon;
			}
			else if(option_bits & POS_TIME_STOP_BIT){
				/* Reference taken at end of ensemble */
		   	npt->curr.time.yd = rec->nav.time.stop;
				npt->curr.time.hun = (ULONG) (npt->curr.time.yd * 8640000.0);
				npt->curr.pos.lat = rec->nav.pos.stop.lat;
				npt->curr.pos.lon = rec->nav.pos.stop.lon;
			}
			else{
				/* If no bit is set for this option, reference is taken at middle 
				   point of ensemble */
		   	npt->curr.time.yd = (rec->nav.time.start + rec->nav.time.stop)/2.0;
				npt->curr.time.hun = (ULONG) (npt->curr.time.yd * 8640000.0);
				npt->curr.pos.lat =  (rec->nav.pos.start.lat +
										rec->nav.pos.stop.lat)/2.0;
				npt->curr.pos.lon =  (rec->nav.pos.start.lon +
										rec->nav.pos.stop.lon)/2.0;
			}
		}
		else{
			/* Reference taken from ADCP raw ensemble */
			npt->curr.number = rec->ens.leader.ensemble_number;
			npt->curr.time.yd = rtc_to_yd(&(rec->ens.leader.ensemble_start_time),
													year_base);
			npt->curr.pos.lat = BADDOUBLE;
			npt->curr.pos.lon = BADDOUBLE;
		}
		/* Fill time in hundredth of seconds */											
		npt->curr.time.hun = (ULONG) (npt->curr.time.yd * 8640000.0);
		break;
	case PREVIOUS_NPT_CODE:
		memcpy((void *) &(npt->prev), (void *) &(npt->curr),
					 sizeof(AVG_NUM_POS_TIME_TYPE));
		break;
	case START_NPT_CODE:
		memcpy((void *) &(npt->start), (void *) &(npt->curr),				
					 sizeof(AVG_NUM_POS_TIME_TYPE));
		break;
	case STOP_NPT_CODE:
		memcpy((void *) &(npt->stop), (void *) &(npt->prev),
					 sizeof(AVG_NUM_POS_TIME_TYPE));
		break;
	case DB_NPT_CODE:
		memcpy((void *) &(npt->db), (void *) &(npt->stop),
					 sizeof(AVG_NUM_POS_TIME_TYPE));
		break;
	default:
		error_msg(func, "No action defined for this code");
		break;
	}	
	
	return(0);
		
}

/* ------------------------------------------------------------------
	 --Initialize Averaging:

	 This function should be called each time an averaging process is going to
	 be started.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_avg(AVG_NPT_TYPE *npt, LOAD_NBR_TYPE *rec)
#else
int init_avg(npt, rec)
#endif
{

	UNISTAT_LIST_TYPE *uni;
	FLAG_LIST_TYPE *f;
	int i;

	/* Set negative flags to zero */
	f = rec->flag_list;
	while(f->name != NULL){
		if(f->code < 0)
			zero_flag_list(rec->flag_list,f->code);
		f++;
	}
	
	/* Set all statistical cells to zero */
	zero_unistat_list(rec->stat_list, BADINT);
	
	/* Put the same time in prev than there is in curr to avoid time checking
		 flags */
	memcpy((void *) &(npt->prev), (void *) &(npt->curr), 
				 sizeof(AVG_NUM_POS_TIME_TYPE));

	/* Put bad in all data values of the statistical list */
	uni = rec->stat_list;
	while(uni->name != NULL){
		for(i=0; i<(uni->size); i++)
			*(uni->data + i) = BADDOUBLE;
		uni++;
	}
		
	return(0);
	
}

/* ------------------------------------------------------------------ 
   --Log Average:
   
   This function logs information each time an averaging has been carried out.
   Depending on the value of the [[AVERAGE_FLAG]], it also logs additionnal
   information.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int log_avg(FILE *fp, AVG_NPT_TYPE *npt, LOAD_NBR_TYPE *rec, int year_base)
#else
int log_avg(fp, npt, rec, year_base)
#endif
{

	UNISTAT_LIST_TYPE *bsol;
	BYTE flag;
	
	static int n=0, first=1;
	int i;

	char str[200], start_str[200], stop_str[200], ensnum_str[200], 
		last_str[200], next_str[200];
	FILE_NAME_TYPE path, file;

	/* Print the header */
	if(first){
		fprintf(fp, "\n");
		fprintf(fp, "%% *** PROCESSING LOG INFORMATION: Data Description ***\n");
		fprintf(fp, "%%  1 : last valid time (%4d decimal days)\n", year_base);
		fprintf(fp, "%%  2 : average status\n");
		fprintf(fp, "%%  3 : number of ensembles\n");
		fprintf(fp, "%%  4 : average time (s)\n");
		fprintf(fp, "%%  5 : last good beam solution\n");
		fprintf(fp, "%%  6 : pcg of bad beam solutions\n");
		fprintf(fp, "%%  7 : pcg of 2 beam solutions\n");
		fprintf(fp, "%%  8 : pcg of 3 beam solutions\n");
		fprintf(fp, "%%  9 : pcg of 4 beam solutions\n");
		fprintf(fp, "%% 10 : pcg of BT bad beam solutions\n");
		fprintf(fp, "%% 11 : pcg of BT 2 beam solutions\n");
		fprintf(fp, "%% 12 : pcg of BT 3 beam solutions\n");
		fprintf(fp, "%% 13 : pcg of BT 4 beam solutions\n");
		fprintf(fp, "%% ****************************************************\n");
		fprintf(fp, "%% \n%% Meanings:\n%%\n");
		fprintf(fp, "%%    status = -1 ABORT_AVERAGE\n");
		fprintf(fp, "%%    status =  1 NORMAL_AVERAGE\n");
		fprintf(fp, "%%    status =  2 FORCE_AVERAGE\n");
		fprintf(fp, "%%    status =  3 LAST_AVERAGE\n%%\n");
		fprintf(fp, "%% ****************************************************\n");
		fprintf(fp, "%% \n%% WARNING:\n%%\n");
		fprintf(fp, "%% pcg is an average over %d bins. Hence, bad beam\n", 
					 MAX_BINS);
		fprintf(fp, "%% solutions will certainly dominate over shallow\n");
		fprintf(fp, "%% depths.\n%%\n");
		fprintf(fp, "%% ****************************************************\n");
		first = 0;
	}

	/* Get the average flag */
	flag = get_flag(rec->flag_list, AVERAGE_FLAG, 0);
	
	/* Build strings */
	yd_to_ymdhms_str(str, npt->start.time.yd, year_base);
	sprintf(start_str, "%%%%%%          Averaging start time: %s\n", str);
	yd_to_ymdhms_str(str, npt->stop.time.yd, year_base);
	sprintf(stop_str, "%%%%%%          Averaging stop time : %s\n", str);
	yd_to_ymdhms_str(str, npt->curr.time.yd, year_base);
	sprintf(next_str, "%%%%%%          Next start time     : %s\n", str);
	yd_to_ymdhms_str(str, npt->prev.time.yd, year_base);
	sprintf(last_str, "%%%%%%          Last valid time     : %s\n", str);
	sprintf(ensnum_str, "%%%%%%          Number of ensembles : %6hu\n",
					npt->stop.number - npt->start.number + 1);
	split_file_path(rec->fi.name, path, file);
	
	/* Warning messages */
	if(flag == FORCE_AVERAGE_CODE){
		report_msg(   "\n%%% WARNING: FORCING AVERAGING\n");
		report_msg(start_str);
		report_msg(stop_str);
		report_msg(ensnum_str);
		report_msg(next_str);
	}
	else if(flag == LAST_AVERAGE_CODE){
		report_msg(   "\n%%% WARNING: FORCING AVERAGING OF LAST ENSEMBLE\n");
		report_msg(start_str);
		report_msg(stop_str);
		report_msg(ensnum_str);
	}
	else if(flag == ABORT_AVERAGE_CODE){
		report_msg(   "\n%%% WARNING: ABORTING AVERAGING\n");
		report_msg(start_str);
		report_msg(last_str);
		report_msg(ensnum_str);
		report_msg(next_str);
	}
	else if(flag == NORMAL_AVERAGE_CODE){
		/* Write data into log file */
		yd_to_ymdhms_str(start_str, npt->start.time.yd, year_base);
		yd_to_ymdhms_str(stop_str, npt->stop.time.yd, year_base);
		sprintf(str, "\n%% %6d:  FILE: %s  ENSEMBLES: %5hu  FROM  %s  TO  %s\n", 
						n, file, (npt->stop.number-npt->start.number+1), 
						start_str, stop_str);
		report_msg(str);

		n++;
	}

	/* Log additionnal data for processing controls: */
	if(npt->prev.time.yd < ADJ_BADFLOAT)
		fprintf(fp, "%14.8f ", npt->prev.time.yd);
	else
		fprintf(fp, "           NaN ");
	fprintf(fp, "%3d ", flag);
	if(flag > 0)
		fprintf(fp, "%6hu ", npt->stop.number - npt->start.number + 1);
	else
		fprintf(fp, "   NaN ");
	if(flag > 0)
		fprintf(fp, "%14.8f ", 
						86400.0 * (npt->stop.time.yd - npt->start.time.yd));
	else
		fprintf(fp, "           NaN ");
	/* Bin of last good beam solution */
	bsol = (UNISTAT_LIST_TYPE *) 
		get_unistat_element(rec->stat_list, LAST_GOOD_BIN_CODE);
	if(flag > 0)
		fprintf(fp, "%14.8f ", *(bsol->data));
	else
		fprintf(fp, "           NaN ");
	/* Velocity beam solutions */
	bsol = (UNISTAT_LIST_TYPE *) 
		get_unistat_element(rec->stat_list, BEAM_SOL_CODE);
	for(i=0; i<(bsol->size); i++){
		if(flag > 0)
			fprintf(fp, "%14.8f ", *(bsol->stat->sum + i));
		else
			fprintf(fp, "           NaN ");
	}
	/* Idem for bottom tracking velocities */
	bsol = (UNISTAT_LIST_TYPE *) 
		get_unistat_element(rec->stat_list, BT_BEAM_SOL_CODE);
	for(i=0; i<(bsol->size); i++){
		if(flag > 0)
			fprintf(fp, "%14.8f ", *(bsol->stat->sum + i));
		else
			fprintf(fp, "           NaN ");
	}

	return(0);
}


#endif /* avg__C_code_already_included */
