#!/usr/bin/env perl
# evigene/scripts/genes/tr2dupgeneclass.pl from genes/tr2ncrna.pl
# 2022/Nov 

=item about 

  EvidentialGene tr2dupgeneclass 
    classifies transcripts as to gene family: paralogs of 2+loci, alts of one locus,
    adding DNA copynumber evidence from Gnodes genexcopy tables

=item 22NOV work notes    

  builds on genes/blasttrset2exons2.pl (exon chain classifier of locus alts),
   + genoasm/gnodes_pipe.pl, genes.genexcopy output (no chr asm required, but DNA reads evidence)
  
  same idea as genes/altparclassify2b.pl, but that one is very/too simple, classify based on cds-self.blast pIdent
  
.. need to modify $evigene/scripts/genes/blasttrset2exons2.pl,
.. see evigene/scripts/genes/altparclassify2b.pl, covers same ground, used by genes/tr2ncrna.pl
.. ?? update to genes/altparclassify3c.pl NO
.. blasttrset2exons2 replaces altparclassify2b, does job of altpar classify based on
    exon aligns, vs altparclass2b uses only simple blast/btall pctident cutoff.. not good.
.. use tr2ncrna.pl as template for dupgeneclass.pl/tr2dupgenes/tr2paralogs ?


=item usage     

$evigene/scripts/genes/tr2dupgeneclass.pl
opts:
  -cds tr2inputs.cds 
  -pubids tr2okset.pubids \
  -genex tr2okset1cds_dnareads_gnodes.genexcopy \
  [-refids reference_genes.idtab ] \
  -outname tr2okset_dupgenes1a

  -refids reference_genes.idtab option to compare refgenes (trid locusid) w/ dupgeneclass table,
    eg w/ NCBI gene refsets built on chrasm,

  Requires Evigene data, from SRA2Genes or tr2aacds, with inputset, okayset, dropset transcripts + tables
  Requires Gnodes genecds.genexcopy results of DNA depth for gene cds, eg 
     genoasm/gnodes_pipe.pl -cds okayset/main.cds -reads xxx.fastq


=cut

use FindBin;
use lib ("$FindBin::Bin","$FindBin::Bin/.."); # assume evigene/scripts/ layout: main, prot/, rnaseq/, ...
use strict;
use Getopt::Long;
use cdna_evigenesub;  
# use evigene_pubsets;
use File::Basename qw(basename dirname fileparse);

use constant VERSION => '2023.01.17'; # '2022.11.01'; # v2c,d,e..
use constant USE_recover_trset => 1; # convert subset.tr <=> subset.trids, works reduces size lots
use constant FIXME => 0;

our $EVIGENES= $FindBin::Bin; $EVIGENES =~ s,scripts/.*,scripts,;
our $EGAPP='tr2dupgeneclass';  # tr2dgc ?
our $EGLOG='tr2dgc';

my $debug=$ENV{debug}||0; 
my $NCPU=$ENV{ncpu}||1; 
my $tidyup=1;
my $MAXPUT= $ENV{maxrun} || 19; ## ($debug)?9:999999; # dogenesimtab tests
my $SKIP_UTRORF= $ENV{utrorf} ? 0 : 1; # problem children, utrorf calls screw checkref, other .. drop for ref tests

## tr2dgc reused opts:
my $REUSE_TMPDATA= 1; # v2: default or no option..
my $CDSBLAST_IDENT= 98; # 98 + -ungapped ; was 95; # or 98; # or 95? ** drop this back to 95 default; at least for high okay count species
my $MIN_MINALT= $ENV{pminminalt} || 89; # pminminalt for algn tree global sim of valid alts; CDSBLAST_IDENT too high (local algn)

## old ncrna stuff .... drop/keep?
my $MIN_NCRNA= $ENV{MIN_NCRNA} || 300; # UPD2222 what size opt? 500 too big
my $MINAA_NCRNA= $ENV{MINAA_NCRNA} || 120; # save ncrna aatrans if aasize>min, should be same var as for tr2aacds etc
my $DROPSHORT_NCRNA= $ENV{DROPSHORT_NCRNA} || 0.20; #??
my $PAL_NCRNAMIN= $ENV{PAL_NCRNAMIN} || 80; # reject ncrna align below this 
my $TEST_OKCDS= $ENV{TEST_OKCDS}||0; # needs testing .. should become default

my $MIN_CDSALN= $ENV{MIN_CDSALN}||150; #? for TEST_OKCDS
my $MINBIGAA= $ENV{MINBIGAA} || 300; # remove_bigcdsdrops : 300? 200 ? or 150? 
my $UPDATEALL= 0;
my $usebself= 1; #v2 default  $ENV{TESTmrnablast} for remove_mrna_aligned() blast method 
my($IDPREncrna,$IDBASEncrna) =("",0); # UPD2222
my($premerge,@submerge)= (0);

# ncrna_altparscore globals
my $MINSCORE=$ENV{minscore} || -999; # need some data on this
my $MINALT= $ENV{minalt}|| 0.50; #??
my $MINDUPALN = $ENV{mindupaln} ||0.80; # ncrna_altparscore option: align(t/r)
my $MINDUPFULL= $ENV{mindupfull}||0.80; # ncrna_altparscore option: size(t/r)
#----------------------------
# evgenesim_script exports: debug pminalt pminminalt snpvar ? pctident?? now for sim..
#    $EGAPP trset=$trset pubids=$inpubids cdsseq=$cdsseq genexcopy=$ingenexf eqgenetab=$eqgenetab

my ($cdsseq,$chrasm,$ingenexf,$trset,$output,$refids,$aaqualf,$inpubids,$logfile,$dogenesimtab);
my ($eqgenetab,$runscript)=("",undef); # or look for?
my $SAVE_RUNSCRIPT=$debug; # debug? default save even if no opt?

# drop exonerate, blastn is problematic, muscle multalign works best for these gene.cds aligns
my $ALIGNER=$ENV{'aligner'}|| 'muscle'; #  eq lastz 'exonerate' 'blast' ..
my %ALOK= ( muscle => 1, lastz => 2, blastn => 3); # ,  exonerate => 3 drop

my @ARGSAVE=@ARGV;
my %opts= (
  "trset|input=s", \$trset, # require?
  "cdsseq=s", \$cdsseq, # require, find 
  "genexcopy=s", \$ingenexf, # require?
  "pubids=s", \$inpubids, # for evgsimtab
  "chrasm=s", \$chrasm, # for make_cdschr_genex
 
  "dogenesimtab!", \$dogenesimtab, 
  "eqgenetab=s", \$eqgenetab, # intermediate, dogenesimtab
  "refids=s", \$refids, # opt 
  "ALIGNER=s", \$ALIGNER, # opt 
  "outname|output=s", \$output, # opt
  "logfile:s", \$logfile, # option
  "runscript:s", \$runscript, # option, write cmds to script file, dont run
  # "aaqualf=s", \$aaqualf, # aaqualf required ? w/ codepot; add mrna/cds/aa seq set??
  # "MIN_NCRNA=i", \$MIN_NCRNA,  
  "MIN_IDENT=i", \$CDSBLAST_IDENT,  
  "MIN_CDSALN=i", \$MIN_CDSALN,  
  # "minalign_ncrna=s", \$PAL_NCRNAMIN,  
  "NCPU=i", \$NCPU, # "MAXMEM=i", \$MAXMEM,  
  # "premerge!", \$premerge, "mergesubsets=s", \@submerge, # UPD20mar
  # "UPDATEALL!", \$UPDATEALL, 
  "REUSE_TMPDATA!", \$REUSE_TMPDATA, 
  "TEST_OKCDS!", \$TEST_OKCDS, 
  "debug!", \$debug, 
  );

  
my $optok= GetOptions(%opts);
my $optlist= ($debug) ? "All opts: ".join(", ",sort keys %opts) : "";
my $DOMERGE= (@submerge > 0)?1:0; #UPD20mar .. inputs not $trset, from submerge[0..n]/ncrnaset/xxx.longnomrna.tr
my @ALIGNOK= sort keys %ALOK; 
$SAVE_RUNSCRIPT=$debug;

die "EvidentialGene $EGAPP, VERSION ",VERSION,"
    classifies transcripts as to gene family: paralogs of 2+loci, alts of one locus,
    adding DNA copynumber evidence from Gnodes genexcopy tables.
  
