Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
grid-wrap.pl 9.58 KiB
#!/usr/bin/env perl
use 5.16.0;
use strict;
use Sort::Key qw(nsort);
use rob_misc;
use binary_grid;
use threads;
use threads::shared;
use Fcntl ':flock'; # import LOCK_* constants
use subs qw(logprint logprintf);
use Carp qw(confess);
use File::Path qw(make_path);
$|=1;
############################################################

my $outdir='/tmp/gridtest'; 
my $nmachines=20;

say "Run across (modulo=) ",scalar(@machines)," machines";
my $modulo=scalar(@machines);

my @pids;
my @datafiles;
my $offset=0;
my @spectral_type_strings=('O','B','A','F','G','K','M');
my %spectral_type;  revspechash();
my @stellar_type_strings;
my @short_stellar_type_strings;
my %short_stellar_type_strings;
my $period_binwidth=0.1; # width in logP of histograms
my $log_fp;
defaults();

foreach my $machine (0..$nmachines)
{
    my $datafile="$outdir/results.$offset";
    my $cmd="./src/perl/scripts-flexigrid/grid-canberra.pl modulo=$modulo offset=$offset results_hash_dumpfile=$datafile";
    
    say "Run $cmd";

    my $forkr;

    # run the models : should outsource this to binary_grid::condor module
    if(1){     
	$forkr=fork();
	if($forkr==0)
	{
	    print `$cmd 2>$outdir/grid.$offset.err > $outdir/grid.$offset.out`;
	    exit;
	}
    }

    push(@pids,$forkr);
    push(@datafiles,$datafile);
    
    $offset++;
}

# wait for children to finish
say "Waiting for children (pids: @pids)";
map { waitpid $_,0; }@pids;

say "Children finished\n";


# put all the data together
my $results=merge_results_hash_dumps(@datafiles);

# save ouput
output();

if(0)
{
    use Data::Dumper;
    open($log_fp,">$outdir/datadump")||confess("cannot open $outdir/datadump"); 
    print {$log_fp} Dumper($results);
    close $log_fp;
}

say "Done\n";
exit;

############################################################


