diff --git a/constraints/constraints/projectedCorrelationFunction_SDSS_z0.07.xml b/constraints/constraints/projectedCorrelationFunction_SDSS_z0.07.xml
deleted file mode 100644
index 853931bb9..000000000
--- a/constraints/constraints/projectedCorrelationFunction_SDSS_z0.07.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- SDSS $z=0.07$ stellar mass-selected projected correlation function
-
- 0.07
- 1.0e8
- 2.0e08
- 1.0e15
- constraints/scripts/projectedCorrelationFunction_SDSS_z0.07.pl
-
diff --git a/constraints/scripts/projectedCorrelationFunction_SDSS_z0.07.pl b/constraints/scripts/projectedCorrelationFunction_SDSS_z0.07.pl
deleted file mode 100755
index 12902022b..000000000
--- a/constraints/scripts/projectedCorrelationFunction_SDSS_z0.07.pl
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env perl
-use strict;
-use warnings;
-use Cwd;
-use lib $ENV{'GALACTICUS_EXEC_PATH'}."/perl";
-use XML::Simple;
-use PDL;
-use PDL::NiceSlice;
-use PDL::IO::HDF5;
-use Data::Dumper;
-use Galacticus::Options;
-use Galacticus::Constraints::Covariances;
-use Galacticus::Constraints::DiscrepancyModels;
-
-# Compute likelihood (and make a plot) for a Galacticus model given the projected correlation function data from Hearin et
-# al. (2013; http://adsabs.harvard.edu/abs/2013arXiv1310.6747H).
-
-# Get name of input and output files.
-die("projectedCorrelationFunction_SDSS_z0.07.pl [options]")
- unless ( scalar(@ARGV) >= 1 );
-my $self = $0;
-my $galacticusFileName = $ARGV[0];
-# Create a hash of named arguments.
-my $iArg = -1;
-my %arguments =
- (
- quiet => 0
- );
-&Galacticus::Options::Parse_Options(\@ARGV,\%arguments);
-
-# Object to hold all data.
-my $data;
-
-# Load observational data.
-my $observations = new PDL::IO::HDF5("data/observations/correlationFunctions/Projected_Correlation_Functions_Hearin_2013.hdf5");
-my $massMinimum = $observations->dataset('massMinimum')->get();
-my $separation = $observations->dataset('separation' )->get();
-my $correlationFunction = $observations->dataset('projectedCorrelationFunctionObserved')->get();
-my $covarianceMatrix = $observations->dataset('covariance')->get();
-for(my $entry=0;$entry<3;++$entry) {
- $data->{'observed'}->{$entry}->{'massMinimum' } = log10($massMinimum->(($entry)));
- $data->{'observed'}->{$entry}->{'separation' } = $separation;
- $data->{'observed'}->{$entry}->{'correlationFunction'} = $correlationFunction->(:,($entry));
- $data->{'observed'}->{$entry}->{'error' } = $covarianceMatrix->diagonal(0,1)->($entry*nelem($separation):($entry+1)*nelem($separation)-1)->sqrt();
-}
-$data->{'observed'}->{'combined'}->{'correlationFunctionCovariance'} = $covarianceMatrix;
-
-# Load model data.
-my $galacticusFile = new PDL::IO::HDF5($galacticusFileName);
-my $correlationGroup = $galacticusFile->group('analysis')->group('sdssClusteringZ0.07');
-foreach ( "separation", "correlationFunction", "correlationFunctionCovariance" ) {
- $data->{'model'}->{$_} = $correlationGroup->dataset($_)->get();
-}
-
-# Create a plot of the correlation function.
-if ( exists($arguments{'plotFile'}) ) {
-use GnuPlot::PrettyPlots;
-use GnuPlot::LaTeX;
-use XMP::MetaData;
- # Iterate over masses.
- for(my $entry=0;$entry<3;++$entry) {
- # Declare variables for GnuPlot;
- my ($gnuPlot, $plotFileEPS, $plot);
- # Open a pipe to GnuPlot.
- (my $mass = $data->{'observed'}->{$entry}->{'massMinimum'}) =~ s/\./p/;
- my $suffix = "_lgM".$mass.".eps";
- ($plotFileEPS = $arguments{'plotFile'}) =~ s/\.pdf$/$suffix/;
- open($gnuPlot,"|gnuplot 1>/dev/null 2>&1");
- print $gnuPlot "set terminal epslatex color colortext lw 2 solid 7\n";
- print $gnuPlot "set output '".$plotFileEPS."'\n";
- print $gnuPlot "set lmargin screen 0.15\n";
- print $gnuPlot "set rmargin screen 0.95\n";
- print $gnuPlot "set bmargin screen 0.15\n";
- print $gnuPlot "set tmargin screen 0.95\n";
- print $gnuPlot "set key spacing 1.2\n";
- print $gnuPlot "set key at screen 0.4,0.2\n";
- print $gnuPlot "set key left\n";
- print $gnuPlot "set key bottom\n";
- print $gnuPlot "set logscale xy\n";
- print $gnuPlot "set mxtics 10\n";
- print $gnuPlot "set mytics 10\n";
- print $gnuPlot "set format x '\$10^{\%L}\$'\n";
- print $gnuPlot "set format y '\$10^{\%L}\$'\n";
- print $gnuPlot "set xrange [0.15:25.0]\n";
- print $gnuPlot "set yrange [1.0:1000.0]\n";
- print $gnuPlot "set title offset 0,-0.5 'Projected correlation function at \$z\\approx 0.07\$ for \$\\log_{10}(M_\\star/M_\\odot) > ".$data->{'observed'}->{$entry}->{'massMinimum'}."\$'\n";
- print $gnuPlot "set xlabel 'Separation; \$r_{\\rm p}\$ [Mpc]'\n";
- print $gnuPlot "set ylabel 'Projected correlation; \$w_{\\rm p}(r_{\\rm p})\$ [Mpc]'\n";
- &GnuPlot::PrettyPlots::Prepare_Dataset(\$plot,
- $data->{'observed'}->{$entry}->{'separation' },
- $data->{'observed'}->{$entry}->{'correlationFunction'},
- errorUp => $data->{'observed'}->{$entry}->{'error'},
- errorDown => $data->{'observed'}->{$entry}->{'error'},
- style => "point",
- symbol => [6,7],
- weight => [5,3],
- color => $GnuPlot::PrettyPlots::colorPairs{'cornflowerBlue'},
- title => "Hearin et al. (2013)"
- );
- my $separationCount = nelem($data->{'model'}->{'separation'});
- my $modelError =
- sqrt(
- $data
- ->{'model'}
- ->{'correlationFunctionCovariance'}
- ->diagonal(0,1)
- ->($entry*$separationCount:($entry+1)*$separationCount-1)
- );
- &GnuPlot::PrettyPlots::Prepare_Dataset(\$plot,
- $data->{'model'}->{'separation' },
- $data->{'model'}->{'correlationFunction'}->(:,($entry)),
- errorUp => $modelError,
- errorDown => $modelError,
- style => "point",
- symbol => [6,7],
- weight => [5,3],
- color => $GnuPlot::PrettyPlots::colorPairs{'redYellow'},
- title => "Galacticus"
- );
- &GnuPlot::PrettyPlots::Plot_Datasets($gnuPlot,\$plot);
- close($gnuPlot);
- &GnuPlot::LaTeX::GnuPlot2PDF($plotFileEPS,margin => 1);
- }
-}
-
-# Construct combined datasets.
-my $separationCount = nelem( $data->{'observed'}->{'0'}->{'separation'});
-$data->{'observed'}->{'combined'}->{'separation' } = pdl zeroes(3*$separationCount );
-$data->{'observed'}->{'combined'}->{'correlationFunction' } = pdl zeroes(3*$separationCount );
-$data->{'observed'}->{'combined'}->{'correlationFunctionError' } = pdl zeroes(3*$separationCount );
-for(my $entry=0;$entry<3;++$entry) {
- $data->{'observed'}->{'combined'}->{'separation' }->($entry*$separationCount:($entry+1)*$separationCount-1)
- .= $data->{'observed'}->{$entry}->{'separation' };
- $data->{'observed'}->{'combined'}->{'correlationFunction' }->($entry*$separationCount:($entry+1)*$separationCount-1)
- .= $data->{'observed'}->{$entry}->{'correlationFunction'};
- $data->{'observed'}->{'combined'}->{'correlationFunctionError'}->($entry*$separationCount:($entry+1)*$separationCount-1)
- .= $data->{'observed'}->{$entry}->{'error'};
-}
-$data->{'model'}->{'combined'}->{'correlationFunction' } = $data->{'model'}->{'correlationFunction' }->flat();
-$data->{'model'}->{'combined'}->{'correlationFunctionCovariance'} = $data->{'model'}->{'correlationFunctionCovariance'};
-$data->{'model'}->{'combined'}->{'correlationFunctionError' } = sqrt($data->{'model'}->{'correlationFunctionCovariance'}->diagonal(0,1));
-
-# Apply discrepancies.
-&Galacticus::Constraints::DiscrepancyModels::Apply_Discrepancies(
- "discrepancySdssClusteringZ0.07.hdf5" ,
- $arguments {'modelDiscrepancies' },
- $data ->{'model'}->{'combined'}->{'correlationFunction' },
- $data ->{'model'}->{'combined'}->{'correlationFunctionError' },
- $data ->{'model'}->{'combined'}->{'correlationFunctionCovariance'}
- )
- if ( exists($arguments{'modelDiscrepancies'}) );
-
-# Output the results to file if requested.
-if ( exists($arguments{'resultFile'}) ) {
- my $resultsFile = new PDL::IO::HDF5(">".$arguments{'resultFile'});
- $resultsFile->dataset('x' )->set($data->{'observed'}->{'combined'}->{'separation' });
- $resultsFile->dataset('y' )->set($data->{'model' }->{'combined'}->{'correlationFunction' });
- $resultsFile->dataset('error' )->set($data->{'model' }->{'combined'}->{'correlationFunctionError' });
- $resultsFile->dataset('covariance' )->set($data->{'model' }->{'combined'}->{'correlationFunctionCovariance'});
- $resultsFile->dataset('yData' )->set($data->{'observed'}->{'combined'}->{'correlationFunction' });
- $resultsFile->dataset('covarianceData')->set($data->{'observed'}->{'combined'}->{'correlationFunctionCovariance'});
-}
-
-# Compute the likelihood:
-if ( exists($arguments{'outputFile'}) ) {
- # Construct the full covariance matrix, which is the covariance matrix of the observations plus that of the model.
- my $fullCovariance =
- $data->{'model' }->{'combined'}->{'correlationFunctionCovariance'}+
- $data->{'observed'}->{'combined'}->{'correlationFunctionCovariance'};
-
- # Compute the likelihood.
- my $constraint;
- my $offsets;
- my $jacobian;
- my $logLikelihood =
- &Galacticus::Constraints::Covariances::ComputeLikelihood(
- $data->{'model' }->{'combined'}->{'correlationFunction'},
- $data->{'observed'}->{'combined'}->{'correlationFunction'},
- $fullCovariance ,
- jacobian => \$jacobian ,
- offsets => \$offsets ,
- productMethod => "linearSolver" ,
- quiet => 0
- );
- $constraint->{'label' } = "sdssClusteringZ0.07";
- $constraint->{'logLikelihood'} = $logLikelihood;
- # Compute the variance in the log-likelihood due to errors in the model.
- my $logLikelihoodVariance = $jacobian x $data->{'model'}->{'combined'}->{'correlationFunctionCovariance'} x transpose($jacobian);
- $constraint->{'logLikelihoodVariance'} = $logLikelihoodVariance->sclr();
- # Output the constraint.
- my $xmlOutput = new XML::Simple (NoAttr=>1, RootName=>"constraint");
- open(oHndl,">".$arguments{'outputFile'});
- print oHndl $xmlOutput->XMLout($constraint);
- close(oHndl);
-}
-
-exit;
diff --git a/source/galacticus.output.analyses.correlation_function.F90 b/source/galacticus.output.analyses.correlation_function.F90
new file mode 100644
index 000000000..f64c2cb74
--- /dev/null
+++ b/source/galacticus.output.analyses.correlation_function.F90
@@ -0,0 +1,1348 @@
+!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
+!! 2019
+!! Andrew Benson
+!!
+!! This file is part of Galacticus.
+!!
+!! Galacticus is free software: you can redistribute it and/or modify
+!! it under the terms of the GNU General Public License as published by
+!! the Free Software Foundation, either version 3 of the License, or
+!! (at your option) any later version.
+!!
+!! Galacticus is distributed in the hope that it will be useful,
+!! but WITHOUT ANY WARRANTY; without even the implied warranty of
+!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+!! GNU General Public License for more details.
+!!
+!! You should have received a copy of the GNU General Public License
+!! along with Galacticus. If not, see .
+
+!% Contains a module which implements a generic two-point correlation function output analysis class.
+
+ !$ use :: OMP_Lib , only : omp_lock_kind
+ use , intrinsic :: ISO_C_Binding , only : c_size_t
+ use :: Geometry_Surveys , only : surveyGeometry , surveyGeometryClass
+ use :: Cosmology_Functions , only : cosmologyFunctions , cosmologyFunctionsClass
+ use :: Galactic_Filters , only : galacticFilter , galacticFilterClass
+ use :: Output_Times , only : outputTimes , outputTimesClass
+ use :: Linear_Growth , only : linearGrowth , linearGrowthClass
+ use :: Output_Analysis_Distribution_Operators, only : outputAnalysisDistributionOperator, outputAnalysisDistributionOperatorClass
+ use :: Output_Analysis_Property_Operators , only : outputAnalysisPropertyOperator , outputAnalysisPropertyOperatorClass
+ use :: Node_Property_Extractors , only : nodePropertyExtractor , nodePropertyExtractorClass
+ use :: Dark_Matter_Profiles_DMO , only : darkMatterProfileDMO , darkMatterProfileDMOClass
+ use :: Dark_Matter_Halo_Biases , only : darkMatterHaloBias , darkMatterHaloBiasClass
+ use :: Halo_Model_Power_Spectrum_Modifiers , only : haloModelPowerSpectrumModifier , haloModelPowerSpectrumModifierClass
+ use :: Power_Spectra , only : powerSpectrum , powerSpectrumClass
+
+ !#
+ !# A generic two-point correlation function output analysis class.
+ !#
+ type, extends(outputAnalysisClass) :: outputAnalysisCorrelationFunction
+ !% A generic two-point correlation function output analysis class.
+ private
+ type (varying_string ) :: label , comment , &
+ & targetLabel
+ class (galacticFilterClass ), pointer :: galacticFilter_ => null()
+ class (outputTimesClass ), pointer :: outputTimes_ => null()
+ class (surveyGeometryClass ), pointer :: surveyGeometry_ => null()
+ class (cosmologyFunctionsClass ), pointer :: cosmologyFunctions_ => null()
+ class (linearGrowthClass ), pointer :: linearGrowth_ => null()
+ class (outputAnalysisDistributionOperatorClass), pointer :: massDistributionOperator_ => null()
+ class (outputAnalysisPropertyOperatorClass ), pointer :: massPropertyOperator_ => null(), separationPropertyOperator_ => null()
+ class (nodePropertyExtractorClass ), pointer :: massPropertyExtractor_ => null()
+ class (darkMatterProfileDMOClass ), pointer :: darkMatterProfileDMO_ => null()
+ class (darkMatterHaloBiasClass ), pointer :: darkMatterHaloBias_ => null()
+ class (haloModelPowerSpectrumModifierClass ), pointer :: haloModelPowerSpectrumModifier_ => null()
+ class (powerSpectrumClass ), pointer :: powerSpectrum_ => null()
+ double precision , allocatable, dimension(: ) :: separations , wavenumber , &
+ & meanDensity , massMinima , &
+ & massMaxima , linearGrowthFactorSquared , &
+ & massMinimaLogarithmic , massMaximaLogarithmic
+ double precision , allocatable, dimension(:,: ) :: outputWeight , meanDensityMainBranch , &
+ & oneHaloTerm , twoHaloTerm , &
+ & termCovariance , integralConstraint , &
+ & binnedProjectedCorrelation , binnedProjectedCorrelationCovariance , &
+ & binnedProjectedCorrelationTarget , binnedProjectedCorrelationCovarianceTarget
+ double precision , allocatable, dimension(:,:,:) :: oneHaloTermMainBranch , twoHaloTermMainBranch
+ integer , allocatable, dimension(: ) :: countMainBranch
+ double precision :: massHaloLogarithmicMinimum , massHaloIntervalLogarithmicInverse , &
+ & wavenumberMinimum , wavenumberMaximum , &
+ & depthLineOfSight
+ integer (c_size_t ) :: binCount , massCount , &
+ & countBinsMassHalo , wavenumberCount
+ logical :: finalized , halfIntegral
+ !$ integer (omp_lock_kind ) :: accumulateLock
+ ! Workspace used while accumulating the correlation function.
+ double precision , allocatable, dimension(: ) :: probabilityCentral
+ double precision , allocatable, dimension(:,: ) :: probabilitySatellite
+ integer :: countSatellites
+ contains
+ !@
+ !@
+ !@
+ !@ accumulateNode
+ !@ \doublezero\ mass\argin, \intzero\ massType\argin, \intzero\ indexOutput\argin, \textcolor{red}{\textless type(treeNode)\textgreater} node\arginout
+ !@ \void
+ !@ Accumulate a node to the correlation function.
+ !@
+ !@
+ !@ accumulateHalo
+ !@ \intzero\ indexOutput\argin, \textcolor{red}{\textless type(treeNode)\textgreater} node\arginout
+ !@ \void
+ !@ Accumulate a halo to the correlation function.
+ !@
+ !@
+ final :: correlationFunctionDestructor
+ procedure :: analyze => correlationFunctionAnalyze
+ procedure :: finalize => correlationFunctionFinalize
+ procedure :: reduce => correlationFunctionReduce
+ procedure :: logLikelihood => correlationFunctionLogLikelihood
+ procedure :: accumulateNode => correlationFunctionAccumulateNode
+ procedure :: accumulateHalo => correlationFunctionAccumulateHalo
+ end type outputAnalysisCorrelationFunction
+
+ interface outputAnalysisCorrelationFunction
+ !% Constructors for the ``correlationFunction'' output analysis class.
+ module procedure correlationFunctionConstructorParameters
+ module procedure correlationFunctionConstructorFile
+ module procedure correlationFunctionConstructorInternal
+ end interface outputAnalysisCorrelationFunction
+
+contains
+
+ function correlationFunctionConstructorParameters(parameters) result(self)
+ !% Constructor for the ``correlationFunction'' output analysis class which takes a parameter set as input.
+ use Input_Parameters, only : inputParameter , inputParameters
+ use Galacticus_Error, only : Galacticus_Error_Report
+ implicit none
+ type (outputAnalysisCorrelationFunction ) :: self
+ type (inputParameters ), intent(inout) :: parameters
+ class (galacticFilterClass ), pointer :: galacticFilter_
+ class (outputTimesClass ), pointer :: outputTimes_
+ class (surveyGeometryClass ), pointer :: surveyGeometry_
+ class (cosmologyFunctionsClass ), pointer :: cosmologyFunctions_
+ class (linearGrowthClass ), pointer :: linearGrowth_
+ class (outputAnalysisDistributionOperatorClass), pointer :: massDistributionOperator_
+ class (outputAnalysisPropertyOperatorClass ), pointer :: massPropertyOperator_ , separationPropertyOperator_
+ class (nodePropertyExtractorClass ), pointer :: massPropertyExtractor_
+ class (darkMatterProfileDMOClass ), pointer :: darkMatterProfileDMO_
+ class (darkMatterHaloBiasClass ), pointer :: darkMatterHaloBias_
+ class (haloModelPowerSpectrumModifierClass ), pointer :: haloModelPowerSpectrumModifier_
+ class (powerSpectrumClass ), pointer :: powerSpectrum_
+ double precision , allocatable , dimension(: ) :: separations , massMinima , &
+ & massMaxima , integralConstraint , &
+ & binnedProjectedCorrelationTarget1D, binnedProjectedCorrelationCovarianceTarget1D
+ double precision , allocatable , dimension(:,:) :: binnedProjectedCorrelationTarge t, binnedProjectedCorrelationCovarianceTarget
+ double precision :: massHaloMinimum , massHaloMaximum , &
+ & wavenumberMinimum , wavenumberMaximum , &
+ & depthLineOfSight
+ logical :: halfIntegral
+ integer (c_size_t ) :: wavenumberCount
+ integer :: massHaloBinsPerDecade
+ type (varying_string ) :: label , comment , &
+ & targetLabel
+
+ allocate(separations(parameters%count('separations')))
+ !#
+ !# label
+ !# parameters
+ !# A label for the mass function.
+ !# string
+ !# 0..1
+ !#
+ !#
+ !# comment
+ !# parameters
+ !# A descriptive comment for the mass function.
+ !# string
+ !# 0..1
+ !#
+ !#
+ !# separations
+ !# parameters
+ !# The separations corresponding to bin centers.
+ !# float
+ !# 0..1
+ !#
+ !#
+ !# massMinima
+ !# parameters
+ !# The minimum mass of each mass sample.
+ !# float
+ !# 0..1
+ !#
+ !#
+ !# massMaxima
+ !# parameters
+ !# The maximum mass of each mass sample.
+ !# float
+ !# 0..1
+ !#
+ !#
+ !# massHaloBinsPerDecade
+ !# 0..1
+ !# 10
+ !# The number of bins per decade of halo mass to use when constructing the mass function covariance matrix for main branch galaxies.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# massHaloMinimum
+ !# 0..1
+ !# 1.0d8
+ !# The minimum halo mass to consider when constructing the mass function covariance matrix for main branch galaxies.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# massHaloMaximum
+ !# 0..1
+ !# 1.0d16
+ !# The maximum halo mass to consider when constructing the mass function covariance matrix for main branch galaxies.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# wavenumberCount
+ !# 0..1
+ !# 60_c_size_t
+ !# The number of bins in wavenumber to use in computing the correlation function.
+ !# output
+ !# parameters
+ !# integer
+ !#
+ !#
+ !# wavenumberMinimum
+ !# 0..1
+ !# 1.0d-3
+ !# The minimum wavenumber to use when computing the correlation function.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# wavenumberMaximum
+ !# 0..1
+ !# 1.0d4
+ !# The maximum wavenumber to use when computing the correlation function.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# integralConstraint
+ !# 0..1
+ !# The integral constraint for these correlation functions.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# depthLineOfSight
+ !# 0..1
+ !# The line-of-sight depth over which the correlation function was projected.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# halfIntegral
+ !# 0..1
+ !# Set to true if the projection integrand should be over line-of-sight depths greater than zero.
+ !# output
+ !# parameters
+ !# real
+ !#
+ if (parameters%isPresent('binnedProjectedCorrelationTarget')) then
+ if (parameters%isPresent('binnedProjectedCorrelationCovarianceTarget')) then
+ !#
+ !# binnedProjectedCorrelationTarget
+ !# parameters
+ !# The target function for likelihood calculations.
+ !# binnedProjectedCorrelationTarget1D
+ !# real
+ !# 0..1
+ !#
+ !#
+ !# binnedProjectedCorrelationCovarianceTarget
+ !# parameters
+ !# binnedProjectedCorrelationCovarianceTarget1D
+ !# The target function covariance for likelihood calculations.
+ !# real
+ !# 0..1
+ !#
+ if (size(binnedProjectedCorrelationCovarianceTarget1D) == size(binnedProjectedCorrelationTarget1D)**2) then
+ allocate(binnedProjectedCorrelationTarget (size(separations ),size(massMinima )))
+ allocate(binnedProjectedCorrelationCovarianceTarget(size(binnedProjectedCorrelationTarget1D),size(binnedProjectedCorrelationTarget1D)))
+ binnedProjectedCorrelationTarget =reshape(binnedProjectedCorrelationTarget1D ,shape(binnedProjectedCorrelationTarget ))
+ binnedProjectedCorrelationCovarianceTarget=reshape(binnedProjectedCorrelationCovarianceTarget1D,shape(binnedProjectedCorrelationCovarianceTarget))
+ else
+ call Galacticus_Error_Report('binnedProjectedCorrelationCovarianceTarget has wrong size'//{introspection:location})
+ end if
+ else
+ call Galacticus_Error_Report('binnedProjectedCorrelationCovarianceTarget must be specified if binnedProjectedCorrelationTarget is present'//{introspection:location})
+ end if
+ else
+ if (parameters%isPresent('binnedProjectedCorrelationCovarianceTarget')) call Galacticus_Error_Report('binnedProjectedCorrelationTarget must be specified if binnedProjectedCorrelationCovarianceTarget is present'//{introspection:location})
+ end if
+ !#
+ !# targetLabel
+ !# parameters
+ !# A label for the target dataset in a plot of this analysis.
+ !# var_str('')
+ !# string
+ !# 0..1
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !# self=outputAnalysisCorrelationFunction( &
+ !# & label , &
+ !# & comment , &
+ !# & separations , &
+ !# & massMinima , &
+ !# & massMaxima , &
+ !# & massHaloBinsPerDecade , &
+ !# & massHaloMinimum , &
+ !# & massHaloMaximum , &
+ !# & reshape(integralConstraint,[size(separations),size(massMinima)]), &
+ !# & wavenumberCount , &
+ !# & wavenumberMinimum , &
+ !# & wavenumberMaximum , &
+ !# & depthLineOfSight , &
+ !# & halfIntegral , &
+ !# & linearGrowth_ , &
+ !# & galacticFilter_ , &
+ !# & surveyGeometry_ , &
+ !# & cosmologyFunctions_ , &
+ !# & outputTimes_ , &
+ !# & darkMatterProfileDMO_ , &
+ !# & darkMatterHaloBias_ , &
+ !# & haloModelPowerSpectrumModifier_ , &
+ !# & powerSpectrum_ , &
+ !# & massDistributionOperator_ , &
+ !# & massPropertyOperator_ , &
+ !# & separationPropertyOperator_ , &
+ !# & massPropertyExtractor_ , &
+ !# & targetLabel &
+ !# & {conditions} &
+ !# & )
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ return
+ end function correlationFunctionConstructorParameters
+
+ function correlationFunctionConstructorFile(label,comment,fileName,massHaloBinsPerDecade,massHaloMinimum,massHaloMaximum,wavenumberCount,wavenumberMinimum,wavenumberMaximum,halfIntegral,linearGrowth_,galacticFilter_,surveyGeometry_,cosmologyFunctions_,outputTimes_,darkMatterProfileDMO_,darkMatterHaloBias_,haloModelPowerSpectrumModifier_,powerSpectrum_,massDistributionOperator_,massPropertyOperator_,separationPropertyOperator_,massPropertyExtractor_) result (self)
+ !% Constructor for the ``correlation'' output analysis class which reads bin information from a standard format file.
+ use IO_HDF5 , only : hdf5Access , hdf5Object
+ use Cosmology_Parameters, only : cosmologyParametersSimple
+ use Cosmology_Functions , only : cosmologyFunctionsMatterLambda
+ implicit none
+ type (outputAnalysisCorrelationFunction ) :: self
+ type (varying_string ), intent(in ) :: label , comment
+ character (len=* ), intent(in ) :: fileName
+ integer (c_size_t ), intent(in ) :: wavenumberCount
+ double precision , intent(in ) :: massHaloMinimum , massHaloMaximum , &
+ & wavenumberMinimum , wavenumberMaximum
+ logical , intent(in ) :: halfIntegral
+ integer , intent(in ) :: massHaloBinsPerDecade
+ class (linearGrowthClass ), intent(in ), target :: linearGrowth_
+ class (galacticFilterClass ), intent(in ), target :: galacticFilter_
+ class (surveyGeometryClass ), intent(in ), target :: surveyGeometry_
+ class (cosmologyFunctionsClass ), intent(in ), target :: cosmologyFunctions_
+ class (outputTimesClass ), intent(in ), target :: outputTimes_
+ class (outputAnalysisDistributionOperatorClass), intent(in ), target :: massDistributionOperator_
+ class (outputAnalysisPropertyOperatorClass ), intent(in ), target :: massPropertyOperator_ , separationPropertyOperator_
+ class (nodePropertyExtractorClass ), intent(in ), target :: massPropertyExtractor_
+ class (darkMatterProfileDMOClass ), intent(in ), target :: darkMatterProfileDMO_
+ class (darkMatterHaloBiasClass ), intent(in ), target :: darkMatterHaloBias_
+ class (haloModelPowerSpectrumModifierClass ), intent(in ), target :: haloModelPowerSpectrumModifier_
+ class (powerSpectrumClass ), intent(in ), target :: powerSpectrum_
+ double precision , allocatable , dimension(: ) :: separations , massMinima , &
+ & massMaxima
+ double precision , allocatable , dimension(:,:) :: integralConstraint , binnedProjectedCorrelationTarget, &
+ & binnedProjectedCorrelationCovarianceTarget
+ type (varying_string ) :: targetLabel
+ type (hdf5Object ) :: dataFile , parametersGroup
+ double precision :: hubbleParameterData , omegaMatterData , &
+ & omegaDarkEnergyData , depthLineOfSight
+
+ !$ call hdf5Access%set()
+ call dataFile%openFile(fileName,readOnly=.true.)
+ ! Extract parameters.
+ parametersGroup=dataFile%openGroup('Parameters')
+ call parametersGroup%readAttribute('H_0' ,hubbleParameterData)
+ call parametersGroup%readAttribute('Omega_Matter' ,omegaMatterData )
+ call parametersGroup%readAttribute('Omega_DE' ,omegaDarkEnergyData)
+ call parametersGroup%readAttribute('projectedCorrelationFunctionLineOfSightDepth',depthLineOfSight )
+ call parametersGroup%close()
+ ! Extract separations.
+ call dataFile%readDataset('separationObserved',separations )
+ ! Extract observed datasets.
+ call dataFile%readAttribute('label' ,targetLabel )
+ call dataFile%readDataset ('projectedCorrelationFunctionObserved',binnedProjectedCorrelationTarget )
+ call dataFile%readDataset ('covariance' ,binnedProjectedCorrelationCovarianceTarget)
+ ! Extract integral constraint.
+ call dataFile%readDataset('integralConstraint',integralConstraint)
+ ! Read the minimum and maximum masses.
+ call dataFile%readDataset("massMinimum" ,massMinima )
+ call dataFile%readDataset("massMaximum" ,massMaxima )
+ ! Finish reading data file.
+ call dataFile%close ( )
+ !$ call hdf5Access%unset()
+ self=outputAnalysisCorrelationFunction(label,comment,separations,massMinima,massMaxima,massHaloBinsPerDecade,massHaloMinimum,massHaloMaximum,integralConstraint,wavenumberCount,wavenumberMinimum,wavenumberMaximum,depthLineOfSight,halfIntegral,linearGrowth_,galacticFilter_,surveyGeometry_,cosmologyFunctions_,outputTimes_,darkMatterProfileDMO_,darkMatterHaloBias_,haloModelPowerSpectrumModifier_,powerSpectrum_,massDistributionOperator_,massPropertyOperator_,separationPropertyOperator_,massPropertyExtractor_,targetLabel,binnedProjectedCorrelationTarget,binnedProjectedCorrelationCovarianceTarget)
+ return
+ end function correlationFunctionConstructorFile
+
+ function correlationFunctionConstructorInternal(label,comment,separations,massMinima,massMaxima,massHaloBinsPerDecade,massHaloMinimum,massHaloMaximum,integralConstraint,wavenumberCount,wavenumberMinimum,wavenumberMaximum,depthLineOfSight,halfIntegral,linearGrowth_,galacticFilter_,surveyGeometry_,cosmologyFunctions_,outputTimes_,darkMatterProfileDMO_,darkMatterHaloBias_,haloModelPowerSpectrumModifier_,powerSpectrum_,massDistributionOperator_,massPropertyOperator_,separationPropertyOperator_,massPropertyExtractor_,targetLabel,binnedProjectedCorrelationTarget,binnedProjectedCorrelationCovarianceTarget) result (self)
+ !% Constructor for the ``correlationFunction'' output analysis class for internal use.
+ use, intrinsic :: ISO_C_Binding , only : c_size_t
+ use :: Galacticus_Error , only : Galacticus_Error_Report
+ use :: Memory_Management , only : allocateArray
+ use :: Output_Analysis_Utilities, only : Output_Analysis_Output_Weight_Survey_Volume
+ use :: Numerical_Ranges , only : Make_Range , rangeTypeLogarithmic
+ implicit none
+ type (outputAnalysisCorrelationFunction ) :: self
+ type (varying_string ), intent(in ) :: label , comment
+ double precision , intent(in ), dimension(: ) :: separations , massMinima , &
+ & massMaxima
+ double precision , intent(in ), dimension(:,:) :: integralConstraint
+ integer (c_size_t ), intent(in ) :: wavenumberCount
+ double precision , intent(in ) :: massHaloMinimum , massHaloMaximum , &
+ & wavenumberMinimum , wavenumberMaximum , &
+ & depthLineOfSight
+ logical , intent(in ) :: halfIntegral
+ integer , intent(in ) :: massHaloBinsPerDecade
+ class (linearGrowthClass ), intent(in ), target :: linearGrowth_
+ class (galacticFilterClass ), intent(in ), target :: galacticFilter_
+ class (outputTimesClass ), intent(in ), target :: outputTimes_
+ class (surveyGeometryClass ), intent(in ), target :: surveyGeometry_
+ class (cosmologyFunctionsClass ), intent(in ), target :: cosmologyFunctions_
+ class (outputAnalysisDistributionOperatorClass), intent(in ), target :: massDistributionOperator_
+ class (outputAnalysisPropertyOperatorClass ), intent(in ), target :: massPropertyOperator_ , separationPropertyOperator_
+ class (nodePropertyExtractorClass ), intent(in ), target :: massPropertyExtractor_
+ class (darkMatterProfileDMOClass ), intent(in ), target :: darkMatterProfileDMO_
+ class (darkMatterHaloBiasClass ), intent(in ), target :: darkMatterHaloBias_
+ class (haloModelPowerSpectrumModifierClass ), intent(in ), target :: haloModelPowerSpectrumModifier_
+ class (powerSpectrumClass ), intent(in ), target :: powerSpectrum_
+ type (varying_string ), intent(in ) , optional :: targetLabel
+ double precision , intent(in ), dimension(:,:), optional :: binnedProjectedCorrelationTarget , binnedProjectedCorrelationCovarianceTarget
+ integer (c_size_t ) :: i
+ !#
+
+ ! Compute weight that applies to each output redshift.
+ self%massCount=size(self%massMinima )
+ self%binCount =size(self%separations,kind=c_size_t)
+ call allocateArray(self%outputWeight,[self%massCount,self%outputTimes_%count()])
+ do i=1,self%massCount
+ self%outputWeight(i,:)=Output_Analysis_Output_Weight_Survey_Volume(self%surveyGeometry_,self%cosmologyFunctions_,self%outputTimes_,massMinima(i))
+ end do
+ ! Pre-compute linear growth factors.
+ allocate(self%linearGrowthFactorSquared(self%outputTimes_%count()))
+ do i=1,self%outputTimes_%count()
+ self%linearGrowthFactorSquared=self%linearGrowth_%value(self%outputTimes_%time(i))**2
+ end do
+ ! Construct halo mass bins.
+ self%massHaloLogarithmicMinimum = log10( massHaloMinimum)
+ self%countBinsMassHalo = int(log10(massHaloMaximum/massHaloMinimum)*dble(massHaloBinsPerDecade)+0.5d0)
+ self%massHaloIntervalLogarithmicInverse=dble(self%countBinsMassHalo)/ log10(massHaloMaximum/massHaloMinimum)
+ ! Allocate wavenumbers.
+ call allocateArray(self%wavenumber ,[self%wavenumberCount ])
+ call allocateArray(self%probabilityCentral ,[ self%massCount ])
+ call allocateArray(self%probabilitySatellite ,[ 1_c_size_t ,self%massCount ])
+ call allocateArray(self%meanDensity ,[ self%massCount ])
+ call allocateArray(self%meanDensityMainBranch,[ self%massCount,self%countBinsMassHalo])
+ call allocateArray(self%countMainBranch ,[ self%countBinsMassHalo])
+ call allocateArray(self%oneHaloTermMainBranch,[self%wavenumberCount,self%massCount,self%countBinsMassHalo])
+ call allocateArray(self%twoHaloTermMainBranch,[self%wavenumberCount,self%massCount,self%countBinsMassHalo])
+ call allocateArray(self%oneHaloTerm ,[self%wavenumberCount,self%massCount ])
+ call allocateArray(self%twoHaloTerm ,[self%wavenumberCount,self%massCount ])
+ call allocateArray(self%termCovariance ,[self%massCount*(2*self%wavenumberCount+1),self%massCount*(2*self%wavenumberCount+1)])
+ self%wavenumber=Make_Range(self%wavenumberMinimum,self%wavenumberMaximum,int(self%wavenumberCount),rangeTypeLogarithmic)
+ ! Compute logarithmic masses.
+ allocate(self%massMinimaLogarithmic(self%massCount))
+ allocate(self%massMaximaLogarithmic(self%massCount))
+ self%massMinimaLogarithmic=log10(self%massMinima)
+ self%massMaximaLogarithmic=log10(self%massMaxima)
+ ! Initialize population statistics.
+ self%countMainBranch =0
+ self%meanDensity =0.0d0
+ self%meanDensityMainBranch=0.0d0
+ self%oneHaloTermMainBranch=0.0d0
+ self%twoHaloTermMainBranch=0.0d0
+ self%oneHaloTerm =0.0d0
+ self%twoHaloTerm =0.0d0
+ self%termCovariance =0.0d0
+ self%probabilityCentral =0.0d0
+ self%probabilitySatellite =0.0d0
+ self%countSatellites =0
+ self%finalized =.false.
+ ! Initialize accumulation lock.
+ !$ call OMP_Init_Lock(self%accumulateLock)
+ return
+ end function correlationFunctionConstructorInternal
+
+ subroutine correlationFunctionDestructor(self)
+ !% Destructor for the ``correlationFunction'' output analysis class.
+ implicit none
+ type(outputAnalysisCorrelationFunction), intent(inout) :: self
+
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !$ call OMP_Destroy_Lock(self%accumulateLock)
+ return
+ end subroutine correlationFunctionDestructor
+
+ subroutine correlationFunctionAnalyze(self,node,iOutput)
+ !% Implement a correlationFunction output analysis.
+ implicit none
+ class (outputAnalysisCorrelationFunction), intent(inout) :: self
+ type (treeNode ), intent(inout) :: node
+ integer (c_size_t ), intent(in ) :: iOutput
+ double precision :: mass
+ integer :: massType
+
+ ! If weights for this output are all zero, we can skip analysis.
+ if (all(self%outputWeight(:,iOutput) == 0.0d0)) return
+ ! Filter this node.
+ ! Extract mass property.
+ massType=self%massPropertyExtractor_%type()
+ select type (extractor_ => self%massPropertyExtractor_)
+ class is (nodePropertyExtractorScalar)
+ mass=extractor_%extract(node)
+ class default
+ mass=0.0d0
+ end select
+ ! Apply operator to mass.
+ mass=self%massPropertyOperator_%operate(mass,node,massType,iOutput)
+ ! Accumulate the node.
+ call self%accumulateNode(mass,massType,iOutput,node)
+ ! Accumulate the halo. Since nodes are visited depth first we can be sure that all satellite of this isolated halo have
+ ! already been visited.
+ if (.not.node%isSatellite()) call self%accumulateHalo(iOutput,node)
+ return
+ end subroutine correlationFunctionAnalyze
+
+ subroutine correlationFunctionAccumulateNode(self,mass,massType,indexOutput,node)
+ !% Accumulate a single galaxy to the population of the current halo. Since galaxy masses
+ !% have random errors, each galaxy added is assigned an inclusion probability, which will be
+ !% taken into account when evaluating the one- and two-halo terms from this halo in the halo
+ !% model.
+ implicit none
+ class (outputAnalysisCorrelationFunction), intent(inout) :: self
+ double precision , intent(in ) :: mass
+ integer , intent(in ) :: massType
+ integer (c_size_t ), intent(in ) :: indexOutput
+ type (treeNode ), intent(inout) :: node
+ double precision , allocatable , dimension(:,:) :: probabilitySatelliteTmp
+ double precision , dimension(1 ) :: massDistribution
+ logical :: satelliteIncluded
+ integer :: j
+
+ ! Evaluate, for each mass bin, the probability of inclusion of the galaxy in that bin. Store any such non-zero probabilities
+ ! for central and satellite galaxies separately.
+ satelliteIncluded=.false.
+ do j=1,size(self%massMinimaLogarithmic)
+ ! Find the probability that this galaxy is included in the sample.
+ massDistribution=self%massDistributionOperator_%operateScalar(mass,massType,self%massMinimaLogarithmic(j:j),self%massMaximaLogarithmic(j:j),indexOutput,node)
+ if (node%isSatellite()) then
+ if (massDistribution(1) > 0.0d0) then
+ if (.not.satelliteIncluded) then
+ satelliteIncluded =.true.
+ self%countSatellites=self%countSatellites+1
+ if (size(self%probabilitySatellite,dim=1) < self%countSatellites) then
+ call move_alloc(self%probabilitySatellite,probabilitySatelliteTmp)
+ allocate(self%probabilitySatellite(2*size(probabilitySatelliteTmp,dim=1),size(self%massMinimaLogarithmic)))
+ self%probabilitySatellite(1:size(probabilitySatelliteTmp,dim=1),:)=probabilitySatelliteTmp
+ deallocate(probabilitySatelliteTmp)
+ end if
+ self%probabilitySatellite(self%countSatellites,:)=0.0d0
+ end if
+ self%probabilitySatellite(self%countSatellites,j)=massDistribution(1)
+ end if
+ else
+ self%probabilityCentral(j)=massDistribution(1)
+ end if
+ end do
+ return
+ end subroutine correlationFunctionAccumulateNode
+
+ subroutine correlationFunctionAccumulateHalo(self,indexOutput,node)
+ !% Assumulate a single halo's contributions to the halo model one- and two-halo terms. For
+ !% the one-halo term we count contributions from central-satellite pairs, and from
+ !% satellite-satellite pairs. Contributions differ in the scalings applied to the
+ !% Fourier-transformed dark matter halo density profile---see
+ !% \cite[][\S6.1]{cooray_halo_2002} for a discussion of this. The number of satellites in
+ !% the halo is assumed to follow a Poisson binomial distribution.
+ use Math_Distributions_Poisson_Binomial, only : Poisson_Binomial_Distribution_Mean, Poisson_Binomial_Distribution_Mean_Pairs, Poisson_Binomial_Distribution_Mean_Pairs_Jacobian
+ use Vectors , only : Vector_Outer_Product
+ use Linear_Algebra , only : matrix , operator(*) , assignment(=)
+ use Galacticus_Nodes , only : nodeComponentBasic
+ use Halo_Model_Power_Spectrum_Modifiers, only : haloModelTermOneHalo , haloModelTermTwoHalo
+ implicit none
+ class (outputAnalysisCorrelationFunction), intent(inout) :: self
+ integer (c_size_t ), intent(in ) :: indexOutput
+ type (treeNode ), intent(inout) :: node
+ class (nodeComponentBasic ), pointer :: basic , basicRoot
+ double precision , dimension(self%wavenumberCount,self%massCount) :: oneHaloTerm , twoHaloTerm
+ double precision , dimension( self%massCount) :: galaxyDensity
+ logical , dimension( self%massCount) :: oneHaloTermActive , twoHaloTermActive
+ double precision , allocatable , dimension(: ,: ) :: termJacobian , termCovariance , &
+ & mainBranchTermCovariance, modifierCovariance
+ double precision , allocatable , dimension(: ) :: satelliteJacobian , modifierCovarianceDiagonal, &
+ & fourierProfile , wavenumber
+ double precision :: countSatellitePairsMean , countSatellitesMean , &
+ & haloWeightOutput , expansionFactor , &
+ & biasHalo , massHalo
+ integer (c_size_t ) :: i , j , &
+ & indexOneHalo , indexTwoHalo , &
+ & indexDensity
+ integer :: haloMassBin , scaleType
+ logical :: mainBranchCounted
+ type (matrix ) :: jacobianMatrix
+
+ ! Return immediately if no nodes have been accumulated.
+ if (all(self%probabilityCentral == 0.0d0) .and. self%countSatellites == 0) return
+ ! Construct the Fourier profile of the host halo.
+ expansionFactor=self%cosmologyFunctions_%expansionFactor(self%outputTimes_%time(indexOutput))
+ allocate(wavenumber (self%wavenumberCount))
+ allocate(fourierProfile(self%wavenumberCount))
+ do i=1,self%wavenumberCount
+ ! Note that wavenumbers must be converted from comoving to physical units for the dark matter profile k-space function.
+ scaleType =outputAnalysisPropertyTypeLinear
+ wavenumber (i)=+1.0d0 &
+ & /self%separationPropertyOperator_%operate(1.0d0/self%waveNumber(i),node,scaleType,indexOutput)
+ fourierProfile(i)=self%darkMatterProfileDMO_%kSpace( &
+ & node , &
+ & wavenumber(i)/expansionFactor &
+ & )
+ end do
+ ! Get the mass of this halo.
+ basic => node %basic()
+ massHalo = basic%mass ()
+ ! Get the bias of this halo.
+ biasHalo=self%darkMatterHaloBias_%bias(node)
+ ! Accumulate.
+ oneHaloTermActive=.false.
+ twoHaloTermActive=.false.
+ mainBranchCounted=.false.
+ allocate(termJacobian (self%massCount*(2*self%wavenumberCount+1),self%countSatellites+1))
+ allocate(satelliteJacobian ( self%countSatellites ))
+ allocate(modifierCovariance ( self%wavenumberCount ,self%wavenumberCount ))
+ allocate(modifierCovarianceDiagonal(self%massCount*(2*self%wavenumberCount+1) ))
+ termJacobian =0.0d0
+ modifierCovariance =0.0d0
+ modifierCovarianceDiagonal=0.0d0
+ ! Iterate over masses.
+ do i=1,self%massCount
+ ! Find mean number of satellites and satellite pairs.
+ if (self%countSatellites > 0) then
+ countSatellitesMean =Poisson_Binomial_Distribution_Mean (self%probabilitySatellite(1:self%countSatellites,i))
+ countSatellitePairsMean=Poisson_Binomial_Distribution_Mean_Pairs(self%probabilitySatellite(1:self%countSatellites,i))
+ else
+ countSatellitesMean =0.0d0
+ countSatellitePairsMean=0.0d0
+ end if
+ ! Skip if this halo contains no galaxies.
+ if (self%probabilityCentral(i) > 0.0d0 .or. countSatellitesMean > 0.0d0) then
+ ! Compute output halo weight.
+ haloWeightOutput=node%hostTree%volumeWeight*self%outputWeight(i,indexOutput)
+ ! Compute contribution to galaxy density.
+ galaxyDensity(i)=+haloWeightOutput &
+ & *( &
+ & +self%probabilityCentral(i) &
+ & +countSatellitesMean &
+ & )
+ ! For main branch galaxies, accumulate their contribution to the density as a function of halo mass, so that we can later subtract this from the variance.
+ if (node%isOnMainBranch()) then
+ basicRoot => node %hostTree%baseNode%basic()
+ haloMassBin = floor((log10(basicRoot%mass())-self%massHaloLogarithmicMinimum)*self%massHaloIntervalLogarithmicInverse)+1
+ ! Accumulate weights to halo mass arrays.
+ if (haloMassBin >= 1 .and. haloMassBin <= self%countBinsMassHalo) then
+ self %meanDensityMainBranch( i,haloMassBin)= &
+ & +self%meanDensityMainBranch( i,haloMassBin) &
+ & + haloWeightOutput &
+ & *self%probabilityCentral ( i )
+ self %oneHaloTermMainBranch(:,i,haloMassBin)= &
+ & +self%oneHaloTermMainBranch(:,i,haloMassBin) &
+ & + haloWeightOutput &
+ & *self%probabilityCentral ( i ) &
+ & * countSatellitesMean &
+ & * fourierProfile
+ self %twoHaloTermMainBranch(:,i,haloMassBin)= &
+ & +self%twoHaloTermMainBranch(:,i,haloMassBin) &
+ & + haloWeightOutput &
+ & *self%probabilityCentral ( i ) &
+ & * biasHalo &
+ & * fourierProfile
+ ! If this is the first mass bin in which the central, main branch galaxy is seen, increment the number of main branch galaxies.
+ if (.not.mainBranchCounted) then
+ mainBranchCounted =.true.
+ self%countMainBranch(haloMassBin)=self%countMainBranch(haloMassBin)+1
+ end if
+ end if
+ end if
+ ! Accumulate contribution to galaxy density.
+ self%meanDensity(i)=+self%meanDensity(i) &
+ & +galaxyDensity (i)
+ ! Compute and accumulate one-halo term.
+ if (countSatellitesMean > 0.0d0) then
+ oneHaloTermActive( i)=.true.
+ oneHaloTerm (:,i)=+haloWeightOutput &
+ & *( &
+ & +self%probabilityCentral (i) &
+ & * countSatellitesMean &
+ & * fourierProfile &
+ & + countSatellitePairsMean &
+ & * fourierProfile **2 &
+ & )
+ call self%haloModelPowerSpectrumModifier_%modify( &
+ & wavenumber , &
+ & haloModelTermOneHalo, &
+ & oneHaloTerm(:,i) , &
+ & modifierCovariance , &
+ & mass=massHalo &
+ & )
+ call correlationFunctionTermIndices(i,self%wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
+ forall(j=1:self%wavenumberCount)
+ modifierCovarianceDiagonal(indexOneHalo+j-1)=modifierCovariance(j,j)
+ end forall
+ modifierCovarianceDiagonal(indexDensity)=0.0d0
+ self%oneHaloTerm(:,i)=+self%oneHaloTerm(:,i) &
+ & + oneHaloTerm(:,i)
+ end if
+ ! Compute and accumulate two-halo term.
+ twoHaloTermActive( i)=.true.
+ twoHaloTerm (:,i)=+galaxyDensity (i) &
+ & *biasHalo &
+ & *fourierProfile
+ call self%haloModelPowerSpectrumModifier_%modify( &
+ & wavenumber , &
+ & haloModelTermTwoHalo, &
+ & twoHaloTerm(:,i) , &
+ & modifierCovariance , &
+ & mass=massHalo &
+ & )
+ call correlationFunctionTermIndices(i,self%wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
+ forall(j=1:self%wavenumberCount)
+ modifierCovarianceDiagonal(indexTwoHalo+j-1)=modifierCovariance(j,j)
+ end forall
+ modifierCovarianceDiagonal(indexDensity)=0.0d0
+ self%twoHaloTerm(:,i)=+self%twoHaloTerm(:,i) &
+ & + twoHaloTerm(:,i)
+ ! Construct Jacobian of the terms being accumulated. The Jacobian here is an MxN matrix, where M=massCount*(2*wavenumberCount+1)
+ ! (the number of terms in halo model quantities being accumulated {wavenumberCount for 1- and 2-halo terms, plus a density, for
+ ! each mass bin}), and N is the total number of galaxies in the halo (number of satellites plus 1 central).
+ ! Compute indices.
+ call correlationFunctionTermIndices(i,self%wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
+ ! One halo terms.
+ if (self%countSatellites > 0) then
+ satelliteJacobian=Poisson_Binomial_Distribution_Mean_Pairs_Jacobian(self%probabilitySatellite(1:self%countSatellites,i))*self%probabilitySatellite(1:self%countSatellites,i)
+ do j=1,self%wavenumberCount
+ termJacobian(indexOneHalo +j -1,1:self%countSatellites )=haloWeightOutput *fourierProfile(j)**2* satelliteJacobian
+ end do
+ end if
+ termJacobian (indexOneHalo:indexOneHalo+self%wavenumberCount-1, self%countSatellites+1)=haloWeightOutput *fourierProfile *self%probabilityCentral ( i)*countSatellitesMean
+ ! Two halo terms.
+ do j=1,self%wavenumberCount
+ termJacobian (indexTwoHalo +j -1,1:self%countSatellites )=haloWeightOutput*biasHalo*fourierProfile(j) *self%probabilitySatellite(1:self%countSatellites,i)
+ end do
+ termJacobian (indexTwoHalo:indexTwoHalo+self%wavenumberCount-1, self%countSatellites+1)=haloWeightOutput*biasHalo*fourierProfile *self%probabilityCentral ( i)
+ ! Compute density terms.
+ termJacobian (indexDensity ,1:self%countSatellites )=haloWeightOutput *self%probabilitySatellite(1:self%countSatellites,i)
+ termJacobian (indexDensity , self%countSatellites+1)=haloWeightOutput *self%probabilityCentral ( i)
+ end if
+ end do
+ ! Construct and accumulate term covariance.
+ allocate(termCovariance(self%massCount*(2*self%wavenumberCount+1),self%massCount*(2*self%wavenumberCount+1)))
+ jacobianMatrix=termJacobian
+ termCovariance=jacobianMatrix*jacobianMatrix%transpose()
+ ! Add modifier covariance.
+ termCovariance=termCovariance+Vector_Outer_Product(modifierCovarianceDiagonal)
+ ! For main branch galaxies, zero all off-diagonal contributions.
+ if (node%isOnMainBranch()) then
+ termJacobian(:,1:self%countSatellites)=0.0d0
+ jacobianMatrix=termJacobian
+ allocate(mainBranchTermCovariance(self%massCount*(2*self%wavenumberCount+1),self%massCount*(2*self%wavenumberCount+1)))
+ mainBranchTermCovariance=jacobianMatrix*jacobianMatrix%transpose()
+ do i=1,self%massCount
+ mainBranchTermCovariance( &
+ & (i-1)*(2*self%wavenumberCount+1)+1:i*(2*self%wavenumberCount+1), &
+ & (i-1)*(2*self%wavenumberCount+1)+1:i*(2*self%wavenumberCount+1) &
+ & ) &
+ & =0.0d0
+ end do
+ termCovariance=termCovariance-mainBranchTermCovariance
+ deallocate(mainBranchTermCovariance)
+ end if
+ self%termCovariance=self%termCovariance+termCovariance
+ deallocate(termJacobian )
+ deallocate(satelliteJacobian)
+ ! Reset counts.
+ self%probabilityCentral=0.0d0
+ self%countSatellites =0
+ return
+ end subroutine correlationFunctionAccumulateHalo
+
+ subroutine correlationFunctionTermIndices(iMass,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
+ !% Return the indices in the term covariances array at which one-halo, two-halo, and density terms are stored for the given
+ !% mass.
+ implicit none
+ integer(c_size_t), intent(in ) :: iMass , wavenumberCount
+ integer(c_size_t), intent( out) :: indexOneHalo, indexTwoHalo , &
+ & indexDensity
+
+ indexOneHalo=(iMass-1)*(2*wavenumberCount+1) +1
+ indexTwoHalo=(iMass-1)*(2*wavenumberCount+1)+ wavenumberCount+1
+ indexDensity=(iMass-1)*(2*wavenumberCount+1)+2*wavenumberCount+1
+ return
+ end subroutine correlationFunctionTermIndices
+
+ subroutine correlationFunctionReduce(self,reduced)
+ !% Implement a {\normalfont \ttfamily correlationFunction} output analysis reduction.
+ use Galacticus_Error, only : Galacticus_Error_Report
+ implicit none
+ class(outputAnalysisCorrelationFunction), intent(inout) :: self
+ class(outputAnalysisClass ), intent(inout) :: reduced
+
+ select type (reduced)
+ class is (outputAnalysisCorrelationFunction)
+ !$ call OMP_Set_Lock(reduced%accumulateLock)
+ reduced%meanDensity =reduced%meanDensity +self%meanDensity
+ reduced%oneHaloTerm =reduced%oneHaloTerm +self%oneHaloTerm
+ reduced%twoHaloTerm =reduced%twoHaloTerm +self%twoHaloTerm
+ reduced%countMainBranch =reduced%countMainBranch +self%countMainBranch
+ reduced%meanDensityMainBranch=reduced%meanDensityMainBranch+self%meanDensityMainBranch
+ reduced%oneHaloTermMainBranch=reduced%oneHaloTermMainBranch+self%oneHaloTermMainBranch
+ reduced%twoHaloTermMainBranch=reduced%twoHaloTermMainBranch+self%twoHaloTermMainBranch
+ reduced%termCovariance =reduced%termCovariance +self%termCovariance
+ !$ call OMP_Unset_Lock(reduced%accumulateLock)
+ class default
+ call Galacticus_Error_Report('incorrect class'//{introspection:location})
+ end select
+ return
+ end subroutine correlationFunctionReduce
+
+ subroutine correlationFunctionFinalize(self)
+ !% Implement a {\normalfont \ttfamily correlationFunction} output analysis finalization.
+ use IO_HDF5 , only : hdf5Object , hdf5Access
+ use Galacticus_HDF5 , only : galacticusOutputFile
+ use Numerical_Constants_Astronomical, only : megaParsec
+ implicit none
+ class(outputAnalysisCorrelationFunction), intent(inout) :: self
+ type (hdf5Object ) :: analysesGroup, analysisGroup, &
+ & dataset
+
+ ! Finalize analysis.
+ call correlationFunctionFinalizeAnalysis(self)
+ ! Output the correlation function.
+ !$ call hdf5Access%set()
+ analysesGroup=galacticusOutputFile%openGroup('analyses' )
+ analysisGroup=analysesGroup %openGroup('correlationFunction'//char(self%label),char(self%comment))
+ ! Write metadata describing this analysis.
+ call analysisGroup%writeAttribute(char(self%comment) ,'description' )
+ call analysisGroup%writeAttribute("function1DSequence" ,'type' )
+ call analysisGroup%writeAttribute('$s\, [_\chi\mathrm{Mpc}]$' ,'xAxisLabel' )
+ call analysisGroup%writeAttribute('$w(s)\, [_\chi\mathrm{Mpc}]$' ,'yAxisLabel' )
+ call analysisGroup%writeAttribute(.true. ,'xAxisIsLog' )
+ call analysisGroup%writeAttribute(.true. ,'yAxisIsLog' )
+ call analysisGroup%writeAttribute('separation' ,'xDataset' )
+ call analysisGroup%writeAttribute('correlationFunction' ,'yDataset' )
+ call analysisGroup%writeAttribute('correlationFunctionTarget' ,'yDatasetTarget' )
+ call analysisGroup%writeAttribute('correlationFunctionCovariance' ,'yCovariance' )
+ call analysisGroup%writeAttribute('correlationFunctionCovarianceTarget' ,'yCovarianceTarget' )
+ ! Write computed datasets.
+ call analysisGroup%writeDataset (self%separations ,'separation' ,'Separation' ,datasetReturned=dataset)
+ call dataset %writeAttribute('ᵪMpc' ,'units' )
+ call dataset %writeAttribute(megaParsec ,'unitsInSI' )
+ call dataset %close ( )
+ call analysisGroup%writeDataset (self%binnedProjectedCorrelation ,'correlationFunction' ,'Projected correlation' ,datasetReturned=dataset)
+ call dataset %writeAttribute('ᵪMpc' ,'units' )
+ call dataset %writeAttribute(megaParsec ,'unitsInSI' )
+ call dataset %close ( )
+ call analysisGroup%writeDataset (self%binnedProjectedCorrelationCovariance ,'correlationFunctionCovariance' ,'Projected correlation covariance' ,datasetReturned=dataset)
+ call dataset %writeAttribute('ᵪMpc²' ,'units' )
+ call dataset %writeAttribute(megaParsec**2 ,'unitsInSI' )
+ call dataset %close ( )
+ ! If available, include the log-likelihood and target dataset.
+ if (allocated(self%binnedProjectedCorrelationTarget)) then
+ call analysisGroup%writeAttribute( self%logLikelihood() ,'logLikelihood' )
+ call analysisGroup%writeAttribute(char(self%targetLabel) ,'targetLabel' )
+ call analysisGroup%writeDataset ( self%binnedProjectedCorrelationTarget ,"correlationFunctionTarget" ,'Projected correlation target' ,datasetReturned=dataset)
+ call dataset %writeAttribute( "ᵪMpc" ,'units' )
+ call dataset %writeAttribute( megaParsec ,'unitsInSI' )
+ call dataset %close ( )
+ call analysisGroup%writeDataset ( self%binnedProjectedCorrelationCovarianceTarget,"correlationFunctionCovarianceTarget",'Projected correlation covariance target',datasetReturned=dataset)
+ call dataset %writeAttribute( "ᵪMpc²" ,'units' )
+ call dataset %writeAttribute( megaParsec**2 ,'unitsInSI' )
+ call dataset %close ( )
+ end if
+ call analysisGroup%close ( )
+ call analysesGroup%close ( )
+ !$ call hdf5Access%unset()
+ return
+ end subroutine correlationFunctionFinalize
+
+ subroutine correlationFunctionFinalizeAnalysis(self)
+ !% Compute final covariances and normalize.
+#ifdef USEMPI
+ use MPI_Utilities , only : mpiSelf
+#endif
+ use Memory_Management , only : allocateArray , deallocateArray
+ use FFTLogs , only : FFTLog , fftLogSine , fftLogForward
+ use Tables , only : table1DLogarithmicLinear , tablesIntegrationWeightFunction
+ use Table_Labels , only : extrapolationTypeExtrapolate
+ use Linear_Algebra , only : matrix , operator(*) , assignment(=)
+ use Vectors , only : Matrix_Copy_Upper_To_Lower_Triangle, Vector_Outer_Product
+ use Numerical_Constants_Math, only : Pi
+ implicit none
+ class (outputAnalysisCorrelationFunction), intent(inout) :: self
+ double precision , allocatable , dimension(: ) :: separation
+ double precision , allocatable , dimension(:,:) :: powerSpectrumCovariance , jacobian , &
+ & correlationCovariance , covarianceTmp , &
+ & projectedCorrelationCovariance, oneTwoHaloCovariance, &
+ & powerSpectrumValue , correlation , &
+ & projectedCorrelation
+ integer (c_size_t ) :: i , j , &
+ & m , n , &
+ & indexOneHalo , indexTwoHalo , &
+ & indexDensity
+ type (table1DLogarithmicLinear ) :: correlationTable
+ double precision :: projectedSeparation , binSeparationMinimum, &
+ & binSeparationMaximum , binWidthLogarithmic
+ type (matrix ) :: jacobianMatrix , covarianceMatrix
+ procedure (tablesIntegrationWeightFunction ), pointer :: integrandWeightFunction
+
+ ! If already finalized, no need to do anything.
+ if (self%finalized) return
+ self%finalized=.true.
+#ifdef USEMPI
+ ! If running under MPI, perform a summation reduction across all processes.
+ self%meanDensity =mpiSelf%sum(meanDensity )
+ self%oneHaloTerm =mpiSelf%sum(oneHaloTerm )
+ self%twoHaloTerm =mpiSelf%sum(twoHaloTerm )
+ self%countMainBranch =mpiSelf%sum(countMainBranch )
+ self%meanDensityMainBranch=mpiSelf%sum(meanDensityMainBranch)
+ self%oneHaloTermMainBranch=mpiSelf%sum(oneHaloTermMainBranch)
+ self%twoHaloTermMainBranch=mpiSelf%sum(twoHaloTermMainBranch)
+ self%termCovariance =mpiSelf%sum(termCovariance )
+#endif
+ ! Copy upper to lower triangle of covariance matrix (we've accumulated only the upper triangle).
+ self%termCovariance=Matrix_Copy_Upper_To_Lower_Triangle(self%termCovariance)
+ ! Find average density contribution of main branch galaxies in each halo mass bin.
+ do n=1,self%massCount
+ where (self%countMainBranch(:) > 0)
+ self %meanDensityMainBranch( n,:) &
+ & =+ self%meanDensityMainBranch( n,:) &
+ & /dble(self%countMainBranch ( :))
+ end where
+ do i=1,self%wavenumberCount
+ where (self%countMainBranch(:) > 0)
+ self %oneHaloTermMainBranch(i,n,:) &
+ & =+ self%oneHaloTermMainBranch(i,n,:) &
+ & /dble(self%countMainBranch ( :))
+ self %twoHaloTermMainBranch(i,n,:) &
+ & =+ self%twoHaloTermMainBranch(i,n,:) &
+ & /dble(self%countMainBranch ( :))
+ end where
+ end do
+ end do
+ ! Subtract out Poisson component of main branch galaxy variance (since these galaxies are not Poisson distributed).
+ do m=1,self%massCount
+ call correlationFunctionTermIndices(m,self%wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
+ do i=1,self%countBinsMassHalo
+ ! Density-density.
+ self %termCovariance ( indexDensity ,indexDensity )= &
+ & + self%termCovariance ( indexDensity ,indexDensity ) &
+ & - self%meanDensityMainBranch( m ,i ) **2 &
+ & * dble(self%countMainBranch ( i ))
+ ! One-halo-one-halo.
+ self %termCovariance ( indexOneHalo:indexOneHalo+self%wavenumberCount-1,indexOneHalo:indexOneHalo+self%wavenumberCount-1)= &
+ & + self%termCovariance ( indexOneHalo:indexOneHalo+self%wavenumberCount-1,indexOneHalo:indexOneHalo+self%wavenumberCount-1) &
+ & -Vector_Outer_Product( &
+ & self%oneHaloTermMainBranch(:,m ,i ), &
+ & self%oneHaloTermMainBranch(:,m ,i ) &
+ & ) &
+ & * dble(self%countMainBranch ( i ))
+ ! Two-halo-two-halo.
+ self %termCovariance ( indexTwoHalo:indexTwoHalo+self%wavenumberCount-1,indexTwoHalo:indexTwoHalo+self%wavenumberCount-1)= &
+ & + self%termCovariance ( indexTwoHalo:indexTwoHalo+self%wavenumberCount-1,indexTwoHalo:indexTwoHalo+self%wavenumberCount-1) &
+ & -Vector_Outer_Product( &
+ & self%twoHaloTermMainBranch(:,m ,i ), &
+ & self%twoHaloTermMainBranch(:,m ,i ) &
+ & ) &
+ & * dble(self%countMainBranch ( i ))
+ ! Density-one-halo.
+ self %termCovariance ( indexDensity ,indexOneHalo:indexOneHalo+self%wavenumberCount-1)= &
+ & + self%termCovariance ( indexDensity ,indexOneHalo:indexOneHalo+self%wavenumberCount-1) &
+ & - self%meanDensityMainBranch( m ,i ) &
+ & * self%oneHaloTermMainBranch(:,m ,i ) &
+ & * dble(self%countMainBranch ( i ))
+ self %termCovariance ( indexOneHalo:indexOneHalo+self%wavenumberCount-1,indexDensity )= &
+ & + self%termCovariance ( indexOneHalo:indexOneHalo+self%wavenumberCount-1,indexDensity ) &
+ & - self%oneHaloTermMainBranch(:,m ,i ) &
+ & * self%meanDensityMainBranch( m ,i ) &
+ & * dble(self%countMainBranch ( i ))
+ ! Density-two-halo.
+ self %termCovariance ( indexDensity ,indexTwoHalo:indexTwoHalo+self%wavenumberCount-1)= &
+ & + self%termCovariance ( indexDensity ,indexTwoHalo:indexTwoHalo+self%wavenumberCount-1) &
+ & - self%meanDensityMainBranch( m ,i ) &
+ & * self%twoHaloTermMainBranch(:,m ,i ) &
+ & * dble(self%countMainBranch ( i ))
+ self %termCovariance ( indexTwoHalo:indexTwoHalo+self%wavenumberCount-1,indexDensity )= &
+ & + self%termCovariance ( indexTwoHalo:indexTwoHalo+self%wavenumberCount-1,indexDensity ) &
+ & - self%twoHaloTermMainBranch(:,m ,i ) &
+ & * self%meanDensityMainBranch( m ,i ) &
+ & * dble(self%countMainBranch ( i ))
+ ! One-halo-two-halo
+ self %termCovariance ( indexOneHalo:indexOneHalo+self%wavenumberCount-1,indexTwoHalo:indexTwoHalo+self%wavenumberCount-1)= &
+ & + self%termCovariance ( indexOneHalo:indexOneHalo+self%wavenumberCount-1,indexTwoHalo:indexTwoHalo+self%wavenumberCount-1) &
+ & -Vector_Outer_Product( &
+ & self%oneHaloTermMainBranch(:,m ,i ), &
+ & self%twoHaloTermMainBranch(:,m ,i ) &
+ & ) &
+ & * dble(self%countMainBranch ( i ))
+ self %termCovariance ( indexTwoHalo:indexTwoHalo+self%wavenumberCount-1,indexOneHalo:indexOneHalo+self%wavenumberCount-1)= &
+ & + self%termCovariance ( indexTwoHalo:indexTwoHalo+self%wavenumberCount-1,indexOneHalo:indexOneHalo+self%wavenumberCount-1) &
+ & -Vector_Outer_Product( &
+ & self%twoHaloTermMainBranch(:,m ,i ), &
+ & self%oneHaloTermMainBranch(:,m ,i ) &
+ & ) &
+ & * dble(self%countMainBranch ( i ))
+ end do
+ end do
+ ! Normalize one- and two-halo terms.
+ call allocateArray(jacobian ,[self%massCount*(2*self%wavenumberCount),self%massCount*(2*self%wavenumberCount+1)])
+ call allocateArray(oneTwoHaloCovariance,[self%massCount*(2*self%wavenumberCount),self%massCount*(2*self%wavenumberCount )])
+ ! One-halo term.
+ jacobian=0.0d0
+ do n=1,self%massCount
+ call correlationFunctionTermIndices(n,self%wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
+ if (self%meanDensity(n) > 0.0d0) then
+ do i=1,self%wavenumberCount
+ jacobian((n-1)*(2*self%wavenumberCount)+i,indexOneHalo+i-1)=1.0d0/self%meanDensity(n)**2
+ end do
+ jacobian((n-1)*(2*self%wavenumberCount)+1:(n-1)*(2*self%wavenumberCount)+self%wavenumberCount,indexDensity)=-2.0d0*self%oneHaloTerm(:,n)/self%meanDensity(n)**3
+ end if
+ end do
+ ! Two-halo term.
+ do n=1,self%massCount
+ call correlationFunctionTermIndices(n,self%wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
+ if (self%meanDensity(n) > 0.0d0) then
+ do i=1,self%wavenumberCount
+ jacobian((n-1)*(2*self%wavenumberCount)+self%wavenumberCount+i,indexTwoHalo+i-1)=1.0d0/self%meanDensity(n)
+ end do
+ jacobian((n-1)*(2*self%wavenumberCount)+self%wavenumberCount+1:(n-1)*(2*self%wavenumberCount)+2*self%wavenumberCount,indexDensity)=-self%twoHaloTerm(:,n)/self%meanDensity(n)**2
+ end if
+ end do
+ jacobianMatrix =jacobian
+ covarianceMatrix =self%termCovariance
+ oneTwoHaloCovariance =jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
+ do n=1,self%massCount
+ if (self%meanDensity(n) > 0.0d0) then
+ self%oneHaloTerm(:,n)=self%oneHaloTerm(:,n)/self%meanDensity(n)**2
+ self%twoHaloTerm(:,n)=self%twoHaloTerm(:,n)/self%meanDensity(n)
+ end if
+ end do
+ call deallocateArray(jacobian)
+ ! Square the two halo term, and multiply by the linear theory power spectrum.
+ call allocateArray(jacobian ,[self%massCount*(2*self%wavenumberCount),self%massCount*(2*self%wavenumberCount)])
+ jacobian=0.0d0
+ do n=1,self%massCount
+ do i=1,self%wavenumberCount
+ jacobian((n-1)*(2*self%wavenumberCount) +i,(n-1)*(2*self%wavenumberCount) +i)=+1.0d0
+ jacobian((n-1)*(2*self%wavenumberCount)+self%wavenumberCount+i,(n-1)*(2*self%wavenumberCount)+self%wavenumberCount+i)=+2.0d0 &
+ & *self%twoHaloTerm (i,n) &
+ & *self%powerSpectrum_%power (self%wavenumber(i )) &
+ & *self%linearGrowthFactorSquared ( n)
+ end do
+ end do
+ jacobianMatrix =jacobian
+ covarianceMatrix =oneTwoHaloCovariance
+ oneTwoHaloCovariance=jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
+ do n=1,self%massCount
+ do i=1,self%wavenumberCount
+ self%twoHaloTerm(i,n)=+self%twoHaloTerm (i,n) **2 &
+ & *self%powerSpectrum_%power (self%wavenumber(i )) &
+ & *self%linearGrowthFactorSquared ( n)
+ end do
+ end do
+ call deallocateArray(jacobian)
+ ! Construct the final power spectra.
+ call allocateArray(powerSpectrumValue ,[ self%wavenumberCount,self%massCount ])
+ call allocateArray(powerSpectrumCovariance,[self%massCount*self%wavenumberCount,self%massCount* self%wavenumberCount ])
+ call allocateArray(jacobian ,[self%massCount*self%wavenumberCount,self%massCount*(2*self%wavenumberCount)])
+ jacobian=0.0d0
+ do n=1,self%massCount
+ do i=1,self%wavenumberCount
+ jacobian((n-1)*self%wavenumberCount+i,(n-1)*(2*self%wavenumberCount) +i)=1.0d0
+ jacobian((n-1)*self%wavenumberCount+i,(n-1)*(2*self%wavenumberCount)+self%wavenumberCount+i)=1.0d0
+ end do
+ end do
+ jacobianMatrix =jacobian
+ covarianceMatrix =oneTwoHaloCovariance
+ powerSpectrumCovariance=jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
+ do n=1,self%massCount
+ powerSpectrumValue(:,n)=self%oneHaloTerm(:,n)+self%twoHaloTerm(:,n)
+ end do
+ call deallocateArray(jacobian )
+ call deallocateArray(oneTwoHaloCovariance)
+ ! Allocate correlation function and separation arrays.
+ call allocateArray(correlation,shape(powerSpectrumValue))
+ call allocateArray(separation ,[self%wavenumberCount])
+ ! Fourier transform the power spectrum to get the correlation function.
+ do n=1,self%massCount
+ call FFTLog( &
+ & self%wavenumber , &
+ & separation , &
+ & +powerSpectrumValue(:,n) &
+ & *self%wavenumber &
+ & * 4.0d0*Pi &
+ & /(2.0d0*Pi)**3 , &
+ & correlation(:,n) , &
+ & fftLogSine , &
+ & fftLogForward &
+ & )
+ correlation(:,n)=correlation(:,n)/separation
+ end do
+ ! Compute the covariance of the correlation function.
+ call allocateArray(covarianceTmp ,[self%massCount*self%wavenumberCount,self%massCount*self%wavenumberCount])
+ call allocateArray(correlationCovariance,[self%massCount*self%wavenumberCount,self%massCount*self%wavenumberCount])
+ ! Apply wavenumber weighting to the power spectrum covariance.
+ do n=1,self%massCount
+ do m=1,self%massCount
+ do i=1,self%wavenumberCount
+ do j=1,self%wavenumberCount
+ powerSpectrumCovariance ((n-1)*self%wavenumberCount+i,(m-1)*self%wavenumberCount+j) &
+ & =+powerSpectrumCovariance((n-1)*self%wavenumberCount+i,(m-1)*self%wavenumberCount+j) &
+ & *self%wavenumber ( i ) &
+ & *self%wavenumber ( j) &
+ & *( &
+ & + 4.0d0*Pi &
+ & /(2.0d0*Pi)**3 &
+ & )**2
+ end do
+ end do
+ end do
+ end do
+ ! Derive the covariance of the correlation function by first Fourier transforming each row of the power spectrum covariance
+ ! matrix, and then Fourier transforming each column.
+ do n=1,self%massCount
+ do m=1,self%massCount
+ do i=1,self%wavenumberCount
+ call FFTlog( &
+ & self%wavenumber , &
+ & separation , &
+ & powerSpectrumCovariance((n-1)*self%wavenumberCount+i,(m-1)*self%wavenumberCount+1:m*self%wavenumberCount), &
+ & covarianceTmp ((n-1)*self%wavenumberCount+i,(m-1)*self%wavenumberCount+1:m*self%wavenumberCount), &
+ & fftLogSine , &
+ & fftLogForward &
+ )
+ end do
+ end do
+ end do
+ do n=1,self%massCount
+ do m=1,self%massCount
+ do i=1,self%wavenumberCount
+ call FFTlog( &
+ & self%wavenumber , &
+ & separation , &
+ & covarianceTmp ((n-1)*self%wavenumberCount+1:n*self%wavenumberCount,(m-1)*self%wavenumberCount+i), &
+ & correlationCovariance ((n-1)*self%wavenumberCount+1:n*self%wavenumberCount,(m-1)*self%wavenumberCount+i), &
+ & fftLogSine , &
+ & fftLogForward &
+ )
+ end do
+ end do
+ end do
+ do n=1,self%massCount
+ do m=1,self%massCount
+ do i=1,self%wavenumberCount
+ do j=1,self%wavenumberCount
+ correlationCovariance ((n-1)*self%wavenumberCount+i,(m-1)*self%wavenumberCount+j) &
+ & =correlationCovariance((n-1)*self%wavenumberCount+i,(m-1)*self%wavenumberCount+j) &
+ & /separation ( i ) &
+ & /separation ( j)
+ end do
+ end do
+ end do
+ end do
+ call deallocateArray(covarianceTmp)
+ ! Construct correlation table.
+ call correlationTable%create(separation(1),separation(self%wavenumberCount),size(separation),extrapolationTypeExtrapolate)
+ ! Project the correlation function.
+ call allocateArray(jacobian ,[self%massCount*self%wavenumberCount,self%massCount*self%wavenumberCount])
+ call allocateArray(projectedCorrelationCovariance,[self%massCount*self%wavenumberCount,self%massCount*self%wavenumberCount])
+ call allocateArray(projectedCorrelation ,[ self%wavenumberCount,self%massCount ])
+ jacobian=0.0d0
+ integrandWeightFunction => projectionIntegrandWeight
+ do i=1,self%wavenumberCount
+ projectedSeparation=correlationTable%x(int(i))
+ jacobian(i,1:self%wavenumberCount)=correlationTable%integrationWeights( &
+ & projectedSeparation , &
+ & sqrt( &
+ & +projectedSeparation **2 &
+ & +self%depthLineOfSight**2 &
+ & ) , &
+ & integrandWeightFunction &
+ & )
+ do n=1,self%massCount
+ if (n > 1) jacobian((n-1)*self%wavenumberCount+i,(n-1)*self%wavenumberCount+1:n*self%wavenumberCount)=jacobian(i,1:self%wavenumberCount)
+ projectedCorrelation(i,n)=sum(jacobian(i,1:self%wavenumberCount)*correlation(:,n))
+ end do
+ end do
+ jacobianMatrix =jacobian
+ covarianceMatrix =correlationCovariance
+ projectedCorrelationCovariance=jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
+ call deallocateArray(jacobian)
+ ! If the integral was taken over the half range, 0 < π < πₘₐₓ, rather than the full range, -πₘₐₓ < π < πₘₐₓ, then divide
+ ! the projected correlation function by two.
+ if (self%halfIntegral) then
+ projectedCorrelation =projectedCorrelation /2.0d0
+ projectedCorrelationCovariance=projectedCorrelationCovariance/2.0d0**2
+ end if
+ ! Integrate the projected correlation function over bins.
+ call allocateArray(self%binnedProjectedCorrelation ,[ size(self%separations,kind=c_size_t),self%massCount ])
+ call allocateArray(self%binnedProjectedCorrelationCovariance,[self%massCount*size(self%separations,kind=c_size_t),self%massCount*size(self%separations ,kind=c_size_t)])
+ call allocateArray( jacobian ,[self%massCount*size(self%separations,kind=c_size_t),self%massCount* self%wavenumberCount ])
+ jacobian=0.0d0
+ integrandWeightFunction => binningIntegrandWeight
+ binWidthLogarithmic=log(self%separations(2)/self%separations(1))
+ do i=1,size(self%separations)
+ binSeparationMinimum =self%separations(i)*exp(-0.5d0*binWidthLogarithmic)
+ binSeparationMaximum =self%separations(i)*exp(+0.5d0*binWidthLogarithmic)
+ jacobian(i,1:self%wavenumberCount)=correlationTable%integrationWeights( &
+ & binSeparationMinimum , &
+ & binSeparationMaximum , &
+ & integrandWeightFunction &
+ & ) &
+ & /Pi &
+ & /( &
+ & +binSeparationMaximum**2 &
+ & -binSeparationMinimum**2 &
+ & )
+ do n=1,self%massCount
+ if (n > 1) jacobian((n-1)*size(self%separations)+i,(n-1)*self%wavenumberCount+1:n*self%wavenumberCount)=jacobian(i,1:self%wavenumberCount)
+ self%binnedProjectedCorrelation(i,n)=sum(jacobian(i,1:self%wavenumberCount)*projectedCorrelation(:,n))
+ end do
+ end do
+ jacobianMatrix =jacobian
+ covarianceMatrix =projectedCorrelationCovariance
+ self%binnedProjectedCorrelationCovariance=jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
+ call deallocateArray(jacobian)
+ call correlationTable%destroy()
+ ! Apply the integral constraint.
+ self%binnedProjectedCorrelation=self%binnedProjectedCorrelation/self%integralConstraint
+ return
+
+ contains
+
+ double precision function projectionIntegrandWeight(separation)
+ !% The weight function applied to the correlation function when integrating to get the projected correlation function.
+ implicit none
+ double precision, intent(in ) :: separation
+
+ if (separation > projectedSeparation) then
+ projectionIntegrandWeight=2.0d0*separation/sqrt(separation**2-projectedSeparation**2)
+ else
+ projectionIntegrandWeight=0.0d0
+ end if
+ return
+ end function projectionIntegrandWeight
+
+ double precision function binningIntegrandWeight(separation)
+ !% The weight function applied to the projected correlation function when integrating into bins.
+ implicit none
+ double precision, intent(in ) :: separation
+
+ binningIntegrandWeight=2.0d0*Pi*separation
+ return
+ end function binningIntegrandWeight
+
+ end subroutine correlationFunctionFinalizeAnalysis
+
+ double precision function correlationFunctionLogLikelihood(self)
+ !% Return the log-likelihood of a correlationFunction output analysis.
+ use Linear_Algebra , only : vector , matrix, assignment(=), operator(*)
+ use Numerical_Constants_Math, only : Pi
+ use Galacticus_Error , only : Galacticus_Error_Report
+ implicit none
+ class (outputAnalysisCorrelationFunction), intent(inout) :: self
+ double precision , allocatable , dimension(:,:) :: functionCovarianceCombined
+ double precision , allocatable , dimension(: ) :: functionValueDifference
+ type (vector ) :: residual
+ type (matrix ) :: covariance , covarianceInverse
+
+ ! Check for existance of a target distribution.
+ if (allocated(self%binnedProjectedCorrelationTarget)) then
+ ! Finalize analysis.
+ call correlationFunctionFinalizeAnalysis(self)
+ ! Allocate workspaces.
+ allocate(functionCovarianceCombined(self%binCount*self%massCount,self%binCount*self%massCount))
+ allocate(functionValueDifference (self%binCount*self%massCount ))
+ ! Find combined covariance and difference between model and target.
+ functionValueDifference =reshape( &
+ & +self%binnedProjectedCorrelation &
+ & -self%binnedProjectedCorrelationTarget , &
+ & [ &
+ & +self%binCount &
+ & *self%massCount &
+ & ] &
+ & )
+ functionCovarianceCombined= +self%binnedProjectedCorrelationCovariance &
+ & +self%binnedProjectedCorrelationCovarianceTarget
+ residual =functionValueDifference
+ covariance =functionCovarianceCombined
+ ! Find the inverse covariance matrix of the combined model and target covariances.
+ covarianceInverse=covariance%invert()
+ ! Compute the log-likelihood.
+ correlationFunctionLogLikelihood=-0.5d0*(residual*(covarianceInverse*residual)) &
+ & -0.5d0*covariance%determinant() &
+ & -0.5d0*dble(self%binCount)*log(2.0d0*Pi)
+ else
+ correlationFunctionLogLikelihood=0.0d0
+ call Galacticus_Error_Report('no target distribution was provided for likelihood calculation'//{introspection:location})
+ end if
+ return
+ end function correlationFunctionLogLikelihood
diff --git a/source/galacticus.output.analyses.correlation_function.Hearin2014_SDSS.F90 b/source/galacticus.output.analyses.correlation_function.Hearin2014_SDSS.F90
new file mode 100644
index 000000000..c0fa856fe
--- /dev/null
+++ b/source/galacticus.output.analyses.correlation_function.Hearin2014_SDSS.F90
@@ -0,0 +1,288 @@
+!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
+!! 2019
+!! Andrew Benson
+!!
+!! This file is part of Galacticus.
+!!
+!! Galacticus is free software: you can redistribute it and/or modify
+!! it under the terms of the GNU General Public License as published by
+!! the Free Software Foundation, either version 3 of the License, or
+!! (at your option) any later version.
+!!
+!! Galacticus is distributed in the hope that it will be useful,
+!! but WITHOUT ANY WARRANTY; without even the implied warranty of
+!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+!! GNU General Public License for more details.
+!!
+!! You should have received a copy of the GNU General Public License
+!! along with Galacticus. If not, see .
+
+!% Contains a module which implements a correlation function output analysis class for the \cite{hearin_dark_2013} analysis.
+
+ !#
+ !# A correlation function output analysis class for the \cite{hearin_dark_2013} analysis.
+ !#
+ type, extends(outputAnalysisCorrelationFunction) :: outputAnalysisCorrelationFunctionHearin2013SDSS
+ !% A correlation function function output analysis class for the \cite{hearin_dark_2013} analysis.
+ private
+ end type outputAnalysisCorrelationFunctionHearin2013SDSS
+
+ interface outputAnalysisCorrelationFunctionHearin2013SDSS
+ !% Constructors for the ``correlationFunctionHearin2013SDSS'' output analysis class.
+ module procedure correlationFunctionHearin2013SDSSConstructorParameters
+ module procedure correlationFunctionHearin2013SDSSConstructorInternal
+ end interface outputAnalysisCorrelationFunctionHearin2013SDSS
+
+contains
+
+ function correlationFunctionHearin2013SDSSConstructorParameters(parameters) result (self)
+ !% Constructor for the ``correlationFunctionHearin2013SDSS'' output analysis class which takes a parameter set as input.
+ use :: Input_Parameters, only : inputParameter, inputParameters
+ use, intrinsic :: ISO_C_Binding , only : c_size_t
+ implicit none
+ type (outputAnalysisCorrelationFunctionHearin2013SDSS) :: self
+ type (inputParameters ), intent(inout) :: parameters
+ class (cosmologyFunctionsClass ), pointer :: cosmologyFunctions_
+ class (linearGrowthClass ), pointer :: linearGrowth_
+ class (outputTimesClass ), pointer :: outputTimes_
+ class (darkMatterProfileDMOClass ), pointer :: darkMatterProfileDMO_
+ class (darkMatterHaloBiasClass ), pointer :: darkMatterHaloBias_
+ class (haloModelPowerSpectrumModifierClass ), pointer :: haloModelPowerSpectrumModifier_
+ class (powerSpectrumClass ), pointer :: powerSpectrum_
+ double precision , allocatable , dimension(:) :: randomErrorPolynomialCoefficient, systematicErrorPolynomialCoefficient
+ double precision :: massHaloMinimum , massHaloMaximum , &
+ & randomErrorMinimum , randomErrorMaximum
+ integer :: massHaloBinsPerDecade
+
+ ! Check and read parameters.
+ if (parameters%isPresent( 'randomErrorPolynomialCoefficient')) then
+ allocate( randomErrorPolynomialCoefficient(parameters%count( 'randomErrorPolynomialCoefficient')))
+ else
+ allocate( randomErrorPolynomialCoefficient(1 ))
+ end if
+ if (parameters%isPresent('systematicErrorPolynomialCoefficient')) then
+ allocate(systematicErrorPolynomialCoefficient(parameters%count('systematicErrorPolynomialCoefficient')))
+ else
+ allocate(systematicErrorPolynomialCoefficient(1 ))
+ end if
+ !#
+ !# randomErrorMinimum
+ !# parameters
+ !# randomErrorMinimum
+ !# 0.07d0
+ !# The minimum random error for SDSS stellar masses.
+ !# float
+ !# 0..1
+ !#
+ !#
+ !# randomErrorMaximum
+ !# parameters
+ !# randomErrorMaximum
+ !# 0.07d0
+ !# The minimum random error for SDSS stellar masses.
+ !# float
+ !# 0..1
+ !#
+ !#
+ !# randomErrorPolynomialCoefficient
+ !# parameters
+ !# randomErrorPolynomialCoefficient
+ !# [0.07d0]
+ !# The coefficients of the random error polynomial for SDSS stellar masses.
+ !# float
+ !# 0..1
+ !#
+ !#
+ !# systematicErrorPolynomialCoefficient
+ !# parameters
+ !# systematicErrorPolynomialCoefficient
+ !# [0.0d0]
+ !# The coefficients of the systematic error polynomial for SDSS stellar masses.
+ !# float
+ !# 0..1
+ !#
+ !#
+ !# massHaloBinsPerDecade
+ !# 0..1
+ !# 10
+ !# The number of bins per decade of halo mass to use when constructing the mass function covariance matrix for main branch galaxies.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# massHaloMinimum
+ !# 0..1
+ !# 1.0d8
+ !# The minimum halo mass to consider when constructing the mass function covariance matrix for main branch galaxies.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !# massHaloMaximum
+ !# 0..1
+ !# 1.0d16
+ !# The maximum halo mass to consider when constructing the mass function covariance matrix for main branch galaxies.
+ !# output
+ !# parameters
+ !# real
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ self=outputAnalysisCorrelationFunctionHearin2013SDSS(massHaloBinsPerDecade,massHaloMinimum, massHaloMaximum,randomErrorMinimum,randomErrorMaximum,randomErrorPolynomialCoefficient,systematicErrorPolynomialCoefficient,linearGrowth_,cosmologyFunctions_,outputTimes_,darkMatterProfileDMO_,darkMatterHaloBias_,haloModelPowerSpectrumModifier_,powerSpectrum_)
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ return
+ end function correlationFunctionHearin2013SDSSConstructorParameters
+
+ function correlationFunctionHearin2013SDSSConstructorInternal(massHaloBinsPerDecade,massHaloMinimum,massHaloMaximum,randomErrorMinimum,randomErrorMaximum,randomErrorPolynomialCoefficient,systematicErrorPolynomialCoefficient,linearGrowth_,cosmologyFunctions_,outputTimes_,darkMatterProfileDMO_,darkMatterHaloBias_,haloModelPowerSpectrumModifier_,powerSpectrum_) result (self)
+ !% Constructor for the ``correlationFunctionHearin2013SDSS'' output analysis class for internal use.
+ use, intrinsic :: ISO_C_Binding , only : c_size_t
+ use :: Galacticus_Paths , only : galacticusPath , pathTypeDataStatic
+ use :: Cosmology_Parameters , only : cosmologyParametersSimple
+ use :: Output_Analysis_Property_Operators, only : outputAnalysisPropertyOperatorCsmlgyLmnstyDstnc
+ implicit none
+ type (outputAnalysisCorrelationFunctionHearin2013SDSS ) :: self
+ double precision , intent(in ) , dimension(:) :: randomErrorPolynomialCoefficient , systematicErrorPolynomialCoefficient
+ double precision , intent(in ) :: massHaloMinimum , massHaloMaximum , &
+ & randomErrorMinimum , randomErrorMaximum
+ integer , intent(in ) :: massHaloBinsPerDecade
+ class (linearGrowthClass ), intent(in ), target :: linearGrowth_
+ class (cosmologyFunctionsClass ), intent(in ), target :: cosmologyFunctions_
+ class (outputTimesClass ), intent(in ), target :: outputTimes_
+ class (darkMatterProfileDMOClass ), intent(in ), target :: darkMatterProfileDMO_
+ class (darkMatterHaloBiasClass ), intent(in ), target :: darkMatterHaloBias_
+ class (haloModelPowerSpectrumModifierClass ), intent(in ), target :: haloModelPowerSpectrumModifier_
+ class (powerSpectrumClass ), intent(in ), target :: powerSpectrum_
+ type (cosmologyParametersSimple ), pointer :: cosmologyParametersData_
+ type (cosmologyFunctionsMatterLambda ), pointer :: cosmologyFunctionsData_
+ type (galacticFilterStellarMass ), pointer :: galacticFilter_
+ type (surveyGeometryHearin2014SDSS ), pointer :: surveyGeometry_
+ type (outputAnalysisPropertyOperatorLog10 ), pointer :: massPropertyOperatorLog10_
+ type (outputAnalysisPropertyOperatorSystmtcPolynomial ) , pointer :: massPropertyOperatorSystmtcPolynomial_
+ type (outputAnalysisDistributionOperatorRandomErrorPlynml) , pointer :: massDistributionOperator_
+ type (outputAnalysisPropertyOperatorCsmlgyLmnstyDstnc ), pointer :: massPropertyOperatorCsmlgyLmnstyDstnc_
+ type (outputAnalysisPropertyOperatorCsmlgyAnglrDstnc ), pointer :: separationPropertyOperator_
+ type (nodePropertyExtractorMassStellar ), pointer :: massPropertyExtractor_
+ type (outputAnalysisPropertyOperatorSequence ), pointer :: massPropertyOperator_
+ type (propertyOperatorList ), pointer :: propertyOperators_
+ double precision , parameter :: errorPolynomialZeroPoint =11.3d+0
+ integer (c_size_t ), parameter :: wavenumberCount =60
+ double precision , parameter :: wavenumberMinimum = 1.0d-3, wavenumberMaximum=1.0d+4
+ logical , parameter :: halfIntegral =.false.
+
+ ! Build a filter which selects galaxies above some minimum stellar mass.
+ allocate(galacticFilter_ )
+ !#
+ ! Build the SDSS survey geometry of Hearin et al. (2013) with their imposed redshift limits.
+ allocate(surveyGeometry_ )
+ !#
+ ! Create the data cosmology.
+ allocate(cosmologyParametersData_)
+ allocate(cosmologyFunctionsData_ )
+ !#
+ !#
+ !# cosmologyParametersSimple ( &
+ !# & OmegaMatter = 0.27d0, &
+ !# & OmegaDarkEnergy= 0.73d0, &
+ !# & HubbleConstant =70.00d0, &
+ !# & temperatureCMB = 0.00d0, &
+ !# & OmegaBaryon = 0.00d0 &
+ !# & )
+ !#
+ !#
+ !#
+ !#
+ !# cosmologyFunctionsMatterLambda( &
+ !# & cosmologyParametersData_ &
+ !# & )
+ !#
+ !#
+ ! Stellar mass property extractor.
+ allocate(massPropertyExtractor_ )
+ !#
+ ! Sequence of property operators to correct for cosmological model, convert to logarithm, and apply systematic errors.
+ allocate(massPropertyOperatorCsmlgyLmnstyDstnc_)
+ !#
+ allocate(massPropertyOperatorLog10_ )
+ !#
+ ! Systematic error model.
+ allocate(massPropertyOperatorSystmtcPolynomial_)
+ !#
+ allocate(propertyOperators_ )
+ allocate(propertyOperators_%next )
+ allocate(propertyOperators_%next%next )
+ propertyOperators_ %operator_ => massPropertyOperatorCsmlgyLmnstyDstnc_
+ propertyOperators_%next %operator_ => massPropertyOperatorLog10_
+ propertyOperators_%next%next%operator_ => massPropertyOperatorSystmtcPolynomial_
+ allocate(massPropertyOperator_ )
+ !#
+ ! Build a random error distribution operator.
+ allocate(massDistributionOperator_)
+ !#
+ !#
+ !# outputAnalysisDistributionOperatorRandomErrorPlynml( &
+ !# & randomErrorMinimum , &
+ !# & randomErrorMaximum , &
+ !# & errorPolynomialZeroPoint , &
+ !# & randomErrorPolynomialCoefficient &
+ !# & )
+ !#
+ !#
+ ! Build an operator for separations which corrects for cosmological model.
+ allocate(separationPropertyOperator_)
+ !#
+ ! Build the object.
+ self%outputAnalysisCorrelationFunction= &
+ & outputAnalysisCorrelationFunction( &
+ & var_str('Hearin2013SDSS' ) , &
+ & var_str('Correlation function for the Hearin et al. (2013) SDSS analysis') , &
+ & char(galacticusPath(pathTypeDataStatic)//'/observations/correlationFunctions/Projected_Correlation_Functions_Hearin_2013.hdf5'), &
+ & massHaloBinsPerDecade , &
+ & massHaloMinimum , &
+ & massHaloMaximum , &
+ & wavenumberCount , &
+ & wavenumberMinimum , &
+ & wavenumberMaximum , &
+ & halfIntegral , &
+ & linearGrowth_ , &
+ & galacticFilter_ , &
+ & surveyGeometry_ , &
+ & cosmologyFunctions_ , &
+ & outputTimes_ , &
+ & darkMatterProfileDMO_ , &
+ & darkMatterHaloBias_ , &
+ & haloModelPowerSpectrumModifier_ , &
+ & powerSpectrum_ , &
+ & massDistributionOperator_ , &
+ & massPropertyOperator_ , &
+ & separationPropertyOperator_ , &
+ & massPropertyExtractor_ &
+ & )
+ ! Clean up.
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ !#
+ nullify(propertyOperators_)
+ return
+ end function correlationFunctionHearin2013SDSSConstructorInternal
diff --git a/source/galacticus.output.analysis.correlation_function.F90 b/source/galacticus.output.analysis.correlation_function.F90
deleted file mode 100644
index 59c2f613d..000000000
--- a/source/galacticus.output.analysis.correlation_function.F90
+++ /dev/null
@@ -1,1323 +0,0 @@
-!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
-!! 2019
-!! Andrew Benson
-!!
-!! This file is part of Galacticus.
-!!
-!! Galacticus is free software: you can redistribute it and/or modify
-!! it under the terms of the GNU General Public License as published by
-!! the Free Software Foundation, either version 3 of the License, or
-!! (at your option) any later version.
-!!
-!! Galacticus is distributed in the hope that it will be useful,
-!! but WITHOUT ANY WARRANTY; without even the implied warranty of
-!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-!! GNU General Public License for more details.
-!!
-!! You should have received a copy of the GNU General Public License
-!! along with Galacticus. If not, see .
-
-!% Contains a module which performs analysis to compute a variety of correlation functions.
-
-module Galacticus_Output_Analyses_Correlation_Functions
- !% Performs analysis to compute a variety of correlation functions.
- use, intrinsic :: ISO_C_Binding
- use :: Galacticus_Nodes, only : treeNode
- use Galactic_Structure_Options
- use Geometry_Surveys
- use Numerical_Constants_Astronomical
- use Numerical_Constants_Prefixes
- implicit none
- private
- public :: Galacticus_Output_Analysis_Correlation_Functions, Galacticus_Output_Analysis_Correlation_Functions_Output
-
- ! Record of module initialization.
- logical :: moduleInitialized =.false.
-
- ! Record of whether this analysis is active.
- logical :: analysisActive
-
- ! Number of supported mass functions.
- integer , parameter :: correlationFunctionsSupportedCount=1
-
- ! Labels for supported mass functions.
- character(len=25), dimension(correlationFunctionsSupportedCount) :: correlationFunctionLabels= &
- & [ &
- & 'sdssClusteringZ0.07' &
- & ]
-
- ! Interface for mass mapping functions.
- abstract interface
- double precision function Map_Mass(mass,node)
- import treeNode
- double precision , intent(in ) :: mass
- type (treeNode), intent(inout), pointer :: node
- end function Map_Mass
- end interface
-
- ! Interface for mass error functions.
- abstract interface
- double precision function Mass_Error(mass,node)
- import treeNode
- double precision , intent(in ) :: mass
- type (treeNode), intent(inout), pointer :: node
- end function Mass_Error
- end interface
-
- ! Type for descriptors of correlation functions.
- type :: correlationFunctionDescriptor
- double precision :: massSystematicLogM0
- procedure (Mass_Error ), pointer , nopass :: massRandomErrorFunction
- double precision :: massLogarithmicMinimum
- integer :: massSystematicCoefficientCount, massRandomCoefficientCount
- integer :: massType
- double precision :: massUnitsInSI
- logical :: halfIntegral
- character (len= 32 ) :: label
- character (len=128 ) :: comment
- procedure (Map_Mass ), pointer , nopass :: mapMass
- class (surveyGeometryClass), allocatable :: geometry
- end type correlationFunctionDescriptor
-
- ! Correlation function descriptors.
- type(correlationFunctionDescriptor), dimension(correlationFunctionsSupportedCount), target :: correlationFunctionDescriptors= &
- & [ &
- ! Hearin et al. (2013) SDSS.
- & correlationFunctionDescriptor( &
- & 11.300d0 , &
- & null() , &
- & 8.000d0 , &
- & 2 , &
- & 2 , &
- & massTypeStellar , &
- & massSolar , &
- & .false. , &
- & 'sdssClusteringZ0.07' , &
- & 'SDSS galaxy clustering at z=0.07' , &
- & null() , &
- & null() &
- & ) &
- & ]
-
- ! Type to store size functions.
- type :: correlationFunction
- ! Copy of the mass function descriptor for this mass function.
- type (correlationFunctionDescriptor), pointer :: descriptor
- ! Parameters for the systematic error model.
- double precision , allocatable, dimension(: ) :: massSystematicCoefficients, massRandomCoefficients
- double precision :: massRandomMinimum , massRandomMaximum
- ! Weights to apply to each output.
- double precision , allocatable, dimension(:,: ) :: outputWeight
- ! Mass range.
- double precision , allocatable, dimension(: ) :: massMinimum
- double precision , allocatable, dimension(: ) :: massMinimumLogarithmic
- ! Separations.
- double precision , allocatable, dimension(: ) :: separation
- ! Integral constraint.
- double precision , allocatable, dimension(:,: ) :: integralConstraint
- ! Line-of-sight integration depth.
- double precision :: lineOfSightDepth
- ! Population statistics.
- double precision , allocatable, dimension(: ) :: meanDensity
- ! Density and count of galaxies on the main branches of trees.
- double precision , allocatable, dimension(:,: ) :: meanDensityMainBranch
- double precision , allocatable, dimension(:,:,:) :: oneHaloTermMainBranch, twoHaloTermMainBranch
- integer , allocatable, dimension(: ) :: countMainBranch
- ! Power spectrum wavenumbers.
- double precision , allocatable, dimension(: ) :: wavenumber
- ! Power spectra.
- double precision , allocatable, dimension(:,: ) :: oneHaloTerm , twoHaloTerm
- ! Covariances.
- double precision , allocatable, dimension(:,: ) :: termCovariance
- ! Cosmology conversion factors.
- double precision , allocatable, dimension(: ) :: cosmologyConversionMass , cosmologyConversionSize
- ! Weighted linear growth factor.
- double precision , allocatable, dimension(: ) :: linearGrowthFactor
- end type correlationFunction
-
- ! Correlation functions.
- type(correlationFunction), allocatable, dimension(:) :: correlationFunctions
-
- ! Type for storing temporary size functions during cumulation.
- type :: correlationFunctionWork
- double precision , allocatable, dimension(:,:) :: satelliteProbability
- double precision , allocatable, dimension( :) :: centralProbability , fourierProfile
- integer :: satelliteCount
- integer (c_size_t ) :: outputNumber
- double precision :: haloBias , haloWeight , &
- & haloTime , haloMass , &
- & hostMass
- logical :: propertiesSet , isMainBranch , &
- & initialized
- ! Indices of current halo.
- integer (kind=kind_int8) :: treeIndex , haloIndex
- end type correlationFunctionWork
-
- ! Work array.
- type(correlationFunctionWork), allocatable, dimension(:) :: haloWork
- !$omp threadprivate(haloWork)
-
- ! Halo mass binning.
- double precision :: analysisProjectedCorrelationFunctionsHaloMassMinimum , analysisProjectedCorrelationFunctionsHaloMassMaximum , &
- & analysisProjectedCorrelationFunctionsHaloMassMinimumLogarithmic, haloMassIntervalLogarithmicInverse
- integer :: analysisProjectedCorrelationFunctionsHaloMassBinsCount , analysisProjectedCorrelationFunctionsHaloMassBinsPerDecade
-
- abstract interface
- double precision function integrandTemplate(x)
- double precision, intent(in ) :: x
- end function integrandTemplate
- end interface
-
-contains
-
- !#
- !# Galacticus_Output_Analysis_Correlation_Functions
- !#
- subroutine Galacticus_Output_Analysis_Correlation_Functions(tree,node,nodeStatus,iOutput,mergerTreeAnalyses)
- !% Construct correlation functions to compare to various observational determinations.
- use, intrinsic :: ISO_C_Binding
- use :: Galacticus_Nodes, only : mergerTree
- use Galacticus_Paths
- use ISO_Varying_String
- use Memory_Management
- use Cosmology_Parameters
- use Galactic_Structure_Enclosed_Masses
- use Input_Parameters
- use Output_Times
- use Galacticus_Error
- use Cosmology_Functions
- use String_Handling
- use Galacticus_Output_Analyses_Cosmology_Scalings
- use Numerical_Comparison
- use Numerical_Ranges
- use IO_HDF5
- use Linear_Growth
- use Galacticus_Output_Merger_Tree_Data
- implicit none
- type (mergerTree ), intent(inout) :: tree
- type (treeNode ), intent(inout), pointer :: node
- integer , intent(in ) :: nodeStatus
- integer (c_size_t ), intent(in ) :: iOutput
- type (varying_string ), intent(in ), dimension(: ) :: mergerTreeAnalyses
- class (cosmologyFunctionsClass ) , pointer :: cosmologyFunctionsModel
- class (linearGrowthClass ) , pointer :: linearGrowth_
- integer , parameter :: wavenumberCount =60
- double precision , parameter :: wavenumberMinimum=0.001d0, wavenumberMaximum=10000.0d0
- type (cosmologyFunctionsMatterLambda) :: cosmologyFunctionsObserved
- type (cosmologyParametersSimple ), pointer :: cosmologyParametersObserved => null()
- class (outputTimesClass ), pointer :: outputTimes_
- double precision :: mass, massLogarithmic, dataHubbleParameter, dataOmegaMatter, dataOmegaDarkEnergy, redshift, timeMinimum, timeMaximum, distanceMinimum, distanceMaximum, weight
- integer :: i,j,k,m, currentAnalysis, activeAnalysisCount,massCount
- integer (c_size_t ) :: jOutput
- type (varying_string ) :: parameterName, cosmologyScalingMass, cosmologyScalingSize, message
- type (hdf5Object ) :: dataFile , parameters, dataset
-
- ! Initialize the module if necessary.
- if (.not.moduleInitialized) then
- !$omp critical(Galacticus_Output_Analysis_Correlation_Functions_Initialize)
- if (.not.moduleInitialized) then
- !#
- !# analysisProjectedCorrelationFunctionsHaloMassBinsPerDecade
- !# 0..1
- !# 10
- !# The number of bins per decade of halo mass to use when constructing the mass function covariance matrix for main branch galaxies.
- !# output
- !# globalParameters
- !# real
- !#
- !#
- !# analysisProjectedCorrelationFunctionsHaloMassMinimum
- !# 0..1
- !# 1.0d8
- !# The minimum halo mass to consider when constructing the mass function covariance matrix for main branch galaxies.
- !# output
- !# globalParameters
- !# real
- !#
- !#
- !# analysisProjectedCorrelationFunctionsHaloMassMaximum
- !# 0..1
- !# 1.0d16
- !# The maximum halo mass to consider when constructing the mass function covariance matrix for main branch galaxies.
- !# output
- !# globalParameters
- !# real
- !#
- analysisProjectedCorrelationFunctionsHaloMassMinimumLogarithmic=log10(analysisProjectedCorrelationFunctionsHaloMassMinimum)
- analysisProjectedCorrelationFunctionsHaloMassBinsCount=int(log10(analysisProjectedCorrelationFunctionsHaloMassMaximum/analysisProjectedCorrelationFunctionsHaloMassMinimum)*dble(analysisProjectedCorrelationFunctionsHaloMassBinsPerDecade)+0.5d0)
- haloMassIntervalLogarithmicInverse=dble(analysisProjectedCorrelationFunctionsHaloMassBinsCount)/log10(analysisProjectedCorrelationFunctionsHaloMassMaximum/analysisProjectedCorrelationFunctionsHaloMassMinimum)
- ! Validate correlation function descriptors.
- call validateDescriptors(correlationFunctionDescriptors)
- ! Establish mapping functions for correlation function descriptors.
- correlationFunctionDescriptors(1)%mapMass => null()
- ! Determine how many supported mass functions are requested.
- activeAnalysisCount=0
- do i=1,correlationFunctionsSupportedCount
- if (any(trim(mergerTreeAnalyses) == trim(correlationFunctionLabels(i)))) activeAnalysisCount=activeAnalysisCount+1
- end do
- ! Allocate mass function arrays and populate with required data.
- if (activeAnalysisCount <= 0) then
- analysisActive=.false.
- else
- analysisActive=.true.
- cosmologyFunctionsModel => cosmologyFunctions()
- outputTimes_ => outputTimes ()
- ! Establish survey geometries.
- allocate(surveyGeometryHearin2014SDSS :: correlationFunctionDescriptors(1)%geometry)
- select type (g => correlationFunctionDescriptors(1)%geometry)
- type is (surveyGeometryHearin2014SDSS)
- g=surveyGeometryHearin2014SDSS(cosmologyFunctionsModel)
- end select
- ! Initialize correlation functions.
- currentAnalysis=0
- allocate(correlationFunctions(activeAnalysisCount))
- linearGrowth_ => linearGrowth()
- do i=1,size(mergerTreeAnalyses)
- do j=1,correlationFunctionsSupportedCount
- if (mergerTreeAnalyses(i) == trim(correlationFunctionLabels(j))) then
- currentAnalysis=currentAnalysis+1
- ! Set a pointer to the descriptor for this size function.
- correlationFunctions(currentAnalysis)%descriptor => correlationFunctionDescriptors(j)
- ! Read parameters of the systematic error model.
- if (correlationFunctionDescriptors(j)%massSystematicCoefficientCount > 0) then
- allocate(correlationFunctions(currentAnalysis)%massSystematicCoefficients(correlationFunctionDescriptors(j)%massSystematicCoefficientCount))
- do k=1,correlationFunctionDescriptors(j)%massSystematicCoefficientCount
- parameterName=trim(correlationFunctionLabels(j))//'MassSystematic'
- parameterName=parameterName//(k-1)
- !#
- !# char(parameterName)
- !# correlationFunctions(currentAnalysis)%massSystematicCoefficients(k)
- !# globalParameters
- !# (sdssClustering)Z[0-9\.]+MassSystematic[0-9]+
- !# 0.0d0
- !# Correlation function systematic error model parameters.
- !# real
- !# 1
- !#
- end do
- end if
- ! Read parameters of the random error model.
- if (correlationFunctionDescriptors(j)%massRandomCoefficientCount > 0) then
- allocate(correlationFunctions(currentAnalysis)%massRandomCoefficients(correlationFunctionDescriptors(j)%massRandomCoefficientCount))
- do k=1,correlationFunctionDescriptors(j)%massRandomCoefficientCount
- parameterName=trim(correlationFunctionLabels(j))//'MassRandom'
- parameterName=parameterName//(k-1)
- !#
- !# char(parameterName)
- !# correlationFunctions(currentAnalysis)%massRandomCoefficients(k)
- !# (sdssClustering)Z[0-9\.]+MassRandom[0-9]+
- !# 0.0d0
- !# globalParameters
- !# Correlation function mass random parameters.
- !# real
- !# 1
- !#
- end do
- end if
- parameterName=trim(correlationFunctionLabels(j))//'MassRandomMinimum'
- !#
- !# char(parameterName)
- !# correlationFunctions(currentAnalysis)%massRandomMinimum
- !# (sdssClustering)Z[0-9\.]+MassRandomMinimum
- !# 1.0d-3
- !# globalParameters
- !# Correlation function mass random minimum.
- !# real
- !# 1
- !#
- parameterName=trim(correlationFunctionLabels(j))//'MassRandomMaximum'
- !#
- !# char(parameterName)
- !# correlationFunctions(currentAnalysis)%massRandomMaximum
- !# (sdssClustering)Z[0-9\.]+MassRandomMaximum
- !# 1.0d-3
- !# globalParameters
- !# Correlation function mass random maximum.
- !# real
- !# 1
- !#
- ! Read the appropriate observational data definition.
- select case (trim(correlationFunctionLabels(j)))
- case ('sdssClusteringZ0.07')
- ! Read data for the Hearin et al. (2013) projected correlation function.
- !$ call hdf5Access%set()
- call dataFile%openFile(char(galacticusPath(pathTypeDataStatic)//'/observations/correlationFunctions/Projected_Correlation_Functions_Hearin_2013.hdf5'),readOnly=.true.)
- ! Extract parameters.
- parameters =dataFile%openGroup('Parameters')
- call parameters %readAttribute('H_0' ,dataHubbleParameter )
- call parameters %readAttribute('Omega_Matter' ,dataOmegaMatter )
- call parameters %readAttribute('Omega_DE' ,dataOmegaDarkEnergy )
- call parameters %readAttribute('projectedCorrelationFunctionLineOfSightDepth',correlationFunctions(currentAnalysis)%lineOfSightDepth)
- call parameters %close()
- ! Read cosmology scalings.
- dataset=dataFile%openDataset('massMinimum')
- call dataset%readAttribute('cosmologyScaling',cosmologyScalingMass,allowPseudoScalar=.true.)
- call dataset%close()
- dataset=dataFile%openDataset('separation')
- call dataset%readAttribute('cosmologyScaling',cosmologyScalingSize,allowPseudoScalar=.true.)
- call dataset%close()
- ! Extract minimum mass.
- call dataFile%readDataset('massMinimum' ,correlationFunctions(currentAnalysis)%massMinimum )
- correlationFunctions(currentAnalysis)%massMinimumLogarithmic=log10(correlationFunctions(currentAnalysis)%massMinimum)
- ! Extract separations.
- call dataFile%readDataset('separationObserved',correlationFunctions(currentAnalysis)%separation )
- ! Extract integral constraint.
- call dataFile%readDataset('integralConstraint',correlationFunctions(currentAnalysis)%integralConstraint)
- ! Done.
- call dataFile%close()
- !$ call hdf5Access%unset()
- ! Create the observed cosmology.
- allocate(cosmologyParametersObserved)
- cosmologyParametersObserved=cosmologyParametersSimple ( &
- & OmegaMatter =dataOmegaMatter , &
- & OmegaDarkEnergy=dataOmegaDarkEnergy, &
- & HubbleConstant =dataHubbleParameter, &
- & temperatureCMB =0.0d0 , &
- & OmegaBaryon =0.0d0 &
- & )
- cosmologyFunctionsObserved =cosmologyFunctionsMatterLambda( &
- & cosmologyParametersObserved &
- & )
- ! Allocate wavenumbers.
- massCount=size(correlationFunctions(currentAnalysis)%massMinimum)
- call allocateArray(correlationFunctions(currentAnalysis)%wavenumber ,[wavenumberCount ])
- call allocateArray(correlationFunctions(currentAnalysis)%meanDensity ,[ massCount ])
- call allocateArray(correlationFunctions(currentAnalysis)%meanDensityMainBranch,[ massCount,analysisProjectedCorrelationFunctionsHaloMassBinsCount])
- call allocateArray(correlationFunctions(currentAnalysis)%countMainBranch ,[ analysisProjectedCorrelationFunctionsHaloMassBinsCount])
- call allocateArray(correlationFunctions(currentAnalysis)%oneHaloTermMainBranch,[wavenumberCount,massCount,analysisProjectedCorrelationFunctionsHaloMassBinsCount])
- call allocateArray(correlationFunctions(currentAnalysis)%twoHaloTermMainBranch,[wavenumberCount,massCount,analysisProjectedCorrelationFunctionsHaloMassBinsCount])
- call allocateArray(correlationFunctions(currentAnalysis)%oneHaloTerm ,[wavenumberCount,massCount ])
- call allocateArray(correlationFunctions(currentAnalysis)%twoHaloTerm ,[wavenumberCount,massCount ])
- call allocateArray(correlationFunctions(currentAnalysis)%termCovariance ,[massCount*(2*wavenumberCount+1),massCount*(2*wavenumberCount+1) ])
- correlationFunctions(currentAnalysis)%wavenumber=Make_Range(wavenumberMinimum,wavenumberMaximum,wavenumberCount,rangeTypeLogarithmic)
- case default
- massCount=0
- call Galacticus_Error_Report('unknown size function'//{introspection:location})
- end select
- ! Get cosmological conversion factors.
- call allocateArray(correlationFunctions(currentAnalysis)%cosmologyConversionMass,[outputTimes_%count()])
- call allocateArray(correlationFunctions(currentAnalysis)%cosmologyConversionSize,[outputTimes_%count()])
- do jOutput=1,outputTimes_%count()
- redshift= &
- & cosmologyFunctionsModel %redshiftFromExpansionFactor( &
- & cosmologyFunctionsModel%expansionFactor ( &
- & outputTimes_%time(jOutput) &
- & ) &
- & )
- call Cosmology_Conversion_Factors( &
- & redshift , &
- & cosmologyFunctionsModel , &
- & cosmologyFunctionsObserved , &
- & cosmologyScalingMass =cosmologyScalingMass , &
- & cosmologyScalingSize =cosmologyScalingSize , &
- & cosmologyConversionMass =correlationFunctions(currentAnalysis)%cosmologyConversionMass(jOutput), &
- & cosmologyConversionSize =correlationFunctions(currentAnalysis)%cosmologyConversionSize(jOutput) &
- & )
- end do
- nullify(cosmologyParametersObserved)
- ! Compute output weights for correlation function. We assume a volume limited survey at the minimum mass.
- call allocateArray(correlationFunctions(currentAnalysis)%linearGrowthFactor,[ massCount ])
- call allocateArray(correlationFunctions(currentAnalysis)%outputWeight ,[int(massCount,kind=c_size_t),outputTimes_%count()])
- correlationFunctions(currentAnalysis)%outputWeight =0.0d0
- correlationFunctions(currentAnalysis)%linearGrowthFactor=0.0d0
- do k=1,massCount
- do jOutput=1,outputTimes_%count()
- do m=1,correlationFunctions(currentAnalysis)%descriptor%geometry%fieldCount()
- if (jOutput == outputTimes_%count()) then
- timeMaximum= outputTimes_%time(jOutput)
- else
- timeMaximum=sqrt(outputTimes_%time(jOutput)*outputTimes_%time(jOutput+1))
- end if
- if (jOutput == 1) then
- timeMinimum= outputTimes_%time(jOutput)
- else
- timeMinimum=sqrt(outputTimes_%time(jOutput)*outputTimes_%time(jOutput-1))
- end if
- distanceMinimum=max( &
- & cosmologyFunctionsModel%distanceComoving(timeMaximum) , &
- & correlationFunctions(currentAnalysis)%descriptor%geometry%distanceMinimum(correlationFunctions(currentAnalysis)%massMinimum(k),field=m) &
- & )
- distanceMaximum=min( &
- & cosmologyFunctionsModel%distanceComoving(timeMinimum) , &
- & correlationFunctions(currentAnalysis)%descriptor%geometry%distanceMaximum(correlationFunctions(currentAnalysis)%massMinimum(k),field=m) &
- & )
- weight=+correlationFunctions(currentAnalysis)%descriptor%geometry%solidAngle(m) &
- & /3.0d0 &
- & * &
- & max( &
- & +0.0d0 , &
- & +distanceMaximum**3 &
- & -distanceMinimum**3 &
- & )
- correlationFunctions (currentAnalysis)%outputWeight(k,jOutput) &
- & =correlationFunctions(currentAnalysis)%outputWeight(k,jOutput) &
- & +weight
- correlationFunctions (currentAnalysis)%linearGrowthFactor(k)= &
- & +correlationFunctions(currentAnalysis)%linearGrowthFactor(k) &
- & +weight &
- & *linearGrowth_%value(outputTimes_%time(jOutput))**2
- end do
- end do
- where(correlationFunctions(currentAnalysis)%outputWeight(k,:) < 0.0d0)
- correlationFunctions(currentAnalysis)%outputWeight(k,:)=0.0d0
- end where
- if (any(correlationFunctions(currentAnalysis)%outputWeight(k,:) > 0.0d0)) then
- correlationFunctions (currentAnalysis)%linearGrowthFactor(k ) &
- & =sqrt( &
- & + correlationFunctions(currentAnalysis)%linearGrowthFactor(k ) &
- & /sum(correlationFunctions(currentAnalysis)%outputWeight (k,:)) &
- & )
- correlationFunctions (currentAnalysis)%outputWeight (k,:) &
- & = + correlationFunctions(currentAnalysis)%outputWeight (k,:) &
- & /sum(correlationFunctions(currentAnalysis)%outputWeight (k,:))
- else
- message="correlation function '"//trim(correlationFunctions(currentAnalysis)%descriptor%label)//"' mass bin "
- message=message//k//" has zero weights"
- call Galacticus_Error_Report(message//{introspection:location})
- end if
- end do
- ! Initialize population statistics.
- correlationFunctions(currentAnalysis)%countMainBranch =0
- correlationFunctions(currentAnalysis)%meanDensity =0.0d0
- correlationFunctions(currentAnalysis)%meanDensityMainBranch=0.0d0
- correlationFunctions(currentAnalysis)%oneHaloTermMainBranch=0.0d0
- correlationFunctions(currentAnalysis)%twoHaloTermMainBranch=0.0d0
- correlationFunctions(currentAnalysis)%oneHaloTerm =0.0d0
- correlationFunctions(currentAnalysis)%twoHaloTerm =0.0d0
- correlationFunctions(currentAnalysis)%termCovariance =0.0d0
- exit
- end if
- end do
- end do
- end if
- ! Record that module is initialized.
- moduleInitialized=.true.
- end if
- !$omp end critical(Galacticus_Output_Analysis_Correlation_Functions_Initialize)
- end if
- ! Return if this analysis is not active.
- if (.not.analysisActive) return
- ! Accumulate halo and return on tree finalization.
- if (nodeStatus == nodeStatusFinal) then
- if (allocated(haloWork)) then
- do i=1,size(correlationFunctions)
- if (haloWork(i)%initialized) call Accumulate_Halo(correlationFunctions(i),haloWork(i))
- end do
- end if
- return
- end if
- ! Allocate work arrays.
- if (.not.allocated(haloWork)) then
- allocate(haloWork(size(correlationFunctions)))
- haloWork%initialized=.false.
- end if
- ! Iterate over active analyses.
- do i=1,size(correlationFunctions)
- ! Return if this correlation function receives no contribution from this output number.
- if (all(correlationFunctions(i)%outputWeight(:,iOutput) <= 0.0d0)) cycle
- ! Get the galactic mass.
- mass= &
- & Galactic_Structure_Enclosed_Mass(node,radiusLarge,componentType=componentTypeDisk ,massType=correlationFunctions(i)%descriptor%massType) &
- & +Galactic_Structure_Enclosed_Mass(node,radiusLarge,componentType=componentTypeSpheroid,massType=correlationFunctions(i)%descriptor%massType)
- if (mass <= 0.0d0) cycle
- if (associated(correlationFunctions(i)%descriptor%mapMass)) mass=correlationFunctions(i)%descriptor%mapMass(mass,node)
- mass=mass*correlationFunctions(i)%cosmologyConversionMass(iOutput) ! Convert for cosmology.
- massLogarithmic=log10(mass)
- do j=1,correlationFunctions(i)%descriptor%massSystematicCoefficientCount
- massLogarithmic=+massLogarithmic &
- & +correlationFunctions(i)%massSystematicCoefficients(j) &
- & *( &
- & +log10(mass) &
- & -correlationFunctions(i)%descriptor%massSystematicLogM0 &
- & )**(j-1)
- end do
- if (massLogarithmic < correlationFunctions(i)%descriptor%massLogarithmicMinimum) cycle
- ! Accumulate the node.
- call Accumulate_Node(correlationFunctions(i),haloWork(i),tree,node,mass,massLogarithmic,iOutput)
- ! Accumulate halo if this is the last node in the tree.
- if (nodeStatus == nodeStatusLast) call Accumulate_Halo(correlationFunctions(i),haloWork(i))
- end do
- return
- end subroutine Galacticus_Output_Analysis_Correlation_Functions
-
- subroutine Accumulate_Node(correlationFunction_,haloWork,tree,node,mass,massLogarithmic,iOutput)
- !% Accumulate a single galaxy to the population of the current halo. Since galaxy masses
- !% have random errors, each galaxy added is assigned an inclusion probability, which will be
- !% taken into account when evaluating the one- and two-halo terms from this halo in the halo
- !% model.
- use, intrinsic :: ISO_C_Binding
- use :: Galacticus_Nodes, only : mergerTree, nodeComponentBasic
- use Dark_Matter_Halo_Biases
- use Cosmology_Functions
- use Dark_Matter_Profiles_DMO
- use Memory_Management
- use Galacticus_Output_Merger_Tree_Data
- implicit none
- type (correlationFunction ), intent(inout) :: correlationFunction_
- type (correlationFunctionWork), intent(inout) :: haloWork
- type (mergerTree ), intent(in ) :: tree
- type (treeNode ), intent(inout), pointer :: node
- double precision , intent(in ) :: mass , massLogarithmic
- integer (c_size_t ), intent(in ) :: iOutput
- type (treeNode ) , pointer :: hostNode
- class (cosmologyFunctionsClass) , pointer :: cosmologyFunctions_
- class (nodeComponentBasic ) , pointer :: basic , basicRoot
- class (darkMatterProfileDMOClass ) , pointer :: darkMatterProfileDMO_
- class (darkMatterHaloBiasClass) , pointer :: darkMatterHaloBias_
- double precision , allocatable , dimension(:,:) :: satelliteProbabilityTmp
- integer , parameter :: satelliteCountMinimum=100
- integer (kind=kind_int8 ) :: hostIndex
- integer :: i, j
- double precision :: expansionFactor , galaxyInclusionProbability, &
- & randomError
- logical :: satelliteIncluded
-
- ! Get the index of the host halo.
- if (node%isSatellite()) then
- hostNode => node%parent
- else
- hostNode => node
- end if
- hostIndex=hostNode%uniqueID()
- ! Allocate arrays.
- if (.not.haloWork%initialized) then
- call allocateArray(haloWork%centralProbability,[size(correlationFunction_%massMinimumLogarithmic)])
- call allocateArray(haloWork%fourierProfile ,[size(correlationFunction_%wavenumber )])
- allocate (haloWork%satelliteProbability(0,0))
- deallocate(haloWork%satelliteProbability )
- haloWork%propertiesSet =.false.
- haloWork%satelliteCount =0
- haloWork%centralProbability=0.0d0
- haloWork%isMainBranch =.false.
- haloWork%initialized =.true.
- haloWork%treeIndex =-1_kind_int8
- haloWork%haloIndex =-1_kind_int8
- end if
- ! Check if the host has changed.
- if ( &
- & tree %index /= haloWork%treeIndex &
- & .or. &
- & hostIndex /= haloWork%haloIndex &
- & ) &
- & call Accumulate_Halo(correlationFunction_,haloWork)
- ! Accumulate properties to the current halo.
- haloWork%treeIndex=tree%index
- haloWork%haloIndex=hostIndex
- ! Find the random error on the galaxy mass.
- if (associated(correlationFunction_%descriptor%massRandomErrorFunction)) then
- randomError=correlationFunction_%descriptor%massRandomErrorFunction(mass,node)
- else
- randomError=0.0d0
- do j=1,correlationFunction_%descriptor%massRandomCoefficientCount
- randomError=+randomError &
- & +correlationFunction_%massRandomCoefficients(j) &
- & *( &
- & +log10(mass) &
- & -correlationFunction_%descriptor%massSystematicLogM0 &
- & )**(j-1)
- end do
- randomError=max(min(randomError,correlationFunction_%massRandomMaximum),correlationFunction_%massRandomMinimum)
- end if
- ! Iterate over mass ranges.
- satelliteIncluded=.false.
- do j=1,size(correlationFunction_%massMinimumLogarithmic)
- ! Find the probability that this galaxy is included in the sample.
- galaxyInclusionProbability=0.5d0*(1.0d0-erf((correlationFunction_%massMinimumLogarithmic(j)-massLogarithmic)/randomError/sqrt(2.0d0)))
- if (node%isSatellite()) then
- if (galaxyInclusionProbability > 0.0d0) then
- if (.not.satelliteIncluded) then
- satelliteIncluded=.true.
- haloWork%satelliteCount=haloWork%satelliteCount+1
- if (.not.allocated(haloWork%satelliteProbability)) then
- call allocateArray(haloWork%satelliteProbability,[satelliteCountMinimum,size(correlationFunction_%massMinimumLogarithmic)])
- else if (size(haloWork%satelliteProbability,dim=1) < haloWork%satelliteCount) then
- call Move_Alloc(haloWork%satelliteProbability,satelliteProbabilityTmp)
- call allocateArray(haloWork%satelliteProbability,[2*size(satelliteProbabilityTmp,dim=1),size(correlationFunction_%massMinimumLogarithmic)])
- haloWork%satelliteProbability(1:size(satelliteProbabilityTmp,dim=1),:)=satelliteProbabilityTmp
- call deallocateArray(satelliteProbabilityTmp)
- end if
- haloWork%satelliteProbability(haloWork%satelliteCount,:)=0.0d0
- end if
- haloWork%satelliteProbability(haloWork%satelliteCount,j)=galaxyInclusionProbability
- end if
- else
- haloWork%centralProbability(j)= galaxyInclusionProbability
- end if
- if (galaxyInclusionProbability > 0.0d0 .and. .not.haloWork%propertiesSet) then
- cosmologyFunctions_ => cosmologyFunctions ( )
- darkMatterProfileDMO_ => darkMatterProfileDMO ( )
- darkMatterHaloBias_ => darkMatterHaloBias ( )
- haloWork%propertiesSet = .true.
- haloWork%isMainBranch = hostNode %isOnMainBranch( )
- basic => hostNode %basic( )
- basicRoot => tree %baseNode%basic( )
- haloWork%haloMass = basicRoot%mass ( )
- haloWork%hostMass = basic%mass ( )
- haloWork%haloWeight = tree %volumeWeight
- haloWork%outputNumber = iOutput
- haloWork%haloTime = basic%time ( )
- haloWork%haloBias = darkMatterHaloBias_%bias(hostNode)
- expansionFactor = cosmologyFunctions_%expansionFactor(basic%time())
- do i=1,size(correlationFunction_%wavenumber)
- ! Note that wavenumbers must be converted from comoving to physical units for the dark matter profile k-space function.
- haloWork%fourierProfile(i)=darkMatterProfileDMO_%kSpace( &
- & hostNode , &
- & correlationFunction_%waveNumber (i ) &
- & *correlationFunction_%cosmologyConversionSize(iOutput) &
- & /expansionFactor &
- & )
- end do
- end if
- end do
- return
- end subroutine Accumulate_Node
-
- subroutine Accumulate_Halo(correlationFunction_,haloWork)
- !% Assumulate a single halo's contributions to the halo model one- and two-halo terms. For
- !% the one-halo term we count contributions from central-satellite pairs, and from
- !% satellite-satellite pairs. Contributions differ in the scalings applied to the
- !% Fourier-transformed dark matter halo density profile---see
- !% \cite[][\S6.1]{cooray_halo_2002} for a discussion of this. The number of satellites in
- !% the halo is assumed to follow a Poisson binomial distribution.
- use Math_Distributions_Poisson_Binomial
- use Vectors
- use Halo_Model_Power_Spectrum_Modifiers
- use Linear_Algebra
- implicit none
- type (correlationFunction ), intent(inout) :: correlationFunction_
- type (correlationFunctionWork ), intent(inout) :: haloWork
- double precision , dimension( &
- & size(correlationFunction_%wavenumber ), &
- & size(correlationFunction_%massMinimumLogarithmic) &
- & ) :: oneHaloTerm , twoHaloTerm
- double precision , dimension(size(correlationFunction_%massMinimumLogarithmic)) :: galaxyDensity
- logical , dimension(size(correlationFunction_%massMinimumLogarithmic)) :: oneHaloTermActive , twoHaloTermActive
- double precision , allocatable , dimension(:,: ) :: termJacobian , termCovariance , &
- & mainBranchTermCovariance , modifierCovariance
- double precision , allocatable , dimension(: ) :: satelliteJacobian , modifierCovarianceDiagonal
- class (haloModelPowerSpectrumModifierClass), pointer :: haloModelPowerSpectrumModifier_
- double precision :: satellitePairsCountMean , satelliteCountMean , &
- & haloWeightOutput
- integer :: wavenumberCount , haloMassBin , &
- & i , j , &
- & indexOneHalo , indexTwoHalo , &
- & indexDensity , massCount
- logical :: mainBranchCounted
- type (matrix ) :: jacobianMatrix
-
- ! Return immediately if no nodes have been accumulated.
- if (haloWork%treeIndex /= -1_kind_int8) then
- oneHaloTermActive=.false.
- twoHaloTermActive=.false.
- mainBranchCounted=.false.
- massCount =size(correlationFunction_%massMinimumLogarithmic)
- wavenumberCount =size(correlationFunction_%wavenumber )
- allocate(termJacobian (massCount*(2*wavenumberCount+1),haloWork%satelliteCount+1))
- allocate(satelliteJacobian ( haloWork%satelliteCount ))
- allocate(modifierCovariance ( wavenumberCount ,wavenumberCount ))
- allocate(modifierCovarianceDiagonal(massCount*(2*wavenumberCount+1) ))
- haloModelPowerSpectrumModifier_ => haloModelPowerSpectrumModifier()
- termJacobian =0.0d0
- modifierCovariance =0.0d0
- modifierCovarianceDiagonal=0.0d0
- ! Iterate over masses.
- do i=1,massCount
- ! Find mean number of satellites and satellite pairs.
- if (haloWork%satelliteCount > 0) then
- satelliteCountMean =Poisson_Binomial_Distribution_Mean (haloWork%satelliteProbability(1:haloWork%satelliteCount,i))
- satellitePairsCountMean=Poisson_Binomial_Distribution_Mean_Pairs(haloWork%satelliteProbability(1:haloWork%satelliteCount,i))
- else
- satelliteCountMean =0.0d0
- satellitePairsCountMean=0.0d0
- end if
- ! Skip if this halo contains no galaxies.
- if (haloWork%centralProbability(i) > 0.0d0 .or. satelliteCountMean > 0.0d0) then
- ! Compute output halo weight.
- haloWeightOutput=haloWork%haloWeight*correlationFunction_%outputWeight(i,haloWork%outputNumber)
- ! Compute contribution to galaxy density.
- galaxyDensity(i)= haloWeightOutput &
- & *( &
- & +haloWork%centralProbability(i) &
- & +satelliteCountMean &
- & )
- ! For main branch galaxies, accumulate their contribution to the density as a function of halo mass, so that we can later subtract this from the variance.
- if (haloWork%isMainBranch) then
- haloMassBin=floor((log10(haloWork%haloMass)-analysisProjectedCorrelationFunctionsHaloMassMinimumLogarithmic)*haloMassIntervalLogarithmicInverse)+1
- ! Accumulate weights to halo mass arrays.
- if (haloMassBin >= 1 .and. haloMassBin <= analysisProjectedCorrelationFunctionsHaloMassBinsCount) then
- !$omp critical (Analyses_Correlation_Functions_Main_Branch)
- correlationFunction_ %meanDensityMainBranch( i,haloMassBin)= &
- & +correlationFunction_%meanDensityMainBranch( i,haloMassBin) &
- & +haloWeightOutput &
- & *haloWork %centralProbability ( i )
- correlationFunction_ %oneHaloTermMainBranch(:,i,haloMassBin)= &
- & +correlationFunction_%oneHaloTermMainBranch(:,i,haloMassBin) &
- & +haloWeightOutput &
- & *haloWork %centralProbability ( i ) &
- & *satelliteCountMean &
- & *haloWork%fourierProfile
- correlationFunction_ %twoHaloTermMainBranch(:,i,haloMassBin)= &
- & +correlationFunction_%twoHaloTermMainBranch(:,i,haloMassBin) &
- & +haloWeightOutput &
- & *haloWork %centralProbability ( i ) &
- & *haloWork%haloBias &
- & *haloWork%fourierProfile
- !$omp end critical (Analyses_Correlation_Functions_Main_Branch)
- ! If this is the first mass bin in which the central, main branch galaxy is seen, increment the number of main branch galaxies.
- if (.not.mainBranchCounted) then
- mainBranchCounted=.true.
- !$omp atomic
- correlationFunction_%countMainBranch(haloMassBin)=correlationFunction_%countMainBranch(haloMassBin)+1
- end if
- end if
- end if
- ! Accumulate contribution to galaxy density.
- !$omp atomic
- correlationFunction_%meanDensity(i)= correlationFunction_%meanDensity(i) &
- & +galaxyDensity (i)
- ! Compute and accumulate one-halo term.
- if (satelliteCountMean > 0.0d0) then
- oneHaloTermActive( i)=.true.
- oneHaloTerm (:,i)= haloWeightOutput &
- & *( &
- & +haloWork%centralProbability(i) &
- & *satelliteCountMean &
- & *haloWork%fourierProfile &
- & +satellitePairsCountMean &
- & *haloWork%fourierProfile **2 &
- & )
- call haloModelPowerSpectrumModifier_%modify( &
- & correlationFunction_%wavenumber &
- & *correlationFunction_%cosmologyConversionSize(haloWork%outputNumber), &
- & haloModelTermOneHalo , &
- & oneHaloTerm(:,i) , &
- & modifierCovariance , &
- & mass=haloWork%hostMass &
- & )
- call Term_Indices(i,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
- forall(j=1:wavenumberCount)
- modifierCovarianceDiagonal(indexOneHalo+j-1)=modifierCovariance(j,j)
- end forall
- modifierCovarianceDiagonal(indexDensity)=0.0d0
- !$omp critical(Analyses_Correlation_Functions_Accumulate1)
- correlationFunction_%oneHaloTerm(:,i)= correlationFunction_%oneHaloTerm(:,i) &
- & +oneHaloTerm (:,i)
- !$omp end critical(Analyses_Correlation_Functions_Accumulate1)
- end if
- ! Compute and accumulate two-halo term.
- twoHaloTermActive( i)=.true.
- twoHaloTerm (:,i)= galaxyDensity(i) &
- & *haloWork%haloBias &
- & *haloWork%fourierProfile
- call haloModelPowerSpectrumModifier_%modify( &
- & correlationFunction_%wavenumber &
- & *correlationFunction_%cosmologyConversionSize(haloWork%outputNumber), &
- & haloModelTermTwoHalo , &
- & twoHaloTerm(:,i) , &
- & modifierCovariance , &
- & mass=haloWork%hostMass &
- & )
- call Term_Indices(i,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
- forall(j=1:wavenumberCount)
- modifierCovarianceDiagonal(indexTwoHalo+j-1)=modifierCovariance(j,j)
- end forall
- modifierCovarianceDiagonal(indexDensity)=0.0d0
- !$omp critical(Analyses_Correlation_Functions_Accumulate2)
- correlationFunction_%twoHaloTerm(:,i)= correlationFunction_%twoHaloTerm(:,i) &
- & +twoHaloTerm (:,i)
- !$omp end critical(Analyses_Correlation_Functions_Accumulate2)
- ! Construct Jacobian of the terms being accumulated. The Jacobian here is an MxN matrix, where M=massCount*(2*wavenumberCount+1)
- ! (the number of terms in halo model quantities being accumulated {wavenumberCount for 1- and 2-halo terms, plus a density, for
- ! each mass bin}), and N is the total number of galaxies in the halo (number of satellites plus 1 central).
- ! Compute indices.
- call Term_Indices(i,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
- ! One halo terms.
- if (haloWork%satelliteCount > 0) then
- satelliteJacobian=Poisson_Binomial_Distribution_Mean_Pairs_Jacobian(haloWork%satelliteProbability(1:haloWork%satelliteCount,i))*haloWork%satelliteProbability(1:haloWork%satelliteCount,i)
- do j=1,wavenumberCount
- termJacobian(indexOneHalo +j -1,1:haloWork%satelliteCount )=haloWeightOutput *haloWork%fourierProfile(j)**2*satelliteJacobian
- end do
- end if
- termJacobian (indexOneHalo:indexOneHalo+wavenumberCount-1, haloWork%satelliteCount+1)=haloWeightOutput *haloWork%fourierProfile *haloWork%centralProbability( i)*satelliteCountMean
- ! Two halo terms.
- do j=1,wavenumberCount
- termJacobian (indexTwoHalo +j -1,1:haloWork%satelliteCount )=haloWeightOutput*haloWork%haloBias*haloWork%fourierProfile(j) *haloWork%satelliteProbability(1:haloWork%satelliteCount,i)
- end do
- termJacobian (indexTwoHalo:indexTwoHalo+wavenumberCount-1, haloWork%satelliteCount+1)=haloWeightOutput*haloWork%haloBias*haloWork%fourierProfile *haloWork% centralProbability( i)
- ! Compute density terms.
- termJacobian (indexDensity ,1:haloWork%satelliteCount )=haloWeightOutput *haloWork%satelliteProbability(1:haloWork%satelliteCount,i)
- termJacobian (indexDensity , haloWork%satelliteCount+1)=haloWeightOutput *haloWork% centralProbability( i)
- end if
- end do
- ! Construct and accumulate term covariance.
- allocate(termCovariance(massCount*(2*wavenumberCount+1),massCount*(2*wavenumberCount+1)))
- jacobianMatrix=termJacobian
- termCovariance=jacobianMatrix*jacobianMatrix%transpose()
- ! Add modifier covariance.
- termCovariance=termCovariance+Vector_Outer_Product(modifierCovarianceDiagonal)
- ! For main branch galaxies, zero all off-diagonal contributions.
- if (haloWork%isMainBranch) then
- termJacobian(:,1:haloWork%satelliteCount)=0.0d0
- jacobianMatrix=termJacobian
- allocate(mainBranchTermCovariance(massCount*(2*wavenumberCount+1),massCount*(2*wavenumberCount+1)))
- mainBranchTermCovariance=jacobianMatrix*jacobianMatrix%transpose()
- do i=1,massCount
- mainBranchTermCovariance( &
- & (i-1)*(2*wavenumberCount+1)+1:i*(2*wavenumberCount+1), &
- & (i-1)*(2*wavenumberCount+1)+1:i*(2*wavenumberCount+1) &
- & ) &
- & =0.0d0
- end do
- termCovariance=termCovariance-mainBranchTermCovariance
- deallocate(mainBranchTermCovariance)
- end if
- !$omp critical(Analyses_Correlation_Functions_Accumulate3)
- correlationFunction_%termCovariance=correlationFunction_%termCovariance+termCovariance
- !$omp end critical(Analyses_Correlation_Functions_Accumulate3)
- deallocate(termJacobian )
- deallocate(satelliteJacobian)
- end if
- ! Reset counts.
- if (allocated(haloWork%centralProbability)) haloWork%centralProbability=0.0d0
- haloWork%satelliteCount=0
- haloWork%propertiesSet =.false.
- ! Reset indices.
- haloWork%treeIndex=-1_kind_int8
- haloWork%haloIndex=-1_kind_int8
- return
- end subroutine Accumulate_Halo
-
- !#
- !# Galacticus_Output_Analysis_Correlation_Functions_Output
- !#
- subroutine Galacticus_Output_Analysis_Correlation_Functions_Output
- !% Outputs correlation functions to file.
- use, intrinsic :: ISO_C_Binding
- use Galacticus_HDF5
- use Power_Spectra
- use Array_Utilities
- use FFTLogs
- use Memory_Management
- use Tables
- use Table_Labels
- use Linear_Algebra
- use Vectors
- implicit none
- double precision , allocatable, dimension(: ) :: separation
- double precision , allocatable, dimension(:,:) :: powerSpectrumCovariance , jacobian , &
- & correlationCovariance , covarianceTmp , &
- & projectedCorrelationCovariance, binnedProjectedCorrelationCovariance, &
- & powerSpectrumValue , correlation , &
- & projectedCorrelation , binnedProjectedCorrelation , &
- & oneTwoHaloCovariance
- class (powerSpectrumClass ), pointer :: powerSpectrum_
- integer :: i , k , &
- & j , wavenumberCount, m, n, massCount, indexDensity, indexOneHalo, indexTwoHalo
- type (hdf5Object ) :: analysisGroup , correlationFunctionGroup , &
- & dataset
- type (table1DLogarithmicLinear ) :: correlationTable
- double precision :: projectedSeparation , binSeparationMinimum , &
- & binSeparationMaximum , binWidthLogarithmic
- type (matrix ) :: jacobianMatrix , covarianceMatrix
- procedure (integrandTemplate ), pointer :: integrandWeightFunction
-
- ! Return immediately if this analysis is not active.
- if (.not.analysisActive) return
- ! Get required objects.
- powerSpectrum_ => powerSpectrum()
- ! Iterate over mass functions.
- do k=1,size(correlationFunctions)
- ! Copy upper to lower triangle of covariance matrix (we've accumulated only the upper triangle).
- correlationFunctions(k)%termCovariance=Matrix_Copy_Upper_To_Lower_Triangle(correlationFunctions(k)%termCovariance)
- ! Get count of mass bins and wavenumbers.
- massCount =size(correlationFunctions(k)%massMinimumLogarithmic)
- wavenumberCount=size(correlationFunctions(k)%wavenumber )
- ! Find average density contribution of main branch galaxies in each halo mass bin.
- do n=1,massCount
- where (correlationFunctions(k)%countMainBranch(:) > 0)
- correlationFunctions (k)%meanDensityMainBranch(n,:) &
- & = correlationFunctions(k)%meanDensityMainBranch(n,:) &
- & /dble(correlationFunctions(k)%countMainBranch ( :))
- end where
- do i=1,wavenumberCount
- where (correlationFunctions(k)%countMainBranch(:) > 0)
- correlationFunctions (k)%oneHaloTermMainBranch(i,n,:) &
- & = correlationFunctions(k)%oneHaloTermMainBranch(i,n,:) &
- & /dble(correlationFunctions(k)%countMainBranch ( :))
- correlationFunctions (k)%twoHaloTermMainBranch(i,n,:) &
- & = correlationFunctions(k)%twoHaloTermMainBranch(i,n,:) &
- & /dble(correlationFunctions(k)%countMainBranch ( :))
- end where
- end do
- end do
- ! Subtract out Poisson component of main branch galaxy variance (since these galaxies are not Poisson distributed).
- do m=1,massCount
- call Term_Indices(m,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
- do i=1,analysisProjectedCorrelationFunctionsHaloMassBinsCount
- ! Density-density.
- correlationFunctions (k)%termCovariance ( indexDensity ,indexDensity )= &
- & + correlationFunctions(k)%termCovariance ( indexDensity ,indexDensity ) &
- & - correlationFunctions(k)%meanDensityMainBranch( m ,i ) **2 &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- ! One-halo-one-halo.
- correlationFunctions (k)%termCovariance ( indexOneHalo:indexOneHalo+wavenumberCount-1,indexOneHalo:indexOneHalo+wavenumberCount-1)= &
- & + correlationFunctions(k)%termCovariance ( indexOneHalo:indexOneHalo+wavenumberCount-1,indexOneHalo:indexOneHalo+wavenumberCount-1) &
- & - Vector_Outer_Product( &
- & correlationFunctions(k)%oneHaloTermMainBranch(:,m ,i ), &
- & correlationFunctions(k)%oneHaloTermMainBranch(:,m ,i ) &
- & ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- ! Two-halo-two-halo.
- correlationFunctions (k)%termCovariance ( indexTwoHalo:indexTwoHalo+wavenumberCount-1,indexTwoHalo:indexTwoHalo+wavenumberCount-1)= &
- & + correlationFunctions(k)%termCovariance ( indexTwoHalo:indexTwoHalo+wavenumberCount-1,indexTwoHalo:indexTwoHalo+wavenumberCount-1) &
- & - Vector_Outer_Product( &
- & correlationFunctions(k)%twoHaloTermMainBranch(:,m ,i ), &
- & correlationFunctions(k)%twoHaloTermMainBranch(:,m ,i ) &
- & ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- ! Density-one-halo.
- correlationFunctions (k)%termCovariance ( indexDensity ,indexOneHalo:indexOneHalo+wavenumberCount-1)= &
- & + correlationFunctions(k)%termCovariance ( indexDensity ,indexOneHalo:indexOneHalo+wavenumberCount-1) &
- & - correlationFunctions(k)%meanDensityMainBranch( m ,i ) &
- & * correlationFunctions(k)%oneHaloTermMainBranch(:,m ,i ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- correlationFunctions (k)%termCovariance ( indexOneHalo:indexOneHalo+wavenumberCount-1,indexDensity )= &
- & + correlationFunctions(k)%termCovariance ( indexOneHalo:indexOneHalo+wavenumberCount-1,indexDensity ) &
- & - correlationFunctions(k)%oneHaloTermMainBranch(:,m ,i ) &
- & * correlationFunctions(k)%meanDensityMainBranch( m ,i ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- ! Density-two-halo.
- correlationFunctions (k)%termCovariance ( indexDensity ,indexTwoHalo:indexTwoHalo+wavenumberCount-1)= &
- & + correlationFunctions(k)%termCovariance ( indexDensity ,indexTwoHalo:indexTwoHalo+wavenumberCount-1) &
- & - correlationFunctions(k)%meanDensityMainBranch( m ,i ) &
- & * correlationFunctions(k)%twoHaloTermMainBranch(:,m ,i ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- correlationFunctions (k)%termCovariance ( indexTwoHalo:indexTwoHalo+wavenumberCount-1,indexDensity )= &
- & + correlationFunctions(k)%termCovariance ( indexTwoHalo:indexTwoHalo+wavenumberCount-1,indexDensity ) &
- & - correlationFunctions(k)%twoHaloTermMainBranch(:,m ,i ) &
- & * correlationFunctions(k)%meanDensityMainBranch( m ,i ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- ! One-halo-two-halo
- correlationFunctions (k)%termCovariance ( indexOneHalo:indexOneHalo+wavenumberCount-1,indexTwoHalo:indexTwoHalo+wavenumberCount-1)= &
- & + correlationFunctions(k)%termCovariance ( indexOneHalo:indexOneHalo+wavenumberCount-1,indexTwoHalo:indexTwoHalo+wavenumberCount-1) &
- & - Vector_Outer_Product( &
- & correlationFunctions(k)%oneHaloTermMainBranch(:,m ,i ), &
- & correlationFunctions(k)%twoHaloTermMainBranch(:,m ,i ) &
- & ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- correlationFunctions (k)%termCovariance ( indexTwoHalo:indexTwoHalo+wavenumberCount-1,indexOneHalo:indexOneHalo+wavenumberCount-1)= &
- & + correlationFunctions(k)%termCovariance ( indexTwoHalo:indexTwoHalo+wavenumberCount-1,indexOneHalo:indexOneHalo+wavenumberCount-1) &
- & - Vector_Outer_Product( &
- & correlationFunctions(k)%twoHaloTermMainBranch(:,m ,i ), &
- & correlationFunctions(k)%oneHaloTermMainBranch(:,m ,i ) &
- & ) &
- & * dble(correlationFunctions(k)%countMainBranch ( i ))
- end do
- end do
- ! Normalize one- and two-halo terms.
- call allocateArray(jacobian ,[massCount*(2*wavenumberCount),massCount*(2*wavenumberCount+1)])
- call allocateArray(oneTwoHaloCovariance,[massCount*(2*wavenumberCount),massCount*(2*wavenumberCount )])
- ! One-halo term.
- jacobian=0.0d0
- do n=1,massCount
- call Term_Indices(n,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
- if (correlationFunctions(k)%meanDensity(n) > 0.0d0) then
- do i=1,wavenumberCount
- jacobian((n-1)*(2*wavenumberCount)+i,indexOneHalo+i-1)=1.0d0/correlationFunctions(k)%meanDensity(n)**2
- end do
- jacobian((n-1)*(2*wavenumberCount)+1:(n-1)*(2*wavenumberCount)+wavenumberCount,indexDensity)=-2.0d0*correlationFunctions(k)%oneHaloTerm(:,n)/correlationFunctions(k)%meanDensity(n)**3
- end if
- end do
- ! Two-halo term.
- do n=1,massCount
- call Term_Indices(n,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
- if (correlationFunctions(k)%meanDensity(n) > 0.0d0) then
- do i=1,wavenumberCount
- jacobian((n-1)*(2*wavenumberCount)+wavenumberCount+i,indexTwoHalo+i-1)=1.0d0/correlationFunctions(k)%meanDensity(n)
- end do
- jacobian((n-1)*(2*wavenumberCount)+wavenumberCount+1:(n-1)*(2*wavenumberCount)+2*wavenumberCount,indexDensity)=-correlationFunctions(k)%twoHaloTerm(:,n)/correlationFunctions(k)%meanDensity(n)**2
- end if
- end do
- jacobianMatrix =jacobian
- covarianceMatrix =correlationFunctions(k)%termCovariance
- oneTwoHaloCovariance =jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
- do n=1,massCount
- if (correlationFunctions(k)%meanDensity(n) > 0.0d0) then
- correlationFunctions(k)%oneHaloTerm(:,n)=correlationFunctions(k)%oneHaloTerm(:,n)/correlationFunctions(k)%meanDensity(n)**2
- correlationFunctions(k)%twoHaloTerm(:,n)=correlationFunctions(k)%twoHaloTerm(:,n)/correlationFunctions(k)%meanDensity(n)
- end if
- end do
- call deallocateArray(jacobian)
- ! Square the two halo term, and multiply by the linear theory power spectrum.
- call allocateArray(jacobian ,[massCount*(2*wavenumberCount),massCount*(2*wavenumberCount)])
- jacobian=0.0d0
- do n=1,massCount
- do i=1,wavenumberCount
- jacobian((n-1)*(2*wavenumberCount) +i,(n-1)*(2*wavenumberCount) +i)=+1.0d0
- jacobian((n-1)*(2*wavenumberCount)+wavenumberCount+i,(n-1)*(2*wavenumberCount)+wavenumberCount+i)=+2.0d0&
- & * correlationFunctions(k)%twoHaloTerm (i,n) &
- & *powerSpectrum_%power(correlationFunctions(k)%wavenumber (i )) &
- & * correlationFunctions(k)%linearGrowthFactor( n) **2
- end do
- end do
- jacobianMatrix =jacobian
- covarianceMatrix =oneTwoHaloCovariance
- oneTwoHaloCovariance =jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
- do n=1,massCount
- do i=1,wavenumberCount
- correlationFunctions(k)%twoHaloTerm(i,n)= correlationFunctions(k)%twoHaloTerm (i,n) **2 &
- & *powerSpectrum_%power(correlationFunctions(k)%wavenumber (i )) &
- & * correlationFunctions(k)%linearGrowthFactor( n) **2
- end do
- end do
- call deallocateArray(jacobian)
- ! Construct the final power spectra.
- call allocateArray(powerSpectrumValue ,[ wavenumberCount,massCount ])
- call allocateArray(powerSpectrumCovariance,[massCount*wavenumberCount,massCount* wavenumberCount ])
- call allocateArray(jacobian ,[massCount*wavenumberCount,massCount*(2*wavenumberCount)])
- jacobian=0.0d0
- do n=1,massCount
- do i=1,wavenumberCount
- jacobian((n-1)*wavenumberCount+i,(n-1)*(2*wavenumberCount) +i)=1.0d0
- jacobian((n-1)*wavenumberCount+i,(n-1)*(2*wavenumberCount)+wavenumberCount+i)=1.0d0
- end do
- end do
- jacobianMatrix =jacobian
- covarianceMatrix =oneTwoHaloCovariance
- powerSpectrumCovariance =jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
- do n=1,massCount
- powerSpectrumValue(:,n)=correlationFunctions(k)%oneHaloTerm(:,n)+correlationFunctions(k)%twoHaloTerm(:,n)
- end do
- call deallocateArray(jacobian )
- call deallocateArray(oneTwoHaloCovariance)
- ! Allocate correlation function and separation arrays.
- call allocateArray(correlation,shape(powerSpectrumValue))
- call allocateArray(separation ,[wavenumberCount])
- ! Fourier transform the power spectrum to get the correlation function.
- do n=1,massCount
- call FFTLog( &
- & correlationFunctions(k)%wavenumber, &
- & separation , &
- & +powerSpectrumValue(:,n) &
- & *correlationFunctions(k)%wavenumber &
- & * 4.0d0*Pi &
- & /(2.0d0*Pi)**3 , &
- & correlation(:,n) , &
- & fftLogSine , &
- & fftLogForward &
- & )
- correlation(:,n)=correlation(:,n)/separation
- end do
- ! Compute the covariance of the correlation function.
- call allocateArray(covarianceTmp ,[massCount*wavenumberCount,massCount*wavenumberCount])
- call allocateArray(correlationCovariance,[massCount*wavenumberCount,massCount*wavenumberCount])
- ! Apply wavenumber weighting to the power spectrum covariance.
- do n=1,massCount
- do m=1,massCount
- do i=1,wavenumberCount
- do j=1,wavenumberCount
- powerSpectrumCovariance ((n-1)*wavenumberCount+i,(m-1)*wavenumberCount+j) &
- & =powerSpectrumCovariance ((n-1)*wavenumberCount+i,(m-1)*wavenumberCount+j) &
- & *correlationFunctions(k)%wavenumber( i ) &
- & *correlationFunctions(k)%wavenumber( j) &
- & *( &
- & + 4.0d0*Pi &
- & /(2.0d0*Pi)**3 &
- & )**2
- end do
- end do
- end do
- end do
- ! Derive the covariance of the correlation function by first Fourier transforming each row of the power spectrum covariance
- ! matrix, and then Fourier transforming each column.
- do n=1,massCount
- do m=1,massCount
- do i=1,wavenumberCount
- call FFTlog( &
- & correlationFunctions(k)%wavenumber , &
- & separation , &
- & powerSpectrumCovariance((n-1)*wavenumberCount+i,(m-1)*wavenumberCount+1:m*wavenumberCount), &
- & covarianceTmp ((n-1)*wavenumberCount+i,(m-1)*wavenumberCount+1:m*wavenumberCount), &
- & fftLogSine , &
- & fftLogForward &
- )
- end do
- end do
- end do
- do n=1,massCount
- do m=1,massCount
- do i=1,wavenumberCount
- call FFTlog( &
- & correlationFunctions(k)%wavenumber , &
- & separation , &
- & covarianceTmp ((n-1)*wavenumberCount+1:n*wavenumberCount,(m-1)*wavenumberCount+i), &
- & correlationCovariance ((n-1)*wavenumberCount+1:n*wavenumberCount,(m-1)*wavenumberCount+i), &
- & fftLogSine , &
- & fftLogForward &
- )
- end do
- end do
- end do
- do n=1,massCount
- do m=1,massCount
- do i=1,wavenumberCount
- do j=1,wavenumberCount
- correlationCovariance ((n-1)*wavenumberCount+i,(m-1)*wavenumberCount+j) &
- & =correlationCovariance((n-1)*wavenumberCount+i,(m-1)*wavenumberCount+j) &
- & /separation ( i ) &
- & /separation ( j)
- end do
- end do
- end do
- end do
- call deallocateArray(covarianceTmp)
- ! Construct correlation table.
- call correlationTable%create(separation(1),separation(wavenumberCount),size(separation),extrapolationTypeExtrapolate)
- ! Project the correlation function.
- call allocateArray(jacobian ,[massCount*wavenumberCount,massCount*wavenumberCount])
- call allocateArray(projectedCorrelationCovariance,[massCount*wavenumberCount,massCount*wavenumberCount])
- call allocateArray(projectedCorrelation ,[wavenumberCount,massCount ])
- jacobian=0.0d0
- integrandWeightFunction => projectionIntegrandWeight
- do i=1,wavenumberCount
- projectedSeparation=correlationTable%x(i)
- jacobian(i,1:wavenumberCount)=correlationTable%integrationWeights( &
- & projectedSeparation , &
- & sqrt( &
- & +projectedSeparation **2 &
- & +correlationFunctions(k)%lineOfSightDepth**2 &
- & ) , &
- & integrandWeightFunction &
- & )
- do n=1,massCount
- if (n > 1) jacobian((n-1)*wavenumberCount+i,(n-1)*wavenumberCount+1:n*wavenumberCount)=jacobian(i,1:wavenumberCount)
- projectedCorrelation(i,n)=sum(jacobian(i,1:wavenumberCount)*correlation(:,n))
- end do
- end do
- jacobianMatrix =jacobian
- covarianceMatrix =correlationCovariance
- projectedCorrelationCovariance=jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
- call deallocateArray(jacobian)
- ! If the integral was taken over the half range, 0 binningIntegrandWeight
- binWidthLogarithmic=log(correlationFunctions(k)%separation(2)/correlationFunctions(k)%separation(1))
- do i=1,size(correlationFunctions(k)%separation)
- binSeparationMinimum =correlationFunctions(k)%separation(i)*exp(-0.5d0*binWidthLogarithmic)
- binSeparationMaximum =correlationFunctions(k)%separation(i)*exp(+0.5d0*binWidthLogarithmic)
- jacobian(i,1:wavenumberCount)=correlationTable%integrationWeights( &
- & binSeparationMinimum , &
- & binSeparationMaximum , &
- & integrandWeightFunction &
- & ) &
- & /Pi &
- & /( &
- & +binSeparationMaximum**2 &
- & -binSeparationMinimum**2 &
- & )
- do n=1,massCount
- if (n > 1) jacobian((n-1)*size(correlationFunctions(k)%separation)+i,(n-1)*wavenumberCount+1:n*wavenumberCount)=jacobian(i,1:wavenumberCount)
- binnedProjectedCorrelation(i,n)=sum(jacobian(i,1:wavenumberCount)*projectedCorrelation(:,n))
- end do
- end do
- jacobianMatrix =jacobian
- covarianceMatrix =projectedCorrelationCovariance
- binnedProjectedCorrelationCovariance=jacobianMatrix*(covarianceMatrix*jacobianMatrix%transpose())
- call deallocateArray(jacobian)
- call correlationTable%destroy()
- ! Apply the integral constraint.
- binnedProjectedCorrelation=binnedProjectedCorrelation/correlationFunctions(k)%integralConstraint
- ! Output the correlation function.
- !$ call hdf5Access%set()
- analysisGroup =galacticusOutputFile%openGroup('analysis','Model analysis')
- correlationFunctionGroup=analysisGroup %openGroup(trim(correlationFunctions(k)%descriptor%label),trim(correlationFunctions(k)%descriptor%comment))
- call correlationFunctionGroup%writeDataset (correlationFunctions(k)%separation ,'separation' ,'Separation' ,datasetReturned=dataset)
- call dataset %writeAttribute(megaParsec ,'unitsInSI' )
- call dataset %close ( )
- call correlationFunctionGroup%writeDataset (binnedProjectedCorrelation ,'correlationFunction' ,'Projected correlation' ,datasetReturned=dataset)
- call dataset %writeAttribute(megaParsec ,'unitsInSI' )
- call dataset %close ( )
- call correlationFunctionGroup%writeDataset (binnedProjectedCorrelationCovariance,'correlationFunctionCovariance','Projected correlation covariance',datasetReturned=dataset)
- call dataset %writeAttribute(megaParsec**2 , 'unitsInSI' )
- call dataset %close ( )
- call correlationFunctionGroup%close ( )
- call analysisGroup %close ( )
- !$ call hdf5Access%unset()
- call deallocateArray(binnedProjectedCorrelation )
- call deallocateArray(binnedProjectedCorrelationCovariance)
- end do
- return
-
- contains
-
- double precision function projectionIntegrandWeight(separation)
- !% The weight function applied to the correlation function when integrating to get the projected correlation function.
- implicit none
- double precision, intent(in ) :: separation
-
- if (separation > projectedSeparation) then
- projectionIntegrandWeight=2.0d0*separation/sqrt(separation**2-projectedSeparation**2)
- else
- projectionIntegrandWeight=0.0d0
- end if
- return
- end function projectionIntegrandWeight
-
- double precision function binningIntegrandWeight(separation)
- !% The weight function applied to the projected correlation function when integrating into bins.
- implicit none
- double precision, intent(in ) :: separation
-
- binningIntegrandWeight=2.0d0*Pi*separation
- return
- end function binningIntegrandWeight
-
- end subroutine Galacticus_Output_Analysis_Correlation_Functions_Output
-
- subroutine Term_Indices(iMass,wavenumberCount,indexOneHalo,indexTwoHalo,indexDensity)
- !% Return the indices in the term covariances array at which one-halo, two-halo, and density terms are stored for the given mass.
- implicit none
- integer, intent(in ) :: iMass , wavenumberCount
- integer, intent( out) :: indexOneHalo, indexTwoHalo , indexDensity
-
- indexOneHalo=(iMass-1)*(2*wavenumberCount+1) +1
- indexTwoHalo=(iMass-1)*(2*wavenumberCount+1)+ wavenumberCount+1
- indexDensity=(iMass-1)*(2*wavenumberCount+1)+2*wavenumberCount+1
- return
- end subroutine Term_Indices
-
- subroutine validateDescriptors(descriptors)
- !% Perform some validation on correlation function descriptors to catch potential errors.
- use Galacticus_Error
- use ISO_Varying_String
- implicit none
- type (correlationFunctionDescriptor), dimension(:), intent(in ) :: descriptors
- type (varying_string ) :: message
- character(len=8 ) :: label
- integer :: i
-
- do i=1,size(descriptors)
- if ( &
- & descriptors(i)%massSystematicLogM0 < 6.0d0 &
- & .or. &
- & descriptors(i)%massSystematicLogM0 > 16.0d0 &
- & ) then
- write (label,'(f8.5)') descriptors(i)%massSystematicLogM0
- message="Error model mass zero-point ["//trim(adjustl(label))//"] for correlation function descriptor ["//trim(descriptors(i)%label)//"] is outside of plausible range"
- call Galacticus_Error_Report(message//{introspection:location})
- end if
- end do
- return
- end subroutine validateDescriptors
-
-end module Galacticus_Output_Analyses_Correlation_Functions
-