\$evigene/scripts/genes/tr2dupgeneclass.pl
opts:
  -cds    tr2inputs.cds   : required, gene coding sequences, with public/original ids
  -pubids tr2okset.pubids : required (?), evi-gene class table with  public-group and original ids 
  -genex  tr2okset1cds_dna_gnodes.genexcopy : required, from Evigene gnodes, or chrasm
  -chrasm chromosome-assembly.fasta         : alternate way to calculate gene copy num
  -outname tr2dupgenes1a   : option
  -[no]reuse : no/reuse existing tmps/temporary data (default=$REUSE_TMPDATA)
  
  -refids reference_genes.idtab : option, as (tr_id locus_id) to compare refgenes w/ dupgene class table,
    eg w/ NCBI gene refsets built on chrasm
  -aligner @ALIGNOK : compatible cds aligner programs (default=$ALIGNER)
  
  Multiple aligner muscle v3 gives best results, v5 is not supported (http://www.drive5.com/muscle)
  Requires Evigene data, from SRA2Genes or tr2aacds, with inputset, okayset, dropset transcripts + tables
    : -cds should be either inputset/name.cds or okayset/name.okay.cds
    : -pubids should be okayset/name.pubids
  Requires Gnodes genecds.genexcopy results of DNA depth for gene cds, eg 
     genoasm/gnodes_pipe.pl -cds okayset/main.cds -reads xxx.fastq
  Or, alternately, -chrasm chrname.fa, which produces a genexcopy table from cds x chr alignments.
  Chrasm is more likely to give flawed copy numbers in areas of poor duplicate assembly.

\n" unless($optok and ($trset or $cdsseq)); 

our $DEBUG= $debug;  # set package dbg
$ENV{debug}=$debug; #set for callees
unless($trset) { $trset= basename($cdsseq); $trset =~ s/\.gz$//; $trset =~ s/\.\w+$//; }

openloggit($logfile,basename($trset)); # inputset/name.tr > inputset/ncrna.log is bad
loggit(1, "EvidentialGene $EGAPP, VERSION",VERSION);
loggit 1, "$EGAPP  @ARGSAVE \n";

if($ALIGNER){  # set default ALIGNER above
  unless($ALOK{$ALIGNER}) { 
    my ($al)= lc(substr($ALIGNER,0,1)); 
    for my $aok (@ALIGNOK) { if(substr($aok,0,1) eq $al){ $ALIGNER=$aok; last; } }
    if($ALOK{$ALIGNER}) { loggit 1, "ALIGNER=$ALIGNER \n"; }
    unless($ALOK{$ALIGNER}) { loggit LOG_DIE, "opt -ALIGNER need one of these:  @ALIGNOK \n"; }
    #?? else { findapp($ALIGNER,kDIEonERR); }
  }  
}

#? die if not findapp() for muscle or blastn ?
use constant { kNODIEonERR => 1, kDIEonERR => 0 };
# my $APPfastanrdb= findapp("fastanrdb");  

my $APPblastn= findapp("blastn",kNODIEonERR);  
my $APPmakeblastdb= findapp("makeblastdb",kNODIEonERR);  
my $APPmuscle= findapp("muscle",kNODIEonERR);  # need vers=3.n not 5.n
my $APPexonr= findapp("exonerate",kNODIEonERR);
my $APPlastz= findapp("lastz",kNODIEonERR);

our (@dupgeneset, @ncrnaset, @okayset,@dropset,@inputset,@tmpfiles,@erasefiles,@publicset); # tidyup file sets
# add @dupgeneset ? @altparset ? @paraltset @redupset .. == this work public set
my $outputh=undef; # *STDOUT; # unused now

sub MAIN_stub {}

my($trname,$trclass,$cdsseqo,$cdsblast,$okaysetd,$pubsetd) = find_evgtr2aacds($trset,$cdsseq);
  
$cdsseq=$cdsseqo;
unless($inpubids) { #? add to find_evgtr2aacds()
  my $pf="$pubsetd/$trname.pubids";
  if(-s $pf){ $inpubids=$pf; } 
  else { $inpubids=$pf; } # ? fail w/ missing pubids.
}
unless($eqgenetab) {
  $eqgenetab=basename($inpubids); $eqgenetab=~s/\.\w+$//; $eqgenetab.="_evsim.eqgene"; #always try for?
}

#INSERT option create genextab from cds x chrasm blastn, if no dna.genexcopy, but have chrasm
if($chrasm and not $ingenexf) { 
  ($ingenexf)= make_cds_chr_genextab($cdsseq,$chrasm,); 
  push @dupgeneset, $ingenexf if(-s $ingenexf);
}

my($nucg,$ngenex,$Cucg,$genextab)=  ($ingenexf)? read_genexcopy($ingenexf) : (0,0);

if(defined $runscript) {
  unless($runscript) { $runscript=$trname; $runscript=~s/\.\w+$//; $runscript.="_run_evsim.sh"; }
}

my $needeqgene= (-s $inpubids and -s $cdsseq and not -s $eqgenetab);
$dogenesimtab=2 if($needeqgene and $runscript);

# FIXME: replace eqgene output w/ apvals => apclass, using apclass_idxdnacn.pl
#  apclass_idxdnacn.pl produces new pubids, need evg parts to update okayset/ or publicset/ w/ that for alt/par class
# FIXME: opt run exonerate on cds pairs instead of muscle multaln

if($dogenesimtab) {  # or $needeqgene
  my($nsim,$simtabs);
  if($runscript) { 
    ($nsim,$eqgenetab,$simtabs)= evgenesim_script($inpubids,$cdsseq,$eqgenetab,$runscript); 
  } elsif($APPmuscle =~ /MISSING/i and $APPexonr =~ /MISSING/i){  # or $APPexonr
    loggit(1,"evgenesim requires muscle: $APPmuscle or/and exonerate: $APPexonr"); 
  } elsif($NCPU>1) {
    ($nsim,$eqgenetab,$simtabs)= evgenesim_ncpu($inpubids,$cdsseq,$eqgenetab,$NCPU); 
  } else {
    #old,drop: ($nsim,$eqgenetab,$simtabs)= evgenesim($inpubids,$cdsseq,$eqgenetab); 
    ($nsim,$eqgenetab,$simtabs)= evgenesim_ncpu($inpubids,$cdsseq,$eqgenetab,$NCPU);  # NCPU==1 ok now
  }
  push @dupgeneset, $eqgenetab if($nsim); #?
}

if($refids and -s $inpubids) {
  my($rets,$nevgroup,$ntr,$nsame,$ndif,$negsame,$negdif,$nmiss,$evgdifa)= checkref_pubids($inpubids,$refids);
  if(ref($rets)){ map{ loggit(1,$_) } @$rets; }
  else { loggit(1, "checkref_pubids($inpubids,$refids) error"); }
  #loggit(1, "checkref_pubids ngroup=$nevgroup, ngsame=$negsame, ngdif=$negdif, ntr=$ntr, nsame=$nsame, ndif=$ndif, nmiss=$nmiss"); 
  # checkref_pubids ngroup=1551, ngsame=86, ngdif=261, ntr=2194, nsame=176, ndif=453, nmiss=21
  # ngroup >> ngsame+ngdif due to noclass-singleton groups not counted
  if($ndif){ 
    my $evgdifs=join", ",@$evgdifa; 
    if($negdif > 20) { (my $fo=$inpubids)=~s/\.\w+$//; $fo.="_refdiff.list"; open(O,">$fo"); map{ print O $_,"\n"; } @$evgdifa; close(O);
      $evgdifs= join", ",@{$evgdifa}[0..9], ".. n=$negdif in $fo";
      }
    loggit(1, "checkref_pubids ref-diff groups: $evgdifs");  # can be long list, chop?
    }
  }

if($refids and $eqgenetab) { # was  -s $eqgenetab; allow stdin|-
  my($rets,$nevgroup,$ntr,$nsame,$ndif,$negsame,$negdif,$nmiss,$evgdifa)= checkref_eqgene($eqgenetab,$refids);
  if(ref($rets)){ map{ loggit(1,$_) } @$rets; }
  else { loggit(1, "checkref_eqgene($eqgenetab,$refids) error"); }
  #loggit(1, "checkref_eqgene ngroup=$nevgroup, ngsame=$negsame, ngdif=$negdif, ntr=$ntr, nsame=$nsame, ndif=$ndif, nmiss=$nmiss"); 
  if($ndif){
    my $evgdifs=join", ",@$evgdifa; 
    if($negdif > 20) { (my $fo=$eqgenetab)=~s/\.\w+$//; $fo.="_refdiff.list"; open(O,">$fo"); map{ print O $_,"\n"; } @$evgdifa; close(O);
      $evgdifs= join", ",@{$evgdifa}[0..9], ".. n=$negdif in $fo";
      }
    loggit(1, "checkref_eqgene ref-diff groups: $evgdifs"); 
    }
}

if(FIXME) {
  unless(-s $cdsblast) { 
    # if($APPblastn =~ /MISSING/i){ loggit(1,"evgenesim requires blastn: $APPblastn"); }    
    # else { ($cdsblast)= blastn_cds($cdsseq); }
  }

  MAIN_tr2dupgeneclass2b($trname, $trclass, $cdsseq, $cdsblast, $eqgenetab);
  #old MAIN_tr2dupgeneclass_ncrna();
  FINISH_tr2dgc(0,'done okay',$trname);
} else {
  # warn "FIXME: MAIN_tr2dupgeneclass2b($trname, $trclass, $cdsseq, $cdsblast, $eqgenetab);\n";
}

#================================================================


sub filegz{ my($f)=@_; unless(-f $f){ $f="$f.gz" if(-f "$f.gz"); } return $f; }
sub step_log_or_fini{ my($fini,$msg)=@_; if($fini){ FINISH_tr2dgc(-1,$msg); } else { loggit( 0, $msg); } }

# locate Evigene tr2aacds data sets .. die if not found??  see top MAIN_tr2dupgeneclass_ncrna
# SEE trclass2pubset.pl get_evgtrset()
sub find_evgtr2aacds {
  my($trset,$cdsseq)=@_; # global cdsseq?
  
  unless($trset) {
    my $trc=`ls *.trclass`; if($trc){ chomp($trc); $trset=$trc; }
    step_log_or_fini(  (not $trset), "start with trset=$trset");
  }
  
  my $trname= basename($trset); $trname =~ s/\.gz$//; $trname =~ s/\.\w+$//;
  my $trclass="$trname.trclass"; 
  unless( -s $trclass) {
    step_log_or_fini(0, "$trname tr2aacds data class=$trclass"); # dont fail if miss trclass, not used yet?
  }
  
  my @okpubs1a= qw( okayset publicset);
  my @okpubs2b= qw( okayset1st okayset);
  ($okaysetd,$pubsetd)= @okpubs2b; 
  unless( -d $okaysetd and -d $pubsetd ) {   
    ($okaysetd,$pubsetd)= @okpubs1a;
    unless( -d $okaysetd and -d $pubsetd ) {
      #? step_log_or_fini( -1, "find evigene data directories:  @okpubs2b or @okpubs1a");
    }
  }
  
  unless($cdsseq){ # FIXME which cds to start on? option
    $cdsseq= filegz("tmpfiles/${trname}nrcd1x.cds"); 
  }
  # okayset/at18tair_mrna.okay.cds  n=38973  (and okayset1st/main,alt.cds)
  # dropset/at18tair_mrna.drop.cds  n=10377
  # tmpfiles/at18tair_mrnanrcd1x.cds   n=40654  NOT extended
  # tmpfiles/at18tair_mrnanrxucd1.cds  n=40654  extended cds, cdhit -c1.0 no dups
  # tmpfiles/at18tair_mrnanrxu.cds  n=42357  extended cds
  # tmpfiles/at18tair_mrnanr.cds    n=42357
  # inputset/at18tair_mrna.cds      n=50025
  
  # tmpfiles/at18tair_mrnanrcd1x-self98.blastn
  # tmpfiles/at18tair_mrnanrcd1x-self100.btall
  
  my $cdsblast="";
  $cdsblast= makename($cdsseq,"-self$CDSBLAST_IDENT.blastn"); # filegz(makename()) ?
  #   ($cdsseqnr)= nonredundant_cds($cdsseq);
  #     my $cdsnrseq = makename($cdsseq,"nr.cds");
  #   $cdsseqnrcd1 = faextract($cdsseq, makename($cdsseqnr,"cd1x.cds"), $cdsnrids,1);
  #   ($cdsblast)= blastn_cds($cdsseqnrcd1);
  #     my $cdsbltab= makename($cdsseq,"-self$CDSBLAST_IDENT.blastn");
  if( -s "tmpfiles/$cdsblast") { $cdsblast="tmpfiles/$cdsblast"; }

  step_log_or_fini(  (! -s $cdsseq), "$trname tr2aacds data cds=$cdsseq");
  return($trname,$trclass,$cdsseq,$cdsblast,$okaysetd,$pubsetd);
}



=item sub tr2aacds4_stage2b, 2nd stage filter

  code from evigene/scripts/prot/tr2aacds4_stg2a.pl
  
=cut

sub MAIN_tr2dupgeneclass2b {  # tr2aacds4_stage2b
  my($trname, $trclass, $cdsseq, $cdsblast,$eqgenetab)= @_; #? genextab global
  my $tidy2stg = 0;

  #   step_log_or_fini(  ( ! -s $trclass ), "$trname tr2aacds data class=$trclass");
  unless ( -s $trclass ) { loggit(1,"ERR: missing -class $trclass"); return(-1); }
  unless ( -s $cdsblast ) { loggit(1,"ERR: missing cdslbast $cdsblast"); return(-1); }

  my $idprefix=$ENV{idprefix} || ""; # fixme, from ORGANISM / species
  
  # my $trname= $trclass; $trname=~s/.trclass$//; # .gz?
  (my $trnrname = $cdsblast) =~ s/.self\d+.blastn.*//;

  my($cmd,$opts,$err);
  $cmd="env outcds=1 $EVIGENES/prot/cdsqual.sh $cdsseq"; # $trnrname.cds"; #?? err if missing cds
  $err= runcmd($cmd);

  my $inbtall="$trnrname-self$CDSBLAST_IDENT.btall"; 
  if ( ! -s $inbtall and -s "tmpfiles/$inbtall") { $inbtall="tmpfiles/$inbtall"; }
  if ( -s $inbtall ) {
    $cmd=""; $err= 0; loggit(0, "Reusing $inbtall" );
  } else {
    #SEE below:   my($okb)= blastn2btall($cdsblast,"$cdsseq.qual",$inbtall);
    $cmd="$EVIGENES/makeblastscore.pl -pIDENTMIN $CDSBLAST_IDENT -pmin 0.01 -CDSSPAN -showspan=2 -tall -sizes $cdsseq.qual $cdsblast > $inbtall";
    $err= runcmd($cmd);
  }

# INSERT asmrna_dupfilter4b.pl .. opts for alt/paralog class, adding -eqgene $evgsimtab data
=item INSERT asmrna_dupfilter4b.pl for alt/par class

env phi=99 pmid=95.0 plow=95.0 $evigene/scripts/rnaseq/asmrna_dupfilter4b.pl \
  -eqgene $eqgenetab \
  -MINALIGN=50 -debug   -CDSALIGN -pCDSOK=20 -pCDSBAD=20 -ALTFRAG=0.5 \
  -aasize inputset/at18tair_mrna.aa.qual -blastab adupfilt4b/${pt}.self90i.blastn  \
  -outeqtab adupfilt4b/${pt}_pi95paln50f.alntab -outclass adupfilt4b/${pt}_pi95paln50f.trclass

$evigene/scripts/genes/trclass2pubset.pl  -cullothers -onlypub -norealt -noaltdrops -notidy  -log -debug  \
  -class adupfilt4b/${pt}_pi95paln50f.trclass

=cut


  #NOTE: need trclass2pubset.pl in 2 steps here, 1st is env norealt=1 to skip altreclass, 2nd after blasttrset2exons
  $opts="-onlypub -norealt -noaltdrops -log -debug"; # make -norealt an option in trclass2pubset
  $opts .=" -idpre $idprefix" if($idprefix);
  $cmd="$EVIGENES/genes/trclass2pubset.pl $opts -class $trclass"; # was env norealt=1 ..
  # my $pubset1cmd= $cmd;  
  $err= runcmd($cmd);
  return ($err) if($err);  
  
  # assume here pubids is always made new, so always recalc exontab
  my $pubids="publicset/$trname.pubids"; # made by trclass2pubset

#*** DROP blasttrset2exons2
  ## UPD20jan: trclass_resolve_strandmix.pl .. after 1st trclass2pubset ? before blasttrset2exons ?
  ## .. skip? for dupgenes
  
  if ( -s $inbtall and -s $pubids ) {
    # FIXME: DGC: add opts to blasttrset2exons2 for pIDENT cutoff for alt/par, genexcopy, gene.covtab? 
    $cmd= "sort -k7,7nr -k2,2 -k6,6nr -k1,1 $inbtall | env pubids=$pubids debug=1 $EVIGENES/genes/blasttrset2exons2.pl > $trnrname.exontab";
    $err= runcmd($cmd); # return ($err) if($err); 
  }
  
  ## final step, integrate into trclass2pubset; see trclass2pubset:altreclass_block()
  ##  -NOALTDROPS, same as -nodrops for  asmrna_altreclass3c, this turns drops to culls, separate files

  $opts="-noaltdrops -exontab $trnrname.exontab  -log -debug ";
  $opts .=" -idpre $idprefix" if($idprefix);
  $cmd="$EVIGENES/genes/trclass2pubset.pl $opts -class $trclass";
  $err= runcmd($cmd);
  return ($err) if($err);  

  ## FIXME: FINISH_tr2dgc may need this
  # if($tidy2stg) { # FINISH_tr2dgc
  #   loggit(0,"tidy okayset => okayset1st, stage2 reduction => okayset");
  #   rename("okayset","okayset1st");
  #   my($pubd,@pubseq);
  #   
  #   ## FIXME: prepubset $trname.{mrna,cds,aa} need to move .. these are eq okayset1st/*.tr,cds,aa ; erase?
  #   ($pubd,@pubseq)= getFileset('publicset','mrna$|cds$|aa$',$pubd,$trname); 
  #   for my $ps (grep { not /_pub|_cull/ }  @pubseq) {
  #     (my $tps=$ps) =~ s/publicset/tmpfiles/;
  #     rename($ps,$tps);
  #   }
  #   
  #   ($pubd,@pubseq)= getFileset('publicset','fa',$pubd,$trname);  
  #   for my $ps (grep/_pub.fa|_cull.fa/, @pubseq) {
  #     my ($ok,$oks)= (0,$ps);
  #     if($oks =~ s/(\w+)_pub.fa/okay.$1/ ) { $ok=1; }
  #     elsif($oks =~ s/(\w+)_cull.fa/cull.$1/ ) { $ok=1; }
  #     rename($ps, $oks) if($ok); # symlink($ps,$oks); #?? or rename them, and culls also      
  #   }
  # 
  #   rename("publicset","okayset"); #  reserve pubset for later named annots
  # }
  
  return(0); #??
}


sub FINISH_tr2dgc {
  my($status,$atstep,$trname)= @_;
  
  my $tmpfolder= "tr2dupgenetmp";
  my $outfolder= "tr2dupgeneset"; # $okaysetd; # source files are here, need to merge reorfiles still
  loggit( LOG_WARN,"FAILED at step:",$atstep) if($status<0);
  
  if( $tidyup ) {  #  and $nupdate > 0 
    tidyupFileset($outfolder,@ncrnaset) if(@ncrnaset);  # not used so far
    tidyupFileset($tmpfolder,@tmpfiles) if(@tmpfiles);  # all data here so far ncrnaset/
    my @rmlist;
    if($status<0) { 
      tidyupFileset("tr2dupgene_failtmp",@erasefiles) if(@erasefiles);  ## dont erase
    } else {
      foreach my $fn (@erasefiles) { if(-f $fn) { unlink($fn); push @rmlist,$fn; } }  
      if(@rmlist) { my $nrm=@rmlist; my $rml=join" ",@rmlist[0..4]; loggit(0,"tidyup erase: n=$nrm, $rml .."); }
    } 
    
    #UPD2222: cleanup should include turning all name.parts.tr into name.parts.trids list of ids only ..
    # if(USE_recover_trset and $status>=0 and $atstep =~ /done okay/) {
    #   my($tdir,@trs)= getFileset($tmpfolder,'tr$','',$trname);
    #   for my $tr (@trs) {
    #     (my $trid= $tr) =~ s/\.\w+$/.trids/;
    #     ($trid)= faidlist($tr,$trid,'update');          
    #     unlink($tr) if(-s $trid);  # push @rmlist,$tr;
    #   }
    # }
    
  }
  loggit(0, "DONE at date=",`date`);
  loggit(0, "======================================"); # log may append runs
  exit($status);
}

#------------------------------

sub _min { return ($_[1] < $_[0]) ? $_[1] : $_[0]; }
sub _max { return ($_[1] > $_[0]) ? $_[1] : $_[0]; }

# my($nucg,$ngenex,$Cucg,$genextab)=  ($ingenexf)? read_genexcopy($ingenexf) : (0,0);

sub read_genexcopy {
  my($genexcopy)=@_;
  my($nucg,$ngene,$cmd,$cav,$cerr)= (0) x 9;
  my($ok,$inh)= openRead($genexcopy); 
  unless($ok) { loggit( LOG_WARN, "Fail to read $genexcopy"); return (0,0); }
  my %genextab; # change to global?
  while(<$inh>) {
    if(/^\W/){
      # Uniq Gene Cov Depth n=954, .. C.Map/W=38.4, 38.0 +/-1.26 (mdn,ave,sem) 
      if(/Uniq Gene Cov Depth n=(\d+)/ and not $cmd ) {  
        $nucg=$1;
        if( m/C.Map.W=([\d\.]+), ([\d\.]+)\W+([\d\.]+)/ ) { ($cmd,$cav,$cerr)= ($1,$2,$3);}
        elsif( m/C.Map.W=([\d\.]+)/) { $cmd=$1; }      
      }
    } else { # per gene
      # (Gene_ID Glen Nread Rdlen tCopy C.M Uniq Merr C.nz S.Dup,Unq,Nt,Equ,UCG);
      # my($gid,$glen,$nrd,$rdlen,$tcopy,$cm,$cla,$merr,$cnz,$sdune)= @v;
      my($gid,@gv)= split;
      unless($gid eq 'Gene_ID'){ $genextab{$gid}= \@gv; $ngene++; }
    }
  } close($inh);
  
  loggit(0, "read_genexcopy nucg=$nucg, ngene=$ngene Cucg=$cmd of $genexcopy");
  return($nucg,$ngene,$cmd,\%genextab);  
}

#---------

=item genefam mult align tree

  steps for gene family discrim into alt vs paralog seqs
  1. collect gene fam seqs, using evg tr2cds pubids + dropids of each gene group
  2. mult-align w/ muscle to muscle maketree (newick format tree output w/ distances/branch)
  3. new evg omcl/newickparse.pl, input gene.tree + nparalog=NN from genex, plus opts
     .. nkparse decides from opts where/whether to cut tree into alts / paralogs,
  4. output evg eqgene table for asmdupfilt alt/par classify

  .. see at18tr2cdsdupx_muspar.txt
  .. reuse/replace here NCRNA opts, for alt/par classes
  
my $PAL_NCRNAMIN= $ENV{PAL_NCRNAMIN} || 80; # reject ncrna align below this 
my $MIN_CDSALN= $ENV{MIN_CDSALN}||150; #? for TEST_OKCDS
my $CDSBLAST_IDENT= 98; # 98 + -ungapped ; was 95; # or 98; # or 95? ** drop this back to 95 default; at least for high okay count species
# ncrna_altparscore globals
my $MINSCORE=$ENV{minscore} || -999; # need some data on this
my $MINALT= $ENV{minalt}|| 0.50; #??
my $MINDUPALN = $ENV{mindupaln} ||0.80; # ncrna_altparscore option: align(t/r)
my $MINDUPFULL= $ENV{mindupfull}||0.80; # ncrna_altparscore option: size(t/r)
  
=item muscle maketree

https://drive5.com/muscle/manual/maketree.html
Make a UPGMA tree from a multiple alignment:
 muscle -maketree -in seqs.afa -out seqs.phy

Make a Neighbor-Joining tree from a multiple alignment:
  muscle -maketree -in seqs.afa -out seqs.phy -cluster neighborjoining

UPGMA or Neighbor joining?
Neighbor-joining trees will usually be a better estimate of the true
phylogenetic tree. UPGMA is faster, which can be useful with large
datasets when N-J is too slow.

*** UPGMA uses same percent ident/dist as calculated from msa pairwise SNP diffs,
    can use as sim/dist score w/ pct alt ident cutoffs,
    but NJ uses something else, larger dist, cant use w/ pct ident cutoffs
    
=item maketree case

#iname=tmps/EVGm005059.mutree
#itree=( AT1G70650t2 :0.0445342 , ( AT1G70660t1 :0.00940967 , ( AT1G70650t1 :0.00630521 , AT1G70660t2 :0.00630521 ):0.00310446 ):0.0351245 ) ; 
#tree_common_branch_altpar_cut: 1:99.06%:3 (n:simcut:combr), for options pminalt=99, nparalog=1.1 
#tree_common_branch_paralogs: par=0:100.00%: alt=3:95.55%:1,3,5 (n:simcut:combr), for option nparalog=1 
AT1G70650t1	AT1G70650t1	AT1G70650t2/95.55,AT1G70660t1/99.06,AT1G70660t2/99.37	0	0	0
AT1G70650t2	AT1G70650t2	AT1G70650t1/95.55,AT1G70660t1/95.55,AT1G70660t2/95.55	0	0	0
AT1G70660t1	AT1G70660t1	AT1G70650t1/99.06,AT1G70650t2/95.55,AT1G70660t2/99.06	0	0	0
AT1G70660t2	AT1G70660t2	AT1G70650t1/99.37,AT1G70650t2/95.55,AT1G70660t1/99.06	0	0	0
#............

pt=EVGm005059
muscle  -in $pt.msb -maketree -out $pt.treed
( AT1G70650t2 :0.0445342 , ( AT1G70660t1 :0.00940967 , ( AT1G70650t1 :0.00630521 , AT1G70660t2 :0.00630521 ):0.00310446 ):0.0351245 ) ; 

muscle  -in $pt.msb -maketree -out $pt.treenj -cluster neighborjoining # better tree?
( ( ( AT1G70660t2 :0.00597379 , AT1G70660t1 :0.0121506 ):0.180924 , AT1G70650t2 :0.221875 ):-0.0838349 , AT1G70650t1 :-0.0838349 ) ; 

muscle  -in $pt.cds -out $pt.msb -tree2 $pt.treeb  # same rel-dist,order as UPGMA but diff dist magnitudes?
( AT1G70650t2 :0.133985 , ( AT1G70660t1 :0.0524321 , ( AT1G70650t1 :0.0410526 , AT1G70660t2 :0.0410526 ):0.0113795 ):0.0815526 ) ; 

pt=EVGm005481
#itree=( AT2G27790t3 :0.00929632 , ( ( AT2G27790t2 :-0 , AT2G27790t4 :-0 ):0.00837937 , 
  ( ( AT5G27300t1 :-0 , AT5G27300t3 :-0 ):0.00040772 , AT5G27300t2 :0.00040772 ):0.00797165 ):0.000916949 ) ; 
#njtree .. better?  BUT dist score >> (1 - pct-ident)
( ( ( 
 ( ( AT2G27790t4 :-0.0277587 , AT2G27790t3 :0.0432508 ):0.0360706 , AT2G27790t2 :-0.0360706 ):0.0617164 , 
 AT5G27300t3 :-0.014903 ):0.014903 , AT5G27300t2 :0.0157185 ):-0.00745151 , AT5G27300t1 :-0.00745151 ) ; 

  MUSCLE v3.8.31 by Robert C. Edgar
      -diags             Find diagonals (faster for similar sequences)
      -maxiters <n>      Maximum number of iterations (integer, default 16)
  Without refinement (very fast, avg accuracy similar to T-Coffee): -maxiters 2
  Fastest possible (nucleotides): -maxiters 1 -diags

 muscle -quiet -in $seq -out $omsa -tree2 $otre;  -tree2 opt replace 2nd call to -maketree ?
 NO: this -tree2 or -tree1 produce a different tree, at least diff node score.. keep -maketree
 
=cut


sub cmd_mutr{ 
  my($seq,$otre,$omsa)=@_;
  unless($omsa){ $omsa=$otre; $omsa=~s/\.\w+$//; $omsa.=".msa"; }
  ## add opt??:  -maxiters 2 -diags
  # my $cmd="$APPmuscle -quiet -in $seq -out $omsa && $APPmuscle -quiet -maketree -in $omsa -out $otre";
  my $cmd="$APPmuscle -quiet -maxiters 2 -diags -in $seq -out $omsa && $APPmuscle -quiet -maketree -in $omsa -out $otre";
  return ($cmd);  
} 
sub run_mutr { return runcmd(cmd_mutr(@_)); } 


=item cmd_blastaln
  
  .. bl outfmt 0, default pair align
  .. maybe better than exonr, easier to support.
  .. altparsnpdist.pl now handles blastaln, and exonr
  optb = '-evalue 1e-9';
  blastn $optb -query $evgseq -subject $evgseq -out $qna-$gna.bln
   
=cut

sub cmd_blastaln { 
  my($grpseq,$oblast)=@_;
  my $optb='-evalue 1e-9';
  my $cmd="$APPblastn $optb -query $grpseq -subject $grpseq -out $oblast";
  return ($cmd);  
} 
sub run_blastaln { return runcmd(cmd_blastaln(@_)); } 

=item cmd_lastz

  
=cut

sub cmd_lastz { 
  my($grpseq,$outf)=@_;
  #   lastz --format=axt --strand=both --self --output=tmps/$evid.pairlz "tmps/$evid.cds[multiple]"
  my $optx="--format=axt --strand=both --self";
  my $cmd="$APPlastz $optx --output=$outf $grpseq" . '[multiple]';
  return ($cmd);  
} 
sub run_lastz { return runcmd(cmd_lastz(@_)); } 

=item cmd_exonr

  2. Gapped alignment of Mouse proteins to Fugu proteins:
      exonerate --model affine:local mouse.fa fugu.fa

  .. do each seq query x evgroup.cds
  .. dont need this, just : exonr opts evgseq evgseq "
  evgseq=tmps4d/EVGm005481.cds
  for qseq in splitseq($evgseq) do { 
    exonerate --model affine:local --showalignment yes --alignmentwidth 10000 --showvulgar no  $qseq  $evgseq > $qna-$gna.exa 
  }
  
=cut

sub cmd_exonr { 
  my($grpseq,$oexonr)=@_;
  my $optx="--model affine:local --showalignment yes --alignmentwidth 10000 --showvulgar no";
  my $qseq=$grpseq;
  
  # ?? need to loop true grpseq for qseq, all output to oexonr
  # i=0; qseq="tmpquery.fa"; while [ $i -le 299 ]; do { i=$((i+1)); 
  # env si=$i perl -ne 'if(/^>/){ ++$at; if($at>$ENV{si}){ exit; } else{ $ok=($at==$ENV{si}); }  } print if($ok); ' $grpseq > $qseq;
  # if [ ! -s $qseq ]; then echo done; break; fi;  
  # exonerate $optx $qseq $grpseq;
  # } done

  my $cmd="$APPexonr $optx $qseq $grpseq > $oexonr";
  return ($cmd);  
} 
sub run_exonr { return runcmd(cmd_exonr(@_)); } 

sub cmd_nkpars2eg {
  my($otre,$oegtab,$npar)=@_; $npar||=0; # get npar from genexcopy

  #? change env opts pminalt=99 pminminalt=97 
  # reuse CDSBLAST_IDENT=98 as pminminalt ? or reuse MINALT ? or reuse MIN_CDSALN (bases) ??
  # ^^^ NO, 98% is too high (for global align sim), many ref alts have 95%..90% sim
  # ... need nparalog as classifier, pminminalt not good.
  my $xenv="";  # shouldnt need to add ENV to child call
  if(my $x=$ENV{pminalt}){ $xenv.=" pminalt=$x"; }
  #bad# if(my $x= $ENV{pminminalt}||$CDSBLAST_IDENT ){ $xenv.=" pminminalt=$x"; } 
  if(my $x= $ENV{pminminalt}||$MIN_MINALT ){ $xenv.=" pminminalt=$x"; } 
  
  my $cmd="env prt=1 nparalog=$npar$xenv otype=eg $EVIGENES/omcl/newickparse.pl $otre > $oegtab";
  return ($cmd);  
}
sub run_nkpars2eg { return runcmd(cmd_nkpars2eg(@_)); } 

sub cmd_snpdist2eg {
  my($omsa,$otre,$oegtab,$npar)=@_; $npar||=0; # get npar from genexcopy  
  # $MINPAR_snpvar = $ENV{snpvar} || 10; # this needs testing, cutoff for alt/par eqgene table
  my $xenv="";  # shouldnt need to add ENV to child call
  if(my $x=$ENV{snpvar}){ $xenv.=" snpvar=$x"; }
  if(my $x=$ENV{altpartype}){ $xenv.=" otype=$x"; }  # ? else $xenv.=" otype=eg"; 

  # now uses $omsa $otre args .. otre from omsa name
  # drop  otype=eg ? or opt; otre may not exist; omsa may be exa==exonerate aln
  my $cmd="env nparalog=$npar$xenv $EVIGENES/genes/altparsnpdist.pl $omsa $otre > $oegtab";
  return ($cmd);  
}
sub run_snpdist2eg { return runcmd(cmd_snpdist2eg(@_)); }

sub cmd4egsim {
  my($evd,$seq,@oids)=@_; 
  return cmd_or_run_egsim(0, $evd,$seq,@oids); # ret=($evdtab,$cmd)
}
sub putseq { 
  my($evd,$seq,@oids)=@_; 
  return cmd_or_run_egsim(1, $evd,$seq,@oids);
}

# change putseq seq write to
use constant UPD_PUB2SIM => 1;

sub pubids2egsim {
  my($pubids, $seq,) = @_;
  
  # add maxput limit for debug?
  # last if($nput>=$MAXPUT); 
  
  my $subd="tmps"; mkdir($subd) unless(-d $subd);
  open(F,$pubids) or do { loggit LOG_WARN, "miss pubids:$pubids"; return 0; };
  my( $ngroup, $ngitems, $nsingle, %egoid, %oideg, %egone)=(0,0);
  while(<F>) { 
    next if(/^\W|^Public/);
    my($ed,$od,$eg,$ti,$cla,$aaw,$pia)=split; 
    if($eg and $od and $cla) {
      my $val= [$eg,$od,$ed,$cla,$pia]; #add ed
      push @{$egoid{$eg}}, $val; 
    }
    # unless($eg and $od and $cla){ next; }
    # elsif($cla=~/noclass/) { push @{$egone{$eg}}, $val; $nsingle++; } # keep in @onelist?
    # else { push @{$egoid{$eg}}, $val; $oideg{$od}=$eg; $ngitems++; } 
  } close(F);
  
  #FIXME: check @{$egoid{$eg}} > 1, move singletons .. dont rely on noclass?
  for my $eg (sort keys %egoid){
    my $oids= $egoid{$eg};
    if(@$oids < 2) {
      delete $egoid{$eg}; $egone{$eg}= $oids;  $nsingle++; 
    } else {
      for my $ov (@$oids){ my $od=$ov->[1]; my $ed=$ov->[2]; $oideg{$ed}=$oideg{$od}=$eg; $ngitems++; }
    }
  }
  $ngroup= scalar(keys %egoid);
  
  # putseq new
  open(S,$seq) or do { loggit(LOG_WARN, "miss seq:$seq"); return; };
  my($egid,%egseq,@seqs); 
  # FIXME: input.cds has eg pubid not oid.. 
  while(<S>){ if(/^>(\S+)/){ $egid= $oideg{$1}||0; } if($egid){ $egseq{$egid}.=$_; } } close(S); 
  for my $evd (sort keys %egseq){
    my $fa= $egseq{$evd} or next;
    my $evdfa="$subd/$evd.cds"; 
    #push @seqs,$evdfa; #? save or remake from evd id
    open(SO,">$evdfa"); print SO $fa; close(SO);
  }
  
  # other cmd_or_run_egsim parts: 
  #  nparalog from $genextab->{$od} ..
  #  cmd or run apps on evdfa, .. need $subd/$evd.cds
  
  return($ngroup, $ngitems, $nsingle, \%egoid, \%egone); # need? egoid, oideg, egone ?
}

sub cmd_or_run_egsim { 
  my($dorun,$evd,$seq,@oids)=@_; 
  
  # $evd should be subdir/EVGid or add subdir == tmp/ here?
  my $subd="tmps"; mkdir($subd) unless(-d $subd);
  my $evdfa="$subd/$evd.cds"; # UPD_PUB2SIM: should exist, see above
  my $evdmsa="$subd/$evd.msa";    # << require this output
  my $evdtre="$subd/$evd.mutree"; #? .tree << this becomes optional output, 
  my $evdtab="$subd/$evd.egsimtab"; # << change to evg.apvals or like name for apval table instead of egsimtab

  if($ALIGNER eq 'lastz') { $evdmsa="$subd/$evd.axt"; $evdtre=""; } #??
  elsif($ALIGNER eq 'blastn') { $evdmsa="$subd/$evd.bla"; $evdtre=""; }
  elsif($ALIGNER eq 'exonerate') { $evdmsa="$subd/$evd.exa"; $evdtre=""; }
  
  if($REUSE_TMPDATA and -s $evdtab and -s $evdmsa) {  # was evdtre
    loggit(0, "reusing $evdtab");
    return ($dorun)? ($evdtab) : ($evdtab,""); 
  }
    
  my %oids; map{ my($eg,$od,$ed)=@$_; $oids{$od}=$eg; $oids{$ed}=$eg if($ed ne $od); } @oids; 
  if(UPD_PUB2SIM) {
    unless(-s $evdfa) { loggit(LOG_WARN, "miss evdfa:$evdfa"); return 0; } # bug?
      #tr2dgc: miss evdfa:tmps/PublicGeneID.cds
    
  } elsif($REUSE_TMPDATA and -s $evdfa) { 
    loggit(0, "reusing $evdfa");
  } else {
    # THIS is SLOW: write each genegroup.cds, has to run thru all input seq for each of 1000s of groups
    # .. revise .. how? splitSeq2Groups: per inseq, collect fa, touch evgroup.cds, cat fa >> evgroup.cds ?
    open(S,$seq) or die "cant read seq=$seq";
    open(SO,">$evdfa"); 
    my $ok=0; while(<S>){ if(/^>(\S+)/){ $ok= $oids{$1}; } print SO $_ if($ok); } close(S); close(SO);
  }
  
  my $npar=0;
  if($ngenex){
    # $gid => ($glen,$nrd,$rdlen,$tcopy,$cm,$cla,$merr,$cnz,$sdune)
    # $genextab{$gid}= \@gv;  
    my($tmax,$tsum,$ngx)=(0) x 9;
    my @od=sort keys %oids;
    for my $od (@od) { if(my $gv=$genextab->{$od}) {  
      if(@$gv < 8) { } # truncated genex table
      my($glen,$nrd,$rdlen,$tcopy,$cm,$cla,$merr,$cnz,$sdune)=@$gv;
      $tmax= _max($tcopy, $tmax); $tsum+=$tcopy; $ngx++;
    } }
    my $tca= ($ngx<2) ? $tmax :  sprintf"%.0f",$tsum/$ngx;
    if($tmax > 3*$tca) { $npar= _max(2,$tca); } else { $npar=$tmax; }
  } else {
    $npar=0; #default for no data? 2 or 0
  }
 
  my($cmd_mutr,$cmd,$runerr)=("","",0);
  if($REUSE_TMPDATA and -s $evdmsa) { #? was evdtre
    loggit(0, "reusing $evdmsa");
  } elsif($ALIGNER eq 'lastz') { # fixme: blastn, exonerate, muscle choices
    if($dorun){ $runerr= run_lastz($evdfa,$evdmsa); } # fixme evdfa = group.cds, evdmsa => rename
    else { $cmd_mutr= cmd_lastz($evdfa,$evdmsa); }
  } elsif($ALIGNER eq 'exonerate') { # fixme: blastn, exonerate, muscle choices
    if($dorun){ $runerr= run_exonr($evdfa,$evdmsa); } # fixme evdfa = group.cds, evdmsa => rename
    else { $cmd_mutr= cmd_exonr($evdfa,$evdmsa); }
  } elsif($ALIGNER eq 'blastn') { # fixme: blastn, exonerate, muscle choices
    if($dorun){ $runerr= run_blastaln($evdfa,$evdmsa); } # fixme evdfa = group.cds, evdmsa => rename
    else { $cmd_mutr= cmd_blastaln($evdfa,$evdmsa); }
  } else { # $ALIGNER eq 'muscle'
    if($dorun){ $runerr= run_mutr($evdfa,$evdtre,$evdmsa); } 
    else { $cmd_mutr= cmd_mutr($evdfa,$evdtre,$evdmsa); }
  }
  
  #cmd_snpdist2eg($omsa,$otre,$oegtab,$npar): modify cmd_mutr >> make evd.msa;  
  use constant USE_SNPDIST2EG => 1;
  if(USE_SNPDIST2EG) {
  if($dorun){ $runerr= run_snpdist2eg($evdmsa,$evdtre,$evdtab,$npar); } # return stats?
  else { 
    my $cmd_snpdist= cmd_snpdist2eg($evdmsa,$evdtre,$evdtab,$npar); 
    $cmd= ($cmd_mutr) ? "( $cmd_mutr && $cmd_snpdist; )" : $cmd_snpdist;  # (cmda && cmdb) ?
  } 
  } else {
  if($dorun){ $runerr= run_nkpars2eg($evdtre,$evdtab,$npar); } # return stats?
  else { 
    my $cmd_nkpars= cmd_nkpars2eg($evdtre,$evdtab,$npar); 
    $cmd= ($cmd_mutr) ? "( $cmd_mutr; $cmd_nkpars; )" : $cmd_nkpars;
  } 
  }
  
  return ($dorun)? ($evdtab,$runerr) : ($evdtab,$cmd); 
  # return($evdtab);
} 

sub evgenesim {   # drop for evgenesim_ncpu(1) ??
  my($pubids, $seq, $eqgenetab)=@_;
  
  unless($seq and -s $seq and $pubids and -s $pubids) {
    loggit( LOG_WARN, "evgenesim missing data:  pubids=$pubids seq=$seq"); return (0); 
  }
  #above: my $MAXPUT=($debug)?9:999999;
  
  loggit(0, "evgenesim pubids=$pubids seq=$seq");
  open(F,$pubids) or do { warn "ERR: miss pubids:$pubids"; return 0; };
  my($nput,$leg)=(0,0);
  my(@simtabs, @oids);
  while(<F>) { 
    my($ed,$od,$eg,$ti,$cla,$aaw,$pia)=split; next if($cla=~/noclass/); 
    if($eg ne $leg){  
      if(@oids>1){ my($otab)= putseq($leg, $seq, @oids); if($otab){ push @simtabs,$otab; $nput++; } }
      @oids=();  last if($nput>=$MAXPUT); 
    }
    push @oids, [$eg,$od,$ed,$cla,$pia]; # fixme add ed
    $leg=$eg;
  } close(F);
  if(@oids>1){ my($otab)= putseq($leg, $seq, @oids); if($otab){ push @simtabs,$otab; $nput++; } }
  
  my $nsim= @simtabs;
  if($nsim>0) {
    unless($eqgenetab){ $eqgenetab=basename($pubids); $eqgenetab=~s/\.\w+$//; $eqgenetab.="_evsim.eqgene"; }
    open(O,">$eqgenetab"); for my $st (@simtabs){ open(I,$st); my @v=<I>; print O @v; close(I); } close(O); 
  }
  loggit(0, "evgenesim nsim=$nsim to $eqgenetab");
  return($nsim, $eqgenetab, \@simtabs);
}

#  ($nsim,$eqgenetab,$simtabs)= evgenesim_script($inpubids,$cdsseq,$eqgenetab,$runscript); 
sub evgenesim_script {
  my($pubids, $seq, $eqgenetab, $runsh)=@_;
  return evgenesim_ncpu_or_script($pubids, $seq, $eqgenetab, 0, $runsh);
}
sub evgenesim_ncpu {
  my($pubids, $seq, $eqgenetab, $ncpu)=@_;
  return evgenesim_ncpu_or_script(@_);
}

sub evgenesim_ncpu_or_script {
  my($pubids, $seq, $eqgenetab, $ncpu, $outScript)=@_;
  
  unless($seq and -s $seq and $pubids and -s $pubids) {
    loggit( LOG_WARN, "evgenesim missing data:  pubids=$pubids seq=$seq"); return (0); 
  }
  loggit(0, "evgenesim pubids=$pubids seq=$seq");

  my $do_outScript=($ncpu < 1 or $SAVE_RUNSCRIPT)?1:0;
  unless($outScript) { $outScript=$trname; $outScript=~s/\.\w+$//; $outScript.="_run_evsim.sh"; }
  
  my($nput,$leg)=(0,0);
  my(@cmdlist, @simtabs, @onelist, @oids);

  if(UPD_PUB2SIM) {
    my $subd="tmps"; # ret from pubids2egsim
    my($ngroup, $ngitems, $nsingle, $egoid, $egsingle)= pubids2egsim($pubids, $seq);
    loggit(0, "pubids2egsim ngroup=$ngroup, ngenes=$ngitems, nsingle=$nsingle");
    
    for my $eg (sort keys %$egoid) {
      my @oids= @{$egoid->{$eg}}; # == arr of [$eg,$od,$ed,$cla,$pia]
      # my @oids= map{ $_->[1] } @ovals; # no cmd4egsim wants [eg,od,..]
      # my $egseq="$subd/$eg.cds";
      my($stab,$cmd)= cmd4egsim($eg, $seq, @oids); # FIXME, egseq or seq ? cmd4egsim does names
      push @cmdlist,$cmd if($cmd); push @simtabs,$stab if($stab); $nput++;
      
      #?? debug: last if($nput>=$MAXPUT); 
    }
    @onelist = sort keys %{$egsingle};
    
  } else {
  #... replace here ..
  open(F,$pubids) or do { warn "ERR: miss pubids:$pubids"; return 0; };
  while(<F>) { 
    my($ed,$od,$eg,$ti,$cla,$aaw,$pia)=split; 
    next if($cla=~/noclass/); # keep in @onelist?
    if($eg ne $leg){  
      if(@oids>1){ my($stab,$cmd)= cmd4egsim($leg, $seq, @oids); 
        push @cmdlist,$cmd if($cmd); push @simtabs,$stab if($stab); $nput++;  
      } else { push @onelist, $leg; }
      @oids=();  # last if($nput>=$MAXPUT); 
    }
    push @oids, [$eg,$od,$ed,$cla,$pia];
    $leg=$eg;
  } close(F);
  
  if(@oids>1){ my($stab,$cmd)= cmd4egsim($leg, $seq, @oids); 
        push @cmdlist,$cmd if($cmd); push @simtabs,$stab if($stab); $nput++;  
  } else { push @onelist, $leg; } # ?? or val [$eg,$od,$cla,$pia]  
  }
  
  #---------
  my $nsim= @simtabs; my $nserr=0;

  # INSERT option here to write @cmdlist to script, dont run ..
  if($do_outScript) { # was ($ncpu < 1)
    # write to $outScript
    open(O,">$outScript");
    print O "#!/bin/bash\n";
    print O "#evgenesim_script=$outScript\n\n";
    print O "#from $EGAPP trset=$trset pubids=$inpubids cdsseq=$cdsseq genexcopy=$ingenexf eqgenetab=$eqgenetab\n";

    print O "EVIGENES=$EVIGENES\n";
    # print O "export PATH=xxx/muscle/bin\n";
    
    # evgenesim_script exports: debug pminalt pminminalt snpvar ? pctident?? now for sim..
    my $exp="debug=$debug";
    for my $ek (qw( pminalt pminminalt snpvar pctident)){ $exp .= " $ek=$ENV{$ek}" if(defined($ENV{$ek})); }
    print O "export $exp\n";
    
    if(-s $eqgenetab){ print O "mv $eqgenetab $eqgenetab.old\n"; }
    print O "touch $eqgenetab\n";
    print O "#------- cmd list -----------\n";
    foreach my $cmd (@cmdlist) { 
      $cmd =~ s/$EVIGENES/\$EVIGENES/g;
      # $cmd =~ s/$APPmuscle/muscle/g;
      print O $cmd,"\n"; 
      }
    print O "#------- cat outputs --------\n";
    foreach my $st (@simtabs) { print O "cat $st >> $eqgenetab\n"; } # may be 1000s, simpler way?
    #?? find tmps/ -name '*.eqgene' -exec cat {} >> $eqgenetab \; 
    print O "#------- END --------\n";
    close(O);
    loggit(0, "run script $outScript for nsim=$nsim to $eqgenetab"); # evgenesim.script=
    # return($nsim, $eqgenetab, \@simtabs);
    #----------------
  
  } # elsif(...)
  
  if($ncpu < 1) {
    return($nsim, $eqgenetab, \@simtabs);
  
  } elsif($ncpu == 1) {
    foreach my $cmd (@cmdlist) {
      my $runerr= runcmd($cmd); #? turn off loggit ?
    }
    
  } elsif($ncpu > 1) {
    my $icpu=0;
    foreach my $cmd (@cmdlist) {
      my $pid= forkcmd($cmd); 
      if(++$icpu > $ncpu) { while (wait() != -1) { }; $icpu= 0; }
      else { sleep(2); } # fork/wait bug on old unix, needs delay here maybe?
    }
    while (wait() != -1) { };
  }
  #---------
  
  if($nsim>0) {
    unless($eqgenetab){ $eqgenetab=$pubids; $eqgenetab=~s/\.\w+$//; $eqgenetab.="_evsim.eqgene"; }
    open(O,">$eqgenetab"); 
    for my $st (@simtabs) {
      if(-s $st) { open(I,$st); my @v=<I>; print O @v; close(I); }
      else { print O "#missing output=$st\n"; $nserr++; }
    } 
    for my $st (@onelist) {
      print O "#singleton=$st\n";
    }
    close(O); 
  }
  loggit(0, "evgenesim nsim=$nsim, nerr=$nserr to $eqgenetab");
  return($nsim, $eqgenetab, \@simtabs);
}

=item egtab

  #iname=mustreat/NonamEVm000344t.mustree
  #itree=( ( ( ( ( AT5G46270t1 , AT5G46270t3 ):0 , AT5G46270t2 ):0 , AT5G46270t4 ):0 , AT5G46270t5 ):0.10105 , ( ( AT5G46520t1 , AT5G46520t2 ):0.0226896 , ( AT5G46510t1 , AT5G46510t2 ):0.0215436 ):0.0783599 ) ; 
  #tree_common_branch_matrix: eqgene, nleaf=7
  PublicID	OID	AltIDs	Locus	Mapqual	ParalogIDs  #<< may be "#PublicID.."
  AT3G24870t1	AT3G24870t1	AT3G24870t2/99.8,AT3G24870t3/99.8,AT3G24870t4/99.8	0	0	AT3G24880t1/99.7,AT3G24880t2/99.7,AT3G24880t3/99.7
  AT3G24870t2	AT3G24870t2	AT3G24870t1/99.8,AT3G24870t3/100.0,AT3G24870t4/100.0	0	0	AT3G24880t1/99.7,AT3G24880t2/99.7,AT3G24880t3/99.7

=cut

sub checkref_eqgene { 
  my($eqgenetab,$refids)= @_;
  my $tabtype=($eqgenetab =~ m/eqgene/)?2 : ($eqgenetab=~m/apvals/)?3 :0;
  return checkref_eqgene_or_pubids($eqgenetab,$refids,$tabtype); # tabtype==0 now means could be apvals or eqgene ..
}

sub checkref_pubids { 
  my($pubids,$refids)= @_;
  return checkref_eqgene_or_pubids($pubids,$refids,1);
}

=item checkref_pubids_nu

  needs diff algo from checkref_eqgene: need to collect all pubid gene groups before calc same/diff,
  refgids split among evgroups is half of check stat
  see aweed20gnodes/tr2aacds_at18tairam/pubid2icgxref.sh

sub checkref_pubids_nu {  
  my($pubids,$refids)= @_;
  #return checkref_eqgene_or_pubids($pubids,$refids,1);

  my($nrefid,$nrefg,$refidh)= read_refids($refids);
  return unless($nrefid>0);

  my($neg,$nalt,$neg2rg,$nrg2eg, $nrg2ic, $nic2rg, $led,$leg,$ltg,$lod)= (0) x 9;
  my(%rgeg,%egrg,%ictg,%rgic);
  
  #?? %gx == genex data, use or drop here?
  sub putv {
    my($leg,$ltg,$nalt,$lod)=@_;  
    my $gx=$gx{$lod}||$gx{$leg}||$gx{$ltg}||"no_gx";
    my @ig=sort keys %ictg; 
    my($ig,$ntg,$nd,$nu,$stg,$nig)=(0) x 9; my %tg; 
    for $ig (@ig){ my @tg=sort keys %{$ictg{$ig}}; $ntg=@tg; map{ $tg{$_}++; } @tg; if($ntg>1) { $nd++; } else {$nu++;} } 
    $stg=scalar(keys %tg); $nig=@ig; $clr=($stg>1)?"rdup":"runi"; 
    my($sxv,$nxv,$xvm,$xcm)=(0) x 9;
    for my $g (sort keys %tg){ 
      my $x=$gx{$g} or next; my($xc,$xv)=split",",$x; $sxv+=$xv; $nxv++; 
      if($xv>$xvm){ $xvm=$xv; $xcm=$x; } 
    }
    if($nxv>0){ $sxv=sprintf"%.1f",$sxv/$nxv; $gx="$xcm,$sxv"; }
    $cla=($nig == $stg)?"ieq$clr":($nig < $stg)?"ilo$clr":($nig>$stg)?"ihi$clr":"othr";
    if(0) {
      print join("\t",qw(Gene_ID nAlt nIg nRg Runi Rdup IRclas genex))."\n" if(1>$didhd++); 
      print join("\t",$leg,$nalt,$nig,$stg,$nu,$nd,$cla,$gx)."\n"; 
      }
    ($gxc=$gx)=~s/,.*//; $gxc="othr" unless($gxc=~/uniq|dup[xs]/); $rcgx{"$clr.c$gxc"}+= $stg;
    $npg++; $sna+=$nalt; $sig+=$nig; $snu+=$nu; $snd+=$nd; $sstg+=$stg; 
    $nrgd++ if($stg>1); $six++ if($stg < $nig);
  }
  
  my($ok,$inh)= openRead($pubids); 
  while(<$inh>) { 
    next if(/^\W/); my @v=split;
    my($ed,$oid,$gd,$ti,$cla,$aaq,$pia,$ann,$oids)=@v;
   
    # my($ict,$icg,$ica)=(0,0,0); 
    # if($ann=~m/,(ichain|icalt|icdup|icsub):(l\d+).t(\d+),/){ ($ict,$icg,$ica)=($1,$2,$3); } #? skip or keep ichains?
    # elsif($ann=~m/,noxloc,/){ ($ict,$icg,$ica)=("icnone",0,0); }
    
    my $td=$oid; my($eg,$tdg)= map{ my $d=$_; $d=~s/utrorf//; $d=~s/t\d+$//; $d; } ($ed,$td);
    my $tg=$refidh->{$oid}||$tdg;
    if($leg ne $eg){ putv($leg,$ltg,$nalt,$lod) if($leg); $neg++; $nalt=0; %ictg=(); $led=$ed; } 
    $nalt++; $rgeg{$tg}{$eg}++; $leg=$eg; $ltg=$tg; $lod=$oid; 
    #? $ictg{$icg}{$tg}++; $rgic{$tg}{$icg}++; 
  } close($inh);
  putv($leg,$ltg,$nalt,$lod); 
   
  $nic2rg=$nrg2ic=$nrg2eg=$neg2rg=$nrg=$neg=0;  
  %egrg=(); %ictg=(); 
  for my $rg (sort keys %rgeg){ $nrg++; my @id=keys %{$rgeg{$rg}}; map{ $egrg{$_}{$rg}++ } @id; $nrg2eg++ if(@id>1); }
  for my $eg (sort keys %egrg){ $neg++; my $ne=(scalar keys %{$egrg{$eg}}); $neg2rg++ if($ne>1); }
  #? for my $rg (sort keys %rgeg){ my @ic=keys %{$rgic{$rg}}; map{ $ictg{$_}{$rg}++ } @ic; $nrg2ic++ if(@ic>1); }
  #? for my $ic (sort keys %ictg){ $nic++; my $ne=(scalar keys %{$ictg{$ic}}); $nic2rg++ if($ne>1); }

  # vv change this to below return stats, drop IG stats
  #  npg == nevgroup; nEALT/sna == ntr?, nRG == nrefg? or refg found == keys $rgeg{$tg}
  print "# nEGene=$npg, nEAlt=$sna, nIGene=$sig, nRGene=$nrg,$sstg/eg, R>EG=$nrgd; R<EG=$nrg2eg, R=IG=$snu, R>IG=$snd, R<IG=$six, \n"; 
  print "# redo nEG=$neg, nIC=$nic, nRG=$nrg, nRG2EG=$nrg2eg, nEG2RG=$neg2rg, nRG2IG=$nrg2ic, nIC2RG=$nic2rg\n";
  print "# RG.Cn "; 
    for $rc (sort keys %rcgx) { $rcn=$rcgx{$rc}; if($rc=~/runi/){ print "\n# RG.Cn " if(1>$oru++); }  print " $rc=$rcn,";} 
  print "\n";  
  
  ## checkref_ out below
  #  return ($nevgroup,$ntr,$nsame,$ndif,$negsame,$negdif,$nmiss,\@evgdif);
 
}

=cut

  
=item checkref_ out

  my($nevgroup,$ntr,$nsame,$ndif,$negsame,$negdif,$nmiss)= checkref_eqgene($eqgenetab,$refids);
  and similar checkref_pubids($pubids,$refids); 

  NOTE: IsPubidtab singleton groups have zero nisame+nidif, nitr==1 .. ok? report?

#tr2dgc: checkref_pubids(adupfilt4b/at18tair_nrcd1x_dupx_pi95paln50f.pubids,at18tair_mrna.gidtab)
         checkref_pubids ngroup=1551, ngsame=86, ngdif=261, ntr=2194, nsame=176, ndif=453, nmiss=21
#tr2dgc: checkref_pubids ref-diff groups: 4:EVGm000004, 12:EVGm000012, 14:EVGm000014, 19:EVGm000019,
          .. 1528:EVGm001528, 1545:EVGm001545 .. long list, ngdif=261

#tr2dgc: checkref_eqgene(adupfilt4b/at18tair_nrcd1x_dupx_pi95paln50f_evsim.eqgene,at18tair_mrna.gidtab)
         checkref_eqgene ngroup=9, ngsame=8, ngdif=1, ntr=24, nsame=42, ndif=2, nmiss=0
#tr2dgc: checkref_eqgene ref-diff groups: 7:tmps/EVGm000039.mutree

=cut

sub read_refids {
  my($refids)=@_;
  my($ok,$inh)= openRead($refids); 
  unless($ok) { loggit(LOG_WARN, "read_refids miss:  refids=$refids"); return (0); }
  my($nrefid,$nrefg,%refid,%refg)=(0,0);
  while(<$inh>) { 
    next if(/^\W/); 
    my($id,$gid)=split; next unless($gid); 
    #FIXME: pars happen, 2 gid per id here
    if($refid{$id}) { $refid{$id}.=",$gid"; }
    else { $refid{$id}=$gid; }
    $refg{$gid}++;
  } close($inh);
  $nrefid=scalar(keys %refid); $nrefg=scalar(keys %refg);
  unless($nrefg>0 and $nrefid>=$nrefg) { #? allow nrefid == nrefg
    loggit(LOG_WARN, "read_refids bad:  nrefid=$nrefid, nrefgene=$nrefg in  $refids"); return (0);
  }
  
  return($nrefid,$nrefg,\%refid);
}

=item apvals.tab

grep Hshi3EVm011790t3  tr2dupgn_hs20ildn3hik-apvals.tab

ID____	JD____	Ispar	par_score	Naln	Nsnp	S_par	S_idmax	S_var	S_ident	d3Codon	S_peak	S_iCBIN	S_MMF	B_paB_ident	D_par	D_idx	EvgroupID

#itree=( Hshi3EVm011790t6 :0.0450272 , ( Hshi3EVm011790t2 :0.0336972 , ( ( Hshi3EVm011790t3 :0.0161223 , Hshi3EVm011790t4 :0.0161223 ):0.00706493 , ( Hshi3EVm011790t1 :0.0184513 , Hshi3EVm011790t5 :0.0184513 ):0.00473596 ):0.0105099 ):0.01133 ) ; 
Hshi3EVm011790t1	Hshi3EVm011790t3	par_i	41	516	22	par_sn	14.9	23.0	95.7	77	s3spot	2.70	92.83	alt_ta	97.7	par_tc	14.9	Hshi3EVm011790p2t1,par_e,p1t1
Hshi3EVm011790t2	Hshi3EVm011790t3	par_i	41	516	63	par_sn	13.2	27.5	87.8	48	s3spot	1.20	83.91	alt_ta	96.6	par_tc	13.2	Hshi3EVm011790p2t2,par_e,p1t1
Hshi3EVm011790t3	Hshi3EVm011790t1	par_i	41	516	22	par_sn	14.9	23.0	95.7	77	s3spot	2.70	92.83	alt_ta	97.7	par_tc	14.9	Hshi3EVm011790p1t1,par_e,p2t1
Hshi3EVm011790t3	Hshi3EVm011790t2	par_i	41	516	63	par_sn	13.2	27.5	87.8	48	s3spot	1.20	83.91	alt_ta	96.6	par_tc	13.2	Hshi3EVm011790p1t1,par_e,p2t2
Hshi3EVm011790t3	Hshi3EVm011790t4	alt_i	0	430	0	alt_sn	100	0	100.0	33	s0spot	100.00	99.77	alt_ta	98.4	alt_tc	100	Hshi3EVm011790p1t1,alt_e,p1t2
Hshi3EVm011790t3	Hshi3EVm011790t5	par_i	41	402	21	par_sn	16.9	27.3	94.8	76	s3spot	2.86	91.29	alt_ta	97.7	par_tc	16.9	Hshi3EVm011790p1t1,par_e,p2t3
Hshi3EVm011790t3	Hshi3EVm011790t6	alt_i	5.1	508	40	alt_sn	83.7	5.1	92.1	32	s1spot	2.56	92.32	alt_ta	95.5	alt_tc	83.75	Hshi3EVm011790p1t1,alt_e,p1t3
Hshi3EVm011790t4	Hshi3EVm011790t3	alt_i	0	430	0	alt_sn	100	0	100.0	33	s0spot	100.00	99.77	alt_ta	98.4	alt_tc	100	Hshi3EVm011790p1t2,alt_e,p1t1
Hshi3EVm011790t5	Hshi3EVm011790t3	par_i	41	402	21	par_sn	16.9	27.3	94.8	76	s3spot	2.86	91.29	alt_ta	97.7	par_tc	16.9	Hshi3EVm011790p2t3,par_e,p1t1
Hshi3EVm011790t6	Hshi3EVm011790t3	alt_i	5.1	508	40	alt_sn	83.7	5.1	92.1	32	s1spot	2.56	92.32	alt_ta	95.5	alt_tc	83.75	Hshi3EVm011790p1t3,alt_e,p1t1

=cut 

sub checkref_eqgene_or_pubids { 
  my($eqgenetab,$refids,$tabtype)= @_;
  
  #UPD23feb02: checkref_eqgene_or_pubids_or_apvals, new altpar val table, replacing eqgene tab
  my ($IsPubidtab,$IsApvals,$IsEqgene,$Unknowntab)=(0,0,0,0);
  # tabtype==0 now means could be apvals or eqgene ..
  if($tabtype==1) { $IsPubidtab=1; } 
  elsif($tabtype==2) { $IsEqgene=1; }
  elsif($tabtype==3) { $IsApvals=1; } 
  else { } #check contents 
  
  ##** DO NEED our() in local sub{} otherwise 2nd call here has wacky zero results..
  our($nevgroup,$nsame,$ndif,$nmiss,$negsame,$negdif,$ntr)=(0) x 9; # was our
  our($nisame,$nidif,$nitr,$iname,$iid)=(0) x 9; #our
  our($nialtn,$nialtok,$nialtbad,$niparn,$niparok,$niparbad, $ngaltn, $ngaltonly, $ngaltok,$ngaltbad, $ngparn, $ngparok,$ngparbad) = (0) x 19;
  our(@evgdif,%apval); #our
  my($lgid,$lastrg,%rgeg, %egrg);
  
  # FIXME: dupl iname at push @evgdif,"$iid:$iname", probably from '#dbg' lines...
  sub additr {
    our($nevgroup,$nsame,$ndif,$nmiss,$negsame,$negdif,$ntr); # was our
    our($nisame,$nidif,$nitr,$iname,$iid); 
    our($nialtn,$nialtok,$nialtbad,$niparn,$niparok,$niparbad, $ngaltn, $ngaltonly, $ngaltok,$ngaltbad, $ngparn, $ngparok,$ngparbad);
    our(@evgdif,%apval); # dont need our() >>
    if($nitr) { #  or $nisame or $nidif
      if($nidif) { $negdif++ ;  push @evgdif,$iname; } elsif($nisame) { $negsame++; } # was "$iid:$iname"
#       my($vn,%vs)=(0);
#       for my $td (sort keys %apval){ for my $ad (sort keys %{$apval{$td}}){ my $v=$apval{$td}{$ad}; map{ $vs{$_}++; }split",",$v; $vn++; } }
#       if($vn>0) { # this way same as below
#         $ngaltn++ if($nialtn); $ngparn++ if($niparn);  $ngaltonly++ unless($niparn); 
#         # vs == an altno,ay altok,pn parno,py = parok; 
#         # note: these count pairs >> ntr, maybe change to count per td, any alt-y,alt-no, par-y, par-n, 
#         #   or sum fractions? might make sense
#         $ngaltok += $vs{'ay'}; $ngaltbad += $vs{'an'}; 
#         $ngparok += $vs{'py'}; $ngparbad += $vs{'pn'}; 
#       } elsif(..)
      if($nialtn or $niparn) {
        $ngaltn++ if($nialtn); $ngparn++ if($niparn);  $ngaltonly++ unless($niparn); 
        $ngaltok += $nialtok; $ngaltbad += $nialtbad;
        $ngparok += $niparok; $ngparbad += $niparbad;
      }
      $nsame+=$nisame; $ndif+= $nidif;
      $nitr=0; $nisame=$nidif=0;   
      $nialtn=$nialtok=$nialtbad=$niparn=$niparok=$niparbad=0;
      $nevgroup++; $iid++;  # note: iid == nevgroup now
    }  
  }  
  
  my($nrefid,$nrefg,$refidh)= read_refids($refids);
  return unless($nrefid>0);

  my($ok,$inh);
  if($eqgenetab=~/^(stdin|-)/i){ $ok=1; $inh=*STDIN; }
  else {  ($ok,$inh)= openRead($eqgenetab); } # FIXME openRead("stdin|-");
  unless($ok) { loggit(LOG_WARN, "checkref_eqgene miss:  eqgenetab=$eqgenetab"); return (0,0); }
  
  # ** NEED this reset for our()
  ($nevgroup,$nsame,$ndif,$nmiss,$negsame,$negdif,$ntr)=(0) x 9; # was our
  ($nisame,$nidif,$nitr,$iname,$iid)=(0) x 9; #our
  ($nialtn,$nialtok,$nialtbad,$niparn,$niparok,$niparbad, $ngaltn, $ngaltonly, $ngaltok,$ngaltbad, $ngparn, $ngparok,$ngparbad) = (0) x 19;
  @evgdif=(); %apval=();
  
  while(<$inh>) {
    if(/^\W/) {
      #bad: additr() if($nitr>0); # FIXME here gets dupl iname entries of same group
    
      if(/^#iname=(\S+)/) { # for eqgene and apvals
        additr() if($nitr>0); $nitr=0; 
        $iname=$1; 
      }

      # #Public_mRNA_ID	originalID	PublicGeneID	AltNum	Class	AAqual	pIdAln	Notes	Oids == pubids
      # #PublicID	OID	AltIDs	Locus	Mapqual	ParalogIDs == eqgene
      # ID____	JD____	Ispar .. == apvals
      if(/^#Public_mRNA_ID/ and /\soriginalID/ and /\sPublicGeneID/) {
        ($IsPubidtab,$IsApvals,$IsEqgene)=(1,0,0); 
      } elsif(/^#PublicID/ and /\sAltIDs/ and /\sParalogIDs/) {
        ($IsPubidtab,$IsApvals,$IsEqgene)=(0,0,1); 
      } elsif(/^#ID/ and /\sIspar/) {
        ($IsPubidtab,$IsApvals,$IsEqgene)=(0,1,0); 
      }

    } elsif(/^ID/ and /\sIspar/) {  #no comm: ID____	JD____	Ispar 
      ($IsPubidtab,$IsApvals,$IsEqgene)=(0,1,0); 
      
    } elsif(/^\w/){ 
    
      unless( $IsPubidtab || $IsApvals || $IsEqgene) {
        my @v=split"\t"; 
        if($v[2]=~ m/(alt|par)_/) { $IsApvals=1; }
        elsif(@v > 7 and $v[3]=~/^\d/) { $IsPubidtab=1; }
        elsif(@v > 5 and @v < 8) { $IsEqgene=1; }
        else { $Unknowntab=1; # skip out?
         loggit(LOG_WARN, "checkref_eqgene unknown format:\nin:$_"); return (0,0); 
         } 
      }
      
      if($IsPubidtab) {
        #Public_mRNA_ID	originalID	PublicGeneID	AltNum	Class	AAqual	pIdAln	Notes	Oids
        chomp; my($pid,$oid,$gid,$ti,$cla,$aaq,$pia,$notes)=split"\t"; 
        next if($SKIP_UTRORF and ($oid =~ /utrorf/ or $pid =~ /utrorf/));
        if($gid ne $lgid) { additr() if($nitr>0); $lastrg=0; $iname=$gid; $lgid=$gid; }
        $ntr++; $nitr++;
        my @tgid=(); my $ngid=1; 
        my $thisgd=$refidh->{$oid} || $refidh->{$pid};  # may be either pubid or oid 
        unless($thisgd){ $nmiss++; next; } # SKIP_UTRORF here
        if($thisgd =~ /,/){ ($thisgd,@tgid)=split",",$thisgd; $ngid=1 + @tgid; } # two+ pars
        if(1) {  #NOTE: IsPubidtab singleton groups have zero nisame+nidif, nitr==1
          if($lastrg){ 
            if(@tgid) { my ($lrg)= grep{ $_ eq $lastrg } @tgid; $thisgd= $lrg if($lrg); }
            if($thisgd eq $lastrg){ $nisame++; } else { $nidif++; } 
          } 
          $rgeg{$thisgd}{$gid}++; $egrg{$gid}{$thisgd}++; # save for end counts of Rg>2Eg cross eg splits
          $lastrg=$thisgd;
        }
      
      } elsif($IsApvals) {
        chomp; my($aid,$bid,$caltpar,@apvals)=split"\t"; 
        next if($SKIP_UTRORF and ($aid =~ /utrorf/ or $bid =~ /utrorf/));
        my $agd=$refidh->{$aid};  
        my $bgd=$refidh->{$bid};   
        unless($agd and $bgd){ $nmiss++;  next; }  
        my $gsame= ($agd eq $bgd);
        my $gdiff= ($agd ne $bgd);
        my $ngref=1;
        if($agd =~ /,/ or $bgd =~ /,/){ 
          $gsame=$gdiff=0;
          my @agid=split",",$agd;
          my @bgid=split",",$bgd; $ngref= @agid + @bgid;
          for(my $i=0; $i<@agid; $i++){ $agd=$agid[$i];
            for(my $j=0; $j<@bgid; $j++) { $bgd=$bgid[$j]; 
              $gsame=1 if($agd eq $bgd); # count both ways
              $gdiff=1 if($agd ne $bgd);
            }
          } 
        }
       
        $ntr++; $nitr++;
        my $ispar= ($caltpar =~ /par/i)?1:($caltpar =~ /alt/i)?0: -1; # i_unk do what?
        #$nialtn=@alts; $niparn=@pars; my $cok=0;
        if($ispar==0) { $nialtn=1; } elsif($ispar==1) { $niparn=1; }
        
        if($gsame and $ispar==0) { $nisame++; $nialtok++; }
        elsif($gdiff and $ispar==1) { $nisame++; $niparok++; } 
        elsif($ngref >=1) {
          $nidif++; if($ispar==1) { $nialtbad++; } elsif($ispar==0) {  $niparbad++; }  
        } 
        #...............
        # if($agd eq $bgd){ 
        #   if($ispar==0) { $nisame++; $nialtok++; } # $cok="y";
        #   elsif($ispar==1) {  $nidif++; $nialtbad++; }          
        # } else { 
        #   if($ispar==1) { $nisame++; $niparok++; } # $cok="y";
        #   elsif($ispar==0) { $nidif++; $niparbad++; }          
        # }
        
      } elsif($IsEqgene) { #eqgene.tab vals
        chomp; my($pid,$oid,$alts,$loc,$mapq,$pars)=split"\t"; 
        next if($SKIP_UTRORF and $oid =~ /utrorf/);
        
        my $thisgd= $refidh->{$oid}||$refidh->{$pid}; 
        unless($thisgd){ $nmiss++; next; }
        #NO: if($thisgd ne $lgid) { additr() if($nitr>0); $nitr=0; $lgid=$thisgd; %apval=(); }# $iname=$thisgd;   $lastrg=0; 
        
        my @alts= grep/\w/, map{ my($d,$v)=split"/",$_,2; $d="" if($d eq "0");  $d; } split",",$alts; 
        my @pars= grep/\w/, map{ my($d,$v)=split"/",$_,2; $d="" if($d eq "0");  $d; } split",",$pars; 
        if($SKIP_UTRORF) { @alts= grep{ not m/utrorf/ } @alts; @pars= grep{ not m/utrorf/ } @pars; }
        next unless(@alts or @pars);

        # $apval{$oid}{alt}=$alts; $apval{$oid}{par}=$pars; # debug out only for nidif?
        # if(nidif) { $apval{$oid}{$d}=$dval{$d}; } #??
        
        $ntr++; $nitr++;
        $nialtn=@alts; $niparn=@pars; my $cok=0;
        for my $d (@alts) { my $gd=$refidh->{$d}; 
          unless($gd){ $nmiss++; $cok="m"; } 
          elsif($gd eq $thisgd){ $nisame++; $nialtok++; $cok="y"; } 
          else { $nidif++; $nialtbad++; $cok="n"; } } # $apval{$oid}{$d}.="a$cok,"; 
        #NOTE: ne for pars: ($gd ne $thisgd)
        for my $d (@pars) { my $gd=$refidh->{$d}; 
          unless($gd){ $nmiss++; $cok="m"; } 
          elsif($gd ne $thisgd){ $nisame++; $niparok++; $cok="y";  } 
          else { $nidif++; $niparbad++; $cok="n"; } } # $apval{$oid}{$d}.="p$cok,"; 
        #? $lgid= $thisgd;
      }
    }
  } close($inh);

  additr() if($nitr>0);
  
  my @rets=();
  unless($IsPubidtab) { # now IsEqgene || IsApvals
    my $ckt=($IsApvals)?"checkref_apvals": ($IsEqgene)?"checkref_eqgene" : "checkref_unk";
    
    # $ngaltn, $ngaltonly, $ngaltok,$ngaltbad, $ngparn, $ngparok,$ngparbad
    my $na= ($ngaltbad+$ngaltok); my $pa=($na<1)?0: $ngaltbad/$na;
    my $np= ($ngparbad+$ngparok); my $pp=($np<1)?0: $ngparbad/$np;
    my($paltbad,$pparbad)=map{ sprintf "%.1f",100*$_ } ($pa,$pp); 
     # div0: ( $ngaltbad/($ngaltbad+$ngaltok), $ngparbad/($ngparbad+$ngparok));
    
    push @rets, "$ckt($eqgenetab,$refids)";
    push @rets, "$ckt ngroup=$nevgroup, ngsame=$negsame, ngdif=$negdif, ntr=$ntr, nsame=$nsame, ndif=$ndif, nmiss=$nmiss";
    push @rets, "$ckt ngaltn=$ngaltn, ngparn=$ngparn, ngaltonly=$ngaltonly," .
     " NTaltok=$ngaltok, NTaltbad=$ngaltbad, %Altbad=$paltbad;   NTparok=$ngparok, NTparbad=$ngparbad, %Parbad=$pparbad";
    #NOTE: NT should be NP for num pairs, these are not now num transcripts (ntr << sum(NP))
    
  } 
  if($IsPubidtab) {  # if($IsPubidtab)
    my($nrg,$neg,$nrg2eg,$neg2rg, $nrg1eg, $neg1rg)= (0) x 9; #? new ret stats
    for my $rg (sort keys %rgeg){ $nrg++; my $ne=(scalar keys %{$rgeg{$rg}}); if($ne>1){ $nrg2eg++; } else { $nrg1eg++; } } 
    for my $eg (sort keys %egrg){ $neg++; my $ne=(scalar keys %{$egrg{$eg}}); if($ne>1){ $neg2rg++; } else { $neg1rg++; }  }
   
    # rg split over eg, need 2nd stat not negdif
    # .. should report nrg2eg, neg2rg instead of negdif..
    push @rets, "checkref_pubids($eqgenetab,$refids)";
    push @rets, "checkref_pubids ngroup=$nevgroup, ngsame=$negsame, ngdif=$negdif, ntr=$ntr, nsame=$nsame, ndif=$ndif, nmiss=$nmiss";
    push @rets, "checkref_pubids Eloci=$neg/$nevgroup, Refloci=$nrg, Eg2Rg=$neg2rg/$negdif, Eg1Rg=$neg1rg, ".
                "Rg2Eg=$nrg2eg, Rg1Eg=$nrg1eg, ngsame=$negsame";
    
    # $neg2rg == $negdif *should be* here
    if($neg != $nevgroup) { } ## miscalc 
    if($nrg2eg>0) { $negdif+=$nrg2eg;  $ndif+=$nrg2eg; $negsame -= $nrg2eg; $nsame -= $nrg2eg; } 
    # additr:
    # if($nidif) { $negdif++ ; push @evgdif,"$iid:$iname"; } elsif($nisame) { $negsame++; }
    # $nsame+=$nisame; $ndif+= $nidif;
    # if(1){ $nevgroup++; $iid++; } # note: iid == nevgroup now

  }
  
  return (\@rets,$nevgroup,$ntr,$nsame,$ndif,$negsame,$negdif,$nmiss,\@evgdif);
  # return ($nevgroup,$ntr,$nsame,$ndif,$negsame,$negdif,$nmiss,\@evgdif);
}

#---------

# blastn2btall($blastn,$obtall);
# env ndupout=9999999 $evigene/scripts/makeblastscore3.pl  -pMINLOW 0.50 -tandupok -spans=2  \
# -size ../arath18tair1cds.fa.qual -out at22vcan2d_chrs-arath18tair1cds.nubtall at22vcan2d_chrs-arath18tair1cds.i90blastn
sub blastn2btall {
  my($blastn,$cdssizes,$obtall)= @_;
  
  # my $cdssizes="FIXME.fa.qual"; # required ??
  $ENV{ndupout}=9999999;  # or upd22sep opt: -ndupout=9999999
  my @cmd= ("$EVIGENES/makeblastscore3.pl", "-pMINLOW=0.50", "-tandupok", "-spans=2",
          "-size", $cdssizes, "-out", $obtall, $blastn);
  my $err= runcmd(join(" ",@cmd));
  # warn "#run: ",join(" ",@cmd),"\n" if $debug;
  # my $err= system(@cmd); # runcmd(@cmd)
  # if($err) { warn "ERR: ",join(" ",@cmd),"\n"; }
  return($obtall,$err);
}

=item make_cds_chr_genextab

  ($ingenexf)= make_cds_chr_genextab($cdsseq,$chrasm,); 
  
  see at18cdsblast2covtab.info
  at22vcan2d_chrs-arath18tair1cds.i90blastn is example

  # full cds-chr-blastn > genecovtab w/ tcopy == nparalog vals
  gunzip -c at22vcan2d_chrs-arath18tair1cds.i90blastn.gz | \
  env minp=97  perl -ne \
  'if(/^\W/){ if($ltd and $tw){ putb($ltd,$tw); } $ltd=""; if(/Query: (\S+)/){ $td=$1; ($tw)=m/ len=(\d+)/?$1:0;
  if($hdr){ print "#$hdr noval\n"; } $hdr="id=$td len=$tw"; }  next; } 
  my($td,$cr,$pi,$al,$mm,$nd,$tb,$te,$cb,$ce)=split; putb($ltd,$tw) if($ltd and $ltd ne $td);  next if($pi <
  $MINP); ($bb,$be)=map{ int($_/$BN) } ($tb,$te); for(my $i=$tb; $i<=$te; $i++){ my $bi=int($i/$BN);
  $al[$bi]+=$pi; $an[$bi]++; } $nh++; $bmax=$be if($be>$bmax); $ltd=$td; sub putb{ my($id,$len)=@_; my $blen=
  int($len/$BN) || $bmax; my($na,$sa)=(0,0); for (@an){ $sa+=$_; $na++; } my
  $tcopy=($na<1)?0:sprintf"%.1f",$sa/($BN*$na); $hdr="id=$id len=$len" unless($hdr); print "#$hdr tCopy=$tcopy\n";
   for(my $i=0; $i<=$blen; $i++){ my $bn= $BN*(1+$i); my $al=$al[$i]; my $an=$an[$i]; my $aal=($an<1)?0:
  int(0.5+$al/$an); my $tal=int(0.5+$al)/$BN;  $an=int($an)/$BN;  print join("\t",$id,$bn,$tal,$aal,$an)."\n"; }
  @al=@an=(); $bmax=$hdr=$nh=0; }  END{ putb($ltd,$tw) if($ltd); } BEGIN{ $BN=100; $MINP=$ENV{minp}||97; print
  "#".join("\t",qw(ChrID Pos aCovT aCovM tCopy))."\n"; }' \
    > at22vcan2d_chrs-arath18tair1cds_i97.genecovtab
  
  # make genexcopy table
  # expand genecovtab to match gnodes.covtab cols, note replace aCovM w/ aCovT == assume no knowledge of paralog cover
  perl -ne 'if(/^#ChrID/){ s/Pos/Pos\tCovT\tCovM\tCovU/; s/aCovM/aCovM\taCovU/; print; } elsif(/^\w/){ @v=split;
  ($ct,$cm)=@v[2,3]; $cu=($ct < $cm+2)?$cm:($cm - ($ct - $cm)); $cu=0 if($cu<0); 
  print join("\t",@v[0,1],0,0,0,$ct,$ct,$cu,$v[-1])."\n"; } else { print; } ' \
    at22vcan2d_chrs-arath18tair1cds_i97.genecovtab > at22vcan2d_chrs-arath18tair1cds_i97.genex2covtab
  
  # covert to genexcopy table
  $evigene/scripts/genoasm/gnodes_std2genecov.pl -debug -inIsCovtab  -idclass arath18tair1cds.idclass -out at22vcan2d_chrs_at18cds_blast97i.geneccopy -input at22vcan2d_chrs-arath18tair1cds_i97.genex2covtab 
  
  # note no read counts, no genosize est..
  #gnodes_sam2genecov options: minident=0.4, mindupid=0.98, maxdup=0.05,  trimends=0, idclass=arath18tair1cds.idclass
  # read nid=27444, nclass=2 from arath18tair1cds.idclass
  # read(at22vcan2d_chrs-arath18tair1cds_i97.genex2covtab)=27395
  # UCG Class Genes, 1050 of 27395 total, Filters:UCG,size>=1k,covspan>=90, --------------
  # Uniq Gene Cov Depth n=1050, C.Map/W=97.91, 97.38 +/-0.09 (mdn,ave,sem) for W.genes=1956900, LN.reads=0
  # Genome_size= 0.0 Mb of L*N/C= 0 * 0 / 97.9, CDS_size= 0.0 Mb,
  ...
  
=cut

sub blast2genecov {
  my($inblastab,$ogenecov)=@_;
  
  our $BN=100; 
  my $MINP= $ENV{pctident} || 97; # $ENV{minp}||97; #? or CDSBLAST_IDENT == 98 default
  # my $NCBLAST_IDENT=  $ENV{pctident} || 97; # option  below
  
  my($ok,$inh)= openRead($inblastab); return unless($ok);
  unless($ogenecov){ $ogenecov=basename($inblastab); $ogenecov =~ s/.gz//; $ogenecov=~s/\.\w+$//; $ogenecov.=".genecovtab"; }
  open(my $outh,">$ogenecov");
  
  #.print $outh "#".join("\t",qw(ChrID Pos aCovT aCovM tCopy))."\n"; # FIXME full covtab, change aCovM<aCovT
  print $outh "#".join("\t",qw(ChrID Pos CovT CovM tCopy aCovT aCovM aCovU ))."\n"; # FIXME full covtab, change aCovM<aCovT

  our($bmax,$tmax,$hdr,@al,@an);
  
  sub putb { 
    my($outh,$id,$len)=@_;  our($BN,$bmax,$tmax,$hdr,@al,@an);
    $len ||= $tmax;
    my $blen= int($len/$BN) || $bmax; 
    my($na,$sa)=(0,0);  for my $an (@an){ if($an){ $sa+=$an; $na++; } }
    my $tcopy=($na<1)?0:sprintf"%.1f",$sa/($BN*$na); 
    $hdr="id=$id len=$len" unless($hdr); print $outh "#$hdr tCopy=$tcopy\n";
    for(my $i=0; $i<=$blen; $i++){ 
      my $bn= $BN*(1+$i); my $al=$al[$i]||0; my $an=$an[$i]||0; 
      my $aal=($an<1)?0: int(0.5+$al/$an); 
      my $tal=int(0.5+$al)/$BN;  $an=int($an)/$BN;  
      my $ual= ($tal < $aal+3)?$aal:($aal - ($tal - $aal)); $ual=0 if($ual<0); $ual=sprintf"%.2f",$ual;
      # print $outh join("\t",$id,$bn,$tal,$aal,$an)."\n"; # orig
      print $outh join("\t",$id,$bn,0,$aal,$an,$tal,$tal,$ual)."\n"; # full covtab, replacing aal/CovM w/ tal
      }
    @al=@an=(); $tmax=$bmax=$hdr=0; 
    return 1;
  }  
  
  my($nout,$ltd,$tw,$td,$qid)=(0) x 9;  
  while(<$inh>){ 
    if(/^\W/){ 
      if($ltd){ $nout+= putb($outh,$ltd,$tw); @al=@an=(); $tmax=$bmax=$hdr=0;  $ltd="";  }
      if(/Query: (\S+)/){ $qid=$1; 
        #($tw)=m/ len=(\d+)/?$1:0; # also clen= and offs= or aalen=
        # Query: cacao19crncbi:g18585699t1 type=CDS; aalen=496,77%,complete; clen=1927; strand=+; offs=223-1713;
        if(m/ len=(\d+)/){ $tw=$1; } elsif(m/ offs=(\d+).(\d+)/){ $tw= 1 + $2 - $1; }
        elsif(m/ aalen=(\d+)/){ $tw=3 * $1; }
        if($hdr){ print $outh "#$hdr noval\n"; } $hdr="id=$qid len=$tw"; 
      }  
      next; 
    }
   
    my($td,$cr,$pi,$al,$mm,$nd,$tb,$te,$cb,$ce)=split; 
    next if($pi < $MINP); 
    if($ltd and $ltd ne $td) { $nout+= putb($outh,$ltd,$tw); @al=@an=(); $tmax=$bmax=$hdr=0; $ltd=""; }  
    my($bb,$be)=map{ int($_/$BN) } ($tb,$te); 
    for(my $i=$tb; $i<=$te; $i++){ my $bi=int($i/$BN); $al[$bi]+=$pi; $an[$bi]++; } 
    $tmax=$te if($te>$tmax); $bmax=$be if($be>$bmax); 
    $ltd=$td; 
  } # inh  
  $nout+= putb($outh,$ltd,$tw) if($ltd); 
  close($inh); close($outh);  
  return($nout, $ogenecov);
}


sub make_cds_chr_genextab {
  my($cdsseq,$chrasm,)= @_;

  my $NCBLAST_IDENT=  $ENV{pctident} || 97; # option should be same as above $ENV{minp}
  my $NCBLAST_EVALUE= $ENV{evalue} || 1e-9; # option

  # check for existing cds-chr.blastn ..
#need basename(xxx)
#tr2dgc: CMD= /bio/apps/ncbi/bin/blastn -perc_identity 97 -evalue 1e-09  -num_threads 1 -db ../gdata/cacao19crio_chr -query inputset/cacao19crncbi_mrna.cds -outfmt 7 \
#  -out inputset/cacao19crncbi_mrna-../gdata/cacao19crio_chr.blastn
# Command line argument error: Argument "out". File is not accessible:  `inputset/cacao19crncbi_mrna-../gdata/cacao19crio_chr.blastn'
# #tr2dgc: ERR=256  /bio/apps/ncbi/bin/blastn -perc_identity 97 -evalue 1e-09  -num_threads 1 -db ../gdata/cacao19crio_chr -query inputset/cacao19crncbi_mrna.cds -outfmt 7 -out inputset/cacao19crncbi_mrna-../gdata/cacao19crio_chr.blastn

  my $chrna= basename($chrasm); $chrna=~s/.gz//; $chrna=~s/\.\w+$//;
  my $cdsna= basename($cdsseq); $cdsna=~s/.gz//; $cdsna=~s/\.\w+$//;
  
  my($cmd,$err,$ok,$hin);
  my $blout="$cdsna-$chrna.blastn"; push @tmpfiles, $blout;
  my $ccovtab="$cdsna-$chrna.covtab"; push @tmpfiles, $ccovtab;
  my $cgenex="$cdsna-$chrna.genexcopy"; # push @tmpfiles, $cgenex;
  if($REUSE_TMPDATA and -s $cgenex) { loggit(0, "reusing $cgenex"); return($cgenex); }
  if($REUSE_TMPDATA and -s $ccovtab) { loggit(0, "reusing $cgenex"); }
  else {
  
  if($REUSE_TMPDATA and  -s $blout) { loggit(0, "reusing $blout"); }
  else {
    if($APPblastn =~ /MISSING/i){ loggit(1,"evgenesim requires blastn: $APPblastn");  return; }    
    if($chrasm =~ /\.gz$/){ 
      $cmd="gunzip -c $chrasm | $APPmakeblastdb -dbtype nucl -title $chrna -out $chrna -logfile /dev/null";  
    } else {
      $cmd="$APPmakeblastdb -dbtype nucl -in $chrasm  -out $chrna -logfile /dev/null";  
    }
    push @erasefiles, map{ "$chrna.$_" } qw(nsq nin nhr);
    $err= runcmd($cmd); return if($err);
  
    my $bloptnu="-perc_identity $NCBLAST_IDENT -evalue $NCBLAST_EVALUE ";  
    $cmd= "$APPblastn $bloptnu -num_threads $NCPU -db $chrna -query $cdsseq -outfmt 7 -out $blout";
    $err= runcmd($cmd); return if($err);
    }
  
  # parse blout, create cds_chr.covtab 
  my($ncov)= blast2genecov($blout, $ccovtab);
  loggit(0, "blast2genecov($blout, $ccovtab) n=$ncov");
  unless($ncov) { loggit(LOG_WARN, "err in blast2genecov($blout, $ccovtab)"); return; }
  }
  
  # run  gnodes_std2genecov.pl -inIsCovtab -idclassf cds.idclass -input cds_chr.covtab -output name.genexcopy
  # ?? no -idclass arath18tair1cds.idclass  here; but *known* C.UCG = 100
  $cmd= "$EVIGENES/genoasm/gnodes_std2genecov.pl  -inIsCovtab -input $ccovtab -output $cgenex";
  $err= runcmd($cmd); # return if($err);

  #add useful, not now used? blast2evgff.pl , note new -mincovdup 0.80 default blocks most partial dupls .. want here?
  use constant DOBLGFF => 1; #UPD23JAN23  
  my $blgff="";
  if(DOBLGFF) {
  $blgff="$cdsna-$chrna-loci.gff"; 
  unless( -f "$cdsseq.qual"){ $cmd="env ismrna=1 $EVIGENES/prot/aaqual.sh $cdsseq"; runcmd($cmd); }
  my $blgopt=" -mincovdup 0.25 -lowscore 0.10 -alignmax 999 -noaddcds -exont CDS  -source evg ";
  $cmd= "$EVIGENES/genes/blast2evgff.pl $blgopt  -sizes $cdsseq.qual -out $blgff $blout";
  $err= runcmd($cmd); 
  }
  
  return( $cgenex); # blgff ?
}

=item make_cds_chr_genextab try1

$evigene/scripts/genes/tr2dupgeneclass1a.pl -trset cacao19crncbi_mrna -refids cacao19crncbi_mrna.gidtab \
  -cds inputset/cacao19crncbi_mrna.cds -chrasm ../gdata/cacao19crio_chr.fa  -debug  \
  -pubids okayset/cacao19crncbi_mrna.pubids \
  -runscript -eqgenetab cacao19cr_cdschr1a.eqgene 
  
#tr2dgc: EvidentialGene tr2dupgeneclass, VERSION 2022.11.01
#tr2dgc: tr2dupgeneclass  -trset cacao19crncbi_mrna -refids cacao19crncbi_mrna.gidtab -cds inputset/cacao19crncbi_mrna.cds -chrasm ../gdata/cacao19crio_chr.fa -debug -pubids okayset/cacao19crncbi_mrna.pubids -runscript -eqgenetab cacao19cr_cdschr1a.eqgene 
#tr2dgc: app=blastn, path=/bio/apps/ncbi/bin/blastn
#tr2dgc: app=makeblastdb, path=/bio/apps/ncbi/bin/makeblastdb
#tr2dgc: app=muscle, path=/bio/apps/muscle/bin/muscle
#tr2dgc: cacao19crncbi_mrna tr2aacds data cds=inputset/cacao19crncbi_mrna.cds
#tr2dgc: CMD= /bio/apps/ncbi/bin/makeblastdb -dbtype nucl -in ../gdata/cacao19crio_chr.fa  -out cacao19crio_chr -logfile /dev/null
#tr2dgc: CMD= /bio/apps/ncbi/bin/blastn -perc_identity 97 -evalue 1e-09  -num_threads 1 -db cacao19crio_chr -query inputset/cacao19crncbi_mrna.cds -outfmt 7 -out cacao19crncbi_mrna-cacao19crio_chr.blastn

#tr2dgc: err in blast2genecov(cacao19crncbi_mrna-cacao19crio_chr.blastn, cacao19crncbi_mrna-cacao19crio_chr.covtab)
>>>
cacao19crncbi_mrna-cacao19crio_chr.blastn
# BLASTN 2.13.0+
# Query: cacao19crncbi:g18585699t1 type=CDS; aalen=496,77%,complete; clen=1927; strand=+; offs=223-1713; 
#  codepot=Code/0.036;  gene=LOC18585699; geneid=18585699; db_xref=ncbiprot:XP_007008706.2,ncbirna:XM_007008644; isoform=1; Name=ent-kaurenoic acid oxidase 1; species=Theobroma_cacao;
# Database: cacao19crio_chr
# Fields: query acc.ver, subject acc.ver, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score
# 8 hits found
cacao19crncbi:g18585699t1	cacao19crio:Chr10	100.000	482	0	0	231	712	49130	48649	0.0	891
cacao19crncbi:g18585699t1	cacao19crio:Chr10	100.000	267	0	0	710	976	48566	48300	8.23e-138	494
cacao19crncbi:g18585699t1	cacao19crio:Chr10	100.000	233	0	0	1	233	50691	50459	6.54e-119	431
cacao19crncbi:g18585699t1	cacao19crio:Chr10	100.000	123	0	0	1252	1374	47589	47467	9.21e-58	228
cacao19crncbi:g18585699t1	cacao19crio:Chr10	100.000	118	0	0	1374	1491	47210	47093	5.54e-55	219
>>>
cacao19crncbi_mrna-cacao19crio_chr.covtab
#ChrID	Pos	CovT	CovM	tCopy	aCovT	aCovM	aCovU
#id=cacao19crncbi:g18585699t1 len=0 noval
#id=cacao19crncbi:g18585704t1 len=0 noval
#id=cacao19crncbi:g18585705t1 len=0 noval
#id=cacao19crncbi:g18585705t2 len=0 noval
#id=cacao19crncbi:g18585706t1 len=0 noval

^^^ FIXED BUG
#tr2dgc: reusing cacao19crncbi_mrna-cacao19crio_chr.blastn
#tr2dgc: blast2genecov(cacao19crncbi_mrna-cacao19crio_chr.blastn, cacao19crncbi_mrna-cacao19crio_chr.covtab) n=31500
#tr2dgc: CMD= /media/volume/sdb/vol_c/biogrid/mb/evigene/scripts/genoasm/gnodes_std2genecov.pl  -inIsCovtab -input cacao19crncbi_mrna-cacao19crio_chr.covtab -output cacao19crncbi_mrna-cacao19crio_chr.genexcopy
#gnodes_sam2genecov options: minident=0.4, mindupid=0.98, maxdup=0.05,  trimends=0, idclass=
# read(cacao19crncbi_mrna-cacao19crio_chr.covtab)=31500
# Measured Unique Genes, 19476 of 31500 total, Filters:size>=1k,covspan>=90, --------------
# Uniq Gene Cov Depth n=19476, C.Map/W=97.67, 97.17 +/-0.02 (mdn,ave,sem) for W.genes=36895400, LN.reads=0
# Genome_size= 0.0 Mb of L*N/C= 0 * 0 / 97.7, CDS_size= 0.0 Mb,
# Gsize_alt  = 0.0 Mb of LN/C= 0 / 97.7 for Lr: 0, Nr: 0 = 0+ 0+ 0+ 0 [ok,nomap,noucg,bad]
#   for  Nr.allcds=0 (0%), Nr.total=0, Lrdlen=0, MapErr=0 (0%), Nshort=0
#tr2dgc: read_genexcopy nucg=19476, ngene=31500 Cucg=97.67 of cacao19crncbi_mrna-cacao19crio_chr.genexcopy

grep -v '#' cacao19crncbi_mrna-cacao19crio_chr.genexcopy | cut -f7 | sort | uniq -c | head
   1682 dups    796 dupx     29 skew  28987 uniq      6 zero

#tr2dgc: evgenesim pubids=okayset/cacao19crncbi_mrna.pubids seq=inputset/cacao19crncbi_mrna.cds

... write 4000 tmps/EVGgroup.cds takes too long ...

#tr2dgc: run script cacao19crncbi_mrna_run_evsim.sh for nsim=4075 to cacao19cr_cdschr1a.eqgene

#tr2dgc: checkref_pubids(okayset/cacao19crncbi_mrna.pubids,cacao19crncbi_mrna.gidtab)
#tr2dgc: checkref_pubids ngroup=21044, ngsame=3714, ngdif=349, ntr=27099, nsame=5531, ndif=506, nmiss=236
#tr2dgc: checkref_pubids Eloci=20826/21044, Refloci=21312, Eg2Rg=349/349, Eg1Rg=20477, Rg2Eg=14, Rg1Eg=21298, ngsame=3714
#tr2dgc: checkref_pubids ref-diff groups: 46:NonamEVm000046, 47:NonamEVm000047, 49:NonamEVm000049, 55:NonamEVm000055, 86:NonamEVm000086, 94:NonamEVm000094, 100:NonamEVm000100, 114:NonamEVm000114, 133:NonamEVm000133, 143:NonamEVm000143, .. n=363 in okayset/cacao19crncbi_mrna_refdiff.list

#tr2dgc: ERR: openRead cacao19cr_cdschr1a.eqgene
#tr2dgc: checkref_eqgene miss:  eqgenetab=cacao19cr_cdschr1a.eqgene
Can't use string ("0") as an ARRAY ref while "strict refs" in use at /bio/bio-grid/mb/evigene/scripts/genes/tr2dupgeneclass1a.pl line 228.

=item try1 cacao19crncbi_mrna_run_evsim.sh

** ? add export PATH=/bio/apps/muscle/bin:..
   EVS=/media/volume/sdb/vol_c/biogrid/mb/evigene/scripts
   
#!/bin/bash
#evgenesim_script=cacao19crncbi_mrna_run_evsim.sh

#from tr2dupgeneclass trset=cacao19crncbi_mrna pubids=okayset/cacao19crncbi_mrna.pubids cdsseq=inputset/cacao19crncbi_mrna.cds genexcopy=cacao19crncbi_mrna-cacao19crio_chr.genexcopy eqgenetab=cacao19cr_cdschr1a.eqgene
export debug=1
touch cacao19cr_cdschr1a.eqgene
#------- cmd list -----------
( /bio/apps/muscle/bin/muscle -quiet -in tmps/NonamEVm000003.cds -out tmps/NonamEVm000003.msa \
 && /bio/apps/muscle/bin/muscle -quiet -maketree -in tmps/NonamEVm000003.msa -out tmps/NonamEVm000003.mutree \
 && env nparalog=1.0 otype=eg $evigene/scripts/genes/altparsnpdist.pl tmps/NonamEVm000003.msa tmps/NonamEVm000003.mutree > tmps/NonamEVm000003.egsimtab; )
( /bio/apps/muscle/bin/muscle -quiet -in tmps/NonamEVm000004.cds -out tmps/NonamEVm000004.msa \
  && /bio/apps/muscle/bin/muscle -quiet -maketree -in tmps/NonamEVm000004.msa -out tmps/NonamEVm000004.mutree \
  && env nparalog=1.0 otype=eg $evigene/scripts/genes/altparsnpdist.pl tmps/NonamEVm000004.msa tmps/NonamEVm000004.mutree > tmps/NonamEVm000004.egsimtab; )

( /bio/apps/muscle/bin/muscle -quiet -in tmps/NonamEVm000100.cds -out tmps/NonamEVm000100.msa \
 && /bio/apps/muscle/bin/muscle -quiet -maketree -in tmps/NonamEVm000100.msa -out tmps/NonamEVm000100.mutree \
 && env nparalog=2.0 otype=eg /media/volume/sdb/vol_c/biogrid/mb/evigene/scripts/genes/altparsnpdist.pl tmps/NonamEVm000100.msa tmps/NonamEVm000100.mutree > tmps/NonamEVm000100.egsimtab; )

# FIXME .egsimtab:  ID1/evd1,evd2,evd3,ID2/evd.. change ',' to / for evd1/2/3
 tmps/NonamEVm000100.egsimtab
#iname=tmps/NonamEVm000100.msa
#altpar_snp_params: nparalog=2.0, snpvar=10 (np>1) .. 20 (np==1)
#altpar_tree_params: ident_altmin=98 (np>1), ident_parmust=90 (np==1)
#itreename=tmps/NonamEVm000100.mutree
#altpar_snp_dist_matrix: eqgene, maxaltsnp=10, nid=3
#PublicID	OID	AltIDs	Locus	Mapqual	ParalogIDs
cacao19crncbi:g18589680t1	cacao19crncbi:g18589680t1	cacao19crncbi:g18589680t2/sn0:0,0pp2,cb-1:100.0,cp0:3	0	cacao19crncbi:g18589684t1/sn1:25.7,0.0212,cb0:98.9,cp1:1
cacao19crncbi:g18589680t2	cacao19crncbi:g18589680t2	cacao19crncbi:g18589680t1/sn0:0,0pp2,cb-1:100.0,cp0:3	0	cacao19crncbi:g18589684t1/sn1:27.5,0.0226,cb0:98.9,cp1:1
cacao19crncbi:g18589684t1	cacao19crncbi:g18589684t1	0	0	0	cacao19crncbi:g18589680t1/sn1:25.7,0.0212,cb0:98.9,cp1:1,cacao19crncbi:g18589680t2/sn1:27.5,0.0226,cb0:98.9,cp1:1


=cut 

__END__

sub MAIN_tr2dupgeneclass_ncrna {   
  loggit(0, "BEGIN with input=",$trset,"date=",`date`);
  my $trname=$trset; $trname =~ s/\.gz$//; $trname=~s/.\w+$//; $trname =~ s,^.*/,,;
  
  my @okpubs1a= qw( okayset publicset);
  my @okpubs2b= qw( okayset1st okayset);
  ($okaysetd,$pubsetd)= @okpubs2b; 
  unless( -d $okaysetd and -d $pubsetd ) {  # symlink dir bad here? maybe not, was missing okayset1st
    ($okaysetd,$pubsetd)= @okpubs1a;
    unless( -d $okaysetd and -d $pubsetd ) {
      loggit(LOG_DIE,"Cannot find evigene data directories:  @okpubs2b or @okpubs1a");
    }
  }
  
  # locate data associated w/ trclass
  unless($mrna) { 
    $mrna= filegz("$pubsetd/$trname.okay.mrna");  # mrna.gz ?? fixed remove_mrna_aligned
    }
  unless($aaqualf) { 
    $aaqualf= filegz("inputset/$trname.aa.qual");   # presume trset is all inputset/ or contained in that
    $aaqualf="$trname.aa.qual" unless(-f $aaqualf);
    }
  
  loggit(0,"$EGAPP( $trset, $mrna)");
  loggit(LOG_DIE,"Cannot find mrna $mrna") unless(-f $mrna);
  # unless(ref $outputh) { $outputh=*STDOUT; }

  my($ntrnew1, $trnomrna, $ntrtotal, $mrnaoids)=(0) x 9;
  my($ntrnew2,$trnomrnab,$trsetagree)=(0) x 9;
  my($ntrnew3,$trlongnomrna,$trlongsizes)=(0) x 9; # DOMERGE sets these..
  
  if($DOMERGE) { # input is trlongnomrna, not trset
    my $nsubset=0;
    ($ntrnew3,$nsubset,$trlongnomrna,$trlongsizes)= makeSubmergeTr($trname,\@submerge);
    step_log_or_fini( ($ntrnew3 < 1),"makeSubmergeTr ntr=$ntrnew3 from $nsubset sets, $trlongnomrna");
    $ntrtotal=$ntrnew1=$ntrnew3; 
    
    # FIXME: replace aaqualf w/ trname_mrg.nclong.aa.qual ?? .. only for trseq_qual(trlong) ?
    (my $trlongnc_aaqual= $trlongnomrna) =~ s/\.\w+$/.aa.qual/; # makename($trlongnomrna,"aa.qual");
    $aaqualf=$trlongnc_aaqual if( -f $trlongnc_aaqual);
    
    # get trsetagree from makeSubmergeTr() trsets.nr ?
    my $trlongnc_agree= "$trlongnomrna.consensus";
    $trsetagree=$trlongnc_agree if( -f $trlongnc_agree);
   
  } else { # full pipeline
  
    ($ntrnew1,$trnomrna,$ntrtotal, $mrnaoids)= remove_mrna_oids($trname,$trset,$mrna); # .gz ok, v2OK
    step_log_or_fini( 0,"remove_mrna_oids kept=$ntrnew1/$ntrtotal, $trnomrna");
    
    # UPD20f15: insert step to remove dropset/perfectdup,perfectfrag where CDS size is large and match:ID is in okayset/
    my($ntrnew1b,$trnomrna1b)= remove_bigcdsdrops($trname, $trnomrna, $mrna, $mrnaoids); # .gz ok, v2OK
    step_log_or_fini( 0,"remove_bigcdsdrops kept=$ntrnew1b/$ntrtotal, $trnomrna1b"); 
    if($ntrnew1b > 0){ $trnomrna= $trnomrna1b; }
    
    ($ntrnew2,$trnomrnab,$trsetagree)= remove_mrna_aligned($trname,$trnomrna,$mrna); # .gz NOW ok yet, v2OK
    step_log_or_fini( 0,"remove_mrna_aligned kept=$ntrnew2/$ntrtotal, $trnomrnab");
    
    ($ntrnew3,$trlongnomrna,$trlongsizes)= long_seqs($trname, $trnomrnab, $MIN_NCRNA); # v2OK
    step_log_or_fini( ($ntrnew3<1), "long_seqs(>=$MIN_NCRNA) kept=$ntrnew3/$ntrtotal, $trlongnomrna");
    
    if($premerge) { 
      # FINISH special, not for premerge? .. no /done okay/
      #   if(USE_recover_trset and $status>=0 and $atstep =~ /done okay/);
      FINISH_tr2dgc( 1, "done pre-merge of subset $trlongnomrna");
    }
    
  } # unless DOMERGE

  ## ncrna_replicates and altparclass meed trlongsizes.qual file; for new btall method, 
  my($ntrq,$trlongsizef)= trseq_qual($trname, $trlongnomrna, $trlongsizes, $aaqualf); #   v2OK
  
  #** NOTE:   ncrna_selfalign() and altparclass() both do blastn self-align, should merge them
  # but need new parsing for ncrna_replicates : btall blast table, pick out full aligns from that
  # ?? opt for altparclass -use_selfblast $selfblast
  # my $REUSE_TMPDATA= $ENV{REUSE_TMPDATA} || 0;

  ##UPD2222 changes here.........
  my($nokcds, $hasokcds) =(0,{}); # not yet tested, dont know value yet
  my($ntrnew4, $trselfblast, $ntrnew5, $truniqrna)=(0) x 9;
  my($ngene,$genetab)=(0,"");
  
    $REUSE_TMPDATA= 1; # v2 always
    ($ntrnew5, $truniqrna)= ($ntrnew3,$trlongnomrna); # this will change? truniq = remove drops of classgene
    
    ($ntrnew4, $trselfblast)= ncrna_selfalign($trname, $trlongnomrna, $REUSE_TMPDATA);
    step_log_or_fini( ($ntrnew4<1),"ncrna_selfalign count=$ntrnew4/$ntrtotal, $trselfblast");

    ($ngene,$genetab)= altparclass2a($trname, $trlongnomrna, $trselfblast, $trlongsizef); # ?? , $hasokcds
    step_log_or_fini(  ($ngene<1), "altparclass loci=$ngene for $ntrnew4 tr, in $genetab");

    #v2: dont need altpar genetab ?? >> needed at make_allevdtab()
    #v2upd: altparclass2a() and makeSelfDupTab() now both read self.btall, do related things, could be merged
    
    my($ntab, $selfduptab, $havedups, $hasduphash, $nagree)
        = ncrna_makeSelfDupTab($trname, $trlongnomrna, $trselfblast, $trsetagree, $trlongsizef);
    step_log_or_fini( 0, "makeSelfDupTab ndups=$havedups, nagree=$nagree");
    # ret: nagree,%blagree, ndup, %hasdup ??

    ## add here? class b/n truniq matching okay.cds, truniq.okcds.tr, and those w/o truniq.ncrna.tr
    $hasokcds= undef;
    (my $okcds=$mrna) =~ s/.mrna/.cds/; # allow cds.gz ?
    if($TEST_OKCDS and -f $okcds) {  # should become default if -f okcds
      ($nokcds, $hasokcds) = ncrna_align_okcds($trname,$trlongnomrna,$okcds);
      step_log_or_fini( 0, "ncrna_align_okcds hasokcds=$nokcds/$ntrnew5");
    } 
    $TEST_OKCDS=0 unless($nokcds>0); # turn off this flag for follow ons
    
    #v2: insert here .. want altpar genetab, blagree/selfdup table, aa.qual + fickett codepot of trset
    # ?? add $hasduphash as allevdtab col ? rather than thru classgenes()
    #    ^^ not good, need to add duptrids as column, classgenes ranks by quals then keeps 1st of dup set
    
    my($nevd,$allevdtab)= make_allevdtab( $trname, $trlongnomrna, $genetab, $trlongsizef,  $selfduptab, $hasokcds );
    step_log_or_fini(  ($nevd<1), "make_allevdtab nevd=$nevd/$ntrnew5 in $allevdtab");

    #v2: final step? ncrna_classgene(@dgenetrs), where @dgenetrs are all trset in gene group, w/ evidence
    # classifier weights evidence for rank by trscore, keeps/drops alt/par of gene group depending on scores
    # output table in publicset/pubids format? w/ class 'main/alt/noclass=uni' and 'drop|cull' qualifier
    # ncrna_classgenes: read evdtab, each tr sorted by genetab dgene ids, with evidence    
    
    my($ngeneok,$ntrok,$ntrdrop,$classtab)= ncrna_classgenes($trname, $trlongnomrna, $genetab, $allevdtab, $hasduphash);
    step_log_or_fini( 0, "ncrna_classgenes ngene=$ngeneok,ok=$ntrok,drop=$ntrdrop/$ntrnew5 in $classtab");
    
    # update ($ntrnew5, $truniqrna) removing drops in classtab
    my($ntrnew5, $truniqrna, $truniqncaa)= ncrna_pubseqset($trname,$trlongnomrna,$classtab);  
    step_log_or_fini( 0, "ncrna_pubseqset kept=$ntrnew5/$ntrtotal, in $truniqrna"); 

    # Maybe insert here ncaablastp( ncrnaset/nc.aa, refaa, okayset.aa.btall) matchup to find uniq ref prots
    # .. or in sra2genes .. need from that refaa, okayset.aa.btall 
    my($aok,$refaa,$okbtall)= ($truniqncaa) ? has_okayset_refblast($trname) : (0); 
    if($aok) {
      my($ntab,$ncaareftab,$ncuniq)= ncrna_aauniq_refblast($trname, $truniqncaa, $refaa,$okbtall);
      ## ntab == -1 on error, needs REFAA, REF_OKAA_BTALL to work
      step_log_or_fini( 0, "ncrna_aauniq_refblast refuniq=$ncuniq/$ntab, in $ncaareftab");
      # output now has  trname.ref_ncaa_okaa.uniqtab , want to pull ncaa/cds/mrna of those to merge w/ pubset?
    }
    
  
  # close($outputh) if($output);
  step_log_or_fini( 0, "tr2ncrna nin=$ntrtotal, nout=$ntrnew5, ngene=$ngene\n");
  
  ## no rewriteTrClass(), but want some ncrna.pubids table output
  FINISH_tr2dgc(0,'done okay',$trname);
}

#=======================================================
  

sub recover_trset {
  my($trname,$trset,$trsetnew)= @_;

  # also maybe look in subdir ncrnaset/ 
  $trsetnew= "ncrnaset/$trsetnew" if( ! -f $trsetnew and -f "ncrnaset/$trsetnew");
  if( -s $trsetnew ) {
    return( facount($trsetnew), $trsetnew); 
  } else {
    (my $trnewids= $trsetnew) =~ s/\.\w+$/.trids/;
    $trnewids= "ncrnaset/$trnewids" if( ! -f $trnewids and -f "ncrnaset/$trnewids");
    if(-s $trnewids) {
      my($newfa,$ntrnew)= faextract($trset,$trsetnew,$trnewids);
      return($ntrnew, $newfa); 
    }
  }
  return(0,$trsetnew);
}


=item long_seqs algo

  my($ntrnew,$trsetnew,$trsizes)= long_seqs($trname,$trset,$minsize);
  my($ntrnew3,$trlongnomrna,$trlongsizes)= long_seqs($trname, $trnomrnab, $MIN_NCRNA);
  
  env ismrna=1 $evigene/scripts/prot/aaqual.sh $trname.notokmrna.tr
  perl -ne 'BEGIN{ $MINW=$ENV{minw}||500; } if(/^>(\S+)/){ $ok=$ok{$1}; $infa=1; print if $ok; }
  elsif($infa){ print if $ok; } else { ($d,$w)=split; $ok{$d}=1 if($w>=$MINW); } ' \
    $trname.notokmrna.tr.qual $trname.notokmrna.tr > $trname.longnok.tr
  
  trsetlong=$trname.longnok.tr

=cut

sub long_seqs {
  my($trname,$trset,$minsize)= @_;
  my $trsetnew="$trname.longnok.tr"; push @tmpfiles,$trsetnew;
  my $ntrnew= 0;
  my($cmd,$err,$ok,$hin);

if(USE_recover_trset) {  
  unless($UPDATEALL) {
    ($ntrnew,$trsetnew)= recover_trset($trname,$trset,$trsetnew); # handles .trids to .tr recovery
    if($ntrnew > 0) { 
      my $trlongs= fasizes_nogap($trsetnew,"","",1); #  1=only.nt or $fasizes{$id}= join"\t",$nokay,$nt,$ngap; 
      return($ntrnew, $trsetnew, $trlongs); 
    }
  }
} else {  
  if( -s $trsetnew and not $UPDATEALL) {
    my $trlongs= fasizes_nogap($trsetnew,"","",1); #  1=only.nt or $fasizes{$id}= join"\t",$nokay,$nt,$ngap; 
    $ntrnew= scalar(keys %$trlongs);
    return($ntrnew,$trsetnew,$trlongs);
  }
}
  
  # #ncrna: FAILED at step: long_seqs(>=500) kept=/1080380, plJBND.notokmrna.tr

  # my $trsizes= fasizes_nogap($trset); #  $fasizes{$id}= join"\t",$nokay,$nt,$ngap; 
  my $trsizes= fasizes_nogap($trset,"","",1); # only.nt
  my %trlongs=(); for my $d (keys %$trsizes) { 
    my $nt= $trsizes->{$d};  $trlongs{$d}= $nt if($nt >= $minsize); 
    #  my($nok,$nt)= split "\t",$trs;  #?? nt or all trs ?
  } 
  ($trsetnew,$ntrnew)= faextract($trset,$trsetnew,\%trlongs); # grep trsizes >= $MIN_NCRNA
  # NOTE faextract() returns (trset) if no ids in trlongs
  
  return($ntrnew,$trsetnew,\%trlongs);
}

sub makeSubmergeTr {
  my($trname,$submergeh)=@_; 
  
  my($cmd,$err,$ok,$hin);
  my($nsubs,$ntr,$trsizes)=(0,0);
  # my $submergetr="$trname.longnok.tr";
  my $submergetr= $trname . "_mrg.longnok.tr"; #?

#   FIXME here? need also inputset/ aaqualf, aa, cds of subasm matching oids of trlongnomrna subsets,
#     for -merge outputs at pubseqset, refblastp
  
  if( -s $submergetr  and not $UPDATEALL ) { # recover
    $trsizes= fasizes_nogap($submergetr,"","",1); # only.nt
    $nsubs=1; $ntr= scalar(keys %$trsizes);
    return($ntr,$nsubs,$submergetr,$trsizes);
  }
  
  # @$submergeh == global @submerge
  # @submerge ==  @$submergeh from -merge subasm1,subasm2 -merge subasm3,subasm4
  # likely mixed set of paths to subset assemblies w/ ncrnaset/
  
  my @smd= map{ split/[,;\s]+/, $_ } @$submergeh; # @submerge;
  my @subtr;
  for my $smd (@smd) {  
    # my($smnctr)= finddata("$sm/ncrnaset/*.longnok.tr"); #? is .tr.gz or .trids allowed ?
    # $sm= "$sm/ncrnaset" unless($sm=~/ncrna/);
    my $sm=$smd; $sm= "$sm/ncrnaset" if( -d "$sm/ncrnaset");
    my($smdh,$smnctr)= getFileset($sm,'(tr|tr.gz)$',undef,'longnok');
    push @subtr,$smnctr if(-f $smnctr);
  }
  $nsubs= @subtr;
  return($ntr,$nsubs,$submergetr) if($nsubs<1);
  
  my(%trsizes); # ,%stroiddont need stroid? just trsizes{id} : replace %trsizes w/ $trsizes=fasizes(subnrtr)
  open(SF,'>',$submergetr);  push @tmpfiles, $submergetr;    
  for my $str (@subtr) {
    ($ok,$hin)= openRead($str);
    if($ok) { 
      my($id,$len)=(0,0);
      while(<$hin>) { 
        print SF $_; 
        if(/^>(\S+)/) { 
          $trsizes{$id}=$len if($id);  
          $id=$1; $len=0; $ntr++; 
        } else { chomp; $len += length($_); }
      } 
      close($hin); $trsizes{$id}=$len if($id);
      loggit(LOG_DEBUG,"merge $str, nt=$ntr");
    } 
  } close(SF);

  ## ?? Insert here fastanrdb submerge.tr > submerge.nrtr; mv submerge.nrtr submerge.tr;
  ## premerge longnok.tr should be nr reduced. Maybe not enough dups left to bother?
  # sub67mrg.longnok.tr  921051, tr.nr 921002 = 49 shared in sub6,7
  # sub47mrg.longnok.tr 1467462, tr.nr  1467462 = 0 shared

  my $trsizes= \%trsizes;  # use this
  my $subtragree="";
  if(1) { # for pipe data, subtr is from fastanrdb w/ dupids in header, so this will work
    $cmd="$EVIGENES/prot/make_consensus.pl $submergetr";
    $err= runcmd($cmd);
    unless($err){ $subtragree="$submergetr.consensus"; push @tmpfiles, $subtragree if(-f $subtragree); }
  }
  
  
  ## make also _mrg.longnok.aa,cds,aa.qual .. messy
  my @suba=();
  for my $smd (@smd) {  
    my $sm=$smd; $sm= "$sm/inputset" if( -d "$sm/inputset"); # problem if this isnt 
    my($smdh,$saa,$scds,$saaq);
    ($smdh,$saa)= getFileset($sm,'(aa|aa.gz)$',undef); # NOT ,$trname
    ($smdh,$scds)= getFileset($sm,'(cds|cds.gz)$',$smdh); # ,$trname
    ($smdh,$saaq)= getFileset($sm,'(aa.qual|aa.qual.gz)$',$smdh); # ,$trname
    push @suba, [$saa,$scds,$saaq] if(-f $saa or -f $scds or -f $saaq);
  }
  
  if(@suba > 0) { 
    my %outs; # openwrite _mrg.longnok.aa,cds,aa.qual
    
    sub puto { 
      my($oh,$sin,$trsizes,$istab)=@_; my $n=0; 
      my($ok,$hin)= openRead($sin); return($n) unless($ok);
      while(<$hin>) {  
        if($istab){ my($d)=split; $ok=$trsizes->{$d}||0; $n++ if($ok); } 
        elsif(/^>(\S+)/){ my $d=$1; $ok=$trsizes->{$d}||0; $n++ if($ok); } 
        print $oh $_ if($ok); 
        } 
      close($hin); return($n); 
      }
    
    my($naa,$ncds,$naq)=(0) x 3;
    for my $sf ('aa','cds','aa.qual') {
      (my $onam=$submergetr) =~ s/.\w+$//; $onam.=".$sf";
      open(my $oh,'>',$onam); $outs{$sf}= $oh; push @tmpfiles,$onam; # or erasefiles ??
    }
    for my $suba (@suba) { 
      my($saa,$scds,$saaq)= @$suba;
      $naa += puto($outs{'aa'},$saa,$trsizes,0);  
      $ncds+= puto($outs{'cds'},$scds,$trsizes,0);  
      $naq += puto($outs{'aa.qual'},$saaq,$trsizes,1);  
    } 
    for my $sf (keys %outs) { close( $outs{$sf} ); }
    loggit(LOG_DEBUG,"merge $submergetr, tr=$ntr,aa=$naa,cds=$ncds,aaq=$naq");
  }
  
  return($ntr,$nsubs,$submergetr,$trsizes);
}


#  my($ntrq,$trlongsizef)= trseq_qual($trname, $trlongnomrna, $trlongsizes, $aaqualf);
sub trseq_qual {
  my($trname,$trset, $trsizeh, $aaqualf)= @_;
  my($nts,%aaqual)=(0);
  my $trsizef= "$trset.qual"; 
  if(-s $trsizef and not $UPDATEALL) {
    open(F,$trsizef); while(<F>) { $nts++ if(/^\w/); } close(F); # $nts=`wc -l $trsizef`; chomp($nts);
    return ($nts, $trsizef);
  }
  
  ## BUG fixed .. got all zero $nok? was BAD tr/$pat/$pat/ in fasizes_nogap
  unless(ref $trsizeh) { $trsizeh= fasizes_nogap($trset); } # was BUG HERE: $fasizes{$id}= join"\t",$nokay,$nt,$ngap; 

  if( -f $aaqualf ) {
    my($ok,$hin)= openRead($aaqualf);
    if($ok){ while(<$hin>){ my @v=split; my($id)=$v[0]; if($trsizeh->{$id}){ $aaqual{$id}=\@v;} } close($hin); }
  } 
  open(SF,'>',$trsizef);  push @tmpfiles, $trsizef;  
  foreach my $id (sort keys %$trsizeh) {
    my $ts= $trsizeh->{$id};  my $aq= $aaqual{$id};
    my ($tnok,$tgap,$aaq,$tw,$ofsocp,$ofsicp)=(0) x 9;
    if(ref $aq) { ($tnok,$tgap,$aaq,$tw,$ofsocp,$ofsicp)= @{$aq}[4,2,3,4,5,6]; } # my($id,$aw,$agap,$aaq,$tw,$ofsOrCP,$ofsIfCP)=@v;
    if($ts =~ /\s/){ ($tnok,$tw,$tgap)= split" ",$ts; }
    elsif($ts=~/^\d+$/){ $tnok= $tw= $ts; } #?? fasizes_nogap(,,,1)
    print SF join("\t",$id,$tnok,$tgap,$aaq,$tw,$ofsocp,$ofsicp)."\n"; $nts++;
  }
  close(SF); 
  
  return ($nts,$trsizef);
}


=item remove_mrna_oids algo

  ($ntrnew,$trsetnew)= remove_mrna_oids($trname,$trset,$mrna);
  
  trsetnew=$trname.nomrna.tr
  grep '>' $mrna | perl -ne '($id)=m/>(\S+)/; ($od)= m/oid=([^;,\s]+)/ ? $1 :$id; print "$od\n";' > $mrna.oids
  perl -ne 'if(/^>(\S+)/){ $ok=not $nok{$1}; $infa=1; print if $ok; } elsif($infa){ print if $ok; } elsif(/^\w/){ ($d)=split; $nok{$d}=1; } ' \
   $mrna.oids $trset > $trsetnew

=cut

sub remove_mrna_oids { # STEP1a_
  my($trname,$trset,$mrna)= @_;
  
  my $trsetnew="$trname.nomrna.tr"; push @tmpfiles,$trsetnew;
  my $ntrnew= 0; my $ntrcut=0;
  my ($ok,$hin); 
  
## FIXME: not UPDATEALL here misses IDPREncrna setting from mrna .. recover where?
if(USE_recover_trset) {  
  unless($UPDATEALL) {
    ($ntrnew,$trsetnew)= recover_trset($trname,$trset,$trsetnew); # handles .trids to .tr recovery
    if($ntrnew > 0) { return($ntrnew, $trsetnew, facount($trset)); }
  }
} else {  
  if( -s $trsetnew and not $UPDATEALL) {
    $ntrnew= facount($trsetnew); my $ntotal=facount($trset);
    return($ntrnew, $trsetnew, $ntotal);
  }
}
  
  my(%mrnaoids,%mrnagid,%mrnapre,%mrnaid);  
  ($ok,$hin)= openRead($mrna); return(0) unless($ok);  # .gz ok
  while(<$hin>) { 
    if(/^>(\S+)/){ 
      my $id=$1; my($ods)= m/oid=([^;,\s]+)/;  
      map{ $mrnaoids{$_}= $id; } split(",","$id,$ods");
       
      if($id =~ m/^(\w+\D)(\d+)t(\d+)$/) {
        my($idpre,$gid,$ti)= ($1,$2,$3); 
        $mrnapre{$idpre}++; $mrnagid{$gid}++; $mrnaid{$gid."t$ti"}++;      
      } else {
        $mrnapre{$id}++; # fail evg pubid
      }
      } 
  } close($hin); 

  if(scalar(keys %mrnapre) == 1) { # set pubid vals
    my @gid= sort{ $a <=> $b } keys %mrnagid;
    my $gmax= $gid[-1];
    ($IDPREncrna)= keys %mrnapre;
    $IDBASEncrna= 1000 + 1000*int(0.5 + $gmax/1000);
    loggit(0,"ncRNA public ID: $IDPREncrna,$IDBASEncrna");
  }
  
  #? ($trsetnew,$ntrnew)= faextract($trset,$trsetnew,\%mrnaoids,'notid');
  ($ok,$hin)= openRead($trset); return(0) unless($ok);
  open(TO,'>',$trsetnew) or return(0); 
  $ok=0; 
  while(<$hin>) { 
    if(/^>(\S+)/){ $ok= $mrnaoids{$1}?0:1; 
      if($ok and my($ods)= m/oid=([^;,\s]+)/) {
        $ok=0 if(grep { $mrnaoids{$_} } split(",",$ods)); 
        }
      if($ok){ $ntrnew++; } else { $ntrcut++; }
      } 
    print TO $_ if($ok);
  } close($hin); close(TO); 

  return($ntrnew, $trsetnew, $ntrnew+$ntrcut, \%mrnaoids);
}

=item remove_bigcdsdrops

   * this works well
  
   UPD20f15: insert step to remove dropset/perfectdup,perfectfrag where CDS size is large and match:ID is in okayset/
   my($ntrnew1b,$trnomrna1b)= remove_bigcdsdrops($trname,$trnomrna,$mrna); # .gz ok
   step_log_or_fini( 0,"remove_bigcdsdrops kept=$ntrnew1b/$ntrtotal, $trnomrna1b"); 

  eg. dropset/plHILW.drop.cds.gz
  >Acmpantridba1a_sBn1l1ERR2040842idbaidbtk27Loc10 type=CDS; aalen=3783,92%,complete; clen=12237; strand=+; offs=406-11757; codepot=Code/0.15; 
     evgclass=perfectdup,drop,match:Acmpantridba1a_sBn1l1ERR2040842idbaidbtk27Loc1
  >Acmpantridba1a_sBn1l1ERR2040842idbaidbtk27Loc21 type=CDS; aalen=3563,97%,partial3; clen=10962; strand=-; offs=10689-1; codepot=Code/0.11; 
     evgclass=perfectfrag,drop,match:Acmpantridba1a_sBn1l1ERR2040842idbaidbtk67Loc35

=cut

sub remove_bigcdsdrops {
  my($trname,$trset,$mrna, $mrnaoids)= @_;  
  # reuse %mrnaoids from remove_mrna_oids()
  
  my $trsetnew="$trname.nodropbigcds.tr";  push @tmpfiles,$trsetnew;
  my $ntrnew= 0;
  my($cmd,$err,$ok,$hin);

if(USE_recover_trset) {
  unless($UPDATEALL) {
    ($ntrnew,$trsetnew)= recover_trset($trname,$trset,$trsetnew); # handles .trids to .tr recovery
    if($ntrnew > 0) { return($ntrnew, $trsetnew); }
    }
} else {  
  if( -s $trsetnew and not $UPDATEALL) {
    return(facount($trsetnew),$trsetnew);
  }
}

  # my $dropcds="dropset/$trname.drop.cds";  
  #    $dropcds="dropset/$trname.drop.cds.gz"  unless(-f $dropcds);
  my $dropcds= filegz("dropset/$trname.drop.cds");  
  return(0) unless(-s $dropcds and $mrnaoids and ref($mrnaoids) );

  my($nbigdrop,$ntrcut,%bigdropcds)=(0,0);  
  ($ok,$hin)= openRead($dropcds);  # .gz ok
  if($ok) { while(<$hin>){ 
    if(/^>(\S+)/){ my $oid=$1; 
      my($evc)= m/evgclass=([^;\s]+)/;  
      next unless($evc=~/(perfectdup|perfectfrag)/);
      
      my($aaw,$pcds)= (m/aalen=(\d+),(\d+)/) ? ($1,$2) : (m/aalen=(\d+)/)? ($1,0) : (0,0); 
      next unless($aaw > $MINBIGAA or $pcds > 65); # what %cds?
      next if($aaw < 150 and $pcds < 90); #?? minaa what?
      #x next if($aaw < $MINBIGAA and $pcds < 66); # what %cds?
      #x next if($aaw < 120 and $pcds < 90); #?? minaa what?
      
      # >oid type=CDS; aalen=257,80%,complete; clen=959; strand=+; offs=136-909;
      #? modify this to check %cds, minbigaa small if %cds is high
      #x next unless($aaw >= $MINBIGAA and $evc=~/(perfectdup|perfectfrag)/);
      
      my($mid)= $evc=~m/match:([\.\w]+)/;
      if($mrnaoids->{$mid}) { $bigdropcds{$oid}=$evc; $nbigdrop++; }
      } 
  } close($hin); }

  #? ($trsetnew,$ntrnew)= faextract($trset,$trsetnew,\%bigdropcds,'notid');
  ($ok,$hin)= openRead($trset); 
  if($ok) { 
    open(TO,'>',$trsetnew);  #a push @tmpfiles, $trsetnew;
    $ok=1; while(<$hin>) { 
    if(/^>(\S+)/){ $ok= $bigdropcds{$1}?0:1; 
      if($ok){ $ntrnew++; } else { $ntrcut++; }
      } 
    print TO $_ if($ok);
    } close($hin); close(TO); 
  }

  return($ntrnew, $trsetnew, $ntrnew+$ntrcut);
}


=item remove_mrna_aligned algo

    ($ntrnew,$trsetnew,$trsetagree)= remove_mrna_aligned($trname,$trset,$mrna);

  fastanrdb $trsetnew > $trsetnew.nr
  mv $trsetnew $trsetnew.old; mv $trsetnew.nr $trsetnew;
  $evigene/scripts/prot/make_consensus.pl $trsetnew
  # consensus transcripts n=33652 tabled in pig3c.notokmrna.nrtr.consensus
  trsetagree=$trsetnew.consensus

  makeblastdb -dbtype nucl -in $mrna -logfile /dev/null
  
  # bloptbada="-perc_identity 98 -qcov_hsp_perc 90 -culling_limit 1"
  # bloptbadb="-perc_identity 98 -qcov_hsp_perc 90  -ungapped -xdrop_ungap 4 -dust no"
  # bloptbadc="-perc_identity 98 -qcov_hsp_perc 90 "

  ** UPD/RETEST this, missing very large aligns from drops/perfdup,perffrag .. change to std blastn, btall?
  bloptnu="-perc_identity 98 -qcov_hsp_perc 90 -dust no "
  
  blastn $bloptnu -num_threads $ncpu -db $mrna -query $trsetnew -outfmt 6 -out mrnaperfaln.blastn

  perl -ne 'if(/^>(\S+)/){ $ok=not $nok{$1}; $infa=1; print if $ok; } elsif($infa){print if $ok; } elsif(/^\w/) { ($d)=split; $nok{$d}=1; }' \
    mrnaperfaln.blastn $trsetnew > $trname.notokmrna.tr

=cut

sub remove_mrna_aligned { # STEP1b_ now 1c
  my($trname,$trset,$mrna)= @_; # trset=="$trname.nomrna.tr";
  
  my $trsetnew="$trname.notokmrna.tr";  push @tmpfiles,$trsetnew;
  my $trsetagree="$trset.consensus";
  my $ntrnew= 0;
  my($cmd,$err,$ok,$hin);
  my $pident= 98; # -pHetero fixme
  
if(USE_recover_trset) {
  unless($UPDATEALL) {
    # fixme: where is trsetagree
    ($ntrnew,$trsetnew)= recover_trset($trname,$trset,$trsetnew); # handles .trids to .tr recovery
    if($ntrnew > 0) { return($ntrnew, $trsetnew,$trsetagree); }
    }
} else {  
  if( -s $trsetnew and not $UPDATEALL) {
    return(facount($trsetnew),$trsetnew,$trsetagree);
  }
}
  
  $cmd="$APPfastanrdb -i -f $trset > $trset.nr";
  $err= runcmd($cmd);
  unless($err){ rename("$trset.nr",$trset); } # orig trset is tmpfile

  $cmd="$EVIGENES/prot/make_consensus.pl $trset";
  $err= runcmd($cmd);
  $trsetagree="$trset.consensus"; push @tmpfiles, $trsetagree;
  # trap cmd.warn: consensus transcripts n=13046 tabled in plJBND.nomrna.tr.consensus

  # mrna.gz patch: gunzip -c $mrnagz | makeblastdb -title $mrna -output $mrna
  if($mrna =~ m/.gz$/) {
    my $mrnagz= $mrna; $mrna =~ s/.gz//;
    $cmd="gunzip -c $mrnagz | $APPmakeblastdb -dbtype nucl -title $mrna -out $mrna -logfile /dev/null"; # .gz NOT ok
  } else {
    $cmd="$APPmakeblastdb -dbtype nucl -in $mrna -logfile /dev/null"; # .gz NOT ok
  }
  push @erasefiles, map{ "$mrna.$_" } qw(nsq nin nhr);
  $err= runcmd($cmd); return if($err);

  # ** UPD/RETEST this, missing very large aligns from drops/perfdup,perffrag .. change to std blastn, btall?
  #above: my $usebself= $ENV{TESTmrnablast}||0; # ? TESTmrnablast UPD2222 default
  my $pctalign_trismrna= $PAL_NCRNAMIN;
  my $ralign_trismrna= $pctalign_trismrna/100;
  my $bloptself="-perc_identity $pident -evalue 1e-19 -dust no "; 

  my $bloptnu="-perc_identity $pident  -evalue 1e-19 -qcov_hsp_perc $pctalign_trismrna -dust no "; #? check opts again, maybe no -qcov, -dust yes
  my $blopt= ($usebself)? $bloptself : $bloptnu;
  
  my $blout="$trname.mrnaperf.blastn"; push @tmpfiles, $blout;

  $cmd= "$APPblastn $blopt -num_threads $NCPU -db $mrna -query $trset -outfmt 6 -out $blout";
  $err= runcmd($cmd); return if($err);

  my %ismrna; 
  if($usebself) { # add align hsps ? need tr sizes? ie 80-90% of trsize as per -qcov_hsp_perc
    my $trsizes= fasizes_nogap($trset,"","",1); # only.nt
    my($sal,$ltd,$lmd,$tdsize)=(0) x 9;
    open(B,$blout); 
    while(<B>){ if(/^\w/) { 
      my($td,$md,$pi,$al)=split; 
      if($td ne $ltd or $md ne $lmd){ $sal=0; } 
      if($td ne $ltd) { $tdsize= $trsizes->{$td}||$al; }
      $sal += $al;
      $ismrna{$td}=1 if($sal >= $ralign_trismrna * $tdsize); 
      $ltd=$td; $lmd=$md; 
      } } close(B);
    
  } else { # each align ismrna
    open(B,$blout); while(<B>){ if(/^\w/) { my($d)=split; $ismrna{$d}=1; } } close(B);
  }
  
  #? ($trsetnew,$ntrnew)= faextract($trset,$trsetnew,\%ismrna,'notid');
  ($ok,$hin)= openRead($trset); 
  if($ok) { 
    open(TO,'>',$trsetnew);  # ab: push @tmpfiles, $trsetnew;
    $ok=0; while(<$hin>) { 
    if(/^>(\S+)/){ $ok= $ismrna{$1}?0:1; 
      if($ok and my($ods)= m/oid=([^;,\s]+)/) {
        $ok=0 if(grep { $ismrna{$_} } split(",",$ods)); 
        }
      $ntrnew++ if $ok; 
      } 
    print TO $_ if($ok);
    } close($hin); close(TO); 
  }
  
  return($ntrnew,$trsetnew,$trsetagree);
}


=item ncrna_selfalign algo

  ($ntrnew, $blasttab)= ncrna_selfalign($trname,$trset, $use_altparopt)

  makeblastdb -dbtype nucl -in $trsetlong -logfile /dev/null
  
  ## FIXME odd problem due maybe to qcov_hsp_perc: no hits found for self.blast .. always should have self.tr
  ## switch to evg tr2cds self-blast opts?
  ## selfblopt="-task megablast -ungapped -xdrop_ungap 4 -dust no -perc_identity $CDSBLAST_IDENT -evalue $CDSBLAST_EVALUE "
  ## pident=95, eval=1e-5
  
  # test blastn opts, qcov_hsp_perc? 80 .. 60 ?  pctident? 98 97 96 ?
  # NOTE these opts block any seq with gaps, ie no hits even to self .. solution? dont use -qcov_hsp, use -dust ?
  bloptnu="-perc_identity 98 -qcov_hsp_perc 80 -dust no "
  
  echo blastn $bloptnu -num_threads $ncpu -db $trsetlong -query $trsetlong -outfmt 7 -out $trname.self98.blastn

=cut

sub ncrna_blastopt {
  my($trname, $use_altparopt, $ungapped, $pminalign)= @_; 

  # altparclassify.pl uses this, use same here?
  my $NCBLAST_IDENT=  $ENV{pctident} || 97; # option
  my $NCBLAST_EVALUE= $ENV{evalue} || 1e-9; # option
  
  my $bloptself="-task megablast -dust no -perc_identity $NCBLAST_IDENT -evalue $NCBLAST_EVALUE "; 
  $bloptself .=" -ungapped -xdrop_ungap 4 " if($ungapped);
          #^^ this way assumes will use btall sum of gapped hsps
  
  $pminalign ||= $PAL_NCRNAMIN;
  my $bloptnu="-perc_identity $NCBLAST_IDENT -evalue $NCBLAST_EVALUE -qcov_hsp_perc $pminalign -dust no "; #??
  
  return ($use_altparopt) ? $bloptself : $bloptnu;  
}

sub ncrna_selfalign {
  my($trname,$trset, $use_altparopt)= @_; 

  # altparclassify.pl uses this, use same here?
  my $NCBLAST_IDENT=  $ENV{pctident} || 97; # option
  my $NCBLAST_EVALUE= $ENV{evalue} || 1e-9; # option
  my $selfblopt="-task megablast -ungapped -xdrop_ungap 4 -dust no -perc_identity $NCBLAST_IDENT -evalue $NCBLAST_EVALUE "; 
  my $nuselfblopt="-perc_identity $NCBLAST_IDENT -evalue $NCBLAST_EVALUE -dust no "; # TEST? does it improve agreements

  # my $pminalign= $PAL_NCRNAMIN;
  my $bloptnu="-perc_identity $NCBLAST_IDENT -qcov_hsp_perc $PAL_NCRNAMIN -dust no "; #??
  
  my $blopt= ($use_altparopt) ? $selfblopt : $bloptnu; #??

  # use constant UNGAPPED => 1;
  # my $blopt= ncrna_blastopt($trname, $use_altparopt, UNGAPPED);
  
  # my $trsetnew="$trname.self98"; # 98 => $CDSBLAST_IDENT
  (my $trsetnew= $trset) =~ s/\.\w+$//; $trsetnew .= ".self$NCBLAST_IDENT";
  my $blout="$trsetnew.blastn";  
  my $ntrnew= 0;
  my($cmd,$err,$ok,$hin);
  if(not $UPDATEALL and ! -f $blout and -f "ncrnaset/$blout") { $blout= "ncrnaset/$blout"; }
  if( -s $blout and not $UPDATEALL) {
    ($ntrnew) = `grep -c '# Query' $blout`; chomp($ntrnew); #? need this grep?
    return($ntrnew, $blout);
  }
  
  $cmd="$APPmakeblastdb -dbtype nucl -in $trset -logfile /dev/null";
  $err= runcmd($cmd); return if($err);

  $blout="$trsetnew.blastn"; push @tmpfiles, $blout;
  $cmd= "$APPblastn $blopt -num_threads $NCPU -db $trset -query $trset -outfmt 7 -out $blout";
  $err= runcmd($cmd); return if($err);

  push @erasefiles, map{ "$trset.$_" } qw(nsq nin nhr);
  # for my $suf (qw(nsq nin nhr)) { unlink("trset.$suf"); } # blast idx  
  ($ntrnew) = `grep -c '# Query' $blout`; chomp($ntrnew);
  return ($ntrnew, $blout); #? or parse here
}

=item ncrna_replicates algo

  ($ntrnew, $trsetnew)= ncrna_replicates($trname,$trselfblast,$trsetagree,$trset);

  .. dont need/want  $trname.self98.blagree tmpfile here ?
  .. only need $trname.self98.blagree.trids, maybe as .consensus table as per make_consensus
  
  perl -ne '...' $trsetagree $trname.self98.blastn > $trname.self98.blagree

  grep 'replace=' $trname.self98.blagree | cut -f12 | sed 's/replace=//;' | sort -u > $trname.self98.blagree.dropids
  perl -ne '($d)=@v=split; if(@v==1){ $nok{$d}=1 } else { print "$d\n" unless($nok{$d}); }' \
    $trname.self98.blagree.dropids  $trname.self98.blagree | sort -u > $trname.self98.blagree.trids
  
  perl -ne 'if(/^>(\S+)/){ $ok=$ok{$1}; $infa=1; print if $ok; } elsif($infa){print if $ok; } elsif(/^\w/) { ($d)=split; $ok{$d}=1; }' \
    $trname.self98.blagree.trids $trsetlong > $trname.uniqrna.tr

=cut

sub ncrna_replicates {
  my($trname,$trselfblast,$trsetagree,$trset,$trsizes)= @_; 
  # my($ntrnew5, $truniqrna)  = ncrna_replicates($trname,$trselfblast,$trsetagree,$trlongnomrna,$trlongsizes);
  ## FAILING HERE blagree == 0 .. needs test .. typo if( -f bareword ) not $trselfblast

  my $check_align = ($trsizes and ref $trsizes) ? 1 : 0;#? option

  use constant RepFromBtall => 1;  # probably want this method
  
  (my $btall=$trselfblast) =~ s/\.\w+$/.btall/; # make/use this table for blagree ..
  (my $blagree=$trselfblast) =~ s/\.\w+$/.blagree/;
  my $trsetnew="$trname.uniqrna.tr";
  my $ntrnew= 0;
  my($cmd,$err,$ok,$hin);
  if( -s $trsetnew and not $UPDATEALL) {
    return(facount($trsetnew), $trsetnew);
  }

  our($agreeout,%agree,%blagree,%blreplace,%rsn,@rds,%didid,%did);
  open($agreeout,'>',$blagree); push @tmpfiles,$blagree;
  
  # write to $trname.self98.blagree ? as .consensus table as per make_consensus
  ## BUG trids missing Loc .. consensusof() bug
  ## FIXME block replace= for higher value nr agree{} set
  ## eg: arab6roo3dn4msoapk103loc4405t2 4 rep (soap,velv) ..
  ## replaced at blastn align by arab6roo3dntatrinLocDN33581c0g1t6 no reps.. but scored for 4 of prior.

  sub putagree { 
    my($ltd,$topal)=@_; 
    our($agreeout,%agree,%blagree,%blreplace,%rsn,@rds,%didid,%did);
    my @rsn=sort keys %rsn;  my $nput=0;
    my $nagree= @rsn + $agree{$ltd};
    if($nagree > 1) {
      my $pok=1; my $repok=0; # nu
      if(my $oal= $did{$ltd}) {
        my $od= $didid{$ltd};
        my $agr= $agree{$ltd}||0; my $ogr= $agree{$od} || 0;
        my $oblg= $blagree{$od}||0;
        if($agr == 0 and $ogr == 0) { $agr=$nagree; $ogr=$oblg; }
        if( $topal <= $oal and $agr <= $ogr ) { $pok= -1; }
        elsif($topal > $oal and $agr >= $ogr ) { $pok= 2; $repok=1 unless($oblg>$nagree); }
        elsif($topal > $oal and $agr < $ogr ) { $pok= ($agr>1) ? 2 : 0; } 
      }
      if($pok > 0) {      
        my $rsv= join",",map{ $_.":".$rsn{$_}; } @rsn; 
        $rsv = "equals" unless(@rsn);
        my $repval=0; 
        if($repok and my $od=$didid{$ltd}) { $repval="replace=$od"; $blreplace{$od}=$ltd; }
        $blagree{$ltd}=$nagree; # local dont bother w/ agreeout
        print $agreeout join("\t",$ltd,$nagree,$rsv,"aln=$topal",$repval)."\n"; $nput++;
        $didid{$ltd}=$ltd; $did{$ltd}=$topal; 
        for my $d (@rds) { if($did{$d} < $topal) { $didid{$d}=$ltd; $did{$d}=$topal; }  }
      }
    } 
    return($nput);
  }
  #------------------------------
  
  my ($nag)= (0);
  if(-f $trsetagree) {
    ($ok,$hin)= openRead($trsetagree);
    while(<$hin>) { next if(/^\W/);  my($td,$nagr)=split;  $agree{$td}=$nagr; $nag++; }
    close($hin);
    loggit(0,"nagree=$nag in $trsetagree");
  }
  
  ## Maybe replace this w/ makeblastscore btall table parse .. simplifies decisioh,
  ## use sametr ==  min( align/tlen, align/rlen) > 0.90 and min(rlen/tlen, tlen/rlen) > 0.90
 
  if(RepFromBtall and -f $trselfblast) {
    #  $evigene/scripts/makeblastscore3.pl -each -needlen -pminlow 0.5 -sizes bevgc_evg3weed1rd.longnok.tr.qual bevgc_evg3weed1rd.longnok.self97.blastn > bevgc_evg3weed1rd.longnok.self97.btall
    my $trsizef="$trset.qual"; #?? CHECK
    unless(-f $trsizef) {
      if($trsizes and ref $trsizes) {
        open(F,'>', $trsizef); 
        for my $id (sort keys %$trsizes){ print F $id,"\t",$trsizes->{$id},"\n"; } close(F);
      } 
    }
    
    my $cmd= "$EVIGENES/makeblastscore3.pl -each -needlen -pminlow 0.5 -sizes $trsizef $trselfblast > $btall";
    my $err= runcmd($cmd);
    push @tmpfiles, $btall;
    
    my $MINPAL=$ENV{blagree_pal} || 0.80; # smaller? larger?
    my $MINPRW=$ENV{blagree_prw} || 0.70; #? smaller

    my $nokmer= ($ENV{'conkmer'})?0:1; # make_consensus.pl:consensusof() ($aconsensus =~ m/kmer/) ..
    my($ltd,$lrd,$topal,$sumal)= (0) x 9;
    ($ok,$hin)= openRead($btall);
    while(<$hin>) { 
      next if(/^\W/);  
      my($td,$rd,$bs,$ida,$aln,$tw,$rw)=split; # blast btall table OR agree table
      next if($td eq $rd or $tw<1 or $rw<1);
      my $pal= ($tw>$rw)? $aln/$tw : $aln/$rw;
      my $prw= ($tw>$rw)? $rw/$tw  : $tw/$rw;
      ## cancel this skip if $agree{$td} .. but dont add rd rsn
      my $ok = ($pal < $MINPAL or $prw < $MINPRW) ? 0 : 1;
    
      if($td ne $ltd) { $ntrnew += putagree($ltd,$topal) if($ltd); %rsn=@rds=(); } 
      $ltd=$td; $lrd=$rd;
      if($ok) {
        $topal= $aln if($aln > $topal); # $tpal=$pal; $tprw=$prw; 
        foreach my $sd ($td,$rd) {  
          my $st= $sd;
          if($st=~s/[Ll]oc.*$//) { $st =~ s/k\d+$//; } 
          else { $st=substr($sd,0,9); }
          $rsn{$st}++;
        }
        push @rds,$rd;
      }        
    
    } close($hin);
    if(1) { $ntrnew += putagree($ltd,$topal) if($ltd); %rsn=@rds=(); }        
  } # RepFromBtall
 
  if(not RepFromBtall and -f $trselfblast) { # if not, putagree(%agree) ??
    ## this should be from trasm-consensus parser:
    ##  my($s)= (m/^(\w+)k\d+[Ll]oc.*$/)? $1 : substr($_,0,9);
    my $nokmer= ($ENV{'conkmer'})?0:1; # make_consensus.pl:consensusof() ($aconsensus =~ m/kmer/) ..
    
    my($ltd,$lrd,$topal,$sumal)= (0) x 9;
    ($ok,$hin)= openRead($trselfblast);
    while(<$hin>) { 
      next if(/^\W/);  
      my($td,$rd,$pi,$al)=split; next if($td eq $rd);
 
      if($td ne $ltd) { $ntrnew += putagree($ltd,$topal) if($ltd); %rsn=@rds=(); $sumal=$topal=$lrd=0; } 
      $sumal=0 if($rd ne $lrd);
      $sumal += $al; # multiple hsp per td x rd
      
      # need align size / tr size check, unless using blastn -qcov_hsp_pct to enforce long align
      # if this blastn has align split to hsps, need to add hsps .. as with makeblastscore.pl
      my $ok=1;
      if($check_align and not $agree{$td}) { 
        my $tw= $trsizes->{$td}||0;  # bug bad trsizes ?
        my $pal= ($tw>0) ? $sumal/$tw : 0; # use sum align here for multiple hsp per td x rd
        $ok= ($pal*100 >= $PAL_NCRNAMIN); 
        # $ok=1 if($agree{$td});
        # next unless($ok); 
        }
      
      $ltd=$td; $lrd=$rd;
      if($ok) {
        $topal= $sumal if($sumal > $topal);
        # see make_consensus.pl:consensusof()
        foreach my $sd ($td,$rd) {  #?? this changes td, rd ?? shouldnt
          my $st= $sd;
          if($st=~s/[Ll]oc.*$//) { $st =~ s/k\d+$// if($nokmer or $st=~/idba/); } 
          else { $st=substr($sd,0,9); }
          $rsn{$st}++;
        }
        #o my($ts,$rs)= map { my($s)= (m/^(\w+)k\d+[Ll]oc.*$/)? $1 : substr($_,0,9); $rsn{$s}++; $s; } ($td,$rd);  
        push @rds,$rd; #  unless($rd eq $lrd); ## AND ok lrd ..
      }  
        
      #? $ltd=$td; $lrd=$rd; # mangled from above s change??
      } close($hin);
    $ntrnew += putagree($ltd,$topal) if($ltd);
  }  # not RepFromBtall
  
  close($agreeout);
  
  # write list to $trname.self98.blagree.trids ? or just refer to agreeout table
  my @truniqids= sort grep{ not $blreplace{$_} }  keys %blagree;
  $trsetnew="$trname.uniqrna.tr"; push @tmpfiles, $trsetnew;
  ($trsetnew,$ntrnew)= faextract($trset,$trsetnew,\@truniqids) if(@truniqids);
  # NOTE faextract() returns (trset) if no ids in trlongs
  
  return ($ntrnew, $trsetnew);  
}



=item ncrna_classgene / classifylocus

  change output table to match pubids? for merging w/ that:
    pubtrid oid pubgene alti [drop|cull]altclass aaqual pidn/aln notes/tscore/tscorevec
  
=cut

my($didclhdr);

sub ncrna_classgene { # from ncrna_altparscore.pl
  my($outh, $nout, $dgeneid, $dgenesar, $hasduphash, $hasokcds)=@_; #drop: $havedups,
  my($ng,$maxlen,$nok,$ndrop)=(0) x 9; 
  my(%tsc,%tsv,%tscvec,%tdid);
  return($nok,$ndrop) unless(@$dgenesar);

  ## NOW allevd.hdr: IDtrasm	trlen	aalen	pcds	cdpot	agree	dglocus	dgclass
  ## Maybe use @$dgenesar == hash of qualkey=>qualval ? eg fir $TEST_OKCDS:  add  cdsaln
  ##? add col for hasokcds{td} == align to okay.cds
  
  my (@hdr,%ihdr); # IDtrasm >> originalID better
  # pubids: #Public_mRNA_ID	originalID	PublicGeneID	AltNum	Class	AAqual	pIdAln	Notes	Oids

  my @DEFhdr=qw(IDtrasm trlen aalen pcds cdpot	agree	dglocus dgclass); 
  push @DEFhdr, 'cdsaln' if($hasokcds); #$TEST_OKCDS: add hasokcds col here 
  @hdr= @DEFhdr;
  #x if($colhdr and ref($colhdr) =~ /ARRAY/){ @hdr= @$colhdr; } else {  }
  #x for my $i (0..$#hdr){ $ihdr{ $hdr[$i] }= 1+$i; }
  
  #X these are bad .. change to @$dgenesar == hash of qualkey=>qualval
  #X sub valof{ my($tsv,$k)=@_; if(my $i= $ihdr{$k}){ return $$tsv[$i-1] || 0; } else { return 0; } } 
  #X sub setvalof{ my($tsv,$k,$val)=@_; if(my $i= $ihdr{$k}){  $$tsv[$i-1]=$val; } } 
  # my($td,$trlen,$aalen,$pcds,$cdpot,$agree,$dgid,$dgcla,$cdsaln)= map{ valof($tsv,$_) } @DEFhdr;
  
  #  WT may be option? report in out table?
  # my %WT4d=( trlen=> 0.50, pcds => 0.25, cdpot => 0.25, agree => 0.25 ); 
  my %WT5e=( trlen=> 0.70, pcds => 0.15, cdpot => 0.15, agree => 0.25 ); 
  my %WT6f=( trlen=> 0.70, pcds => 0.15, cdpot => 0.15, agree => 0.25, notcds=> 0.25 ); 
  my %WT7g=( trlen=> 0.70, pcds => 0.15, cdpot => 0.15, agree => 0.25, cdsaln=> -0.25 ); 
  my %WT= %WT7g;
  
  # my @dgenes= @$dgenesar;
  for my $tsv (@$dgenesar) {
    my($td,$trlen,$aalen,$pcds,$cdpot,$agree,$dgid,$dgcla)= @$tsv;
    # my($trlen)= valof($tsv,'trlen'); # bad
    $maxlen=$trlen if($trlen>$maxlen); $ng++;
  }
  return(0) unless($ng>0 and $maxlen>0); # Urgh: maxlen==0 
  
  # calc trscore for ranking best > worst
  for my $tsv (@$dgenesar) {
    my($td,$trlen,$aalen,$pcds,$cdpot,$agree,$dgid,$dgcla,$cdsaln)= @$tsv;

    # scale vars to approx 1..100  range, 100 is best score
    my $trlensc= int(0.5 + 100*$trlen/$maxlen);  # 10..100
    my $putr   = 100 - $pcds;  # 10 .. 100
    my $ncpot  = int(100*(1 - $cdpot));  # -50 .. 70 ?
    $agree     = 10*$agree; # 20..60 ?
    
    #?? WT{trlen} may be too low vs others .. WT pcds/cdpot too high?
    ##  saves some rather short alts (10% of longtr) via high score from pcds/cdpot
    my $tscorevec= join",",$trlensc,$putr,$ncpot,$agree;
    my $tscore = $trlensc * $WT{trlen} + $putr * $WT{pcds} + $ncpot * $WT{cdpot} + $agree * $WT{agree};
    if($hasokcds) { 
      $cdsaln ||= 0; 
      my($okid)= ($cdsaln=~s/,(.*)$//) ? $1 : 0;  
      $cdsaln=100 if($cdsaln>100); 
      
      #? if cdsaln > 70..80, this should be dropped as redundant w/ okcds , use -WT or flag drop?
      # OR these are valid mRNA/CDS with long UTR that now bumps them into ncrna class .. relocus by good CDS align?
      # preserve cdsaln,okid
      
      # negative WT.cdsaln now: -0.25
      $tscore +=  $cdsaln * $WT{cdsaln}; $tscorevec.=",$cdsaln";  
      #o my $notcds = int(100 - $cdsaln); # maybe should be 100/0 value .. any scored cdsaln is bad/dupl qual?
      #o $tscore +=  $notcds * $WT{notcds}; $tscorevec.=",$notcds";  
      }
    
    $tsc{$td} = $tscore; $tscvec{$td} = $tscorevec; $tsv{$td}= $tsv; 
  }
  
  my @tdo= sort{ $tsc{$b} <=> $tsc{$a} } keys %tsc; 
  my $nt=@tdo;
  my $td1= $tdo[0];
  my $tsv1= $tsv{$td1}; 
  my $tscvec1= $tscvec{$td1}; 
  my $tsc1 = $tsc{$td1}; 
  my($tlen1)= $tscvec1=~m/^(\d+)/;
  
  #     my($td,$trlen,$aalen,$pcds,$cdpot,$tagree1,$tgid,$dgcla,$cdsaln)= @$tsv;
  my($tagree1)= $$tsv1[5];
  my $tgid= $$tsv1[6]; # must be same for all @tdo
  # my($tagree1)= valof($tsv1,'agree');
  # my($tgid)= valof($tsv1,'dglocus');
  my($mlong,$mpar,$magree)=(0,0,0);
  my $idpre= $IDPREncrna || "EVn"; # EVr EVm EVn .. which?
  
  for my $i (0..$#tdo) {
    my $td=$tdo[$i]; my $tsv=$tsv{$td}; 
    my $tscore= sprintf "%.1f", $tsc{$td}; 
    my $tscorevec= $tscvec{$td};
    
    my($tdX,$trlen,$aalen,$pcds,$cdpot,$tagree,$dgid,$tcla,$cdsaln,$aaqualX)= @$tsv;
    # my $tcla= $$tsv[7]; # DANG was 6 == dgeneID
    #  my $tagree= $$tsv[5];
    # my($tcla)= valof($tsv,'dgclass');
    # my($tagree)= valof($tsv,'agree');
    my($tlen)= $tscorevec=~m/^(\d+)/;
    
    # classify, add drop_redundant using table of nearperfect matches from self.btall
    # ie. perfdupl and perffrag are in drop set as per tr2aacds, 1st of id pair in this tscore order wins
    # maybe add okay/drop column as per trclass, or use 'drop|cull' prefix on class as per pubids 
    
    # mainuni == uni == noclass, reuse noclass?
    # mainpar == new subclass, top-scored ~paralog
    # mainlong == keep-alt as longest, revert to 'alt' class?
    
    my($keep,$drop)= (0,0); # count to decide class prefix
    if($i==0){ $keep++; } 
    my $cla= ($nt==1) ? "mainuni" : ($i==0) ? "main" : "alt";
    if($cla eq "alt" and $tlen == 100 and $tlen1 < 98) { unless($mlong++){ $cla="altlong"; $keep++; } }
    # altag/tagree save may be unwanted .. 
    if($cla eq "alt" and $tagree > 1 and $tagree1 == 0) { unless($magree++){ $cla="altag"; $keep++; } }
    if($cla eq "alt" and $tcla eq "par") { $cla= "altpar";  unless($mpar++) { $keep++; } }
    if($tscore < $MINSCORE) { $drop++; $keep=0; } 
    elsif($cla =~ /^alt/ and $tscore < $MINALT * $tsc1) { $drop++; }

    my($isdup,$dupof)=(0,0);
    if(exists $hasduphash->{$td}) { # $havedups and ..
      for my $d (keys %tdid){ if($isdup= $hasduphash->{$td}{$d}){ $dupof=$d; last; } }
      if($isdup) { $drop++; $cla .= $isdup; } # add value of hasdup to class: ($isdup=~/frag/)?"frag":"dup"; 
    }
    
    # my $okdrop=""; # class prefix: okay = "", drop = "drop", cull = "cull" 
    my($okdrop,$okval)=("",0);
    if($drop > 0 and $keep==0) { $okdrop="drop"; $okval=-1; $ndrop++; }
    else { $okdrop=""; $okval=1; $nok++; }
    $cla=  $okdrop . $cla;
    #o $$tsv[7]= $cla; # replace $tcla # DANG was 6 wrong col.
    # setvalof($tsv,'dgclass',$okdrop . $cla);
    
    my $ialt= 1+$i;
    my $geneid= $idpre . sprintf "%06d", $tgid;
    my $pubid = $geneid . "t$ialt";
    
    unless($didclhdr++) { 
      #chng to pubids? #Public_mRNA_ID	originalID	PublicGeneID	AltNum	Class	AAqual	pIdAln	Notes	Oids
      #O print $outh join("\t","PublicID",@hdr,"trscore","scorevec")."\n";
      #o my @addc= qw(trlen aalen pcds cdpot agree cdsaln); # change this..
      #o my @addc= qw(trlen aalen); # change this..
      #o print $outh join("\t",@pubc,"trscore","scorevec",@addc)."\n";
      
      my @pubc= qw(PublicID	originalID	PublicGeneID	AltNum	Class AAqual TRqual Notes);
      print $outh "#".join("\t",@pubc)."\n";
      
      my $wts= join", ", grep /\w/, map{ ($WT{$_}) ? "$_=".$WT{$_} : "" } @hdr; 
      print $outh "#tscore_weights: $wts\n" if($wts); 
      }
      
    #o my @addc= ($trlen,$aalen,$pcds,$cdpot,$tagree,$cdsaln); # change this..
    #o my @addc= ($trlen,"$aalen,$pcds%"); # change this.. into Notes format = taga:vala,tagb:valb,..
    #o print $outh join("\t",$pubid,@$tsv,$tscore,$tscorevec)."\n"; 
    #o print $outh join("\t", $pubid, $td, $geneid, $ialt, $cla, $tscore,$tscorevec,@addc)."\n"; 
    my $aaqual="$aalen,$pcds%,na"; # add ,complete|partial 
    $aaqual=$aaqualX if($aaqualX and $aaqualX =~ m/,\d+%,/);# preserved val>
    
    my $trqual=$trlen; # or? "$trlen,cp$cdpot";
    my @notes=();
    push @notes, "aaref:$cdsaln" if($cdsaln =~ /,/);
    push @notes, "dupof:$dupof" if($dupof);
    push @notes, "agree:$tagree" if($tagree > 1);
    push @notes, "tscore:$tscore";
    push @notes, "scorevec:$tscorevec" if($debug); 
    my $notes= join",", map{ s=,=/=g; $_ } @notes;  
    
    print $outh join("\t", $pubid, $td, $geneid, $ialt, $cla, $aaqual, $trqual, $notes)."\n";
    
    $tdid{$td}++;#? record okay/drop here for dups? 
    # $tdid{$td}= $okval; # ( $okdrop eq "drop" ) ? -1 : ( $okdrop eq "cull" ) ? -2 : 1;
  }
  return($nok,$ndrop);
}


=item ncrna_classgenes

  v2: final step? ncrna_classgene(@dgenetrs), where @dgenetrs are all trset in gene group, w/ evidence
   classifier weights evidence for rank by trscore, keeps/drops alt/par of gene group depending on scores
   output table in publicset/pubids format? w/ class 'main/alt/noclass=uni' and 'drop|cull' qualifier
   
   ($ngeneok,$ntrok,$ntrdrop)= ncrna_classgenes($ngene,$genetab,$allevdtab) : read evdtab, each tr sorted by genetab dgene ids, with evidence
      my($nok,$ndrop)= ncrna_classgene($outputh, $dgeneid,\@dgenes,$hasduphash);
   
   update ($ntrnew5, $truniqrna) removing drops from classgenes

** FIXME: need to be sure of allevdtab columns, match here using header? row 1
human18ncx.longnok.allevd.tab
IDtrasm	trlen	aalen	pcds	cdpot	agree	dglocus	dgclass
humang010008t1	3070	103	10	0.464	0	000694	main
humang010008t3	2929	103	10	0.464	0	000694	alt
humang010008t4	3025	103	10	0.492	0	000694	alt
humang010008t5	2875	103	10	0.464	0	000694	alt

=cut

sub ncrna_classgenes {
  my($trname, $trset, $genetab, $allevdtab, $hasduphash)= @_;
  # genetab not used here, only allevdtab that should contain genetab data
  
  (my $outclass=$allevdtab) =~ s/.\w+$/.ncrna_class/; # change this .. pubids-like, class?
  my $trsetnew=$outclass; # ??
  my $ntrnew= 0; # == $nloc or $snok ?
  my($cmd,$err,$ok,$hin);
  my($nloc,$nok,$ndrop,$ldglocus,$snok,$sndrop)=(0) x 9;
  
  if(not $UPDATEALL and ! -f $outclass and -f "ncrnaset/$outclass") { $outclass= "ncrnaset/$outclass"; }
  if( -s $outclass and not $UPDATEALL) {
    ($ok,$hin)= openRead($outclass);    
    while(<$hin>){ next if(/^\W/); 
      my($pid,$oid,$gid,$ti,$cla)= split;
      if($cla =~ /^drop/){ $sndrop++; } else { $snok++; }
      $nloc++ if($gid ne $ldglocus);
      $ldglocus= $gid;
      } close($hin);
    return( $nloc, $snok, $sndrop, $outclass);  
  }

  #evd cols: (ID trlen aalen pcds cdpot agree dglocus dgclass);
  my(@hdr,@dgenes);
  $hasduphash = {} unless(ref($hasduphash));
  
  my($nout,$outh)=(0);
  open($outh,'>',$outclass); push @tmpfiles, $outclass;
  
  my $hdr=`head -1 $allevdtab`; chomp($hdr); @hdr= split" ",$hdr; # not via sort
  my $hascdsaln= grep(/cdsaln/, @hdr); #?? pass to classgene()
  
  $cmd="sort -k7,7 -k2,2nr -k1,1 $allevdtab |"; # fixme : dgene now always col 7 ?
  open($hin,$cmd) or loggit(LOG_DIE,"ncrna_classgenes: sort $allevdtab");
  while(<$hin>) { 
    next if(/^\W/);  
    my @v= split; 
    if(/^ID/){ next; } # @hdr=@v;  NOT 1st row due to sort; use to get val cols ;
    my($td,$trlen,$aalen,$pcds,$cdpot,$agree,$dglocus,$dgclass)=@v;
    #old: my($td,$trlen,$pcds,$cdpot,$agree,$dgid,$dgcla)= @tsv= @v[0,1,3,5,6,11,12];
  
    if($dglocus ne $ldglocus) { 
      if(@dgenes) {
      ($nok,$ndrop)= ncrna_classgene($outh, $nout, $ldglocus, \@dgenes, $hasduphash, $hascdsaln); # \@hdr
      $nout++; $nloc++ if($nok); $snok+=$nok; $sndrop+=$ndrop;
      }
      @dgenes=(); 
      }
    push @dgenes, [@v]; $ldglocus=$dglocus; 
  }
  close($hin);
  
  ($nok,$ndrop)= ncrna_classgene($outh, $nout, $ldglocus, \@dgenes, $hasduphash, $hascdsaln); # \@hdr
  $nout++; $nloc++ if($nok); $snok+=$nok; $sndrop+=$ndrop; 
  close($outh);
  
  return($nloc,$snok,$sndrop,$outclass);  
}

sub ncrna_pubseqset {
  my($trname,$trset,$pubidtab)= @_;  
  
  my $trsetnew="$trname.ncrna_pub.fa"; # publicset/ suffix
  # my $trsetnew="$trname.okay.ncrna";   # okayset/ suffix ? which
  (my $trids=$trsetnew) =~ s/.\w+$/.trids/; # cut of col2 of $pubidtab, removing drops. dont really need
  
  ## Also, extract .aa, .cds from inputset/trname.aa,cds.gz unless/if option 
  ## .. if aasize > MINAA, need inputset/*.{aa,cds}[.gz]
  my ($naddseq,%addseq)= (0);
  
  for my $seq (qw(aa cds)) {
    my $ins= filegz( "inputset/$trname.$seq"); 
    # $ins .= ".gz" if( ! -f $ins and -f "$ins.gz");
    
    if($DOMERGE) {  # FIXME: look where? for trname_mrg.nclong.aa,cds  see makeSubmergeTr(); also makes aa,cds
      (my $inset= $trset) =~ s/\.w+$/.$seq/;
      $ins= $inset if( -f $inset);      
    } 
    
    if(-f $ins) { 
      #?? what suffix? trname.ncaa_pub.fa trname.nccds_pub.fa; trname.ncrna_aa.fa trname.ncrna_pub.aa
      (my $outs= $trsetnew) =~ s/ncrna/nc$seq/; 
      $addseq{$seq}= "$ins\t$outs"; $naddseq++;
    }
  }
  
  my $ntrnew= 0; my $ntrcut=0;
  my($cmd,$err,$ok,$hin);
  if(not $UPDATEALL and ! -f $trsetnew and -f "ncrnaset/$trsetnew") { $trsetnew= "ncrnaset/$trsetnew"; }
  if( -s $trsetnew and not $UPDATEALL) {
    return(facount($trsetnew),$trsetnew);
  }

  my(%pubid,%puban,%drops);
  ($ok,$hin)= openRead($pubidtab);  unless($ok){ loggit(1,"pubidtab bad: $pubidtab"); return; }
  # qw(PublicID	originalID	PublicGeneID	AltNum	Class AAqual TRqual Notes);
  while(<$hin>) { 
    next if(/^\W/);
    my($pubid,$oid,$gid,$ti,$cla,$aaq,$trlen,$notes)=split"\t";
    chomp($notes); # notes= aaref: agree: dupid: tscore: .. other
    my($aw,$pcds,$ac)= split",",$aaq;
    
    ## FIXME: need some standard for nctype class, aaq: utrpoor/utrbad useful, package aaqual stat?
    my $nctype= ($aw > 120 and $pcds > 60)?"misc_RNA":"ncRNA"; # other quals to call type? codepot? aaref?
    
    $pubid{$oid}= $pubid; 
    $puban{$oid}= "type=$nctype; aalen=$aaq; clen=$trlen; evgclass=$cla; notes=$notes;";
    $drops{$oid}=$cla if($cla =~ /^drop/);
  } close($hin); 

  # write pubid{oid} = pubid to pubset.trids to match other subset.trids, dont really need but for balance
  open(SF,'>',$trids);  push @tmpfiles, $trids;  
  foreach my $oid (grep { not $drops{$_} } sort keys %pubid) { print SF "$oid\n"; } close(SF); 

  ($ok,$hin)= openRead($trset); 
  unless($ok){ loggit(1,"trset bad: $trset"); return; }
  open(TO,'>',$trsetnew); push @tmpfiles, $trsetnew; # ? @tmpfiles now == ncrnaset/
  $ok=0;
  while(<$hin>) { 
    if(/^>(\S+)/) { 
      my $oid=$1; my $pd= $pubid{$oid}; 
      $ok=($pd and not $drops{$oid})?1:0; 
      unless($ok){ $ntrcut++; next; }
      my $an= $puban{$oid}||"type=ncRNA;"; 
      s/^>.*$/>$pd $an oid=$oid/;
      $ntrnew++; 
      } 
    print TO $_ if($ok);
  } close($hin); close(TO); 
 
  # merge w/ above ncrna output; limit to aasize >= MINAA_NCRNA
  my $ncaaset="";
  for my $seq (sort keys %addseq) {
    my $stype= ($seq eq 'aa')?'protein':$seq;
    my($ins,$outs)= split"\t", $addseq{$seq};
    ($ok,$hin)= openRead($ins); unless($ok){ loggit(1,"trset bad: $ins");  next; }
    open(TO,'>',$outs); push @tmpfiles, $outs;  
    my $nok=0;
    while(<$hin>) { 
      if(/^>(\S+)/) { 
        my $oid=$1; my $pd= $pubid{$oid}; 
        $ok=($pd and not $drops{$oid})?1:0; 
        if($ok){ 
          my($aw)= m/aalen=(\d+)/?$1:0; 
          $ok=0 if($aw>0 and $aw < $MINAA_NCRNA);
        }
        next unless($ok); $nok++;
        my $an= $puban{$oid}||"type=ncRNA;"; 
        $an =~ s/type=\w+/type=$stype/;
        s/^>.*$/>$pd $an oid=$oid/;
        } 
      print TO $_ if($ok);
    } close($hin); close(TO); 
    $ncaaset= $outs if($seq eq 'aa' and $nok > 0);
  }
  
  return($ntrnew, $trsetnew, $ncaaset, $ntrnew+$ntrcut);
}


=item ncrna_aauniq_refblast
  
  this is for tr2ncrna pipe, equiv to sra2genes SCRIPT_ncaablastp
  
  
  this probably fits better into tr2ncrna pipe, than in sra2genes following tr2ncrna.
  
  blastp ncrnaset/ncaa x refaa, check for uniq ref hits not in okayset.aa x refaa (btall)
  eg.  aaset=ncrnaset/plEFMS.ncaa_pub.fa

  Note this uses temp  IDprefix 'EVn' for ncrnaset .. change to that?
gunzip -c ../aaeval/refgenes-plEFMS.okay.btall.gz | cat plEFMSncaa_refplant.btalln - | \
perl -ne 'next unless(/^Tortax/);
($td,$rd,$bs,$idn,$al,$tw,$rw)=@v=split; $sc=$bs;
($rg=$rd)=~s/\.\d+$//;  if($td=~/EVn/){ $osc=$topn{$rg}; if($sc>$osc) {
$topa{$rg}=[@v];  $topn{$rg}=$sc; } } else { if($osc=$topn{$rg}) {
$osp=$topp{$rg}||0; $pok=($sc >= $osc - 1 and $sc > $osp); $ppok=($sc
> $osp); if($pok){ $topp{$rg}=$sc; $toppa{$rg}=[@v]; } elsif($ppok){
$topp{$rg}=$sc; $toppb{$rg}=[@v]; } } } END{ for $rg (sort keys %topn)
{ $topa=$topna=$topa{$rg}; $ntop="ncaa"; $pb="napub";
if($toppa=$toppa{$rg}) { $ntop="pubaa"; $topa=$toppa; }
elsif($toppb=$toppb{$rg}) { $pb=join",", @{$toppb}[0,4,5,6,7]; } 
print join("\t",@$topa,$ntop,$pb)."\n"; } }' \
  > plEFMS_puborncaa_refplant.btall

=item ncaatest plEFMS

# these are only 8 cases (6 ncaa genes for 2 ref parlogs)  w/o better, or nearly same, ref hit in okayset/okay.aa 
grep  ncaa plEFMS_puborncaa_refplant.btallb | grep napub

TortaxEVn040514t1       AT1G01470.1     68.6    49      150     227     151     ncaa    napub
TortaxEVn040514t1       AT2G46140.1     67.8    58      157     227     166     ncaa    napub  *refpar
TortaxEVn053096t1       AT1G32630.1     97.8    42      78      171     623     ncaa    napub
TortaxEVn039970t2       AT1G72600.2     163     78      126     128     208     ncaa    napub
TortaxEVn040609t1       AT2G05310.1     112     49      71      128     125     ncaa    napub  *consv
TortaxEVn040609t1       AT4G13500.1     112     50      71      128     125     ncaa    napub  *refpar
TortaxEVn050066t2       AT4G29540.2     73.6    45      65      152     336     ncaa    napub  *consv
TortaxEVn044638t2       AT5G49800.1     175     99      175     173     242     ncaa    napub  *consv

# .. missed conserved genes
# trclass drops these due to gapbad, parthi flag
TortaxEVn044638t2/Tortaxtrsoap1a_sBn1l1ERR2040863soapk31Loc38490t1        drop    althi   Tortaxtrvelo1a_sBn1l1ERR2040863velvk35Loc21493t1        100/72/.        198,51%,complete-utrpoor-gapbad 0,0,pflag:16
TortaxEVn040609t1/Tortaxtrvelo1a_sBn1l1ERR2040863velvk35Loc10438t3        drop    parthi  Tortaxtridba1a_sBn1l1ERR2040863idbaidbtk27Loc2887       100/49/./Tortaxtridba1a_sBn1l1ERR2040863idbaidbtk27Loc2886      128,56%,complete        0,0,aacons:3,pflag:0
TortaxEVn050066t2/Tortaxtrvelo1a_sBn1l1ERR2040863velvk35Loc10768t2        drop    main    Tortaxtrsoap1a_sBn1l1ERR2040863soapk25Loc478t2  100/27/.        184,72%,partial3-gapbad 0,0,pflag:16
#......
  
=cut


sub ncaa_match_okaa_btall {  # match_ncaa_okaa_btall 
  my($outfile,$ncaabtall,$okaabtall)=@_;
  our(%topa,%topn,%topp,%toppa,%toppb);
  
  sub readbtall { 
    my($src, $btall)=@_;    
    our(%topa,%topn,%topp,%toppa,%toppb);
    my($nok)=(0);
    open(B,$btall) or return(0);
    while(<B>) { 
      next if(/^\W|^Query/);
      my @v=split;  my($td,$rd,$bs,$idn,$al,$tw,$rw)=@v;
      my $sc=$bs; # choice of score: bs,idn,al .. idn may be best but namegenes uses bs
      (my $rg=$rd)=~s/[t\.]\d+$//; # ref_ids may not have gene.transcript id patt
      if($src eq 'ncaa') {
        if($sc > $topn{$rg}) { $topa{$rg}=[@v];  $topn{$rg}=$sc; $nok++; } 
      } elsif(my $osc=$topn{$rg}) {
        my $osp= $topp{$rg}||0; 
        my $ppok=($sc > $osp); $nok++ if($ppok);
        my $pok= ($sc >= $osc - 1 and $ppok); 
        if($pok){ $topp{$rg}=$sc; $toppa{$rg}=[@v]; } 
        elsif($ppok){ $topp{$rg}=$sc; $toppb{$rg}=[@v]; }
      }     
    } close(B);
    return($nok);
  }
  
  my($nok)= readbtall('ncaa',$ncaabtall); # read 1st
  my($aok)= readbtall('okaa',$okaabtall); # only ncaa hits
  return(0) unless($nok); # aok ?
  
  open(O,'>',$outfile); 
  my ($mok,$ncuniq)=(0,0);
  for my $rg (sort keys %topn) { 
    my($topa,$topna,$ntop,$pb,$toppa,$toppb);
    $topa=$topna=$topa{$rg}; $ntop="ncaa"; $pb="napub";
    if($toppa=$toppa{$rg}) { $ntop="pubaa"; $topa=$toppa; }
    elsif($toppb=$toppb{$rg}) { $pb=join",", @{$toppb}[0,4,5,6,7]; } 
    # ^^ refine this to test topa.idaln - toppb.idaln, flag if ncaa >> pubaa
    print O join("\t",@$topa,$ntop,$pb)."\n"; 
    $mok++; $ncuniq++ if($ntop eq "ncaa" and $pb eq "napub");
    # ncaa uniq ref are: ncaa.napub
  } close(O);
  
  return($mok,$ncuniq);
}

sub has_okayset_refblast {
  my($trname)= @_; 

  my $P_REFAA = finddata('REFAA') || finddata('refset/ref*.aa');  
  return (0,'REFAA missing') unless($P_REFAA and -f $P_REFAA);
  
  my $refp= basename($P_REFAA); $refp =~ s/\.\w+$//; 
  my $okbtall="$refp*$trname*.btall"; # SCRIPT_evgblastp form
  my $P_OKAABLAST = finddata($okbtall) || finddata("aaeval/$okbtall");  
  return (0,'OKAABLAST data missing:'.$okbtall) unless($P_OKAABLAST and -f $P_OKAABLAST);
  return( 2, $P_REFAA, $P_OKAABLAST);
}

sub ncrna_aauniq_refblast {
  my($trname, $ncrna_aaset, $refaa, $okbtall)= @_; 

  my $blout="$trname.ref_ncaa.blastp";  
  (my $ncaabtall=$blout ) =~ s/\.\w+$/.btall/; 
  (my $outtab=$ncaabtall) =~ s/\.\w+$/_okaa.difftab/; # = trname.ref_ncaa_okaa.difftab ??
  (my $outuniq=$outtab) =~ s/\.\w+$/.uniqtab/;  # = trname.ref_ncaa_okaa.uniqtab ??
  
  my($cmd,$err,$ok,$hin);
  if(not $UPDATEALL and ! -f $outtab and -f "ncrnaset/$outtab") { $outtab= "ncrnaset/$outtab"; }
  if( -s $outtab and not $UPDATEALL) {
    my($ntrnew) = `wc -l $outtab`; chomp($ntrnew); #? need this grep?
    my($nuniq)= `grep -c 'ncaa.napub' $outtab`; chomp($nuniq);
    return($ntrnew, $outtab, $nuniq);
  }
  
  use constant STEPerr => -1;
  my $P_AASET = $ncrna_aaset; # "ncrnaset/$trname.ncaa_pub.fa"; # FIXME check
  if(-s $P_AASET) { loggit(0,"Query data=$P_AASET"); } 
  else { return (STEPerr,'ncrnaset/ncaa_pub.fa');  }

  my($aok,$P_REFAA,$P_OKAABLAST)= ($refaa and $okbtall) ? (2,$refaa,$okbtall) : (0);  
  ($aok,$P_REFAA,$P_OKAABLAST)= has_okayset_refblast($trname) unless($aok); # or params
  loggit(0,"REFAA data=",$P_REFAA,"OKAABLAST data=",$P_OKAABLAST);
  return (STEPerr,'Missing REFAA blast data') unless($aok);
 
  my($P_BLASTP,$P_NCBIBIN)= findapp('blastp', 1); 
  # my($P_MAKEBLAST)= findapp('makeblastdb', 1); 
  
  unless( -f "$P_REFAA.psq") {
  $cmd="$APPmakeblastdb -dbtype prot -in $P_REFAA -logfile /dev/null"; # P_MAKEBLAST
  $err= runcmd($cmd); return if($err);
  }
  
  my $blopt="-evalue 1e-9 ";  # for blastp refaa
  $cmd= "$P_BLASTP $blopt -num_threads $NCPU -db $P_REFAA -query $P_AASET -outfmt 7 -out $blout";
  $err= runcmd($cmd); return if($err);
  push @tmpfiles, $blout;

  my $trsizef="$P_REFAA.qual,$P_AASET.qual"; # FIXME
  unless(-f "$P_REFAA.qual") { runcmd("$EVIGENES/prot/aaqual.sh $P_REFAA"); }
  unless(-f "$P_AASET.qual") { runcmd("$EVIGENES/prot/aaqual.sh $P_AASET"); push @tmpfiles, "$P_AASET.qual"; }
  
  $cmd= "$EVIGENES/makeblastscore3.pl -each -needlen -pminlow 0.75 -sizes $trsizef $blout > $ncaabtall";
  $err= runcmd($cmd);
  push @tmpfiles, $ncaabtall;

  my($mok,$ncuniq)= ncaa_match_okaa_btall($outtab, $ncaabtall, $P_OKAABLAST);
  push @tmpfiles, $outtab;
  if($mok and $ncuniq > 0) {
  runcmd("grep 'ncaa.napub' $outtab > $outuniq"); # want this final list of likely prots
  push @tmpfiles, $outuniq;
  }
  
  return ($mok, $outtab, $ncuniq); #? or parse here
}


=item make_allevdtab

    #v2: insert here .. want altpar genetab, blagree/selfdup table, aa.qual + fickett codepot of trset
    # .. allevdtab sorted by dgeneid, tr size
    # $evigenes/prot/cdshexprob.pl -onlyfick -test $trset -out $trset.codepot

    ($nevd,$allevdtab)= make_allevdtab( $genetab, $trlongsizef, trset.codepot, $selfduptab )
    
    evd cols: (trlen aalen pcds cdpot agree dglocus dgclass);

=cut

sub make_allevdtab {
  my($trname, $trset, $genetab, $trlongsizef, $selfduptab, $hasokcds)= @_;

  ## FIX: output has all input.tr set, want only trlongsizef set
  
  (my $allevdtab=$trset) =~ s/.\w+$/.allevd.tab/;
  my $ntrnew= 0;
  my($cmd,$err,$ok,$hin);
  if(not $UPDATEALL and ! -f $allevdtab and -f "ncrnaset/$allevdtab") { $allevdtab= "ncrnaset/$allevdtab"; }
  if( -s $allevdtab and not $UPDATEALL) {
    $ntrnew= `wc -l $allevdtab`; chomp($ntrnew);
    return($ntrnew, $allevdtab); #???
  }
  
  my $testokcds= ($TEST_OKCDS and ref($hasokcds));
  # my $trcodepot="$trset.codepot";
  (my $trcodepot=$trset) =~ s/\.gz//; $trcodepot.=".codepot";
  unless(-f $trcodepot) {
    ## FIXed trset.gz was bad here
    $cmd= "$EVIGENES/prot/cdshexprob.pl -onlyfick -test $trset -out $trcodepot";
    $err= runcmd($cmd);
    push @tmpfiles, $trcodepot;
  }
  
  # genetab == dRnaID	OrigID	dGeneID	AltI	APClass	AAqual TRlen	lAltIDs	lParIDs	lChrLocs
  # .. use 2-6 cols here, last 8-10 cols are unused, may change
  # trlongsizef == trid tlen 0 aaqual tlen cpold ..
  # selfduptab == trid agree duptype dupval dupids
  use constant ADDAAQ => 1;
  our( $ld, %val, $outh);
  #orig# my @kcols=qw(trlen aalen pcds cdpot cdfick agree rdmap rdpair ppair prdcov dglocus dgclass);
  my @kcols=qw(trlen aalen pcds cdpot agree dglocus dgclass);
  push @kcols, 'cdsaln' if($testokcds); #$TEST_OKCDS: add hasokcds col here 
  push @kcols, 'aaqual' if(ADDAAQ); # for output pubids
  
  open( $outh, '>', $allevdtab); push @tmpfiles, $allevdtab; # rename($allevdtab,"$allevdtab.old");
  print $outh join("\t","IDtrasm",@kcols)."\n";  
  
  sub putval{ our( $ld, %val, $outh); my $ok=0;
    if($ld and $val{trlen}) { print $outh $ld; for my $k (@kcols) { my $v=$val{$k}||0; print $outh "\t$v"; }; print  $outh "\n"; $ok=1; } 
    %val=(); return $ok; } 
    
  sub fpkm{ my($r,$w)=@_; my $f= $r / ($w/1000); return  sprintf "%.2f",log(1+$f); }  
  
  # check-read idprefix/num from genetab: ($IDPREncrna,$IDBASEncrna) =("",0);
  ($ok,$hin)= openRead($genetab); my $gtop=0;
  while(<$hin>) { next if(/^\W/); 
    my($pubid,$oid,$gid)=split; last if(++$gtop > 9);
    if($gid =~ m/^(\w+\D)(\d+)$/) {
      my($idpre,$gid)= ($1,$2);  # $IDBASEncrna= $gid; # dont need?
      last if($idpre eq $IDPREncrna);
      if($IDPREncrna and $idpre ne $$IDPREncrna) { } # err
      else { $IDPREncrna= $idpre; }
      }
  } close($hin);
    
  $cmd= "cut -f2-6 $genetab | sort - $trlongsizef $trcodepot $selfduptab |";
  open(EV,$cmd) or die "$cmd";
  while(<EV>) {
    next if(/^(\W|name|dRnaID|Ident|OrigID)/);  
    
    my(@v); 
    my($id,$e,$f,$g)=@v=split; 
    #NOT NOW, have right trdata: next unless($trok{$id});
    
    $ntrnew += putval($ld) if($ld and $id ne $ld);
    
    if(/aln=/){ $val{agree}=$e; } # Yes now: trid agree duptype dupval dupids; dupval: aln=aln%,size%
    ## ^? add hasdup evd score or not here?
    ## elsif(@v==5 and $e=~/^\d/ and) { } # duptab @v == 5
        
    elsif($e =~ /^dg\d/){ $e=~s/^dg//; $val{dglocus}=$e; $val{dgclass}= $g; } # @v == 5 for cut -f2-5 dgclass.tab
    elsif($IDPREncrna and $e =~ /^$IDPREncrna\d/){ $e=~s/^$IDPREncrna//; $val{dglocus}=$e; $val{dgclass}= $g; } # @v == 5 for cut -f2-5 dgclass.tab
    ## ^^ FIXMEd not dg0000 if using -idprefix -geneid opts , but try IDPREncrna ?
    
    elsif($g eq "test"){ $val{cdpot}=$f; }  
    elsif($f eq "test"){ $val{cdpot}=$e; } # @v == 4 or 5
    elsif(@v >= 5 and $e=~/^\d/ and $g =~ /,/){  # tr.qual @v >= 5
      my($id,$tw,$gap,$aaw,$twb)=@v; 
      if($tw < 0.5 * $twb) { $tw=$twb; } # is this .aa.qual tab? use twb ?
      my($aw,$pcd,$ac)=split",",$aaw;  # preserve all of aaw = aaqual for output
      $val{aaqual}=$aaw;
      $val{trlen}=$tw; $pcd=~s/%//; $val{pcds}=$pcd; $val{aalen}=$aw; 
      if($testokcds) {
        my ($bokcds,$okid)= split",", ($hasokcds->{$id}||"0"); # val is bases aligned
        # turn to %align of what? okcds? or this trlen?
        my $pokcds= ($bokcds==0) ? 0 : int(100 * $bokcds/$tw);
        $pokcds="$pokcds,$okid" if($okid);
        $val{cdsaln}= $pokcds; 
        }
      }
      
    # elsif(@v==4 and $e=~/^\d/){ # drop this trqual variant
    #   my($id,$tw,$aaw,$cp)=@v; my($aw,$pcd)=split",",$aaw;  
    #   $val{trlen}=$tw; $pcd=~s/%//; $val{pcds}=$pcd;  $val{aalen}=$aw; 
    #   } 
    # elsif(@v==5 and $e=~/^\d/){ # readmap.tab : now now
    #   my($id,$tw,$rdm,$rdp,$unc)=@v; my $cov=$tw - $unc; 
    #   $val{prdcov}= sprintf "%.2f", 100*$cov/$tw; 
    #   $val{ppair}= ($rdm>0)?int(1000*$rdp/$rdm)/10:0; 
    #   $val{rdmap}= fpkm($rdm,$tw); 
    #   $val{rdpair}= fpkm($rdp,$tw); 
    # }  
    
    $ld=$id; 
  } close(EV);
  
  $ntrnew += putval($ld);  close($outh);
  return($ntrnew,$allevdtab);
}

=item ncrna_makeSelfDupTab

  merged table from self.blast with 
    a. classified self duplicates (imperfectdup + imperfectfrag)
    b. classified valid replication (cross assembler duplicates)
    
  mix of ncrna_replicates() and ncrna_altpar:ncrna_makeSelfDupTab()


  my($ntab,$selfduptab, $havedups,$hasduphash, $nagree)
    = ncrna_makeSelfDupTab($trname, $trlongnomrna, $trselfblast, $trsetagree, $trlongsizef);
    
=cut

sub ncrna_makeSelfDupTab {
  my($trname,$trset,$trselfblast,$trsetagree,$trsizef)= @_; 

  #above# use constant RepFromBtall => 1;  #UPD2222 only this method
  #? my $check_align = ($trsizes and ref $trsizes) ? 1 : 0;#? option

  my $MINPAL=$ENV{blagree_pal} || 0.80; # smaller? larger? options..
  my $MINPRW=$ENV{blagree_prw} || 0.70; #? smaller
  
  (my $selfbtall=$trselfblast) =~ s/\.\w+$/.btall/; # make/use this table for blagree ..
  (my $selfdups=$trselfblast) =~ s/\.\w+$/.sduptab/; # CHANGE output name
  # my $newtable=$selfdups; # NO trsetnew here.  selfdup table
  
  # my $trsetnew="$trname.uniqrna.tr"; # NO trsetnew here.  selfdup table
  my $ntrnew= 0;
  my($cmd,$err,$ok,$hin);
  if(not $UPDATEALL and ! -f $selfdups and -f "ncrnaset/$selfdups") { $selfdups= "ncrnaset/$selfdups"; }
  if( -s $selfdups and not $UPDATEALL) {
    $ntrnew= `wc -l $selfdups`; chomp($ntrnew);
    # ?? need valid %hasdup here
    # return($ntab, $selfdups, $nhasdup, \%hasdup, $nblagree); 
    return($ntrnew, $selfdups); #???
  }

  # step A. selfblast > selfbtall
  # upd altparclass2a() now makes selfbtall before this
  #---------------------
  
  ## Maybe replace this w/ makeblastscore selfbtall table parse .. simplifies decisioh,
  ## use sametr ==  min( align/tlen, align/rlen) > 0.90 and min(rlen/tlen, tlen/rlen) > 0.90
  unless( -s $selfbtall) { #? reuse
    
    unless($trsizef and -f $trsizef) {
      $trsizef="$trset.qual"; 
      unless(-f $trsizef) { my $nts;
        ($nts,$trsizef)= trseq_qual($trname, $trset, undef, $trsizef );  # reduced from long.tr sizef
      }
    }
    
    # change -pminlow ?
    loggit(LOG_DIE,"missing selfblast $trselfblast") unless(-s $trselfblast);
    my $cmd= "$EVIGENES/makeblastscore3.pl -each -needlen -pminlow 0.5 -sizes $trsizef $trselfblast > $selfbtall";
    my $err= runcmd($cmd);
    push @tmpfiles, $selfbtall;
  }
  
  
  # step B... read selfbtall, call selfdups and assembler replicates, write table
  #---------------------
  my($ntab,$nhasdup,%hasdup,%valdup)=(0); # selfdup
  my($ltd,$topal,$nag,$nblagree)= (0) x 9;
  our(%agree,%blagree,%blreplace,%rsn,@rds,%didid,%did); # agree

  sub saveagree { 
    my($ltd,$topal)=@_; 
    our(%agree,%blagree,%blreplace,%rsn,@rds,%didid,%did);
    my @rsn=sort keys %rsn;  my $nput=0;
    my $nagree= @rsn + $agree{$ltd};
    if($nagree > 1) {
      my $pok=1; my $repok=0; # nu
      if(my $oal= $did{$ltd}) {
        my $od= $didid{$ltd};
        my $agr= $agree{$ltd}||0; my $ogr= $agree{$od} || 0;
        my $oblg= $blagree{$od}||0;
        if($agr == 0 and $ogr == 0) { $agr=$nagree; $ogr=$oblg; }
        if( $topal <= $oal and $agr <= $ogr ) { $pok= -1; }
        elsif($topal > $oal and $agr >= $ogr ) { $pok= 2; $repok=1 unless($oblg>$nagree); }
        elsif($topal > $oal and $agr < $ogr ) { $pok= ($agr>1) ? 2 : 0; } 
      }
      if($pok > 0) {      
        # my $rsv= join",",map{ $_.":".$rsn{$_}; } @rsn; 
        # $rsv = "equals" unless(@rsn);
        # my $repval=0; 
        if($repok and my $od=$didid{$ltd}) {  
          delete $blagree{$od}; #? but keep agree{} 
          $blreplace{$od}=$ltd; # dont need w/ delete ?
          # $repval="replace=$od"; dont need 
        } 
        ### print $agreeout join("\t",$ltd,$nagree,$rsv,"aln=$topal",$repval)."\n"; 
        $blagree{$ltd}=$nagree; $nput++; # local dont bother w/ agreeout
        $didid{$ltd}=$ltd; $did{$ltd}=$topal; 
        for my $d (@rds) { if($did{$d} < $topal) { $didid{$d}=$ltd; $did{$d}=$topal; }  }
      }
    } 
    return($nput);
  }
  #------------------------------

  if(-f $trsetagree) {
    ($ok,$hin)= openRead($trsetagree);
    while(<$hin>) { next if(/^\W/);  my($td,$nagr)=split;  $agree{$td}=$nagr; $nag++; }
    close($hin);
    loggit(0,"nagree=$nag in $trsetagree");
  }

  ($ok,$hin)= openRead($selfbtall);
  loggit(0, "ncrna_makeSelfDupTab read $selfbtall, ok=$ok");
  while(<$hin>) { 
    next if(/^\W/);
    my($td,$rd,$bs,$ida,$aln,$tw,$rw)= split;
    next unless($tw>0 and $rw>0 and $td ne $rd);  
    # next if($td eq $rd or $hasdup{$rd}{$td}); # no self or circular rd/td and td/rd
 
    ## self-dup code
    my $palt= $aln/$tw; my $prwt= $tw/$rw; # for td isDup/Frag
    if($prwt <= 1.0 and $palt >= $MINDUPALN and not $hasdup{$rd}{$td}) { 
      my $dupflag= ($prwt < $MINDUPFULL)? "frag" : "dup";
      $hasdup{$td}{$rd}= $dupflag; $nhasdup++;
      $valdup{$td}{$rd}= sprintf"%d,%d", int(100*$palt), int(100*$prwt); # append pal,prw ?
    }
   
    ##  agree repl code from above
    if($td ne $ltd) { $nblagree += saveagree($ltd,$topal) if($ltd); %rsn=@rds=(); } 
    $ltd=$td;  
    
    my($pala,$prwa) = ($tw > $rw) ? ($aln/$tw, $rw/$tw) : ($aln/$rw, $tw/$rw); # for agree
    ## cancel this skip if $agree{$td} .. but dont add rd rsn
    my $okagree = ($pala < $MINPAL or $prwa < $MINPRW) ? 0 : 1;
    if($okagree) {
      push @rds,$rd;
      $topal= $aln if($aln > $topal);  
      foreach my $sd ($td,$rd) {  
        my $st= $sd;
        if($st=~s/[Ll]oc.*$//) { $st =~ s/k\d+$//; } 
        else { $st=substr($sd,0,9); } #? cancel if no [Ll]oc ? dont want spurious agree measure; need option
        $rsn{$st}++;
      }
    }
   
  } close($hin);
  $nblagree += saveagree($ltd,$topal) if($ltd); 
  
  my %td=(); map{ $td{$_}=1 } (keys %hasdup, keys %blagree);
  my @td= sort keys %td;
  $ntab= @td; my $dhdr=0;
  loggit(0, "ncrna_makeSelfDupTab n=$ntab to $selfdups");
  open(O,'>',$selfdups) or loggit(LOG_DIE,"write $selfdups");
  push @tmpfiles, $selfdups;
  for my $td (@td) { 
    my @did= sort keys %{$hasdup{$td}};
    my $agree= $blagree{$td} || $agree{$td} || 0; # blagree should contain nrident agree set
    next unless(@did > 0 or $agree > 0);  # BUG above? @did == 0 from hasdup rd,td and td,rd

    my $dupflag=""; my $valdup=0;
    for my $d (@did){ $dupflag= $hasdup{$td}{$d}; $valdup=$valdup{$td}{$d}; last if($dupflag eq "frag"); } 
    my $dupids= join",",@did;
    map{ $_ ||= "0" } ($dupflag,$dupids); # ?data bug
    
    print O join("\t",qw(IDentifier agree duptype dupval dupids))."\n" unless($dhdr++); 
    print O join("\t",$td,$agree,$dupflag,"aln=".$valdup,$dupids)."\n"; 
  } close(O);
  
  return($ntab, $selfdups, $nhasdup, \%hasdup, $nblagree); #? \%blagree,\%hasdup
}

=item ncrna_align_okcds

  ($ncds,$hasokcds,$okcdsblastn)= ncrna_align_okcds($trname,$trset,$okcds);
  
  which way?  -db uniqrna -query okcds or rev?
   makeblastdb -dbtype nucl -in $trname.uniqrna.tr -logfile /dev/null
   bloptnu="-perc_identity 98 -evalue 1e-9 -dust yes "
   blastn $bloptnu -num_threads $ncpu -db $trname.uniqrna.tr -query $okcds -outfmt 7 -out $trname.uniqrna.okcds.blastn

=cut 


sub ncrna_align_okcds {
  my($trname,$trset,$okcds)= @_; # trset=="$trname.uniqrna.tr";
  return (0) unless(-f $okcds);
  my ($ncds,%hasokcds)= (0); 
  my $blout="$trset.okcdsaln.blastn";  
  my $pctident=98; # -pHetero fixme
  
  sub countokcds { 
    my($blout)=@_; 
    open(B,$blout) or return(0); %hasokcds=();
    while(<B>){ if(/^\w/) { my($td,$rd,$pid,$aln)=split; 
      if($aln >= $MIN_CDSALN){ my $oal=$hasokcds{$td}||0; 
        if($aln>$oal){ $hasokcds{$td}="$aln,$rd"; $ncds++; } } 
        } 
    } close(B);
    return scalar(keys %hasokcds);
  }
  
  if(not $UPDATEALL and ! -f $blout and -f "ncrnaset/$blout") { $blout= "ncrnaset/$blout"; }
  if( -s $blout and not $UPDATEALL) { 
    $ncds= countokcds($blout);
    return($ncds,\%hasokcds,$blout);
  }

  ## add here? class b/n truniq matching okay.cds, truniq.okcds.tr, and those w/o truniq.ncrna.tr
  # (my $okcds=$mrna) =~ s/.mrna/.cds/;
  # my($hasokcds)  = ncrna_align_okcds($trname,$truniqrna,$okcds);

  my($cmd,$err,$ok,$hin);
  if($okcds =~ /\.gz$/){ 
    my $okcdsgz=$okcds; $okcds =~ s/.gz$//;
    $cmd="gunzip -c $okcdsgz | $APPmakeblastdb -dbtype nucl -title $okcds -out $okcds -logfile /dev/null";  
  } else {
    $cmd="$APPmakeblastdb -dbtype nucl -in $okcds -logfile /dev/null"; # .gz NOT ok 
  }
  push @erasefiles, map{ "$okcds.$_" } qw(nsq nin nhr);
  $err= runcmd($cmd); return if($err);

  #x my $bloptnu="-perc_identity 98 -qcov_hsp_perc 90 -dust no "; #? check opts again, maybe no -qcov, -dust yes
  my $bloptnu="-perc_identity $pctident -evalue 1e-9 -culling_limit 1";  # ? culling_limit 1 need only 1 hit
  $blout="$trset.okcdsaln.blastn"; push @tmpfiles, $blout;
  $cmd= "$APPblastn $bloptnu -num_threads $NCPU -db $okcds -query $trset -outfmt 6 -out $blout";
  $err= runcmd($cmd); return if($err);
  
  $ncds= countokcds($blout);
  return($ncds,\%hasokcds,$blout);
}


=item altparclass algo

  if [ -f $trname.aa.qual ]; then
    perl -ne '($d)=@v=split; if(@v==1) { $ok{$d}=1; } else { print if($ok{$d}); }' \
      $trname.self98.blagree.trids $trname.aa.qual  > $trname.uniqrna.aa.qual
    trsizes=$trname.uniqrna.aa.qual
  else
    env ismrna=1 $evigene/scripts/prot/aaqual.sh $trname.uniqrna.tr
    trsizes=$trname.uniqrna.tr.qual
  fi
  
  $evigene/scripts/genes/altparclassify.pl -ncpu $ncpu -cds $trname.uniqrna.tr -sizes $trsizes
  
  # 3b. FIXME: step2 leaves in notokmrna with large overlap to okmrna : need to separate these from ncrna
  #    step1 removes only contained-in-okmrna subset
  #    use prior step2 + self-agree, add after step3 ? blastn -db uniqrna.tr -query ok.cds -qcov 60-90% ?
  
   okcds=`echo $mrna | sed 's/.mrna/.cds/;'`
   if [ -f $okcds ]; then 
   makeblastdb -dbtype nucl -in $trname.uniqrna.tr -logfile /dev/null
   bloptnu="-perc_identity 98 -evalue 1e-9 -dust yes "
   blastn $bloptnu -num_threads $ncpu -db $trname.uniqrna.tr -query $okcds -outfmt 7 -out $trname.uniqrna.okcds.blastn
   fi

=cut

sub altparclass {  
  my($trname,$trset,$trselfblast,$trsizef,$hasokcds,$evgapp)= @_;  ## trset == truniqrna; trsizef was aaqualf
  my($ngene,$cmd,$err)= (0);
  
  ## add altparclassify -output $trclass option
  (my $cname= $trset) =~ s/\.\w+$//;
  my $genetab= "$cname.dgclass.tab"; push @tmpfiles, $genetab;  
  if(not $UPDATEALL and ! -f $genetab and -f "ncrnaset/$genetab") { $genetab= "ncrnaset/$genetab"; }
  if(-s $genetab and not $UPDATEALL) {
    ($ngene)= `cut -f5 $genetab | egrep -c '^(main|uni)'`; chomp($ngene);
    return($ngene,$genetab);
  }
  
  # FIXME: trselfblast uses trsizef to keep, but now
  #   trsizef == longnok.tr.qual has more than trset == uniqrna.tr
  my($nts,$tsok)= (0,0);
  if(-s $trsizef and ($trsizef eq "$trset.qual")) {
    my $trids= faidlist($trset,undef,'hash');
    $nts= 0; open(F,$trsizef); while(<F>){ $nts++ if(/^\w/); } close(F);
    $tsok= ($nts == scalar(keys %$trids)) ? 1 : 0;
  }
  unless( $tsok ) {
    ($nts,$trsizef)= trseq_qual($trname, $trset, undef, $trsizef );  # reduced from long.tr sizef
  }
    
  return(0) if($nts < 9);
  
  # use %hasokcds{trid} to reclass as miscRNA vs ncRNA .. miscRNA == pseudogene, missed-mRNA, etc
  
  # altparclassify.pl uses this, use same here? change?
  # my $NCBLAST_IDENT=  $ENV{pctident} || 97; # option .. 95 in altparc
  # my $NCBLAST_EVALUE= $ENV{evalue} || 1e-9; # option .. 1e-5 in altparc
  #NOTE: $REUSE_SELFBLAST reusing $trselfblast which has more ids than trset, added -requiresize
  ## altparclassify bug: TRlen col NOT trlen but aasize*3
  
  $evgapp ||= "$EVIGENES/genes/altparclassify.pl";
  $cmd="$evgapp -ncpu $NCPU -cds $trset -sizes $trsizef";
  $cmd .=" -debug" if($debug);
  $cmd .=" -requiresize -selfblast $trselfblast" if($trselfblast and -f $trselfblast);
  # my($IDPREncrna,$IDBASEncrna) =("",0);
  ##?? BAD for above parsing, expecting 'dg0000' ids only from alrparclass.tab
  $cmd.=" -idprefix $IDPREncrna" if($IDPREncrna); # UPD2222
  $cmd.=" -geneid $IDBASEncrna" if($IDBASEncrna);

  $err= runcmd($cmd);
  # note this makes $trset.aa.qual, trset.self95.blastn
  
  ($ngene)= `cut -f5 $genetab | egrep -c '^(main|uni)'`; chomp($ngene);
  # my ($classcount)= `cut -f5 $genetab | sort | uniq -c `;
  # create uniqrna.main.tr from genetab main|uni ?
  
  return($ngene,$genetab);
}

sub altparclass2a {  #UPD2222
  my($trname,$trset,$trselfblast,$trsizef,$hasokcds)= @_;  ## trset == truniqrna; trsizef was aaqualf
  if(0) {
    return altparclass(@_); #v1 looks okay for v2 ... 
  }

  # FIXME -pHetero reduce altparclassify -altpident 99.0 -pctident 95
  
  my $evgapp="$EVIGENES/genes/altparclassify2b.pl"; # TEST, replace orig if ok
  # orig is mem-pig for largish self-blast, too many internal hashes of all that
  # upd 2b uses self.btall sorted by longest tr, same as made w/ makeselfdup,
  ## added opt: altparclassify2b -output $genetab

  my($ngene,$cmd,$err)= (0);
  (my $cname= $trset) =~ s/\.\w+$//;
  my $genetab= "$cname.dgclass.tab"; push @tmpfiles, $genetab;  
  if(not $UPDATEALL and ! -f $genetab and -f "ncrnaset/$genetab") { $genetab= "ncrnaset/$genetab"; }
  if(-s $genetab and not $UPDATEALL) {
    ($ngene)= `cut -f5 $genetab | egrep -c '^(main|uni)'`; chomp($ngene);
    return($ngene,$genetab);
  }
  
  my($nts,$tsok)= (0,0);
  unless($trsizef and -f $trsizef) {
    $trsizef="$trset.qual"; 
    unless(-f $trsizef) { 
      ($nts,$trsizef)= trseq_qual($trname, $trset, undef, $trsizef );  # reduced from long.tr sizef
      return(0) if($nts < 9);
    }
  }

  loggit(0, "altparclass2a start to $genetab");
  # same as makeSelfDupTab: step A. selfblast > selfbtall
  # trselfblast should be valid file here
  #---------------------
  loggit(LOG_DIE,"missing selfblast $trselfblast") unless(-s $trselfblast);
  (my $selfbtall=$trselfblast) =~ s/\.\w+$/.btall/; # make/use this table for blagree ..
  unless( -s $selfbtall) { 
    my $cmd= "$EVIGENES/makeblastscore3.pl -each -needlen -pminlow 0.5 -sizes $trsizef $trselfblast > $selfbtall";
    my $err= runcmd($cmd);
    push @tmpfiles, $selfbtall;
  }
  
  $cmd="$evgapp -ncpu $NCPU -cds $trset -sizes $trsizef";
  $cmd .=" -debug" if($debug);
  $cmd .=" -btallself $selfbtall"; #  if($selfbtall and -f $selfbtall); # NOT -sortedbtall, presumably
  #o# $cmd .=" -requiresize -selfblast $trselfblast" if($trselfblast and -f $trselfblast);
  $cmd.=" -idprefix $IDPREncrna" if($IDPREncrna); # UPD2222
  $cmd.=" -geneid $IDBASEncrna" if($IDBASEncrna);
  $err= runcmd($cmd);
  if($err) {
    #runcmd logs err: loggit(0,"ERR: $err, ");
  } else {
    ($ngene)= `cut -f5 $genetab | egrep -c '^(main|uni)'`; chomp($ngene);
  }
  return($ngene,$genetab);
}


=item run_evgtr2ncrna.sh

  #! /bin/bash
  ### env trset=inputset/name.tr  mrna=okayset/name.okay.mrna  ncpu=12 datad=path/to/data  qsub -q normal run_evgtr2ncrna.sh
  #PBS -N evg_tr2ncrna
  #PBS -A PutAccountIdHere
  #PBS -l nodes=1:ppn=16,walltime=39:55:00
  #PBS -V
  
  # run_evgtr2ncrna.sh = new evigene/scripts/genes/tr2ncrna.pl
  # inputs: okayset/name.okay.mrna inputset/name.tr
  # v1 opt:  -REUSE_SELFBLAST
  
  # env need: $evigene/scripts/ and blastn on path
  evgapps=$HOME/bio/apps
  evigene=$evgapps/evigene
  export PATH=$evgapps/ncbi/bin:$PATH
  export PATH=$evgapps/exonerate/bin:$PATH
  evgapp=$evigene/scripts/genes/tr2ncrna.pl
  
  if [ "X" = "X$ncpu" ]; then ncpu=8; fi
  if [ "X" = "X$maxmem" ]; then maxmem=64000; fi
  if [ "X" = "X$datad" ]; then echo missing datad=/path/to/data; exit -1; fi
  if [ "X" = "X$mrna" ]; then echo missing mrna='name.mrna'; exit -1; fi
  if [ "X" = "X$trset" ]; then echo missing trset='name.tr'; exit -1; fi
  
  cd $datad/
  echo "#START `date` " 
  
  echo $evgapp -debug -log  -ncpu $ncpu  -mrna $mrna -trset $trset
  $evgapp -debug -log  -ncpu $ncpu  -mrna $mrna -trset $trset
  
  echo "#DONE : `date`"

=cut

__END__

