package Build::ChemPreprocess; #------------------------------------------------------------------------------------- # ($chem_nadv) = chem_preprocess( $cfg_ref, $prnt_lvl ) # # This routine does the following: # - Invokes the chemistry preprocessor # - Checks consistency of configure options # - Determines the number of transported chemical tracers # - Sets the chemistry CPP definitions # # Date Contributor Modification #------------------------------------------------------------------------------------- # 19 Sep 2008 Francis Vitt Created # 23 Oct 2009 Francis Vitt moved to perl5lib/Build directory # renamed to ChemPreprocess.pm and implemented as a module #------------------------------------------------------------------------------------- use strict; use Exporter; use File::Copy; our @ISA = qw(Exporter); our @EXPORT = qw(chem_preprocess get_species_list); our $VERSION = 1.00; my $print ; sub chem_preprocess { my ($cfg_ref,$prnt_lvl,$fc_type) = @_; $print = $prnt_lvl; my $chem_nadv = 0; my $edit_chem_mech = $cfg_ref->get('edit_chem_mech'); my $usr_mech_infile = $cfg_ref->get('usr_mech_infile'); my $prog_species = $cfg_ref->get('prog_species'); my $chem_pkg = $cfg_ref->get('chem'); my $cam_root = $cfg_ref->get('cam_root'); my $cam_bld = $cfg_ref->get('cam_bld'); my $chem_proc_src = $cfg_ref->get('chem_proc_src'); if (defined $ENV{CASEBUILD}) { #needed to expand $CASEBUILD in $chem_proc_src for CESM scripts my $root = $ENV{CASEBUILD}; $chem_proc_src =~ s/\$CASEBUILD/$root/; } my $chem_proc_bld = "$cam_bld/chem_proc"; my $chem_src_dir = "$chem_proc_bld/source"; my $chem_preprocessor = "$cam_root/models/atm/cam/chem_proc"; my $chem_mech_infile; if ($print>=2){ print "chem_preprocess: prog_species = $prog_species \n"; } if ($print>=2){ print "chem_preprocess: chem_pkg = $chem_pkg \n"; } if ($print>=2){ print "chem_preprocess: usr_mech_infile = $usr_mech_infile \n"; } if ($print>=2){ print "chem_preprocess: edit_chem_mech = $edit_chem_mech \n"; } if ($prog_species) { if ($chem_pkg =~ /"mozart"/) { die "ERROR: -prog_species $prog_species is NOT allowed with -chem $chem_pkg \n"; } if ($usr_mech_infile) { die "ERROR: -prog_species $prog_species is NOT allowed with -usr_mech_infile $usr_mech_infile \n"; } } if (!$chem_pkg) { if ($usr_mech_infile) { die "ERROR: -usr_mech_infile $usr_mech_infile is NOT allowed without -chem option. \n"; } } # create chem proc directory tree my $cmd = "mkdir -p $chem_proc_bld/tmp"; run_shell_command($cmd); if (!$usr_mech_infile) { if ($prog_species) { if ($usr_mech_infile) { die "ERROR: *** Cannot specify usr_mech_infile with prog_species *** \n" ; } $chem_mech_infile = "$chem_proc_bld/chem_mech.inp"; write_chem_preproc($chem_mech_infile, $cfg_ref, $chem_preprocessor , $chem_proc_bld); } else { $usr_mech_infile = "$cam_root/models/atm/cam/src/chemistry/pp_${chem_pkg}/chem_mech.in"; } } if ($usr_mech_infile) { if ($prog_species) { die "ERROR: *** Cannot specify usr_mech_infile with prog_species *** \n" ; } $chem_mech_infile = "$chem_proc_bld/chem_mech.inp"; write_chem_mech($usr_mech_infile, $chem_mech_infile, $chem_preprocessor , $chem_proc_bld ); } if ($chem_mech_infile) { if ($edit_chem_mech) { edit_chem_preproc($chem_mech_infile); } $cfg_ref->set('chem_proc_bld', $chem_proc_bld); my $chem_proc_exe = "campp"; if (! -e "$chem_proc_bld/$chem_proc_exe") { my $gmake = 'gmake'; build_chem_preproc($gmake,$chem_preprocessor ,$chem_proc_bld,$chem_proc_exe,$fc_type); } run_chem_preproc($chem_proc_bld,$chem_proc_exe,$chem_mech_infile,$chem_proc_src,$cam_bld); if ($usr_mech_infile) { copy( $usr_mech_infile ,"$cam_bld/chem_mech.in") or die "copy failed $! \n"; } else { copy( $chem_mech_infile ,"$cam_bld/chem_mech.inp") or die "copy failed $! \n"; } copy( "$chem_proc_bld/chem_mech.doc" ,$cam_bld) or die "copy failed $! \n"; # determine the number of transported chemical tracers open INPUT, "$chem_proc_src/chem_mods.F90"; while ( my $line = ) { if ( $line =~ m/gas_pcnst\s*=/ ) { if($line =~ m/(\d+)/) { # extract the number of chem species $chem_nadv += $1; if ($print>=2) { print "total number of chemical species = $chem_nadv \n"; } } else { die "**** Not able to determine total number of chemical species ****\n"; } } if ( $line =~ /nslvd\s*=/ ) { if($line =~ m/(\d+)/) { # extract the number of chem species $chem_nadv = $chem_nadv - $1; if ($print>=2) { print "number of short-lived chemical species = $1 \n"; } if ($print>=2) { print "number of transported chemical species = $chem_nadv \n"; } } else { die "**** Not able to determine number of short-lived species ****\n"; } } } close INPUT; my $chem_nwat = 0; my @species = get_species_list($chem_src_dir); foreach my $tracer (@species) { if ( $tracer eq 'H2O' ) { $chem_nwat = 1; } } if ($print>=2) { print "number of water vapor species = $chem_nwat \n"; } $chem_nadv -= $chem_nwat ; } if ($print>=2) { print "Number of chem adv tracers: $chem_nadv \n"; } return ($chem_nadv); } #----------------------------------------------------------------------------------------------- # Utility routines #----------------------------------------------------------------------------------------------- sub get_species_list { my ($chem_src_dir) = @_; if (! -e $chem_src_dir ) { die "**** ERROR ****\n ChemPreprocess::get_species_list cannot find $chem_src_dir \n"; } my @species_list ; my $end_of_rec = $/; $/ = "/)"; open INPUT, "$chem_src_dir/mo_sim_dat.F90"; while ( my $data = ) { if ( $data =~ /\s*solsym\(:/ ) { chomp $data ; my @list = split( /\//, $data ); my @spec_list = split( /\W+/, @list[ $#list ] ); foreach my $item (@spec_list) { if ( length($item) > 0 ){ push ( @species_list, $item ); } } } } close INPUT; $/ = $end_of_rec; return ( @species_list ); } sub run_shell_command { my ($cmd) = @_; if ($print>=2) { print "cmd = $cmd\n";} my @out = `$cmd`; my $cmd_error = $? ; #CHILD_ERROR; foreach my $i (@out) { if ($print>=2) { print "$i";} if ($cmd_error || $i =~ /abort/ || $i =~ /Failed/ ) { die "**** FAILED ****\n$i\n"; } } } #----------------------------------------------------------------------------------------------- sub edit_chem_preproc { my ($chem_proc_inp) = @_; my $cam_chem_editor = 'vi'; if ($print>=2) { print "edit chemistry mechanism file.... \n";} if (defined $ENV{CAMCHEM_EDITOR}) { $cam_chem_editor = $ENV{CAMCHEM_EDITOR}; } my $command = "$cam_chem_editor $chem_proc_inp"; my $status = system("$command"); if (($status >>=8) != 0) { die "Failed to run $command"; } if ($print>=2) { print "edit chemistry mechanism file complete. \n";} } #----------------------------------------------------------------------------------------------- sub run_chem_preproc { my ($chem_proc_bld,$chem_proc_exe,$chem_proc_inp,$src_dir,$cam_bld) = @_; if ($print>=2) { print "run_chem_preproc.... \n";} # clean out old version my $cmd = "rm -rf $src_dir $chem_proc_bld/cam.subs.tar"; run_shell_command($cmd); # run chem preprocessor my $cmd = "$chem_proc_bld/$chem_proc_exe $chem_proc_inp 2>&1"; run_shell_command($cmd); if ($print) { print "creating $src_dir\n"; } # create dir to for new code my $cmd = "mkdir -p $src_dir"; run_shell_command($cmd); # get new code from tar filex #my $cmd = "tar -xf $chem_proc_bld/cam.subs.tar -C $src_dir"; my $cmd = "cd $src_dir && tar -xf $chem_proc_bld/cam.subs.tar"; run_shell_command($cmd); if ($print>=2) { print "run_chem_preproc complete\n"; } } #----------------------------------------------------------------------------------------------- sub build_chem_preproc { my ($gmake,$chem_proc_src,$chem_proc_bld,$chem_proc_exe,$fc_type) = @_; if ($print>=2) { print "build_chem_preproc.... \n"; } if ($print) { print "creating $chem_proc_bld/$chem_proc_exe\n"; } $ENV{'MODEL_EXEDIR'} = "$chem_proc_bld"; $ENV{'EXENAME'} = "$chem_proc_exe"; $ENV{'SRCLIST'} = "$chem_proc_src/src/Base_Srclist_f"; $ENV{'SRCDIRS'} = "$chem_proc_src/src/cam_chempp"; $ENV{'OBJ_DIR'} = "$chem_proc_bld"; my $cmplr ; if ($fc_type) { if ($fc_type eq 'pgi') { $cmplr = 'pgf90'; } elsif ($fc_type eq 'lahey') { $cmplr = 'lf95'; } elsif ($fc_type eq 'intel') { $cmplr = 'ifort'; } elsif ($fc_type eq 'gnu') { $cmplr = 'gfortran'; } elsif ($fc_type eq 'xlf') { $cmplr = 'xlf95'; } } else { $cmplr = $ENV{'CHEMPROC_FC'}; } # if the user specified cam fortran compiler (via CHEMPROC_FC) then use that for chem preprocessor if ($cmplr) { if ($print>=2) { print " ****************************************** \n"; print " ****************************************** \n"; print " ** user has specified compiler : $cmplr \n"; print " ****************************************** \n"; print " ****************************************** \n"; } $ENV{'COMPILER'} = $cmplr ; } else { my $cmplr = find_preproc_compiler(); if ($cmplr) { $ENV{'COMPILER'} = $cmplr ; } else { die "** Not able to find fortran compiler for chemistry preprocessor ** \n"; } } if ($print) { print " **************************************************** \n"; print " compile preprocessor with this fortran compiler:\n"; my $prnt_cmplr = $ENV{'COMPILER'}; print " env var COMPILER = $prnt_cmplr \n"; print " **************************************************** \n"; } my $log_file = "$chem_proc_bld/MAKE.out"; my $makefile = "$chem_proc_src/src/Makefile"; my $cmd = "$gmake -f $makefile > $log_file 2>&1"; run_shell_command($cmd); my $cmd = "rm -f $chem_proc_bld/*.o $chem_proc_bld/*.mod"; run_shell_command($cmd); if ($print>=2) { print "build_chem_preproc complete\n"; } } #----------------------------------------------------------------------------------------------- sub write_chem_mech { my ($file_in, $chem_proc_file, $proc_src, $proc_bld) = @_; my $fh_in = new IO::File; my $fh_out = new IO::File; if ($print) { print "creating $chem_proc_file\n"; } $fh_out->open(">$chem_proc_file") or die "** can't open chem preprocessor input file: $chem_proc_file\n"; print $fh_out <<"EOF"; BEGSIM output_unit_number = 7 output_file = chem_mech.doc temp_path = $proc_bld/tmp/ procout_path = $proc_bld/ output_path = $proc_bld/ src_path = $proc_src/bkend/ procfiles_path = $proc_src/procfiles/cam/ sim_dat_path = $proc_bld/ sim_dat_filename = chem_mech.dat EOF # Copy the chemistry mechanism. $fh_in->open("<$file_in") or die "** can't open file: $file_in\n"; while (<$fh_in>) { print $fh_out $_; } $fh_in->close; print $fh_out <<"EOF"; ENDSIM EOF $fh_out->close; } #----------------------------------------------------------------------------------------------- # searches $PATH for available compiler for the preprocessor sub find_preproc_compiler { # these are the compilers the preprocessor Makefile is setup for : my @compilers = qw(xlf95 pgf90 pgf95 ifort lf95 gfortran g95 f90 f95); my $path = $ENV{'PATH'}; my @dirs = split(':',$path); foreach my $fc (@compilers) { foreach my $dir (@dirs) { if ( -e "$dir\/$fc" ) { return $fc; } } } } #----------------------------------------------------------------------------------------------- sub write_chem_preproc { my ($chem_proc_file, $cfg_ref, $proc_src, $proc_bld) = @_; my $prog_species = $cfg_ref->get('prog_species'); my $fh = new IO::File; if ($print) { print "creating $chem_proc_file\n"; } $fh->open(">$chem_proc_file") or die "** can't open chem preprocessor input file: $chem_proc_file\n"; print $fh <<"EOF"; BEGSIM output_unit_number = 7 output_file = chem_mech.doc temp_path = $proc_bld/tmp/ procout_path = $proc_bld/ output_path = $proc_bld/ src_path = $proc_src/bkend/ procfiles_path = $proc_src/procfiles/cam/ sim_dat_path = $proc_bld/ sim_dat_filename = chem_mech.dat Comments "This is a CAM simulation with :" End Comments SPECIES Solution EOF if ( $prog_species =~ /SO4/ ) { print $fh " H2O2, SO2, SO4, DMS -> CH3SCH3\n"; } if ( $prog_species =~ /OC/ ) { print $fh " OC1 -> C, OC2 -> C\n"; } if ( $prog_species =~ /BC/ ) { print $fh " CB1 -> C, CB2 -> C\n"; } if ( $prog_species =~ /GHG/ ) { print $fh " CH4, N2O, CFC11 -> CFCl3, CFC12 -> CF2Cl2, H2O\n"; } if ( $prog_species =~ /SSLT/ ) { print $fh " SSLT01 -> NaCl, SSLT02 -> NaCl, SSLT03 -> NaCl, SSLT04 -> NaCl\n"; } if ( $prog_species =~ /DST/ ) { print $fh " DST01 -> AlSiO5, DST02 -> AlSiO5, DST03 -> AlSiO5, DST04 -> AlSiO5\n"; } if ( $prog_species =~ /CARBON16/ ) { print $fh " OFPHO -> C, BFPHO -> C, OBPHO -> C, BBPHO -> C \n"; print $fh " OOPHO -> C, BOPHO -> C, NOPHO -> C, MMPHO -> C \n"; print $fh " OFPHI -> C, BFPHI -> C, OBPHI -> C, BBPHI -> C \n"; print $fh " OOPHI -> C, BOPHI -> C, NOPHI -> C, MMPHI -> C \n"; } print $fh <<"EOF"; End Solution Fixed M, N2, O2 EOF if ( $prog_species =~ /SO4/ ) { print $fh " O3, OH, NO3, HO2\n"; } print $fh <<"EOF"; End Fixed Col-int O3 = 0. O2 = 0. End Col-int End SPECIES Solution Classes Explicit End Explicit Implicit EOF if ( $prog_species =~ /SO4/ ) { print $fh " H2O2, SO2, SO4, DMS\n"; } if ( $prog_species =~ /CARBON16/ ) { print $fh " OFPHO,BFPHO,OBPHO,BBPHO,OOPHO,BOPHO,NOPHO,MMPHO \n"; print $fh " OFPHI,BFPHI,OBPHI,BBPHI,OOPHI,BOPHI,NOPHI,MMPHI \n"; } if ( $prog_species =~ /BC/ ) { print $fh " CB1, CB2\n"; } if ( $prog_species =~ /OC/ ) { print $fh " OC1, OC2\n"; } if ( $prog_species =~ /GHG/ ) { print $fh " CH4, N2O, CFC11, CFC12, H2O\n"; } if ( $prog_species =~ /SSLT/ ) { print $fh " SSLT01, SSLT02, SSLT03, SSLT04\n"; } if ( $prog_species =~ /DST/ ) { print $fh " DST01, DST02, DST03, DST04\n"; } print $fh <<"EOF"; End Implicit End Solution Classes CHEMISTRY Photolysis End Photolysis Reactions EOF if ( $prog_species =~ /CARBON16/ ) { print $fh " OFPHO -> OFPHI ; 1.006e-05 \n"; print $fh " BFPHO -> BFPHI ; 1.006e-05 \n"; print $fh " OBPHO -> OBPHI ; 1.006e-05 \n"; print $fh " BBPHO -> BBPHI ; 1.006e-05 \n"; print $fh " OOPHO -> OOPHI ; 1.006e-05 \n"; print $fh " BOPHO -> BOPHI ; 1.006e-05 \n"; print $fh " NOPHO -> NOPHI ; 1.006e-05 \n"; print $fh " MMPHO -> MMPHI ; 1.006e-05 \n"; } if ( $prog_species =~ /BC/ ) { print $fh " CB1 -> CB2 ; 1.006e-05 \n"; } if ( $prog_species =~ /OC/ ) { print $fh " OC1 -> OC2 ; 1.006e-05 \n"; } if ( $prog_species =~ /GHG/ ) { print $fh " [ch4_loss] CH4 -> 2.* H2O\n"; print $fh " [n2o_loss] N2O -> \n"; print $fh " [cfc11_loss] CFC11 -> \n"; print $fh " [cfc12_loss] CFC12 -> \n"; print $fh " [lyman_alpha] H2O -> \n"; } print $fh <<"EOF"; End Reactions Heterogeneous EOF if ( $prog_species =~ /SO4/ ) { print $fh " H2O2, SO2 \n"; } print $fh <<"EOF"; End Heterogeneous Ext Forcing EOF if ( $prog_species =~ /SO4/ ) { print $fh " SO2 <- dataset\n"; print $fh " SO4 <- dataset\n"; } print $fh <<"EOF"; End Ext Forcing END CHEMISTRY SIMULATION PARAMETERS Version Options model = cam machine = intel architecture = hybrid vec_ftns = on multitask = on namemod = on modules = on End Version Options END SIMULATION PARAMETERS ENDSIM EOF $fh->close; } 1; # to appease require