5 jpred - Secondary structure prediction program
9 jpred --sequence <fasta file> [--output <output prefix>] [--db <database>] [--psi <psiblast output>] [--pred-nohits] [--verbose] [--debug] [--help] [--man]
13 This is a program which predicts the secondary structure of a sequence given a path to a FASTA sequence. It does all the PSI-BLAST searching and alignment 'meddling' as required by Jnet.
15 The program is primarily design for use by the Jpred server, but it can be used directly by any user. Some of the output may not be meaningful if used directly - it can be safely ignored.
23 The path to the sequence (in FASTA format) you want to predict.
27 A prefix to the filenames created by Jpred, defaults to the value set by --sequence.
31 Database to use for PSI-BLAST querying. This only accepts databases from a list which is pre-defined in the code. Crap I know, but that's the way it is at the moment. It's probably best to stick the default for the time being.
37 Path to a PSIBLAST output file.
41 Toggle allowing Jpred to make predictions even when there are no PSI-BLAST hits.
45 Verbose mode. Print more information while running jpred.
49 Debug mode. Print debugging information while running jpred.
53 Gives help on the programs usage.
57 Displays this man page.
63 Can't cope with gaps in the query sequence.
65 Doesn't accept alignments.
67 If you find any others please contact me.
71 Jonathan Barber <jon@compbio.dundee.ac.uk>
73 Chris Cole <christian@cole.name> (current maintainer)
77 ## TODO check for gaps in query sequence
78 ## check for disallowed chars in sequence
85 use UNIVERSAL qw(isa);
89 use Jpred; # needed to define BLAST environment variables
93 use HMMER::Profile::Jnet;
104 use Utils qw(profile);
106 use Paths qw($pairwise $oc $jnet $hmmbuild $hmmconvert $psiblastbin);
108 my $VERSION = '3.0.1';
109 my $MAX_ALIGN = 1000; # maximum number of alignment sequences allowed
110 my $NR_CUT = 75; # cut-off seqeunce ID value for defining non-redundancy
112 # Light object to hold sequence information, light to prevent memory overload
113 # for big search results. Even so this is quite memory intensive, I can't see
114 # how to reduce the size further.
117 #use Compress::LZF qw(compress decompress);
120 my ($class, %args) = @_;
123 for (keys %args) { $self->$_($args{$_}) }
128 return defined $_[1] ?
134 return defined $_[1] ?
141 ref $_[1] eq 'ARRAY' or die "Not passed ARRAY ref";
142 #$_[0]->[2] = compress(join "", @{ $_[1] });
143 $_[0]->[2] = join("", @{ $_[1] });
146 #return [ split //, decompress($_[0]->[2]) ];
147 return [ split(//, $_[0]->[2]) ];
152 # Key to database information and information for accessing them
153 my $dbPATH = '/homes/chris/projects/Jnet/db';
154 my $db_entry = "uniref90";
157 ## default database used by Jpred
159 database => 'uniref90.filt',
160 unfiltered => 'uniref90',
163 ## database used during Jnet training
165 database => 'training/uniref90.filt',
166 unfiltered => 'training/uniref90',
169 ## cluster-specific path for Jpred
171 database => '/local/gjb_lab/www-jpred/uniref90.filt',
172 unfiltered => '/local/gjb_lab/www-jpred/uniref90',
175 ## these other DBs are experimental ones used during development.
176 ## check they exist before using them.
178 # generic entry for use with validate_jnet.pl
179 # real db location defined by validate_jnet.pl
180 database => "$dbPATH/swall/swall.filt", # CC new
181 unfiltered => "$dbPATH/swall/swall",
184 # Path to PSIBLAST db
185 database => "$dbPATH/3/swall.filt", # CC new
186 unfiltered => "$dbPATH/3/swall",
189 database => "$dbPATH/6/swall.filt",
190 unfiltered => "$dbPATH/6/swall",
194 # Gap characters in sequences
197 my ($help, $man, $path, $output, $psiblast, $DEBUG, $VERBOSE);
198 my $predNoHits = 0; # define whether to make predictions when no PSI-BLAST hits are found
202 "verbose" => \$VERBOSE,
203 "sequence=s" => \$path,
204 "output=s" => \$output,
205 "psi=s" => \$psiblast,
206 "db=s" => \$db_entry,
207 "pred-nohits" => \$predNoHits,
210 pod2usage(1) if $help;
211 pod2usage(verbose => 2) if $man;
213 pod2usage(' --sequence argument not provided') unless $path;
214 die "--db $db_entry not recognised" unless exists $database->{$db_entry};
215 $output = $path unless $output;
219 [ "output", $output ],
220 [ "psi", $psiblast ],
223 my ($key, $value) = @{$_};
224 defined $value or next;
225 errlog(join(": ", $key, $value), "\n");
228 my $query = FASTA::File->new(read_file => $path);
232 my $psi = PSIBLAST->new; # CC PSIBLAST.pm doesn't have a new() class??
233 unless (defined $psiblast && -e $psiblast) {
234 my $psi_run = PSIBLAST::Run->new(
236 # path => "/software/jpred_bin/blastpgp",
237 path => $psiblastbin, # CC new path
239 output => "$output.blast",
240 matrix => "$output.profile",
241 database => $database->{$db_entry}{database},
242 ## potentially a better set of parameters (esp. -b & -v)
243 ## which avoid PSI-BLAST dying with large number of hits
244 # args => '-e0.05 -h0.01 -m6 -b10000 -v10000 -j3 -F "m S"' # 'soft' filtering of the query sequence
245 # args => '-e0.001 -h0.0001 -m6 -b10000 -v10000 -j3' # stricter searching criteria
246 # args => '-e0.05 -h0.01 -m6 -b10000 -v10000 -j3'
249 # For reduced databases, get the size of the orginal and use this as
250 # the equivilent DB size
251 #print $db_entry, "\n";
252 if ($db_entry =~ /^sp_red_/) {
253 (my $entry = $db_entry) =~ s/^sp_red_/sp_/;
254 $psi_run->args( $psi_run->args . " -z " .
255 fasta_seq_length($database->{$entry}{database}) # CC sub is below
258 print "BLAST matrix: $ENV{BLASTMAT}\n" if $DEBUG;
259 print "BLASTDB path: $ENV{BLASTDB}\n" if $DEBUG;
261 print "Running PSI-BLAST on query against \'$database->{$db_entry}{database}\'...\n" if $VERBOSE;
262 $psi_run->run or die; # CC sub is from PSIBLAST::Run
264 $psi->read_file("$output.blast"); # CC PSIBLAST.pm doesn't have a read_file(), but Read.pm does?
265 system("gzip -9f $output.blast");
268 if ($psiblast =~ /.gz$/) { $psi->read_gzip_file($psiblast) } # CC PSIBALST.pm doesn't have a read_gzip_file() object, but Read.pm does?
269 else { $psi->read_file($psiblast) } # CC ditto above
272 # Convert the last itteration into a collection of PSISEQ objects
273 for ($psi->get_all) { # CC sub is from PSIBLAST.pm
274 my ($id, $start, $align) = @{$_};
275 push @seqs, PSISEQ->new(
278 align => [ split(//, $align) ]
283 ## When there are no PSI-BLAST hits generate an HMM from the query
284 ## and run Jnet against that only.
285 ## Accuracy won't be as good, but at least it's a prediction
287 if ($predNoHits == 0) {
288 warn "\nJPRED: Warning - no PSI-BLAST hits found and '--pred-nohits' option not set. Exiting...\n";
289 print ">>100% complete\n";
292 print ">>50% complete\n";
293 warn "\nJPRED: no PSI-BLAST hits found. Continuing with single query sequence only.\n\n";
294 print "Running HMMer on query...\n" if $VERBOSE;
296 # copy input query to alignment
297 system("cp $path $output.align") == 0 or croak "Error: unable to copy '$path'\n";
299 # Temp files required for HMMer
300 my ($hmmbuild_out, $hmmconvert_out) = map {
301 File::Temp->new->filename
304 system("$hmmbuild -F --fast --amino --gapmax 1 --wblosum $hmmbuild_out $path");
305 system("$hmmconvert -F -p $hmmbuild_out $hmmconvert_out");
307 # Read in the HMMER file
308 my $hmmer = HMMER::Profile->new(
309 read_file => $hmmconvert_out
312 # Convert from HMMER::Profile to HMMER::Profile::Jnet
313 my $hmmer_jnet = HMMER::Profile::Jnet->new;
314 $hmmer_jnet->add_line(@{$_}) for $hmmer->get_line;
315 $hmmer_jnet->write_file("$output.hmm"); # write_file is in the Read.pm called from the HMMER::Profile module
316 print ">>70% complete\n";
318 # Run Jnet for the prediction
319 print "Running JNet using the generated inputs from HMM only...\n" if $VERBOSE;
320 jnet(map { "$output.$_" } qw(hmm jnet)); # CC sub is below
322 print "Jpred Finished\n";
326 psiseq2fasta("0.fasta.gz", @seqs) if $DEBUG; # CC sub is below
327 print ">>40% complete\n";
329 # Make PSIBLAST truncated alignments the right length
330 print "Untruncating the PSIBLAST alignments...\n" if $VERBOSE;
331 @seqs = extend($query, @seqs); # CC sub si below
332 psiseq2fasta("1.fasta.gz", @seqs) if $DEBUG;
334 # Remove masking from PSIBLAST alignment
335 print "Unmasking the alignments...\n" if $VERBOSE;
336 dex($_) for @seqs[ 1..$#seqs ]; ## <-- CC dies here in dex() - found below
337 psiseq2fasta("2.fasta.gz", @seqs) if $DEBUG;
339 # Convert the sequences to upper case
340 print "Converting sequences to the same case...\n" if $VERBOSE;
341 toupper($_) for @seqs; # CC sub is below
342 psiseq2fasta("${output}_backup.fasta.gz", @seqs);
344 # Remove excessive sequences
345 print "Remove excessive sequences...\n" if $VERBOSE;
346 @seqs = reduce($MAX_ALIGN, @seqs); # CC sub is below
347 psiseq2fasta("3.fasta.gz", @seqs) if $DEBUG;
349 # Remove sequences that are too long or too short
350 print "Remove sequences which too long or short...\n" if $VERBOSE;
351 @seqs = del_long_seqs(50, @seqs); # CC sub is below
352 psiseq2fasta("4.fasta.gz", @seqs) if $DEBUG;
354 # Remove redundant sequences based upon pairwise identity and OC clustering
355 print "Remove redundant sequences...\n" if $VERBOSE;
356 @seqs = nonred($NR_CUT, @seqs); # CC sub is below
357 psiseq2fasta("5.fasta.gz", @seqs) if $DEBUG;
359 # Check that we haven't got rid of all of the sequences
361 warn "JPRED: All the sequences found by PSIBLAST were removed during filtering, reverting to prefiltered sequences\n";
362 @seqs = fasta2psiseq("${output}_backup.fasta.gz");
364 unlink("${output}_backup.fasta.gz") unless $DEBUG;
366 # Remove gaps in the query sequence and same positions in the alignment
367 print "Removing gaps in the query sequence...\n" if $VERBOSE;
368 degap(@seqs); # CC sub is below
369 psiseq2fasta("6.fasta.gz", @seqs) if $DEBUG;
371 # Output the alignment for the prediction
372 print "Outputting cleaned-up PSI_BLAST alignment...\n" if $VERBOSE;
373 psiseq2fasta("$output.align", @seqs);
376 # Equivilent to getpssm script
377 print "Output the PSSM matrix from the PSI-BLAST profile...\n";
378 my $pssm = PSIBLAST::PSSM->new(read_file => "$output.profile");
379 $pssm->write_file("$output.pssm"); # CC write_file() sub is in Write.pm loaded via PSIBLAST::PSSM
381 print ">>50% complete\n";
383 # Run HMMER on the sequences
385 print "Running HMMer on sequences found by PSI-BLAST...\n" if $VERBOSE;
386 my $hmmer = hmmer(@seqs); # CC sub is below
387 $hmmer->write_file("$output.hmm"); # write_file is in the Read.pm called from the HMMER::Profile module
389 print ">>70% complete\n";
391 # Run Jnet for the prediction
392 print "Running JNet using the generated inputs from HMM and PSI-BLAST...\n" if $VERBOSE;
393 jnet(map { "$output.$_" } qw(hmm jnet pssm)); # CC sub is below
395 print "Jpred Finished\n";
397 # Then do an accuracy prediction
399 ############################################################
401 ############################################################
405 =head2 $PSISEQ = dex($PSISEQ)
407 Returns a PSISEQ object which has any masked residues replaced by their entry from the unfiltered database. Does it in place.
413 my $idx = Index->new(type => "Index::FastaCMD") or die "Index type cannot be found.";
418 croak "JPRED: dex: can only take a PSISEQ object as an argument" unless isa $seq, 'PSISEQ';
420 # Only bother if we have a sequence which has been masked
421 return unless grep { uc $_ eq 'X' } @{ $seq->align };
423 my ($id, $start, @align) = ($seq->id, $seq->start, @{$seq->align});
425 #$id = "$id"; # Add the EMBOSS USA
426 #$id = "sprot_37:$id"; # Add the EMBOSS USA
427 #$id = "sprot_43:$id"; # Add the EMBOSS USA
428 # $id = $database->{$db_entry}{emboss} . ":$id"; # commented out to try FastaCMD module
429 my $searchdb = $database->{$db_entry}{unfiltered};
430 $start--; # We need this to be zero based
432 my $f = $idx->get_sequence($id, $searchdb) or croak "JPRED: No such entry for $id in $searchdb\n" and return; # CC sub is from Index::EMBOSS
433 my @seqs = $f->get_entries; ## Sub is from Sequence::File
434 my $db = shift @seqs;
437 confess "JPRED: dex: Accession number $id returned no sequences";
440 confess "JPRED: dex: Accession number $id returned more than one sequence";
443 my @db_seq = @{ $db->seq };
445 # $i is a pointer into the original, ungapped, unmasked sequence. $_ is
446 # for the aligned sequence
449 next if $align[$_] =~ /$GAP/;
451 if ($align[$_] eq 'X') {
452 unless (defined $db_seq[$i + $start]) {
453 croak "JPRED: dex: the database sequence is not as long as the query sequence!"
455 $align[$_] = $db_seq[$i + $start];
460 $seq->align(\@align);
464 =head2 @PSISEQS_OUT = reduce ($max, @PSISEQS_IN);
466 Reduces @PSISEQS_IN to at most $max sequences by taking every n sequences in @PSISEQ_IN.
468 Equivilent to reduce script.
473 my ($max, @seqs) = @_;
475 my $num = int(@seqs / $max);
477 my @res = shift @seqs;
479 # Don't bother if we have less than the required sequences
480 if (@seqs < $max) { return @res, @seqs }
481 if ($num == 0) { return @res, @seqs }
483 for (0..$#seqs) { push @res, $seqs[$_] if $_ % $num == 0 }
488 =head2 nonred($cutoff, @PSISEQS);
490 Removes redundant sequences at $cutoff level of sequence identity.
492 Equivilent to nonred script.
497 my ($cutoff, @seqs) = @_;
498 # Run pairwise and then OC
499 # Remove similar sequences
501 unless (defined $cutoff) { croak "JPRED: nonred() not passed a cutoff" }
502 unless (@seqs) { croak "JPRED: No sequences passed to nonred()" }
504 warn "JPRED: Only one sequence passed to nonred(). Not reducing sequence redundancy\n";
508 my $fasta = FASTA::File->new;
510 # Convert the sequences into a FASTA object, which is what
514 my $f = FASTA->new(id => $_->id);
515 $f->seq(@{$_->align});
520 # Run pairwise via wrappers
522 my $pair = Pairwise->new(
525 my $foo = join "\n", $pair->run($fasta) or die $!;
529 path => "$oc sim complete cut $cutoff"
531 $ocres->read_string(join "", $ocres->run($foo) );
533 # Now found those entries that aren't related
536 for ($ocres->get_groups) {
537 my ($group, $score, $size, @labels) = @{ $_ };
539 # Keep the QUERY from the cluster, otherwise just get one
540 if (grep { /QUERY/ } @labels) {
541 # Make sure the query stays at the start
542 unshift @keep, "QUERY";
545 else { push @keep, shift @labels }
548 push @keep, $ocres->get_unclustered;
551 # Return the matching entries.
554 # We use the temporay to mimic the selection of sequences in the nonred
555 # script, which took the sequences in the order they occured in the file.
558 if (grep { $_ =~ /^$label$/ } @keep) {
566 =head2 @seqs = del_long_seqs($percentage, @PSISEQS)
568 Removes those sequences that are more than $percentage longer or shorter than the first sequence in @seqs. @seqs is an array of PSISEQ objects.
570 Equivilent to trim_seqs script.
575 my ($factor, @seqs) = @_;
577 # Keep the query sequence
578 my $query = shift @seqs;
581 # Find the length of the query sequence without any gaps
582 my $length = (() = (join '', @{$query->align}) =~ /[^$GAP]/g);
584 # Calculate the upper and lower allowed bounds
587 my $bounds = ($length / 100) * $factor;
588 ($upper, $lower) = ($length + $bounds, $length - $bounds);
591 # Now try each sequence and see how long they are
593 my $l = (() = (join '', @{$_->align}) =~ /[^$GAP]/g);
594 if ($l >= $lower && $l <= $upper) { push @res, $_ }
600 =head2 toupper ($PSISEQ)
602 Converts sequence held in PSISEQ object to uppercase.
607 croak "JPRED: toupper: argument not a PSISEQ object" unless isa $_[0], 'PSISEQ';
609 [ split //, uc join '', @{ $_[0]->align } ]
613 =head2 degap($PSISEQ_QUERY, @PSISEQS)
615 Removes gaps in the query sequence ($PSISEQ_QUERY) and corresponding positions in @PSISEQS. Change made in place.
617 Equivilent to fasta2jnet script.
624 # Find where the gaps in the query sequence are
628 for (@{$seqs[0]->align}) {
629 push @gaps, $i if $_ !~ /$GAP/;
636 # Remove the gaps in all the sequences.
637 # Derefences the array reference and takes a slice inside the method call
638 # arguments, then coerce back to an array ref.
640 $_->align([ @{$_->align}[@gaps] ]);
644 =head2 getfreq($filename, @PSISEQS)
646 Creates a PSIBLAST like profile and writes it to the $filename.
648 Equivilant to profile or getfreq (older) script. This doesn't create the same answer as the old jpred, as it got the numbers from PSIBLAST (v2.0.3), whereas this a *similar* output, but it's *not* the same.
653 my ($fn, @seqs) = @_;
655 croak "JPRED: Passed non PSISEQ object" if grep { ! isa($_, 'PSISEQ') } @seqs;
657 # Create a PSIBLAST like profile from the alignment
658 # This doesn't greate the same result as old Jpred, I think this is because
659 # differences in the input between old and new
662 # my $f = FASTA::File->new(read_file => "/homes/jon/jnet/test/1bk4/1bk4.align.fa");
663 # my @profile = profile(
664 # map { join "", @{ $_->seq } } $f->get_entries
667 my @profile = profile(
668 map { join "", @{ $_->align } } @seqs
671 open my $fh, ">$fn" or die "JPRED: $fn: $!";
672 print $fh join(" ", @{$_}), "\n" for @profile;
675 =head2 HMMER::Profile::Jnet = hmmer(@PSISEQS)
677 Creates a HMMER profile from the aligned sequences in @PSISEQS. Returns a HMMER::Profile::Jnet object.
679 Equivilent to gethmm script.
686 # Temp files required
687 my ($hmmbuild_out, $hmmconvert_out, $tmp_fasta) = map {
688 File::Temp->new->filename
691 # Create the FASTA file
692 psiseq2fasta($tmp_fasta, @seqs);
694 system("$hmmbuild -F --fast --amino --gapmax 1 --wblosum $hmmbuild_out $tmp_fasta");
695 system("$hmmconvert -F -p $hmmbuild_out $hmmconvert_out");
697 # Read in the HMMER file
698 my $hmmer = HMMER::Profile->new(
699 read_file => $hmmconvert_out
702 # Convert from HMMER::Profile to HMMER::Profile::Jnet
703 my $hmmer_jnet = HMMER::Profile::Jnet->new;
704 $hmmer_jnet->add_line(@{$_}) for $hmmer->get_line;
709 =head2 jnet($hmmer, $out, $pssm )
711 Runs Jnet. Pass the paths of the filenames to do the prediction on
716 my ($hmmer, $outfile, $pssm) = @_;
718 # run Jnet prediction with all the profile data
719 system("$jnet --concise --hmmer $hmmer --pssm $pssm > $outfile");
721 # run Jnet prediction with only HMMer and alignment data
722 system("$jnet --concise --hmmer $hmmer > $outfile");
724 check("jnet", $?) or exit 1;
727 =head1 psiseq2fasta($path, @PSISEQ)
729 Writes a FASTA file given an array of PSISEQ objects.
734 my ($fn, @seqs) = @_;
736 confess "JPRED: Not passed filename" if isa $fn, 'PSISEQ';
737 @seqs or confess "JPRED: not passed PSISEQs";
739 confess "JPRED: Not PSISEQ" if grep { not isa $_, 'PSISEQ' } @seqs;
741 # Changed from using FASTA::File object due to seg faulting on some large,
742 # long alignments, presumably due to running out of memory.
743 # my $fasta = FASTA::File->new;
744 # $fasta->add_entries(
746 # my $f = FASTA->new(id => $_->id);
747 # $f->seq(@{$_->align});
751 # $fasta->write_file($fn);
755 ( open $fh, "| gzip -9 > $fn" or die "JPRED: $!" ):
756 ( open $fh, ">$fn" or die "JPRED: $!" );
759 print $fh ">", $_->id, "\n";
760 my $seq = join("", @{ $_->align });
761 $seq =~ s/(.{72})/$1\n/g;
768 =head1 @PSISEQ = fasta2psiseq($path)
770 Reads in a FASTA file and returns an array of PSISEQ objects.
777 my $fasta = $fn =~ /\.gz$/ ?
778 FASTA::File->new(read_gzip_file => $fn) :
779 FASTA::File->new(read_file => $fn);
780 $fasta or die "JPRED: $!";
783 for ($fasta->get_entries) {
784 my $seq = PSISEQ->new;
786 $seq->align( [ @{ $_->seq } ] );
793 sub fasta2psiseq_lowmem {
799 (open $fh, "gzip -dc $fn|" or die $!) :
800 (open $fh, $fn or die $!);
808 $seq =~ s/ //g if defined $seq;
811 my $psi = PSISEQ->new(id => $id);
812 $psi->align([ split //, $seq ]);
814 undef $id; undef $seq;
823 my $psi = PSISEQ->new(id => $id);
831 =head1 die_if_no_seqs($size, $message, @seqs)
833 Exits with error message if @seqs is not at least $size.
838 my ($size, $message, @seqs) = @_;
840 confess "JPRED: Not PSISEQ" if grep { not isa $_, 'PSISEQ' } @seqs;
843 die "JPRED: $message\n" unless @seqs > $size;
846 =head1 extend($FASTA::File, @PSISEQ)
848 Sometimes PSIBLAST truncates the outputed alignment where it can't matched residues against the query, this function extends the alignment so that all of the query is present in the alignment. The other sequences are extended with gap characters.
853 my ($query, @seqs) = @_;
855 croak "JPRED: Not a Sequence::File" if grep { not isa $_, 'Sequence::File' } $query;
856 croak "JPRED: Not PSISEQ" if grep { not isa $_, 'PSISEQ' } @seqs;
858 # Get the query sequence
859 my $q_query = $query->get_entry(0);
861 # Get the query sequence from the PSIBLAST alignment
862 my $a_query = shift @seqs;
864 # The gap size required to expand the alignment
865 my ($start_gap_length, $end_gap_length);
867 # Make handling the sequence easier
868 my $q_seq = join "", @{[ $q_query->seq ]};
869 my $a_seq = join "", @{ $a_query->align };
874 ($q_seq, $a_seq) = map { uc $_ } $q_seq, $a_seq;
876 $start_gap_length = index($q_seq, $a_seq);
877 croak "JPRED: query sequence from alignment not found in original query sequence" if $start_gap_length == -1;
879 $end_gap_length = length($q_seq) - length($a_seq) - $start_gap_length;
882 # Add the gaps to the end of the alignments
885 ($GAP) x $start_gap_length,
887 ($GAP) x $end_gap_length
891 # Put the query sequence back
892 unshift @seqs, PSISEQ->new(
895 ($start_gap_length ? @{ $q_query->seq }[ 0..($start_gap_length-1) ] : ()),
896 @{ $a_query->align },
897 ($end_gap_length ? @{ $q_query->seq }[ -$end_gap_length .. -1 ] : ()),
904 =head1 $int = fasta_seq_length($path)
906 Given the path to a FASTA database, find the number of residues/bases in it. Counts whitespace as a residue.
910 sub fasta_seq_length {
912 open my $fh, $fn or croak "Can't open file $fn: $!\n";
925 =head1 log(@messages)
927 Report messages to STDERR
931 sub errlog { print STDERR @_ }