#!/bin/sh # -*-Perl-*- (for Emacs) vim:set filetype=perl: (for vim) #======================================================================# # Run the right perl version: if [ -x /usr/local/bin/perl ]; then perl=/usr/local/bin/perl elif [ -x /usr/bin/perl ]; then perl=/usr/bin/perl else perl=`which perl| sed 's/.*aliased to *//'` fi exec $perl -x -S $0 "$@"; # -x: start from the following line #======================================================================# #! /Good_Path/perl -w # line 17 # # Name : mkcparam # Author : wd (Wolfgang.Dobler@kis.uni-freiburg.de) # Started : 06-Jul-2002 # CVS : $Id$ # # Usage: # mkcparam [-b] [ [..]] [-o outfile]\n # # Description: # Checks the headers (everything before the first non-comment non-empty # line) of input files for lines of the sort # ! MVAR CONTRIBUTION 3 # ! MAUX CONTRIBUTION 1 # ! MGLOBAL CONTRIBUTION 1 # ! MSCRATCH CONTRIBUTION 1 # ! COMMUNICATED AUXILIARIES 1 # ! NDUSTSPEC CONTRIBUTION 17 # ! NDUSTRAD CONTRIBUTION 10 # ! NPARTDISP CONTRIBUTION 30 # ! NCHEMSPEC CONTRIBUTION 3 # ! NPSCALAR CONTRIBUTION 3 # and accumulates the numbers mvar, maux, maux_com, mglobal, mscratch, # ndustspecs, etc. from these. # # Lines of the form # ! PENCILS PROVIDED uu(3), u2, uij(3,3), gmi(3,ndustspec) # accumulate lists of pencils provided by the input files. The pencils # must be separated by a "," or ";", and for non-scalar pencils the # dimensions must be specified in parenthesis immediately after the # pencil name. # # Output is written as a Fortran program and supposed to end up in the # local file src/cparam.inc . # # Options: # -b, --backdate -- when set and any of the generated files looks # identical to the original file before mkcparam was # called, revert the timestamp to that of the # original. This avoids unnecessary recompilations. # -o , # --output= -- write cparam.inc output to the given file name. # This option does not make much sense any more, # since by now we write at least three files, so all # of them should just be hard-coded in this script. # Example: # mkcparam entropy.f90 nomagnetic.f90 hydro.f90 > src/cparam.inc # # History: # # 30-nov-02/tony: Modified to use makefile lines where the Make variable # and module name differ by more than just case # e.g. VISCOSITY=visc_shock # Also count maux variables too. # # 12-oct-03/tony: Modified to use in-code declarations of f-array # contributions. # Fortran files should contain a block at the top to # declare any contribution they make to the f-array. # # 07-apr-05/tony: Added the ability to have 'communicated auxiliaries' # ie. variables which are not evolved (hence have no # part in the df array), but which are updated at the # end of a timestep and communicated along with the mvar # variables in the f-array. # # ---------------------------------------------------------------------- # my $mvar_decl = '^\s*!\s*MVAR\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $maux_decl = '^\s*!\s*MAUX\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $mogaux_decl = '^\s*!\s*MOGAUX\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $mglobal_decl = '^\s*!\s*MGLOBAL\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $mscratch_decl = '^\s*!\s*MSCRATCH\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $maux_com_decl = '^\s*!\s*COMMUNICATED\s*AUXILIARIES\s*(-?[0-9]+)\s*$'; my $mpvar_decl = '^\s*!\s*MPVAR\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $mpaux_decl = '^\s*!\s*MPAUX\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $mqvar_decl = '^\s*!\s*MQVAR\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $mqaux_decl = '^\s*!\s*MQAUX\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $ndustrad_decl = '^\s*!\s*NDUSTRAD\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $npartdisp_decl = '^\s*!\s*NPARTDISP\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $dust_decl = '^\s*!\s*NDUSTSPEC\s*CONTRIBUTION\s*(-?[0-9]+\*[0-9])\s*$'; my $chem_decl = '^\s*!\s*NCHEMSPEC\s*CONTRIBUTION\s*(-?[0-9]+\*[0-9])\s*$'; my $pscalar_decl = '^\s*!\s*NPSCALAR\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $pencils_decl = '^\s*!\s*PENCILS\s*PROVIDED\s*(.*)\s*$'; my $cparam_decl = '^\s*!\s*CPARAM\s*(.*?)\s*$'; my $nadsspec_decl = '^\s*!\s*NADSSPEC\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; my $nsurfreacspec_decl = '^\s*!\s*NSURFREACSPEC\s*CONTRIBUTION\s*(-?[0-9]+)\s*$'; # ---------------------------------------------------------------------- # use strict; use Getopt::Long; my $line; my $dust_string = '1*4'; my $chem_string = '1'; my $ndustrad = 1; my $npartdisp = 20; my ($maux, $maux_com, $mvar, $mglobal, $mscratch, $mpvar, $mpaux, $mqvar, $mqaux) = (0) x 20; my ($ndustspec, $nchemspec, $mvar_per_dust, $mvar_per_chem, $mogaux) = (0) x 20; my $npscalar = 0; my $nadsspec = 0; my $nsurfreacspec = 0; my @pencil_names; my @pencil_sizes; my %pencil_file_map; my @cparam_lines; (my $cmdname = $0) =~ s{.*/}{}; my %open_files; my $penc_name_len=''; # # Process command line. # my (%opts); # Variables written by GetOptions GetOptions(\%opts, qw( -h --help -o=s --output=s -b --backdate )); die usage() if ((@ARGV == 0) || $opts{h} || $opts{help}); my $outfile = ($opts{o} || $opts{output} || "cparam.inc"); my $backdate = ($opts{b} || $opts{backdate} || ""); # # Cycle through files (later files will overwrite effect of earlier files) # file: foreach my $infile (@ARGV) { # Extract `?VAR CONTRIBUTION' info from each file unless (open(INPUT,"< $infile")) { die "Can't open $infile for reading"; next file; } # Cycle through all lines up to first non-empty non-comment line in # file: line: while (defined($line=)) { next line if ($line =~ /^\s*$/); # ignore empty lines last line if ($line !~ /^\s*!/); # done if non-comment line extract_decl ($line, $mvar_decl , \$mvar ); extract_decl ($line, $maux_decl , \$maux ); extract_decl ($line, $mogaux_decl , \$mogaux ); extract_decl ($line, $mglobal_decl , \$mglobal ); extract_decl ($line, $mscratch_decl, \$mscratch ); extract_decl ($line, $maux_com_decl, \$maux_com ); extract_decl ($line, $mpvar_decl , \$mpvar ); extract_decl ($line, $mpaux_decl , \$mpaux ); extract_decl ($line, $mqvar_decl , \$mqvar ); extract_decl ($line, $mqaux_decl , \$mqaux ); extract_decl ($line, $pscalar_decl , \$npscalar ); extract_decl ($line, $nadsspec_decl, \$nadsspec ); extract_decl ($line, $nsurfreacspec_decl, \$nsurfreacspec); extract_decl_reset ($line, $ndustrad_decl, \$ndustrad ); extract_decl_reset ($line, $npartdisp_decl, \$npartdisp); # Check for information about number of chemical and dust species # and discretization type: if ($line=~ /$chem_decl/) {$chem_string=$1;} if ($line=~ /$dust_decl/) {$dust_string=$1;} if ($line=~ /$cparam_decl/) {unshift @cparam_lines, $1;} # Extract provided pencils from file headers: if ($line=~ /$pencils_decl/) { # my @pencils = split /\s*;\s*/, $2; # foreach my $pencil (@pencils) { while ($line =~ s{ ^ # anchor at start (?: # group, don't capture !\ PENCILS\ PROVIDED # either initial marker | # ..or.. \s*[,;] # separator ) \s* # arbitrary whitespace ( # capture as $1 [a-zA-Z0-9_]+ # variable name (?: # group, don't capture \( # ( [a-zA-Z0-9_]+ # (,[a-zA-Z0-9_]+)* # optional ,[,]... \) # ) )? # the (..) part is optional ) } {}x) { # delete everything matched my $pencil=$1; my $pencil_name=$pencil; my $pencil_size=$pencil; # Extract name and size of pencils: if ($pencil =~ /\(.*\)/) { $pencil_size=~ s/^.*\((.*)\)/$1/g; } else { $pencil_size=''; } $pencil_name =~ s/\(.*\)//g; # Default pencil size is (nx) if ($pencil_size eq '') { $pencil_size='(nx)' } else { $pencil_size="(nx,$pencil_size)"; } # Store pencil information in arrays: my $pencil_already_used=0; foreach my $pencil_name_used (@pencil_names){ if ($pencil_name eq $pencil_name_used) {$pencil_already_used=1;} } push @{$pencil_file_map{$pencil_name}}, $infile; if ($pencil_already_used eq 0) { push @pencil_names, $pencil_name; push @pencil_sizes, $pencil_size; } } } } } # Warn about ambiguous pencil definitions. # THIS WILL SOON BECOME A FATAL ERROR. while (my ($name, $files_ref) = each %pencil_file_map) { my @files = @{$files_ref}; if (@files > 1) { print "### ¡¡¡WARNING!!! ###: $name multiply declared: in @files\n"; } } # Calculate the total number of pencils my $npencils = $#pencil_names+1; # More processing of dust information: ($ndustspec, $mvar_per_dust) = split /\*/, $dust_string; if ($ndustspec >= 1) { if ($mvar_per_dust > 1) { if ($mvar_per_dust == 2 || $mvar_per_dust == 5) { $mvar = $mvar + ($ndustspec-1)*$mvar_per_dust + 1; } else { if ($mvar_per_dust == 9) { $mvar = $mvar + ($ndustspec)*$mvar_per_dust -1; } else { $mvar = $mvar + ($ndustspec-1)*$mvar_per_dust; } } } else { $mvar = $mvar + ($ndustspec-1)*$mvar_per_dust; } } # More processing of chemistry information: ($nchemspec, $mvar_per_chem) = split /\*/, $chem_string; if ($nchemspec >= 1) { $mvar = $mvar + $nchemspec - 1; } # More processing of passive scalars information: if ($npscalar > 1) { $mvar = $mvar + $npscalar - 1; } else { $npscalar = 1; } # More processing of particle chemistry information: if ($nsurfreacspec >= 1) { $mpvar = $mpvar + $nsurfreacspec; } if ($nadsspec >= 1) { $mpvar = $mpvar + $nadsspec; } # # cparam.inc # my $data_cparam = <<"EOF"; ! -*-f90-*- (for emacs) vim:set filetype=fortran: (for vim) ! cparam.inc ! ! This file was automatically generated by $cmdname, so think twice before ! you modify it. ! ! It is included by cparam.f90 and defines some constants based on the ! settings in Makefile.local ! integer, parameter :: mvar=${\($mvar+0)}, maux=${\($maux+0)} integer, parameter :: maux_com=${\($maux_com+0)} integer, parameter :: mogaux=${\($mogaux+0)} integer, parameter :: mglobal=${\($mglobal+0)} integer, parameter :: mscratch=${\($mscratch+0)} integer, parameter :: mpvar=${\($mpvar+0)} integer, parameter :: mpaux=${\($mpaux+0)} integer, parameter :: mqvar=${\($mqvar+0)} integer, parameter :: mqaux=${\($mqaux+0)} integer, parameter :: ndustspec=${\($ndustspec+0)} integer, parameter :: nchemspec=${\($nchemspec+0)} integer, parameter :: npscalar=${\($npscalar+0)} integer, parameter :: nadsspec=${\($nadsspec+0)} integer, parameter :: nsurfreacspec=${\($nsurfreacspec+0)} integer, parameter :: ndustrad=${\($ndustrad+0)} integer, parameter :: npartdisp=${\($npartdisp+0)} EOF # Set npar (number of particles) to one if particles are not used: if ($mpvar == 0) { $data_cparam .= "integer, parameter :: npar=1\n\n"; } else { $data_cparam .= "! npar should be declared and set in cparam.local\n\n"; } # Set nqpar (number of massive particles, i.e, point masses) to one if point masses are not used: if ($mqvar == 0) { $data_cparam .= "integer, parameter :: nqpar=1\n\n"; } else { $data_cparam .= "! nqpar should be declared and set in cparam.local\n\n"; } # # Read contents of cparam.local # open CPARAM, "cparam.local"; my @cparam = ; close CPARAM; # # Find out which particle parameters are defined in cparam.local. # my $mpar_loc=0; my $npar_mig=0; my $npar_species=0; my $nqpar=0; my $npar_stalk=0; my $nbrickx=0; my $nbricky=0; my $nbrickz=0; my $nblockmax=0; foreach $line (@cparam) { $line=substr($line, 0, index($line,"!")); # ignore comment lines $mpar_loc=1 if ($line =~ 'mpar_loc'); $npar_mig=1 if ($line =~ 'npar_mig'); $npar_species=1 if ($line =~ 'npar_species'); # $nqpar=1 if ($line =~ 'nqpar'); $npar_stalk=1 if ($line =~ 'npar_stalk'); $nbrickx=1 if ($line =~ 'nbrickx'); $nbricky=1 if ($line =~ 'nbricky'); $nbrickz=1 if ($line =~ 'nbrickz'); $nblockmax=1 if ($line =~ 'nblockmax'); } # Write default values of undefined particle parameters to cparam.inc: add_line_avoid_duplicate ($data_cparam, "integer, parameter :: mpar_loc=npar") unless $mpar_loc; add_line_avoid_duplicate ($data_cparam, "integer, parameter :: npar_mig=1") unless $npar_mig; add_line_avoid_duplicate ($data_cparam, "integer, parameter :: npar_species=1") unless $npar_species; #add_line_avoid_duplicate ($data_cparam, "integer, parameter :: nqpar=1") unless $nqpar; add_line_avoid_duplicate ($data_cparam, "integer, parameter :: npar_stalk=0") unless $npar_stalk; add_line_avoid_duplicate ($data_cparam, "integer, parameter :: nbrickx=1") unless $nbrickx; add_line_avoid_duplicate ($data_cparam, "integer, parameter :: nbricky=1") unless $nbricky; add_line_avoid_duplicate ($data_cparam, "integer, parameter :: nbrickz=1") unless $nbrickz; add_line_avoid_duplicate ($data_cparam, "integer, parameter :: nblockmax=1") unless $nblockmax; # Insert all CPARAM lines, extracted from the headers of the chosen physics # modules: foreach $line (@cparam_lines) { add_line_avoid_duplicate ($data_cparam, $line); } update_file ($outfile, $data_cparam); # # cparam_pencils.inc # my $data_cparam_pencil = <<"EOF"; ! -*-f90-*- (for emacs) vim:set filetype=fortran: (for vim) ! cparam_pencils.inc ! ! This file was automatically generated by $cmdname, so think twice before ! you modify it. ! ! It is included by cparam.f90 and defines the pencil_case data type and ! sets some variables related to this. ! EOF # Generate cparam_pencils.inc where the pencil case is defined and # initialized: $data_cparam_pencil .= <<"EOF"; integer, parameter :: npencils=$npencils type pencil_case EOF # Define pencils in pencil case: my $i=0; foreach my $pencil_name (@pencil_names) { $data_cparam_pencil .= " real, dimension $pencil_sizes[$i] :: $pencil_name\n"; $i = $i+1; } $data_cparam_pencil .= "endtype pencil_case\n\n"; # Define pencil indices: $i=1; foreach my $pencil (@pencil_names) { $data_cparam_pencil .= "integer :: i_$pencil=$i\n"; $i++; } unless (open(INPUT,"< cparam.f90")) { die "Can't open cparam.f90 for reading" } while (defined($line=)) { if ( $line =~ /penc_name_len\s*=\s*[0-9]/ ) { ($penc_name_len) = $line =~ m/=([0-9]+)/; last; } } # Define pencil names: $data_cparam_pencil .= "character (len=penc_name_len), parameter, dimension(npencils) :: pencil_names = &\n (/ "; $i=0; foreach my $pencil (@pencil_names){ $data_cparam_pencil .= ", " if ($i != 0); $data_cparam_pencil .= "'$pencil" . " " x ($penc_name_len-length($pencil)) . "'"; $data_cparam_pencil .= " &\n " if (($i % 5) == 3); $i++; } $data_cparam_pencil .= " /)\n"; # Define pencil logicals, used by the code to distinguish between needed # and not needed pencils: $data_cparam_pencil .= <<"EOF"; logical, parameter, dimension(npencils):: lpenc_required = .false. logical, dimension(npencils):: lpenc_diagnos = .false. logical, dimension(npencils):: lpenc_diagnos2d = .false. logical, dimension(npencils):: lpenc_video = .false. logical, dimension(npencils):: lpenc_requested = .false. logical, dimension(npencils):: lpencil = .false. EOF update_file ("cparam_pencils.inc", $data_cparam_pencil); # # pencil_init.inc # # Generate pencil_init.inc, for initializing the pencil case: my $data_pencil_init = <<"EOF"; ! -*-f90-*- (for emacs) vim:set filetype=fortran: (for vim) ! pencil_init.inc ! ! This file was automatically generated by $cmdname, so think twice before ! you modify it. ! ! It is included by equ.f90 and defines a subroutine to reset all pencils to ! a reference value for pencil_consistency_check(). ! subroutine initialize_pencils(p,penc0) type (pencil_case) :: p real :: penc0 EOF # foreach my $pencil (@pencil_names) { $data_pencil_init .= " p%$pencil = penc0\n"; } # $data_pencil_init .= "\nendsubroutine initialize_pencils"; update_file ("pencil_init.inc", $data_pencil_init); # ---------------------------------------------------------------------- # sub add_line_avoid_duplicate { # # Add a line but avoid duplicate lines. # my ($data,$line) = @_; my $search = $line; $search =~ s/=.*$/=/gs; $search =~ s/^ +//s; if (index ($data, "\n".$search) == -1) { # update $data in caller $_[0] .= $line."\n"; } } # ---------------------------------------------------------------------- # sub update_file { # # Update a file's content, if necessary. # my ($file,$data) = @_; my @old_data; if (-e $file) { # read existing file's content open (OLD, "< ".$file); @old_data = ; close (OLD); if (join ('', @old_data) eq $data) { # file exists and is up-to-date => nothing to be done return; } if ($backdate) { # create the requested backup rename $file, backup_file ($file); } } write_file ($file, $data); } # ---------------------------------------------------------------------- # sub write_file { # # Write a file # my ($file,$data) = @_; open (my $fh, "> ".$file) or die "Can't open $file for writing!"; print $fh $data; close ($fh); } # ---------------------------------------------------------------------- # sub backup_file { # # Return filename for backup of given file # my ($file) = @_; return $file . '_previous'; } # ---------------------------------------------------------------------- # sub extract_decl { # # Extract declaration of contribution to mvar and similar. # my $line = shift; my $regexp = shift; my $counter_ref = shift; if ($line =~ /$regexp/) { $$counter_ref += $1; } } # ---------------------------------------------------------------------- # sub extract_decl_reset { # # Extract declaration of contribution to mvar and similar. # my $line = shift; my $regexp = shift; my $counter_ref = shift; if ($line =~ /$regexp/) { $$counter_ref = $1; } } # ---------------------------------------------------------------------- # sub usage { # # Extract description and usage information from this file's header. # my $thisfile = __FILE__; local $/ = ''; # Read paragraphs open(FILE, "<$thisfile") or die "Cannot open $thisfile\n"; while () { # Paragraph _must_ contain `Description:' or `Usage:' next unless /^\s*\#\s*(Description|Usage):/m; # Drop `Author:', etc. (anything before `Description:' or `Usage:') s/.*?\n(\s*\#\s*(Description|Usage):\s*\n.*)/$1/s; # Don't print comment sign: s/^\s*# ?//mg; last; # ignore body } $_ or "\n"; } # ---------------------------------------------------------------------- # # End of file mkcparam