sub output
{
    # open log file
    
    # check for an output directory, otherwise assume a default in /tmp
    
    # output binary_grid::grid_options/bse_options
    open($log_fp,">$outdir/grid_options")||confess("cannot open $outdir/grid_options for output");
    print $log_fp "grid_options\n\n";
    map
    {
	print {$log_fp} $_.' : '.$binary_grid::grid_options{$_}."\n";
    }keys %binary_grid::grid_options;
    close $log_fp;
    open($log_fp,">$outdir/bse_options")||confess("cannot open $outdir/bse_options for output");
    print $log_fp "bse_options\n\n";
    map
    {
	print {$log_fp} $_.' : '.$binary_grid::bse_options{$_}."\n";
    }keys %binary_grid::bse_options;
    close $log_fp;
    
    # output grid results
    open ($log_fp,">$outdir/log") || confess ("cannot open $outdir/log for output");
    logprint "\n\n\nCANBERRA Grid results\n============================================================\n\n";
    logprint "SVN Revision ",`svn info|grep Revision|gawk \"\{print \\\$2\}\"`;
    logprint "Run at ",scalar(localtime),"\n";
    
    logprint "\n\nParameters:\n";
    logprint "Initial binary fraction : Raghavan 2010\n";
    foreach my $p ('alpha_ce','lambda_ce','lambda_ionisation','z','wd_sigma')
    {
	my $opt = ($p eq 'lambda_ce' && $binary_grid::bse_options{$p}==-1) 
	    ? 'Fitted to detailed stellar models' 
	    : 
	    sprintf "%g",$binary_grid::bse_options{$p};

	logprint sprintf "% -30s = %s\n",$p eq'z'?'Metallicity':$p,$opt;
    }

    
    my $dtp_wd=1e-30; # total number count of WDs (single or binary)
    my %dtp_wd;

    {
	my $k='number count';
	# get total WD number count
	foreach my $duplicity (keys %{$results->{$k}})
	{ 
	    foreach my $wd_type (keys %{$results->{$k}->{$duplicity}})
	    {
		$dtp_wd += $$results{$k}->{$duplicity}->{$wd_type};
		$dtp_wd{$duplicity} += $$results{$k}->{$duplicity}->{$wd_type};
	    } 
	}
    }

    my $dtp_wdms=0.0;
    {
	# get total WD-MS number count
	my $k='MSWD spectral types';
	foreach my $spectral_type (nsort keys %{$results->{$k}})
	{
	    $dtp_wdms += $$results{$k}{$spectral_type};
	}    
    }


    foreach my $k (sort keys %$results)
    {
	next if($k eq 'thread_number');
	if($k eq 'number count')
	{
	    logprint sprintf "WD binary fraction %3.2f %%\n",$dtp_wd{'Binary'}/$dtp_wd*100.0;
	    foreach my $duplicity (keys %{$results->{$k}})
	    {
		foreach my $wd_type (nsort keys %{$results->{$k}->{$duplicity}})
		{
		    logprint sprintf "% -6s % -30s %3.2f %%\n",
		    $duplicity,
		    $stellar_type_strings[$wd_type], 
		    $$results{$k}->{$duplicity}->{$wd_type}/$dtp_wd*100.0;
		} 
	    }
	}
	elsif($k eq 'companion types')
	{
	    my $test_tot=0.0;
	    logprint "\n\nWhite Dwarf - ? pairs (as a fraction of all White Dwarf Binaries)\n";
	    foreach my $wd1 (nsort keys %{$results->{$k}})
	    {
		foreach my $wd2 (nsort keys %{$results->{$k}->{$wd1}})
		{
		    logprint sprintf "% -40s - % -40s     % 5.2f %%\n",
		    $stellar_type_strings[$wd1],
		    $stellar_type_strings[$wd2],
		    $$results{$k}{$wd1}{$wd2}
		    /$dtp_wd{'Binary'}*100.0;
		}
	    }
	    logprint "\n";
	}
	elsif($k eq 'test')
	{
	    # test initial binary fraction
	    my $test_tot=0.0;
	    logprint "\n\nTest numbers\n\n";
	    foreach my $duplicity (keys %{$results->{$k}})
	    {
		$test_tot += $$results{$k}->{$duplicity};
	    }
	    foreach my $duplicity (nsort keys %{$results->{$k}})
	    {
		logprint sprintf "MS $duplicity %3.2f %%\n", 100.0*$$results{$k}->{$duplicity}/$test_tot;
	    }
	}
	elsif($k eq 'test dist spectypes')
	{
	    print "ZAMS Binary fraction by spectral type : ",keys %{$results->{$k}->{'Binary'}},"\n\n";
	    foreach my $spec_type (@spectral_type_strings)
	    {
		my $t=$$results{$k}->{'Single'}->{$spec_type}+$$results{$k}->{'Binary'}->{$spec_type};
		logprint sprintf "%s %5.2f %%\n",$spec_type,$$results{$k}->{'Binary'}->{$spec_type}/$t*100.0 if($t>0.0);
	    }
	}
	elsif($k eq 'test dist')
	{
	    # test initial distributions
	    foreach my $duplicity (keys %{$results->{$k}})
	    {
		foreach my $dist (keys %{$results->{$k}->{$duplicity}})
		{
		    my $f="$outdir/init_".$duplicity.'_'.$dist.'.dat';
		    logprint "Output distribution to $f\n";
		    open(FP,">$f")||confess("can't open $f");
		    foreach my $x (nsort keys %{$results->{$k}->{$duplicity}->{$dist}})
		    {
			printf FP "%g %g\n",$x,$$results{$k}{$duplicity}{$dist}{$x};
		    }
		    close FP;
		}
	    }
	}

	elsif($k eq 'MSWD spectral types')
	{
	    my $f="$outdir/MSWD_spectral_types.dat";
	    open(FP,'>'.$f)||confess("cannot open $f for output");
	    logprint "MSWD binaries: spectral types (see datafile $f)\n";
	    pad_datahash($results->{$k},1);
	    foreach my $spectral_type (nsort keys %{$results->{$k}})
	    {
		printf FP "%d %g\n",$spectral_type,$$results{$k}{$spectral_type}/$dtp_wdms;
		logprint sprintf "MSWD spectral type %d = %s = %g\n",
		$spectral_type,$spectral_type_strings[$spectral_type],$$results{$k}{$spectral_type}/$dtp_wdms;
	    } 
	    logprint "\n";
	    close FP;
	}
	# misc period distributions
	elsif($k =~/(\S+) period distribution/)
	{
	    my $distname=$1;
	    my $f="$outdir/$distname".'_period_distribution.dat';
	    #print "Pad datahash $results->{$k}\n";
	    pad_datahash($results->{$k},$period_binwidth);
	    open(FP,'>'.$f)||confess("cannot open $f for output");
	    logprint "$1 binaries: period distribution (see datafile $f)\n";
	    foreach my $logP (nsort keys %{$results->{$k}})
	    {
		printf FP "%g %g\n",$logP,$$results{$k}{$logP};
	    } 
	    close FP;
	}
    }

    # compare to Holberg 2009
    {
	my %obs=(
	    # Holberg 2009
	    'Single WDs'=>0.70, 
	    'WD +dM'=>0.12,
	    'Sirius-Like'=>0.08,
	    'WD + WD'=>0.10,
	    'Total WDs'=>1.0,
	    );
	map{$obs{$_}*=100.0}keys %obs;

	my $format="\% -30s \% 5.2f \%\% (% 5.2f)\n";
	logprint "\n=============\nHolberg 2009 comparison\n\n";

	# Single WD fraction
	my $single_WD = $dtp_wd{'Single'}/$dtp_wd*100.0;
	logprintf $format,'Single WDs',$single_WD,$obs{'Single WDs'};
	# WD + dM fraction
	my $WD_dM=$$results{'MSWD spectral types'}{$spectral_type{'M'}}/$dtp_wd*100.0;
	logprintf $format,'WD +dM',$WD_dM,$obs{'WD +dM'};
	
	# Sirius-like fraction
	my $Sirius=0.0;
	map{$Sirius+=$$results{'MSWD spectral types'}{$spectral_type{$_}}}('O','B','A','F','G','K');
	$Sirius = $Sirius/$dtp_wd * 100.0;
	logprintf $format,'Sirius-Like',$Sirius,$obs{'Sirius-Like'};

	# WD + WD fraction
	my $WDWD=0.0;
	foreach my $wd1 (10,11,12)
	{
	    foreach my $wd2 (10,11,12)
	    {
		$WDWD += $$results{'companion types'}{$wd1}{$wd2};
	    }
	}
	$WDWD = $WDWD/$dtp_wd*100.0;
        logprintf $format,'WD + WD',$WDWD,$obs{'WD + WD'};
	
	# total (should be 100%!)
	logprintf $format,'Total WDs',($single_WD + $WD_dM + $Sirius + $WDWD),$obs{'Total WDs'};
    }

    logprint "\n============================================================\n\n\n";

    close $log_fp;
}

sub logprint
{
    print {$log_fp} "@_";
    print "@_";
}
sub logprintf
{
    my $format=shift @_;
    printf {$log_fp} $format,@_;
    printf $format,@_;
}

sub revspechash
{
    for(my $i=0;$i<=$#spectral_type_strings;$i++)
    {
	$spectral_type{$spectral_type_strings[$i]}=$i;
    }
}

sub spec_to_float
{
    my $s=$_[0]; # spectral type to check
    if($s=~/([A-Z])(\d)/)
    {
	return $spectral_type{$1}+0.1*$2;
    }
    else
    {
	print "Failed to convert spec type $_[1] to float\n";
	exit;
    }
}

sub spec_type_sorter
{
    return spec_to_float($a) <=> spec_to_float($b);
}
sub pad_datahash
{
    # pad datahash $h so it has zeros where there's no data
    my $h=shift;
    my $d=shift;
    my @k=nsort keys %$h;
    my $xmax=$k[$#k]; # max value
    my $x=$k[0]; # start (min) value
    while($x<$xmax)
    {
	$$h{$x}=0.0 if(!defined($$h{$x}));
	$x=sprintf '%g',$x+$d;
    }
}

sub defaults
{
    grid_defaults();
    @stellar_type_strings=@{(stellar_type_strings())[2]};
    @short_stellar_type_strings=@{(stellar_type_strings())[3]};
    %short_stellar_type_strings=%{(stellar_type_strings())[4]};
}