From 186ad7fa2c433bad0beda692abac06c76b1f264f Mon Sep 17 00:00:00 2001 From: Andrew Benson Date: Fri, 18 Oct 2024 10:23:22 -0700 Subject: [PATCH 1/5] fix(style): Formatting only --- source/nodes.operators.multi.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/nodes.operators.multi.F90 b/source/nodes.operators.multi.F90 index 18309f8e2e..1ba3047da6 100644 --- a/source/nodes.operators.multi.F90 +++ b/source/nodes.operators.multi.F90 @@ -85,7 +85,7 @@ function multiConstructorParameters(parameters) result(self) integer :: i self %processes => null() - process_ => null() + process_ => null() do i=1,parameters%copiesCount('nodeOperator',zeroIfNotPresent=.true.) if (associated(process_)) then allocate(process_%next) From a39fa1b760bef2f1f161c9b685f877efe5136a0f Mon Sep 17 00:00:00 2001 From: Andrew Benson Date: Fri, 18 Oct 2024 10:23:38 -0700 Subject: [PATCH 2/5] feat: Support automatic handling of linked lists in `functionClass` objects for lists imported from external modules --- .../Build/SourceTree/Process/FunctionClass.pm | 149 ++++++++++-------- 1 file changed, 84 insertions(+), 65 deletions(-) diff --git a/perl/Galacticus/Build/SourceTree/Process/FunctionClass.pm b/perl/Galacticus/Build/SourceTree/Process/FunctionClass.pm index a61f5cdda8..6c989b076c 100644 --- a/perl/Galacticus/Build/SourceTree/Process/FunctionClass.pm +++ b/perl/Galacticus/Build/SourceTree/Process/FunctionClass.pm @@ -674,7 +674,10 @@ sub Process_FunctionClass { # Handle linked lists. if ( defined($descriptorParameters->{'linkedLists'}) ) { foreach ( @{$descriptorParameters->{'linkedLists'}} ) { - $descriptorCode .= &autoDescriptorLinkedList($_,$descriptorLinkedListVariables); + (my $linkedListCode, my $linkedListModule) = &autoDescriptorLinkedList($_,$descriptorLinkedListVariables); + $descriptorCode .= $linkedListCode; + $descriptorModules{$linkedListModule} = 1 + if ( $linkedListModule ); } } } @@ -981,6 +984,8 @@ CODE my $allowedParametersLinkedListVariables; @{$allowedParametersLinkedListVariables} = (); $allowedParametersCode .= "select type (self)\n"; + my %allowedParametersModules; + $allowedParametersModules{'ISO_Varying_String'} = 1; foreach my $class ( @classes ) { if ( $allowedParameters->{$class->{'name'}}->{'declarationMatches'} ) { my $className = $class->{'name'}; @@ -1112,7 +1117,10 @@ CODE $allowedParametersCode .= " if (associated(self%".$_.")) call self%".$_."%allowedParameters(allowedParameters,'".$source."',.true.)\n"; } # Handle any linked lists. - $allowedParametersCode .= &allowedParametesLinkedList($class,$allowedParametersLinkedListVariables,$source); + (my $linkedListCode, my $linkedListModule) = &allowedParametersLinkedList($class,$allowedParametersLinkedListVariables,$source); + $allowedParametersCode .= $linkedListCode; + $allowedParametersModules{$linkedListModule} = 1 + if ( $linkedListModule ); } } if ( defined($allowedParameters->{$className}->{'classParent'}) ) { @@ -1138,7 +1146,7 @@ CODE type => "void", recursive => "yes", pass => "yes", - modules => "ISO_Varying_String", + modules => join(" ",keys(%allowedParametersModules)), argument => [ "type (varying_string), dimension(:), allocatable, intent(inout) :: allowedParameters", "character(len=* ) , intent(in ) :: sourceName" , @@ -1180,10 +1188,15 @@ CODE last unless ( $node ); # Handle linked lists. - (my $linkedListCode, my $linkedListResetCode, my $linkedListFinalizeCode) = &deepCopyLinkedList($class,$nonAbstractClass,$linkedListVariables,$linkedListResetVariables,$linkedListFinalizeVariables,$debugging); + (my $linkedListCode, my $linkedListResetCode, my $linkedListFinalizeCode, my $linkedListModule) = &deepCopyLinkedList($class,$nonAbstractClass,$linkedListVariables,$linkedListResetVariables,$linkedListFinalizeVariables,$debugging); $deepCopy->{'assignments' } .= $linkedListCode; $deepCopy->{'resetCode' } .= $linkedListResetCode; $deepCopy->{'finalizeCode'} .= $linkedListFinalizeCode; + if ( $linkedListModule ) { + $deepCopy->{'modules' }->{$linkedListModule} = 1; + $deepCopy->{'resetModules' }->{$linkedListModule} = 1; + $deepCopy->{'finalizeModules'}->{$linkedListModule} = 1; + } # Search the node for declarations. my @ignore = exists($class->{'deepCopy'}->{'ignore'}) ? split(/\s*,\s*/,$class->{'deepCopy'}->{'ignore'}->{'variables'}) : (); $node = $node->{'firstChild'}; @@ -1372,9 +1385,11 @@ CODE $node = $node->{'type'} eq "contains" ? $node->{'firstChild'} : $node->{'sibling'}; } # Handle linked lists. - (my $linkedListInputCode, my $linkedListOutputCode) = &stateStoreLinkedList($class,$nonAbstractClass,$stateLinkedListVariables); - $stateStore->{'inputCode'} .= $linkedListInputCode; + (my $linkedListInputCode, my $linkedListOutputCode, my $linkedListModule) = &stateStoreLinkedList($class,$nonAbstractClass,$stateLinkedListVariables); + $stateStore->{'inputCode' } .= $linkedListInputCode; $stateStore->{'outputCode'} .= $linkedListOutputCode; + $stateStores->{'stateStoreModules'}->{$linkedListModule} = 1 + if ( $linkedListModule ); # Handle explicit state store functions. $stateStores->{'explicitFunctionsFound'} = 1 if ( exists($nonAbstractClass->{'stateStore'}->{'stateStore'}->{'restore'}) ); @@ -2775,7 +2790,7 @@ sub deepCopyLinkedList { my $linkedListResetVariables = shift(); my $linkedListFinalizeVariables = shift(); my $debugging = shift(); - return ("","","") + return ("","","",undef()) unless ( exists($class->{'linkedList'}) ); my $linkedList = $class->{'linkedList'}; # Add variables needed for linked list processing. @@ -2785,7 +2800,7 @@ sub deepCopyLinkedList { intrinsic => 'type', type => $linkedList->{'type'}, attributes => [ 'pointer' ], - variables => [ 'item_', 'destination_', 'itemNew_' ] + variables => [ $linkedList->{'object'}.'item', $linkedList->{'object'}.'destination', $linkedList->{'object'}.'itemNew' ] } ) unless ( grep {$_->{'type'} eq $linkedList->{'type'}} @{$linkedListVariables} ); @@ -2795,7 +2810,7 @@ sub deepCopyLinkedList { intrinsic => 'type', type => $linkedList->{'type'}, attributes => [ 'pointer' ], - variables => [ 'item_' ] + variables => [ $linkedList->{'object'}.'item' ] } ) unless ( grep {$_->{'type'} eq $linkedList->{'type'}} @{$linkedListResetVariables} ); @@ -2805,7 +2820,7 @@ sub deepCopyLinkedList { intrinsic => 'type', type => $linkedList->{'type'}, attributes => [ 'pointer' ], - variables => [ 'item_' ] + variables => [ $linkedList->{'object'}.'item' ] } ) unless ( grep {$_->{'type'} eq $linkedList->{'type'}} @{$linkedListFinalizeVariables} ); @@ -2816,56 +2831,57 @@ sub deepCopyLinkedList { $code::objectIntrinsic = exists($linkedList->{'objectIntrinsic'}) ? $linkedList->{'objectIntrinsic'} : "class"; $code::next = $linkedList->{'next' } ; $code::location = &Galacticus::Build::SourceTree::Process::SourceIntrospection::Location($class->{'node'},$class->{'node'}->{'line'}); - $code::debugCode = $debugging ? "if (debugReporting.and.mpiSelf\%isMaster()) call displayMessage(var_str('functionClass[own] (class : ownerName : ownerLoc : objectLoc : sourceLoc): [".$code::objectType."] : ".$code::object." : ')//loc(itemNew_)//' : '//loc(itemNew_%".$code::object.")//' : '//".&Galacticus::Build::SourceTree::Process::SourceIntrospection::Location($class->{'node'},$class->{'node'}->{'line'},compact => 1).",verbosityLevelSilent)\n" : ""; + $code::debugCode = $debugging ? "if (debugReporting.and.mpiSelf\%isMaster()) call displayMessage(var_str('functionClass[own] (class : ownerName : ownerLoc : objectLoc : sourceLoc): [".$code::objectType."] : ".$code::object." : ')//loc(".$code::object."itemNew)//' : '//loc(".$code::object."itemNew%".$code::object.")//' : '//".&Galacticus::Build::SourceTree::Process::SourceIntrospection::Location($class->{'node'},$class->{'node'}->{'line'},compact => 1).",verbosityLevelSilent)\n" : ""; my $deepCopyCode = fill_in_string(<<'CODE', PACKAGE => 'code'); destination%{$variable} => null () -destination_ => null () -item_ => self%{$variable} -do while (associated(item_)) - allocate(itemNew_) - if (associated(destination_)) then - destination_%{$next} => itemNew_ - destination_ => itemNew_ +{$object}destination => null () +{$object}item => self%{$variable} +do while (associated({$object}item)) + allocate({$object}itemNew) + if (associated({$object}destination)) then + {$object}destination%{$next} => {$object}itemNew + {$object}destination => {$object}itemNew else - destination %{$variable} => itemNew_ - destination_ => itemNew_ + destination %{$variable} => {$object}itemNew + {$object}destination => {$object}itemNew end if - nullify(itemNew_%{$object}) - if (associated(item_%{$object})) then - if (associated(item_%{$object}%copiedSelf)) then - select type(s => item_%{$object}%copiedSelf) + nullify({$object}itemNew%{$object}) + if (associated({$object}item%{$object})) then + if (associated({$object}item%{$object}%copiedSelf)) then + select type(s => {$object}item%{$object}%copiedSelf) {$objectIntrinsic} is ({$objectType}) - itemNew_%{$object} => s + {$object}itemNew%{$object} => s class default call Error_Report('copiedSelf has incorrect type'//{$location}) end select - call item_%{$object}%copiedSelf%referenceCountIncrement() + call {$object}item%{$object}%copiedSelf%referenceCountIncrement() else - allocate(itemNew_%{$object},mold=item_%{$object}) - call item_%{$object}%deepCopy(itemNew_%{$object}) - item_%{$object}%copiedSelf => itemNew_%{$object} - call itemNew_%{$object}%autoHook() + allocate({$object}itemNew%{$object},mold={$object}item%{$object}) + call {$object}item%{$object}%deepCopy({$object}itemNew%{$object}) + {$object}item%{$object}%copiedSelf => {$object}itemNew%{$object} + call {$object}itemNew%{$object}%autoHook() end if {$debugCode} end if - item_ => item_%{$next} + {$object}item => {$object}item%{$next} end do CODE my $deepCopyResetCode = fill_in_string(<<'CODE', PACKAGE => 'code'); -item_ => self%{$variable} -do while (associated(item_)) - call item_%{$object}%deepCopyReset() - item_ => item_%{$next} +{$object}item => self%{$variable} +do while (associated({$object}item)) + call {$object}item%{$object}%deepCopyReset() + {$object}item => {$object}item%{$next} end do CODE my $deepCopyFinalizeCode = fill_in_string(<<'CODE', PACKAGE => 'code'); -item_ => self%{$variable} -do while (associated(item_)) - call item_%{$object}%deepCopyFinalize() - item_ => item_%{$next} +{$object}item => self%{$variable} +do while (associated({$object}item)) + call {$object}item%{$object}%deepCopyFinalize() + {$object}item => {$object}item%{$next} end do CODE - return ($deepCopyCode,$deepCopyResetCode,$deepCopyFinalizeCode); + my $deepCopyModule = exists($linkedList->{'module'}) ? $linkedList->{'module'} : undef(); + return ($deepCopyCode,$deepCopyResetCode,$deepCopyFinalizeCode,$deepCopyModule); } sub stateStoreLinkedList { @@ -2873,7 +2889,7 @@ sub stateStoreLinkedList { my $class = shift(); my $nonAbstractClass = shift(); my $linkedListVariables = shift(); - return ("","","") + return ("","","",undef()) unless ( exists($class->{'linkedList'}) ); my $linkedList = $class->{'linkedList'}; # Add variables needed for linked list processing. @@ -2883,7 +2899,7 @@ sub stateStoreLinkedList { intrinsic => 'type', type => $linkedList->{'type'}, attributes => [ 'pointer' ], - variables => [ 'item_' ] + variables => [ $linkedList->{'object'}.'item' ] } ) unless ( grep {$_->{'type'} eq $linkedList->{'type'}} @{$linkedListVariables} ); @@ -2892,28 +2908,29 @@ sub stateStoreLinkedList { $code::object = $linkedList->{'object' }; $code::next = $linkedList->{'next' }; my $inputCode = fill_in_string(<<'CODE', PACKAGE => 'code'); -item_ => self%{$variable} -do while (associated(item_)) - call item_%{$object}%stateRestore(stateFile,gslStateFile,stateOperationID) - item_ => item_%{$next} +{$object}item => self%{$variable} +do while (associated({$object}item)) + call {$object}item%{$object}%stateRestore(stateFile,gslStateFile,stateOperationID) + {$object}item => {$object}item%{$next} end do CODE my $outputCode = fill_in_string(<<'CODE', PACKAGE => 'code'); -item_ => self%{$variable} -do while (associated(item_)) - call item_%{$object}%stateStore(stateFile,gslStateFile,stateOperationID) - item_ => item_%{$next} +{$object}item => self%{$variable} +do while (associated({$object}item)) + call {$object}item%{$object}%stateStore(stateFile,gslStateFile,stateOperationID) + {$object}item => {$object}item%{$next} end do CODE - return ($inputCode,$outputCode); + my $deepCopyModule = exists($linkedList->{'module'}) ? $linkedList->{'module'} : undef(); + return ($inputCode,$outputCode,$deepCopyModule); } -sub allowedParametesLinkedList { +sub allowedParametersLinkedList { # Create allowed parameter instructions for linked list objects. my $nonAbstractClass = shift(); my $linkedListVariables = shift(); my $source = shift(); - return "" + return ("",undef()) unless ( exists($nonAbstractClass->{'linkedList'}) ); my $linkedList = $nonAbstractClass->{'linkedList'}; # Add variables needed for linked list processing. @@ -2923,7 +2940,7 @@ sub allowedParametesLinkedList { intrinsic => 'type', type => $linkedList->{'type'}, attributes => [ 'pointer' ], - variables => [ 'item_' ] + variables => [ $linkedList->{'object'}.'item' ] } ) unless ( grep {$_->{'type'} eq $linkedList->{'type'}} @{$linkedListVariables} ); @@ -2933,13 +2950,14 @@ sub allowedParametesLinkedList { $code::next = $linkedList->{'next' }; $code::source = $source; my $iterator = fill_in_string(<<'CODE', PACKAGE => 'code'); -item_ => self%{$variable} -do while (associated(item_)) - call item_%{$object}%allowedParameters(allowedParameters,'{$source}',.true.) - item_ => item_%{$next} +{$object}item => self%{$variable} +do while (associated({$object}item)) + call {$object}item%{$object}%allowedParameters(allowedParameters,'{$source}',.true.) + {$object}item => {$object}item%{$next} end do CODE - return $iterator; + my $deepCopyModule = exists($linkedList->{'module'}) ? $linkedList->{'module'} : undef(); + return ($iterator,$deepCopyModule); } sub autoDescriptorLinkedList { @@ -2953,7 +2971,7 @@ sub autoDescriptorLinkedList { intrinsic => 'type', type => $linkedList->{'type'}, attributes => [ 'pointer' ], - variables => [ 'item_' ] + variables => [ $linkedList->{'object'}.'item' ] } ) unless ( grep {$_->{'type'} eq $linkedList->{'type'}} @{$linkedListVariables} ); @@ -2962,13 +2980,14 @@ sub autoDescriptorLinkedList { $code::object = $linkedList->{'object' }; $code::next = $linkedList->{'next' }; my $iterator = fill_in_string(<<'CODE', PACKAGE => 'code'); -item_ => self%{$variable} -do while (associated(item_)) - call item_%{$object}%descriptor(parameters) - item_ => item_%{$next} +{$object}item => self%{$variable} +do while (associated({$object}item)) + call {$object}item%{$object}%descriptor(parameters) + {$object}item => {$object}item%{$next} end do CODE - return $iterator; + my $deepCopyModule = exists($linkedList->{'module'}) ? $linkedList->{'module'} : undef(); + return ($iterator,$deepCopyModule); } sub stateStoreExplicitFunction { From 122ab779becac3cea8226e6ae4397f902766ec1c Mon Sep 17 00:00:00 2001 From: Andrew Benson Date: Fri, 18 Oct 2024 10:24:35 -0700 Subject: [PATCH 3/5] feat: Add functionality to track and output galaxy merger trees Includes an example parameter file and plotting script. --- parameters/tutorials/galaxyMergerTree.xml | 295 ++++++++++++++ scripts/analysis/galaxyMergerTree.py | 109 ++++++ ....operators.analyses.galaxy_merger_tree.F90 | 370 ++++++++++++++++++ ....property_extractor.galaxy_merger_tree.F90 | 104 +++++ ...y_extractor.galaxy_merger_tree.indices.F90 | 158 ++++++++ ...ctor.galaxy_merger_tree.merger_indices.F90 | 158 ++++++++ ...tor.galaxy_merger_tree.merger_physical.F90 | 154 ++++++++ ...y_extractor.galaxy_merger_tree.objects.F90 | 44 +++ ..._extractor.galaxy_merger_tree.physical.F90 | 207 ++++++++++ 9 files changed, 1599 insertions(+) create mode 100644 parameters/tutorials/galaxyMergerTree.xml create mode 100755 scripts/analysis/galaxyMergerTree.py create mode 100644 source/nodes.operators.analyses.galaxy_merger_tree.F90 create mode 100644 source/nodes.property_extractor.galaxy_merger_tree.F90 create mode 100644 source/nodes.property_extractor.galaxy_merger_tree.indices.F90 create mode 100644 source/nodes.property_extractor.galaxy_merger_tree.merger_indices.F90 create mode 100644 source/nodes.property_extractor.galaxy_merger_tree.merger_physical.F90 create mode 100644 source/nodes.property_extractor.galaxy_merger_tree.objects.F90 create mode 100644 source/nodes.property_extractor.galaxy_merger_tree.physical.F90 diff --git a/parameters/tutorials/galaxyMergerTree.xml b/parameters/tutorials/galaxyMergerTree.xml new file mode 100644 index 0000000000..89c71a191a --- /dev/null +++ b/parameters/tutorials/galaxyMergerTree.xml @@ -0,0 +1,295 @@ + + + + + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/analysis/galaxyMergerTree.py b/scripts/analysis/galaxyMergerTree.py new file mode 100755 index 0000000000..e61210bc8a --- /dev/null +++ b/scripts/analysis/galaxyMergerTree.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +import numpy as np +import h5py +import matplotlib as mpl +import matplotlib.pyplot as plt + +# Make a simple diagram showing a galaxy merger tree. +# Andrew Benson (18-October-2024) + +# Open the model output and extract merger tree datasets. +model = h5py.File("galaxyMergerTree.hdf5","r") +nodes = model['Outputs/Output1/nodeData'] +propertyNames = [ 'galaxyMergerTreeNodeIndex' , 'galaxyMergerTreeCount' , 'galaxyMergerTreeTotalStarFormationRate', + 'galaxyMergerTreeMassStellarTotal' , 'galaxyMergerTreeTime' , 'galaxyMergerTreeMergeCentralIndex' , + 'galaxyMergerTreeMergeSatelliteIndex', 'galaxyMergerTreeMergeTime', 'nodeIsIsolated' ] +properties = {} +for property in propertyNames: + properties[property] = nodes[property][:] + +# Identify the central galaxy, and extract the relevant tree. +indexCentral = np.nonzero(properties['nodeIsIsolated'] == 1)[0][0] +for property in propertyNames: + properties[property] = properties[property][indexCentral] + +# Generate a color map to color nodes by their star formation rate. +colorMap = mpl.colormaps['coolwarm'] +countColors = 100 +colors = colorMap(np.linspace(1,0,countColors)) + +# Generate a range spanning the number of nodes in tree. +indexNodes = np.array(list(range(len(properties['galaxyMergerTreeTime'])))) + +# Find the start and indexEnd index for each branch of the tree. This is found by simply cumulating the number of nodes in each +# branch. +indexEnd = np.cumsum(properties['galaxyMergerTreeCount']) +indexStart = np.concatenate((np.array([0]),indexEnd[0:len(indexEnd)-1])) + +# Initialize arrays of nodes (x,y positions, size, and color) and edges (tuples giving pairs of nodes that are connected by an +# edge). +edges = [] +nodesX = np.array([] ) +nodesY = np.array([] ) +nodesIndex = np.array([], dtype=np.uint32) +nodesSize = np.array([] ) +nodesColor = [] +countNodes = 0 + +# Find maximum mass and star formation rate so that we can scale positions and colors to these. +massMaximum = np.max(properties['galaxyMergerTreeMassStellarTotal' ]) +sfrMaximum = np.max(properties['galaxyMergerTreeTotalStarFormationRate']) + +# Iterate over branches. +for indexBranch in range(len(properties['galaxyMergerTreeCount'])): + for indexNode in range(indexStart[indexBranch],indexEnd[indexBranch]): + # Determine a color for this node based no its star formation rate. + nodeColor = colors[int((countColors-1)*properties['galaxyMergerTreeTotalStarFormationRate'][indexNode]/sfrMaximum)] + # Determine a size for the node based on its mass. + nodeSize = 100.0*(properties['galaxyMergerTreeMassStellarTotal'][indexNode]/massMaximum)**(1.0/3.0) + # Append node properties to our lists. The x positions are initially all set to the (arbitary) value of 0. + nodesIndex = np.append(nodesIndex,countNodes ) + nodesX = np.append(nodesX ,0.0 ) + nodesY = np.append(nodesY ,properties['galaxyMergerTreeTime'][indexNode]) + nodesSize = np.append(nodesSize ,nodeSize ) + nodesColor.append(nodeColor) + # Add an edge (except for the final node in the branch) connecting to the next node. + if indexNode < indexEnd[indexBranch]-1: + edges.append((countNodes,countNodes+1)) + # Increment the count of nodes. + countNodes += 1 + +# Set the fractional x-offset between nodes about to merge. +xOffsetMerger = 0.05 + +# Iterate over mergers in order of decreasing time. +order = np.flip(np.argsort(properties['galaxyMergerTreeMergeTime'])) +for indexMerger in range(len(order)): + # Find the nodes participating in this merger. + indexSatellite = np.nonzero(properties['galaxyMergerTreeNodeIndex'] == properties['galaxyMergerTreeMergeSatelliteIndex'][order[indexMerger]])[0][0] + indexCentral = np.nonzero(properties['galaxyMergerTreeNodeIndex'] == properties['galaxyMergerTreeMergeCentralIndex' ][order[indexMerger]])[0][0] + # Find the corresponding branches for these nodes. For the central we find just the final node in the branch. + branchSatellite = (indexNodes < indexEnd[indexSatellite]) & (indexNodes >= indexStart[indexSatellite]) + branchCentralEnd = (indexNodes < indexEnd[indexCentral ]) & (indexNodes >= indexStart[indexCentral ]) & (properties['galaxyMergerTreeTime'] == properties['galaxyMergerTreeMergeTime'][order[indexMerger]]) + # Determine the amount by which to shift the satellite branch in the x-direction. + xShift = (properties['galaxyMergerTreeMassStellarTotal'][branchSatellite][-1]/massMaximum)**(1.0/2.0) + # Find all othr nodes that must be shift to make space for this branch. + toShift = (nodesX > nodesX[branchCentralEnd][0]) & (nodesY < nodesY[branchSatellite][-1]) + # Shift all nodes (both on our satellite branch and others that must move to make space for it). The shift increases with time + # before the merger to create a track that merges onto the central. + nodesX[toShift ] += xShift*(1.0-(1.0-xOffsetMerger)*(nodesY[toShift ]/nodesY[branchSatellite][-1])**4) + nodesX[branchSatellite] = nodesX[branchCentralEnd][0]+xShift*(1.0-(1.0-xOffsetMerger)*(nodesY[branchSatellite]/nodesY[branchSatellite][-1])**4) + # Add an edge connecting the two nodes that merge. + edges.append((nodesIndex[branchSatellite][-1],nodesIndex[branchCentralEnd][0])) + +# Create a figure. +fig, ax = plt.subplots(figsize=(5,15)) +# Iterate over edges, drawing lines between the connected nodes. +for indexEdge in range(len(edges)): + edgeX = (nodesX[edges[indexEdge][0]],nodesX[edges[indexEdge][1]]) + edgeY = (nodesY[edges[indexEdge][0]],nodesY[edges[indexEdge][1]]) + ax.plot(edgeX,edgeY,marker='',linestyle='-',color='#aaaaaa',zorder=10) +# Add points showing the nodes. +ax.scatter(nodesX,nodesY,nodesSize,zorder=20,color=nodesColor) +# Remove ticks and labels from the x-axis - position on the x-axis is arbitrary. +ax.tick_params(left = True, right = False , labelleft = True , + labelbottom = False, bottom = False) +# Label the y-axis. +ax.set_ylabel('time [Gyr]') +# Save our figure. +fig.savefig('galaxyMergerTree.pdf') diff --git a/source/nodes.operators.analyses.galaxy_merger_tree.F90 b/source/nodes.operators.analyses.galaxy_merger_tree.F90 new file mode 100644 index 0000000000..a4ceea43f1 --- /dev/null +++ b/source/nodes.operators.analyses.galaxy_merger_tree.F90 @@ -0,0 +1,370 @@ +!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, +!! 2019, 2020, 2021, 2022, 2023, 2024 +!! 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 . + + !!{ + Implements a node operator class that records properties of galaxies in every galaxy's merger tree. + !!} + + use :: Node_Property_Extractors, only : multiExtractorList + + !![ + + A node operator class that records properties of galaxies in every galaxy's merger tree. + + + !!] + type, extends(nodeOperatorClass) :: nodeOperatorGalaxyMergerTree + !!{ + A node operator class that records properties of galaxies in every galaxy's merger tree. + !!} + private + type (multiExtractorList), pointer :: extractors => null() + integer :: uniqueIDBranchTipID , nodeIndexID , & + & countID , timeID , & + & propertyID , mergeIndexID, & + & mergeTargetID , timeMergeID , & + & countExtractors + double precision :: timeStep + contains + !![ + + + + + !!] + final :: galaxyMergerTreeDestructor + procedure :: autoHook => galaxyMergerTreeAutoHook + procedure :: initialize => galaxyMergerTreeInitialize + procedure :: record => galaxyMergerTreeRecord + procedure :: differentialEvolutionPost => galaxyMergerTreeDifferentialEvolutionPost + procedure :: deepCopy => galaxyMergerTreeDeepCopy + end type nodeOperatorGalaxyMergerTree + + interface nodeOperatorGalaxyMergerTree + !!{ + Constructors for the {\normalfont \ttfamily galaxyMergerTree} node operator class. + !!} + module procedure galaxyMergerTreeConstructorParameters + module procedure galaxyMergerTreeConstructorInternal + end interface nodeOperatorGalaxyMergerTree + +contains + + function galaxyMergerTreeConstructorParameters(parameters) result(self) + !!{ + Constructor for the {\normalfont \ttfamily galaxyMergerTree} node operator class which takes a parameter set as input. + !!} + use :: Input_Parameters, only : inputParameters + implicit none + type (nodeOperatorGalaxyMergerTree) :: self + type (inputParameters ), intent(inout) :: parameters + type (multiExtractorList ), pointer :: extractor_ + integer :: i + + !![ + + timeStep + self%timestep + The minimum timestep at which to record galaxy properties. + parameters + + !!] + self %extractors => null() + extractor_ => null() + do i=1,parameters%copiesCount('nodePropertyExtractor') + if (associated(extractor_)) then + allocate(extractor_%next) + extractor_ => extractor_%next + else + allocate(self%extractors) + extractor_ => self%extractors + end if + !![ + + !!] + end do + !![ + + !!] + call self%initialize() + return + end function galaxyMergerTreeConstructorParameters + + function galaxyMergerTreeConstructorInternal(timeStep,extractors) result(self) + !!{ + Internal constructor for the {\normalfont \ttfamily galaxyMergerTree} node operator class. + !!} + implicit none + type (nodeOperatorGalaxyMergerTree) :: self + double precision , intent(in ) :: timeStep + type (multiExtractorList ), intent(in ), target :: extractors + type (multiExtractorList ) , pointer :: extractor_ + !![ + + !!] + + self %extractors => extractors + extractor_ => extractors + do while (associated(extractor_)) + !![ + + !!] + extractor_ => extractor_%next + end do + call self%initialize() + return + end function galaxyMergerTreeConstructorInternal + + subroutine galaxyMergerTreeInitialize(self) + !!{ + Initialize meta-properties needed for galaxy merger trees. + !!} + use :: Galacticus_Nodes, only : defaultBasicComponent + implicit none + class(nodeOperatorGalaxyMergerTree), intent(inout):: self + type (multiExtractorList ), pointer :: extractor_ + + !![ + + + + + + + + + !!] + ! Count extractors. + self%countExtractors = 0 + extractor_ => self%extractors + do while (associated(extractor_)) + self%countExtractors = self %countExtractors+1 + extractor_ => extractor_%next + end do + return + end subroutine galaxyMergerTreeInitialize + + subroutine galaxyMergerTreeAutoHook(self) + !!{ + Attach to various event hooks. + !!} + use :: Events_Hooks, only : satelliteMergerEvent, openMPThreadBindingAtLevel + implicit none + class(nodeOperatorGalaxyMergerTree), intent(inout) :: self + + call satelliteMergerEvent%attach(self,satelliteMerger,openMPThreadBindingAtLevel,label='galaxyMergerTree') + return + end subroutine galaxyMergerTreeAutoHook + + subroutine galaxyMergerTreeDestructor(self) + !!{ + Destructor for the {\normalfont \ttfamily galaxyMergerTree} node operator class. + !!} + use :: Events_Hooks, only : satelliteMergerEvent + implicit none + type(nodeOperatorGalaxyMergerTree), intent(inout) :: self + type(multiExtractorList ), pointer :: extractor_, extractorNext + + if (satelliteMergerEvent%isAttached(self,satelliteMerger)) call satelliteMergerEvent%detach(self,satelliteMerger) + if (associated(self%extractors)) then + extractor_ => self%extractors + do while (associated(extractor_)) + extractorNext => extractor_%next + !![ + + !!] + deallocate(extractor_) + extractor_ => extractorNext + end do + end if + return + end subroutine galaxyMergerTreeDestructor + + subroutine galaxyMergerTreeDifferentialEvolutionPost(self,node) + !!{ + Operate on the node after differential evolution. + !!} + use :: Galacticus_Nodes, only : nodeComponentBasic + implicit none + class (nodeOperatorGalaxyMergerTree), intent(inout) :: self + type (treeNode ), intent(inout) :: node + double precision , allocatable, dimension(:) :: times + class (nodeComponentBasic ), pointer :: basic + logical :: record, isNew + + basic => node %basic ( ) + times = basic%floatRank1MetaPropertyGet(self%timeID) + isNew = size(times) == 0 + record = isNew .or. basic%time() >= times(size(times))+self%timeStep + if (record) call self%record(node) + return + end subroutine galaxyMergerTreeDifferentialEvolutionPost + + subroutine galaxyMergerTreeRecord(self,node) + !!{ + Record a new time in the merger tree. + !!} + use :: Galacticus_Nodes, only : nodeComponentBasic + use :: Node_Property_Extractors, only : nodePropertyExtractorScalar + implicit none + class (nodeOperatorGalaxyMergerTree), intent(inout) :: self + type (treeNode ), intent(inout) :: node + double precision , allocatable , dimension(:) :: times , timesNew , & + & properties , propertiesNew + integer (c_size_t ), allocatable , dimension(:) :: nodeIndices, counts + class (nodeComponentBasic ), pointer :: basic + type (multiExtractorList ), pointer :: extractor_ + logical :: isNew + integer :: i + + basic => node %basic ( ) + times = basic%floatRank1MetaPropertyGet(self%timeID) + isNew = size(times) == 0 + nodeIndices=basic%longIntegerRank1MetaPropertyGet(self%nodeIndexID) + counts =basic%longIntegerRank1MetaPropertyGet(self%countID ) + properties =basic% floatRank1MetaPropertyGet(self%propertyID ) + if (isNew) then + deallocate(nodeIndices ) + deallocate(counts ) + allocate (nodeIndices(1)) + allocate (counts (1)) + counts(1)=0_c_size_t + end if + nodeIndices(size(counts))=basic%longIntegerRank0MetaPropertyGet(self%uniqueIDBranchTipID) + counts (size(counts))=counts(size(counts))+1_c_size_t + allocate(timesNew (size(times )+1 )) + allocate(propertiesNew(size(properties)+self%countExtractors)) + if (size(times ) > 0) timesNew (1:size(times ))=times + if (size(properties) > 0) propertiesNew(1:size(properties))=properties + timesNew(size(times)+1) = basic%time () + extractor_ => self %extractors + i = 0 + do while (associated(extractor_)) + i=i+1 + select type (nodePropertyExtractor_ => extractor_%extractor_) + class is (nodePropertyExtractorScalar) + propertiesNew(size(properties)+i)=nodePropertyExtractor_%extract(node) + end select + extractor_=> extractor_%next + end do + call basic%longIntegerRank1MetaPropertySet(self%nodeIndexID,nodeIndices ) + call basic%longIntegerRank1MetaPropertySet(self%countID ,counts ) + call basic%floatRank1MetaPropertySet (self%propertyID ,propertiesNew) + call basic%floatRank1MetaPropertySet (self%timeID ,timesNew ) + return + end subroutine galaxyMergerTreeRecord + + subroutine satelliteMerger(self,node) + !!{ + Record galaxy-galaxy merges and combine trees. + !!} + use :: Galacticus_Nodes, only : nodeComponentBasic + implicit none + class (* ), intent(inout) :: self + type (treeNode ), intent(inout), target :: node + type (treeNode ) , pointer :: nodeTarget + class (nodeComponentBasic ) , pointer :: basic , basicTarget + double precision , allocatable , dimension(:) :: times , timesTarget , & + & timesNew , properties , & + & propertiesTarget , propertiesNew , & + & timesMerge , timesMergeTarget , & + & timesMergeNew + integer (c_size_t ), allocatable , dimension(:) :: nodeIndices , nodeIndicesTarget , & + & nodeIndicesNew , counts , & + & countsTarget , countsNew , & + & mergeIndices , mergeIndicesTarget, & + & mergeIndicesNew , mergeTargets , & + & mergeTargetsTarget, mergeTargetsNew + + select type (self) + class is (nodeOperatorGalaxyMergerTree) + nodeTarget => node %mergesWith() + basic => node %basic () + basicTarget => nodeTarget%basic () + ! Add new records of the galaxies immediately prior to merging. + call self%record(node ) + call self%record(nodeTarget) + ! Combine the records from both galaxies. + times =basic % floatRank1MetaPropertyGet(self% timeID) + timesMerge =basic % floatRank1MetaPropertyGet(self% timeMergeID) + nodeIndices =basic %longIntegerRank1MetaPropertyGet(self% nodeIndexID) + mergeIndices =basic %longIntegerRank1MetaPropertyGet(self% mergeIndexID) + mergeTargets =basic %longIntegerRank1MetaPropertyGet(self%mergeTargetID) + counts =basic %longIntegerRank1MetaPropertyGet(self% countID) + properties =basic % floatRank1MetaPropertyGet(self% propertyID) + timesTarget =basicTarget% floatRank1MetaPropertyGet(self% timeID) + timesMergeTarget =basicTarget% floatRank1MetaPropertyGet(self% timeMergeID) + nodeIndicesTarget =basicTarget%longIntegerRank1MetaPropertyGet(self% nodeIndexID) + mergeIndicesTarget=basicTarget%longIntegerRank1MetaPropertyGet(self% mergeIndexID) + mergeTargetsTarget=basicTarget%longIntegerRank1MetaPropertyGet(self%mergeTargetID) + countsTarget =basicTarget%longIntegerRank1MetaPropertyGet(self %countID) + propertiesTarget =basicTarget% floatRank1MetaPropertyGet(self% propertyID) + allocate(timesNew (size(times )+size(timesTarget ) )) + allocate(nodeIndicesNew (size(nodeIndices )+size(nodeIndicesTarget ) )) + allocate(countsNew (size(counts )+size(countsTarget ) )) + allocate(propertiesNew (size(properties )+size(propertiesTarget ) )) + allocate(mergeIndicesNew(size(mergeIndices)+size(mergeIndicesTarget)+1)) + allocate(mergeTargetsNew(size(mergeTargets)+size(mergeTargetsTarget)+1)) + allocate(timesMergeNew (size(timesMerge )+size(timesMergeTarget )+1)) + timesNew (1:size(times ))=times ; timesNew (size(times )+1:size(timesNew ) )=timesTarget + propertiesNew (1:size(properties ))=properties ; propertiesNew (size(properties )+1:size(propertiesNew ) )=propertiesTarget + nodeIndicesNew (1:size(nodeIndices ))=nodeIndices ; nodeIndicesNew (size(nodeIndices )+1:size(nodeIndicesNew ) )=nodeIndicesTarget + countsNew (1:size(counts ))=counts ; countsNew (size(counts )+1:size(countsNew ) )=countsTarget + timesMergeNew (1:size(timesMerge ))=timesMerge ; timesMergeNew (size(timesMerge )+1:size(timesMergeNew )-1)=timesMergeTarget ; timesMergeNew (size(timesMergeNew ))=basicTarget%time ( ) + mergeIndicesNew(1:size(mergeIndices))=mergeIndices; mergeIndicesNew(size(mergeIndices)+1:size(mergeIndicesNew)-1)=mergeIndicesTarget; mergeIndicesNew(size(mergeIndicesNew))=basic %longIntegerRank0MetaPropertyGet(self%uniqueIDBranchTipID) + mergeTargetsNew(1:size(mergeTargets))=mergeTargets; mergeTargetsNew(size(mergeTargets)+1:size(mergeTargetsNew)-1)=mergeTargetsTarget; mergeTargetsNew(size(mergeTargetsNew))=basicTarget%longIntegerRank0MetaPropertyGet(self%uniqueIDBranchTipID) + call basicTarget%longIntegerRank1MetaPropertySet(self%nodeIndexID ,nodeIndicesNew ) + call basicTarget%longIntegerRank1MetaPropertySet(self%countID ,countsNew ) + call basicTarget% floatRank1MetaPropertySet(self%propertyID ,propertiesNew ) + call basicTarget% floatRank1MetaPropertySet(self%timeID ,timesNew ) + call basicTarget% floatRank1MetaPropertySet(self%timeMergeID ,timesMergeNew ) + call basicTarget%longIntegerRank1MetaPropertySet(self%mergeIndexID ,mergeIndicesNew) + call basicTarget%longIntegerRank1MetaPropertySet(self%mergeTargetID,mergeTargetsNew) + class default + call Error_Report('incorrect class'//{introspection:location}) + end select + return + end subroutine satelliteMerger + + subroutine galaxyMergerTreeDeepCopy(self,destination) + !!{ + Deep copy a {\normalfont \ttfamily nodeOperatorGalaxyMergerTree} object. + !!} + use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount, nodePropertyExtractorGalaxyMergerTree_ + implicit none + class (nodeOperatorGalaxyMergerTree), intent(inout), target :: self + class (nodeOperatorClass ), intent(inout) :: destination + type (multiExtractorList ), pointer :: extractor_ + integer :: i + + call self%deepCopy_(destination) + select type (destination) + class is (nodeOperatorGalaxyMergerTree) + nodePropertyExtractorGalaxyMergerTreeCount=destination%countExtractors + allocate(nodePropertyExtractorGalaxyMergerTree_(destination%countExtractors)) + extractor_ => self %extractors + i = 0 + do while (associated(extractor_)) + i = i +1 + nodePropertyExtractorGalaxyMergerTree_(i)%extractor_ => extractor_%extractor_ + extractor_ => extractor_%next + end do + end select + return + end subroutine galaxyMergerTreeDeepCopy diff --git a/source/nodes.property_extractor.galaxy_merger_tree.F90 b/source/nodes.property_extractor.galaxy_merger_tree.F90 new file mode 100644 index 0000000000..394281a481 --- /dev/null +++ b/source/nodes.property_extractor.galaxy_merger_tree.F90 @@ -0,0 +1,104 @@ +!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, +!! 2019, 2020, 2021, 2022, 2023, 2024 +!! 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 . + + !!{ + Implements a node property extractor class that combines all extractors needed for building galaxy merger trees. + !!} + + public :: nodePropertyExtractorGalaxyMergerTreeSet + + !![ + + An output extractor property extractor class that combines all extractors needed for building galaxy merger trees. + + !!] + type, extends(nodePropertyExtractorMulti) :: nodePropertyExtractorGalaxyMergerTree + !!{ + An output extractor property extractor class that combines all extractors needed for building galaxy merger trees. + !!} + private + end type nodePropertyExtractorGalaxyMergerTree + + interface nodePropertyExtractorGalaxyMergerTree + !!{ + Constructors for the ``galaxyMergerTree'' output extractor class. + !!} + module procedure galaxyMergerTreeConstructorParameters + module procedure galaxyMergerTreeConstructorInternal + end interface nodePropertyExtractorGalaxyMergerTree + +contains + + function galaxyMergerTreeConstructorParameters(parameters) result(self) + !!{ + Constructor for the ``galaxyMergerTree'' output extractor property extractor class which takes a parameter set as input. + !!} + use :: Input_Parameters, only : inputParameters + implicit none + type(nodePropertyExtractorGalaxyMergerTree) :: self + type(inputParameters ), intent(inout) :: parameters + + self=nodePropertyExtractorGalaxyMergerTree() + !![ + + !!] + return + end function galaxyMergerTreeConstructorParameters + + function galaxyMergerTreeConstructorInternal() result(self) + !!{ + Internal constructor for the ``galaxyMergerTree'' output extractor property extractor class. + !!} + implicit none + type (nodePropertyExtractorGalaxyMergerTree) :: self + + allocate(self%extractors ) + allocate(self%extractors%next ) + allocate(self%extractors%next%next ) + allocate(self%extractors%next%next%next) + allocate(nodePropertyExtractorGalaxyMergerTreeIndices :: self%extractors %extractor_) + allocate(nodePropertyExtractorGalaxyMergerTreePhysical :: self%extractors%next %extractor_) + allocate(nodePropertyExtractorGalaxyMergerTreeMergerIndices :: self%extractors%next%next %extractor_) + allocate(nodePropertyExtractorGalaxyMergerTreeMergerPhysical :: self%extractors%next%next%next%extractor_) + select type(extractor_ => self%extractors %extractor_) + type is (nodePropertyExtractorGalaxyMergerTreeIndices ) + !![ + + !!] + end select + select type(extractor_ => self%extractors%next %extractor_) + type is (nodePropertyExtractorGalaxyMergerTreePhysical ) + !![ + + !!] + end select + select type(extractor_ => self%extractors%next%next %extractor_) + type is (nodePropertyExtractorGalaxyMergerTreeMergerIndices ) + !![ + + !!] + end select + select type(extractor_ => self%extractors%next%next%next%extractor_) + type is (nodePropertyExtractorGalaxyMergerTreeMergerPhysical) + !![ + + !!] + end select + return + end function galaxyMergerTreeConstructorInternal diff --git a/source/nodes.property_extractor.galaxy_merger_tree.indices.F90 b/source/nodes.property_extractor.galaxy_merger_tree.indices.F90 new file mode 100644 index 0000000000..5005ddf485 --- /dev/null +++ b/source/nodes.property_extractor.galaxy_merger_tree.indices.F90 @@ -0,0 +1,158 @@ +!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, +!! 2019, 2020, 2021, 2022, 2023, 2024 +!! 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 . + + !![ + + + A node property extractor which extracts the indices properties of galaxy merger trees. + + + !!] + type, extends(nodePropertyExtractorIntegerList) :: nodePropertyExtractorGalaxyMergerTreeIndices + !!{ + A property extractor which extracts the indices properties of galaxy merger trees. + !!} + private + integer :: nodeIndexID, countID + contains + procedure :: elementCount => galaxyMergerTreeIndicesElementCount + procedure :: extract => galaxyMergerTreeIndicesExtract + procedure :: names => galaxyMergerTreeIndicesNames + procedure :: descriptions => galaxyMergerTreeIndicesDescriptions + procedure :: unitsInSI => galaxyMergerTreeIndicesUnitsInSI + end type nodePropertyExtractorGalaxyMergerTreeIndices + + interface nodePropertyExtractorGalaxyMergerTreeIndices + !!{ + Constructors for the ``galaxyMergerTreeIndices'' output extractor class. + !!} + module procedure galaxyMergerTreeIndicesConstructorParameters + module procedure galaxyMergerTreeIndicesConstructorInternal + end interface nodePropertyExtractorGalaxyMergerTreeIndices + +contains + + function galaxyMergerTreeIndicesConstructorParameters(parameters) result(self) + !!{ + Constructor for the ``galaxyMergerTreeIndices'' property extractor class which takes a parameter set as input. + !!} + use :: Input_Parameters, only : inputParameter, inputParameters + implicit none + type(nodePropertyExtractorGalaxyMergerTreeIndices) :: self + type(inputParameters ), intent(inout) :: parameters + + self=nodePropertyExtractorGalaxyMergerTreeIndices() + !![ + + !!] + return + end function galaxyMergerTreeIndicesConstructorParameters + + function galaxyMergerTreeIndicesConstructorInternal() result(self) + !!{ + Internal constructor for the ``galaxyMergerTreeIndices'' output extractor property extractor class. + !!} + implicit none + type(nodePropertyExtractorGalaxyMergerTreeIndices) :: self + + !![ + + + !!] + return + end function galaxyMergerTreeIndicesConstructorInternal + + integer function galaxyMergerTreeIndicesElementCount(self) + !!{ + Return a count of the number of properties extracted. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeIndices), intent(inout) :: self + + galaxyMergerTreeIndicesElementCount=2 + return + end function galaxyMergerTreeIndicesElementCount + + function galaxyMergerTreeIndicesExtract(self,node,instance) result(galaxyMergerTree) + !!{ + Implement a galaxyMergerTreeIndices output extractor. + !!} + use :: Galacticus_Nodes, only : nodeComponentBasic + implicit none + integer(kind_int8 ), dimension(:,:), allocatable :: galaxyMergerTree + class (nodePropertyExtractorGalaxyMergerTreeIndices), intent(inout) :: self + type (treeNode ), intent(inout) :: node + type (multiCounter ), intent(inout) , optional :: instance + class (nodeComponentBasic ) , pointer :: basic + integer(kind_int8 ), dimension(: ), allocatable :: nodeIndices , counts + !$GLC attributes unused :: instance + !$GLC attributes initialized :: nodeIndices, counts + + basic => node %basic ( ) + nodeIndices = basic%longIntegerRank1MetaPropertyGet(self%nodeIndexID) + counts = basic%longIntegerRank1MetaPropertyGet(self% countID) + allocate(galaxyMergerTree(size(nodeIndices),2)) + galaxyMergerTree(:,1)=nodeIndices + galaxyMergerTree(:,2)=counts + return + end function galaxyMergerTreeIndicesExtract + + subroutine galaxyMergerTreeIndicesNames(self,names) + !!{ + Return the names of the {\normalfont \ttfamily galaxyMergerTreeIndices} properties. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeIndices), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:) , allocatable :: names + !$GLC attributes unused :: self + + allocate(names(2)) + names(1)=var_str('galaxyMergerTreeNodeIndex') + names(2)=var_str('galaxyMergerTreeCount' ) + return + end subroutine galaxyMergerTreeIndicesNames + + subroutine galaxyMergerTreeIndicesDescriptions(self,descriptions) + !!{ + Return the descriptions of the {\normalfont \ttfamily galaxyMergerTreeIndices} properties. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeIndices), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:) , allocatable :: descriptions + !$GLC attributes unused :: self + + allocate(descriptions(2)) + descriptions(1)=var_str('Galaxy merger tree node indices.' ) + descriptions(2)=var_str('Galaxy merger tree sample time counts.') + return + end subroutine galaxyMergerTreeIndicesDescriptions + + function galaxyMergerTreeIndicesUnitsInSI(self) result(unitsInSI) + !!{ + Return the units of the {\normalfont \ttfamily galaxyMergerTreeIndices} properties in the SI system. + !!} + implicit none + double precision , dimension(:) , allocatable :: unitsInSI + class (nodePropertyExtractorGalaxyMergerTreeIndices), intent(inout) :: self + !$GLC attributes unused :: self + + allocate(unitsInSI(2)) + unitsInSI=0.0d0 + return + end function galaxyMergerTreeIndicesUnitsInSI diff --git a/source/nodes.property_extractor.galaxy_merger_tree.merger_indices.F90 b/source/nodes.property_extractor.galaxy_merger_tree.merger_indices.F90 new file mode 100644 index 0000000000..ac0f648edf --- /dev/null +++ b/source/nodes.property_extractor.galaxy_merger_tree.merger_indices.F90 @@ -0,0 +1,158 @@ +!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, +!! 2019, 2020, 2021, 2022, 2023, 2024 +!! 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 . + + !![ + + + A node property extractor which extracts the merger indices properties of galaxy merger trees. + + + !!] + type, extends(nodePropertyExtractorIntegerList) :: nodePropertyExtractorGalaxyMergerTreeMergerIndices + !!{ + A property extractor which extracts the merger indices properties of galaxy merger trees. + !!} + private + integer :: mergeIndexID, mergeTargetID + contains + procedure :: elementCount => galaxyMergerTreeMergerIndicesElementCount + procedure :: extract => galaxyMergerTreeMergerIndicesExtract + procedure :: names => galaxyMergerTreeMergerIndicesNames + procedure :: descriptions => galaxyMergerTreeMergerIndicesDescriptions + procedure :: unitsInSI => galaxyMergerTreeMergerIndicesUnitsInSI + end type nodePropertyExtractorGalaxyMergerTreeMergerIndices + + interface nodePropertyExtractorGalaxyMergerTreeMergerIndices + !!{ + Constructors for the ``galaxyMergerTreeMergerIndices'' output extractor class. + !!} + module procedure galaxyMergerTreeMergerIndicesConstructorParameters + module procedure galaxyMergerTreeMergerIndicesConstructorInternal + end interface nodePropertyExtractorGalaxyMergerTreeMergerIndices + +contains + + function galaxyMergerTreeMergerIndicesConstructorParameters(parameters) result(self) + !!{ + Constructor for the ``galaxyMergerTreeMergerIndices'' property extractor class which takes a parameter set as input. + !!} + use :: Input_Parameters, only : inputParameter, inputParameters + implicit none + type(nodePropertyExtractorGalaxyMergerTreeMergerIndices) :: self + type(inputParameters ), intent(inout) :: parameters + + self=nodePropertyExtractorGalaxyMergerTreeMergerIndices() + !![ + + !!] + return + end function galaxyMergerTreeMergerIndicesConstructorParameters + + function galaxyMergerTreeMergerIndicesConstructorInternal() result(self) + !!{ + Internal constructor for the ``galaxyMergerTreeMergerIndices'' output extractor property extractor class. + !!} + implicit none + type(nodePropertyExtractorGalaxyMergerTreeMergerIndices) :: self + + !![ + + + !!] + return + end function galaxyMergerTreeMergerIndicesConstructorInternal + + integer function galaxyMergerTreeMergerIndicesElementCount(self) + !!{ + Return a count of the number of properties extracted. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeMergerIndices), intent(inout) :: self + + galaxyMergerTreeMergerIndicesElementCount=2 + return + end function galaxyMergerTreeMergerIndicesElementCount + + function galaxyMergerTreeMergerIndicesExtract(self,node,instance) result(galaxyMergerTree) + !!{ + Implement a galaxyMergerTreeMergerIndices output extractor. + !!} + use :: Galacticus_Nodes, only : nodeComponentBasic + implicit none + integer(kind_int8 ), dimension(:,:), allocatable :: galaxyMergerTree + class (nodePropertyExtractorGalaxyMergerTreeMergerIndices), intent(inout) :: self + type (treeNode ), intent(inout) :: node + type (multiCounter ), intent(inout) , optional :: instance + class (nodeComponentBasic ) , pointer :: basic + integer(kind_int8 ), dimension(: ), allocatable :: mergeIndices , mergeTargets + !$GLC attributes unused :: instance + !$GLC attributes initialized :: mergeIndices, mergeTargets + + basic => node %basic ( ) + mergeIndices = basic%longIntegerRank1MetaPropertyGet(self% mergeIndexID) + mergeTargets = basic%longIntegerRank1MetaPropertyGet(self%mergeTargetID) + allocate(galaxyMergerTree(size(mergeIndices),2)) + galaxyMergerTree(:,1)=mergeIndices + galaxyMergerTree(:,2)=mergeTargets + return + end function galaxyMergerTreeMergerIndicesExtract + + subroutine galaxyMergerTreeMergerIndicesNames(self,names) + !!{ + Return the names of the {\normalfont \ttfamily galaxyMergerTreeMergerIndices} properties. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeMergerIndices), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:) , allocatable :: names + !$GLC attributes unused :: self + + allocate(names(2)) + names(1)=var_str('galaxyMergerTreeMergeSatelliteIndex') + names(2)=var_str('galaxyMergerTreeMergeCentralIndex' ) + return + end subroutine galaxyMergerTreeMergerIndicesNames + + subroutine galaxyMergerTreeMergerIndicesDescriptions(self,descriptions) + !!{ + Return the descriptions of the {\normalfont \ttfamily galaxyMergerTreeMergerIndices} properties. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeMergerIndices), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:) , allocatable :: descriptions + !$GLC attributes unused :: self + + allocate(descriptions(2)) + descriptions(1)=var_str('Galaxy merger tree merging satellite indices.') + descriptions(2)=var_str('Galaxy merger tree merging central indices.' ) + return + end subroutine galaxyMergerTreeMergerIndicesDescriptions + + function galaxyMergerTreeMergerIndicesUnitsInSI(self) result(unitsInSI) + !!{ + Return the units of the {\normalfont \ttfamily galaxyMergerTreeMergerIndices} properties in the SI system. + !!} + implicit none + double precision , dimension(:) , allocatable :: unitsInSI + class (nodePropertyExtractorGalaxyMergerTreeMergerIndices), intent(inout) :: self + !$GLC attributes unused :: self + + allocate(unitsInSI(2)) + unitsInSI=0.0d0 + return + end function galaxyMergerTreeMergerIndicesUnitsInSI diff --git a/source/nodes.property_extractor.galaxy_merger_tree.merger_physical.F90 b/source/nodes.property_extractor.galaxy_merger_tree.merger_physical.F90 new file mode 100644 index 0000000000..92011e1438 --- /dev/null +++ b/source/nodes.property_extractor.galaxy_merger_tree.merger_physical.F90 @@ -0,0 +1,154 @@ +!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, +!! 2019, 2020, 2021, 2022, 2023, 2024 +!! 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 . + + !![ + + + A node property extractor which extracts the physical properties of galaxy merger trees. + + + !!] + type, extends(nodePropertyExtractorList) :: nodePropertyExtractorGalaxyMergerTreeMergerPhysical + !!{ + A property extractor which extracts the physical properties of galaxy merger trees. + !!} + private + integer :: timeMergeID + contains + procedure :: elementCount => galaxyMergerTreeMergerPhysicalElementCount + procedure :: extract => galaxyMergerTreeMergerPhysicalExtract + procedure :: names => galaxyMergerTreeMergerPhysicalNames + procedure :: descriptions => galaxyMergerTreeMergerPhysicalDescriptions + procedure :: unitsInSI => galaxyMergerTreeMergerPhysicalUnitsInSI + end type nodePropertyExtractorGalaxyMergerTreeMergerPhysical + + interface nodePropertyExtractorGalaxyMergerTreeMergerPhysical + !!{ + Constructors for the ``galaxyMergerTreeMergerPhysical'' output extractor class. + !!} + module procedure galaxyMergerTreeMergerPhysicalConstructorParameters + module procedure galaxyMergerTreeMergerPhysicalConstructorInternal + end interface nodePropertyExtractorGalaxyMergerTreeMergerPhysical + +contains + + function galaxyMergerTreeMergerPhysicalConstructorParameters(parameters) result(self) + !!{ + Constructor for the ``galaxyMergerTreeMergerPhysical'' property extractor class which takes a parameter set as input. + !!} + use :: Input_Parameters, only : inputParameter, inputParameters + implicit none + type(nodePropertyExtractorGalaxyMergerTreeMergerPhysical) :: self + type(inputParameters ), intent(inout) :: parameters + + self=nodePropertyExtractorGalaxyMergerTreeMergerPhysical() + !![ + + !!] + return + end function galaxyMergerTreeMergerPhysicalConstructorParameters + + function galaxyMergerTreeMergerPhysicalConstructorInternal() result(self) + !!{ + Internal constructor for the ``galaxyMergerTreeMergerPhysical'' output extractor property extractor class. + !!} + implicit none + type(nodePropertyExtractorGalaxyMergerTreeMergerPhysical) :: self + + !![ + + !!] + return + end function galaxyMergerTreeMergerPhysicalConstructorInternal + + integer function galaxyMergerTreeMergerPhysicalElementCount(self) + !!{ + Return a count of the number of properties extracted. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeMergerPhysical), intent(inout) :: self + + galaxyMergerTreeMergerPhysicalElementCount=1 + return + end function galaxyMergerTreeMergerPhysicalElementCount + + function galaxyMergerTreeMergerPhysicalExtract(self,node,instance) result(galaxyMergerTree) + !!{ + Implement a galaxyMergerTreeMergerPhysical output extractor. + !!} + use :: Galacticus_Nodes, only : nodeComponentBasic + implicit none + double precision , dimension(:,:), allocatable :: galaxyMergerTree + class (nodePropertyExtractorGalaxyMergerTreeMergerPhysical), intent(inout) :: self + type (treeNode ), intent(inout) :: node + type (multiCounter ), intent(inout) , optional :: instance + class (nodeComponentBasic ) , pointer :: basic + double precision , dimension(: ), allocatable :: timesMerge + !$GLC attributes unused :: instance + !$GLC attributes initialized :: timesMerge + + basic => node %basic ( ) + timesMerge = basic%floatRank1MetaPropertyGet(self%timeMergeID) + allocate(galaxyMergerTree(size(timesMerge),1)) + galaxyMergerTree(:,1)=timesMerge + return + end function galaxyMergerTreeMergerPhysicalExtract + + subroutine galaxyMergerTreeMergerPhysicalNames(self,names) + !!{ + Return the names of the {\normalfont \ttfamily galaxyMergerTreeMergerPhysical} properties. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeMergerPhysical), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:) , allocatable :: names + !$GLC attributes unused :: self + + allocate(names(1)) + names(1)=var_str('galaxyMergerTreeMergeTime' ) + return + end subroutine galaxyMergerTreeMergerPhysicalNames + + subroutine galaxyMergerTreeMergerPhysicalDescriptions(self,descriptions) + !!{ + Return the descriptions of the {\normalfont \ttfamily galaxyMergerTreeMergerPhysical} properties. + !!} + implicit none + class(nodePropertyExtractorGalaxyMergerTreeMergerPhysical), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:) , allocatable :: descriptions + !$GLC attributes unused :: self + + allocate(descriptions(1)) + descriptions(1)=var_str('Merger times in the galaxy merger tree.') + return + end subroutine galaxyMergerTreeMergerPhysicalDescriptions + + function galaxyMergerTreeMergerPhysicalUnitsInSI(self) result(unitsInSI) + !!{ + Return the units of the {\normalfont \ttfamily galaxyMergerTreeMergerPhysical} properties in the SI system. + !!} + use :: Numerical_Constants_Astronomical, only : gigaYear, massSolar + implicit none + double precision , dimension(:) , allocatable :: unitsInSI + class (nodePropertyExtractorGalaxyMergerTreeMergerPhysical), intent(inout) :: self + !$GLC attributes unused :: self + + allocate(unitsInSI(1)) + unitsInSI(1)=gigaYear + return + end function galaxyMergerTreeMergerPhysicalUnitsInSI diff --git a/source/nodes.property_extractor.galaxy_merger_tree.objects.F90 b/source/nodes.property_extractor.galaxy_merger_tree.objects.F90 new file mode 100644 index 0000000000..fbc75abadc --- /dev/null +++ b/source/nodes.property_extractor.galaxy_merger_tree.objects.F90 @@ -0,0 +1,44 @@ +!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, +!! 2019, 2020, 2021, 2022, 2023, 2024 +!! 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 . + + !!{ + Provides a module storing object references needed for galaxy merger trees. + !!} + + module Node_Property_Extractor_Galaxy_Merger_Trees + !!{ + A module storing object references needed for galaxy merger trees. + !!} + private + + ! NOTE: This is an unpleasant solution - essentially functioning as a communicator between the relevant `nodeOperator` and + ! `nodePropertyExtractor` classes. It is necessitated by the fact that we don't have a good way for objects defined in the + ! parameter file to communicate their behavior. + + type, public :: nodePropertyExtractorList + class(*), pointer :: extractor_ => null() + end type nodePropertyExtractorList + + ! Public-scope pointer to the extractor used in galaxy merger trees. + integer , public :: nodePropertyExtractorGalaxyMergerTreeCount + type (nodePropertyExtractorList), allocatable, dimension(:), public :: nodePropertyExtractorGalaxyMergerTree_ + !$omp threadprivate(nodePropertyExtractorGalaxyMergerTreeCount,nodePropertyExtractorGalaxyMergerTree_) + + end module Node_Property_Extractor_Galaxy_Merger_Trees + diff --git a/source/nodes.property_extractor.galaxy_merger_tree.physical.F90 b/source/nodes.property_extractor.galaxy_merger_tree.physical.F90 new file mode 100644 index 0000000000..7f92654dff --- /dev/null +++ b/source/nodes.property_extractor.galaxy_merger_tree.physical.F90 @@ -0,0 +1,207 @@ +!! Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, +!! 2019, 2020, 2021, 2022, 2023, 2024 +!! 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 . + + !![ + + + A node property extractor which extracts the physical properties of galaxy merger trees. + + + !!] + type, extends(nodePropertyExtractorList) :: nodePropertyExtractorGalaxyMergerTreePhysical + !!{ + A property extractor which extracts the physical properties of galaxy merger trees. + !!} + private + integer :: timeID, propertyID + contains + procedure :: elementCount => galaxyMergerTreePhysicalElementCount + procedure :: extract => galaxyMergerTreePhysicalExtract + procedure :: names => galaxyMergerTreePhysicalNames + procedure :: descriptions => galaxyMergerTreePhysicalDescriptions + procedure :: unitsInSI => galaxyMergerTreePhysicalUnitsInSI + end type nodePropertyExtractorGalaxyMergerTreePhysical + + interface nodePropertyExtractorGalaxyMergerTreePhysical + !!{ + Constructors for the ``galaxyMergerTreePhysical'' output extractor class. + !!} + module procedure galaxyMergerTreePhysicalConstructorParameters + module procedure galaxyMergerTreePhysicalConstructorInternal + end interface nodePropertyExtractorGalaxyMergerTreePhysical + +contains + + function galaxyMergerTreePhysicalConstructorParameters(parameters) result(self) + !!{ + Constructor for the ``galaxyMergerTreePhysical'' property extractor class which takes a parameter set as input. + !!} + use :: Input_Parameters, only : inputParameter, inputParameters + implicit none + type(nodePropertyExtractorGalaxyMergerTreePhysical) :: self + type(inputParameters ), intent(inout) :: parameters + + self=nodePropertyExtractorGalaxyMergerTreePhysical() + !![ + + !!] + return + end function galaxyMergerTreePhysicalConstructorParameters + + function galaxyMergerTreePhysicalConstructorInternal() result(self) + !!{ + Internal constructor for the ``galaxyMergerTreePhysical'' output extractor property extractor class. + !!} + implicit none + type(nodePropertyExtractorGalaxyMergerTreePhysical) :: self + + !![ + + + !!] + return + end function galaxyMergerTreePhysicalConstructorInternal + + integer function galaxyMergerTreePhysicalElementCount(self) + !!{ + Return a count of the number of properties extracted. + !!} + use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount + implicit none + class(nodePropertyExtractorGalaxyMergerTreePhysical), intent(inout) :: self + + galaxyMergerTreePhysicalElementCount=1+nodePropertyExtractorGalaxyMergerTreeCount + return + end function galaxyMergerTreePhysicalElementCount + + function galaxyMergerTreePhysicalExtract(self,node,instance) result(galaxyMergerTree) + !!{ + Implement a galaxyMergerTreePhysical output extractor. + !!} + use :: Galacticus_Nodes , only : nodeComponentBasic + use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount, nodePropertyExtractorGalaxyMergerTree_ + implicit none + double precision , dimension(:,:), allocatable :: galaxyMergerTree + class (nodePropertyExtractorGalaxyMergerTreePhysical), intent(inout) :: self + type (treeNode ), intent(inout) :: node + type (multiCounter ), intent(inout) , optional :: instance + class (nodeComponentBasic ) , pointer :: basic + double precision , dimension(: ), allocatable :: times , properties + integer :: i , j + !$GLC attributes unused :: instance + !$GLC attributes initialized :: times, properties + + basic => node %basic ( ) + times = basic%floatRank1MetaPropertyGet(self% timeID) + properties = basic%floatRank1MetaPropertyGet(self%propertyID) + allocate(galaxyMergerTree(size(times),1+nodePropertyExtractorGalaxyMergerTreeCount)) + galaxyMergerTree(:,1)=times + do i=1,nodePropertyExtractorGalaxyMergerTreeCount + do j=1,size(times) + galaxyMergerTree(j,1+i)=properties((j-1)*nodePropertyExtractorGalaxyMergerTreeCount+i) + end do + end do + return + end function galaxyMergerTreePhysicalExtract + + subroutine galaxyMergerTreePhysicalNames(self,names) + !!{ + Return the names of the {\normalfont \ttfamily galaxyMergerTreePhysical} properties. + !!} + use :: Error , only : Error_Report + use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount, nodePropertyExtractorGalaxyMergerTree_ + use :: String_Handling , only : String_Upper_Case_First + implicit none + class (nodePropertyExtractorGalaxyMergerTreePhysical), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:), allocatable :: names + class (* ) , pointer :: extractor_ + integer :: i + !$GLC attributes unused :: self + + allocate(names(1+nodePropertyExtractorGalaxyMergerTreeCount)) + names(1)=var_str('galaxyMergerTreeTime' ) + do i=1,nodePropertyExtractorGalaxyMergerTreeCount + extractor_ => nodePropertyExtractorGalaxyMergerTree_(i)%extractor_ + select type (extractor_) + class is (nodePropertyExtractorScalar) + names(i+1)=var_str('galaxyMergerTree')//String_Upper_Case_First(char(extractor_%name())) + class default + names(i+1)=var_str('') + call Error_Report("unexpected class"//{introspection:location}) + end select + end do + return + end subroutine galaxyMergerTreePhysicalNames + + subroutine galaxyMergerTreePhysicalDescriptions(self,descriptions) + !!{ + Return the descriptions of the {\normalfont \ttfamily galaxyMergerTreePhysical} properties. + !!} + use :: Error , only : Error_Report + use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount, nodePropertyExtractorGalaxyMergerTree_ + implicit none + class (nodePropertyExtractorGalaxyMergerTreePhysical), intent(inout) :: self + type (varying_string ), intent(inout), dimension(:) , allocatable :: descriptions + integer :: i + class (* ) , pointer :: extractor_ + !$GLC attributes unused :: self + + allocate(descriptions(1+nodePropertyExtractorGalaxyMergerTreeCount)) + descriptions(1)=var_str('Sample times in the galaxy merger tree.') + do i=1,nodePropertyExtractorGalaxyMergerTreeCount + extractor_ => nodePropertyExtractorGalaxyMergerTree_(i)%extractor_ + select type (extractor_) + class is (nodePropertyExtractorScalar) + descriptions(i+1)=var_str('Property in the galaxy merger tree: ')//extractor_%description() + class default + descriptions(i+1)=var_str('') + call Error_Report("unexpected class"//{introspection:location}) + end select + end do + return + end subroutine galaxyMergerTreePhysicalDescriptions + + function galaxyMergerTreePhysicalUnitsInSI(self) result(unitsInSI) + !!{ + Return the units of the {\normalfont \ttfamily galaxyMergerTreePhysical} properties in the SI system. + !!} + use :: Error , only : Error_Report + use :: Numerical_Constants_Astronomical , only : gigaYear + use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount, nodePropertyExtractorGalaxyMergerTree_ + implicit none + double precision , dimension(:) , allocatable :: unitsInSI + class (nodePropertyExtractorGalaxyMergerTreePhysical), intent(inout) :: self + integer :: i + class (* ) , pointer :: extractor_ + !$GLC attributes unused :: self + + allocate(unitsInSI(1+nodePropertyExtractorGalaxyMergerTreeCount)) + unitsInSI(1)=gigaYear + do i=1,nodePropertyExtractorGalaxyMergerTreeCount + extractor_ => nodePropertyExtractorGalaxyMergerTree_(i)%extractor_ + select type (extractor_) + class is (nodePropertyExtractorScalar) + unitsInSI(1+i)=extractor_%unitsInSI() + class default + unitsInSI(1+i)=0.0d0 + call Error_Report("unexpected class"//{introspection:location}) + end select + end do + return + end function galaxyMergerTreePhysicalUnitsInSI From 9075d390fd7f6f8ff7074c560405366f0ba478e3 Mon Sep 17 00:00:00 2001 From: Andrew Benson Date: Fri, 18 Oct 2024 13:42:30 -0700 Subject: [PATCH 4/5] fix: Remove unnecessary symbol import --- source/nodes.property_extractor.galaxy_merger_tree.physical.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/nodes.property_extractor.galaxy_merger_tree.physical.F90 b/source/nodes.property_extractor.galaxy_merger_tree.physical.F90 index 7f92654dff..524303c3b2 100644 --- a/source/nodes.property_extractor.galaxy_merger_tree.physical.F90 +++ b/source/nodes.property_extractor.galaxy_merger_tree.physical.F90 @@ -95,7 +95,7 @@ function galaxyMergerTreePhysicalExtract(self,node,instance) result(galaxyMerger Implement a galaxyMergerTreePhysical output extractor. !!} use :: Galacticus_Nodes , only : nodeComponentBasic - use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount, nodePropertyExtractorGalaxyMergerTree_ + use :: Node_Property_Extractor_Galaxy_Merger_Trees, only : nodePropertyExtractorGalaxyMergerTreeCount implicit none double precision , dimension(:,:), allocatable :: galaxyMergerTree class (nodePropertyExtractorGalaxyMergerTreePhysical), intent(inout) :: self From da106bfeda8f64215a78b14fe305454431edcefd Mon Sep 17 00:00:00 2001 From: Andrew Benson Date: Fri, 18 Oct 2024 13:46:23 -0700 Subject: [PATCH 5/5] fix: Ignore failures to set up `ParserDetails.ini` --- .github/actions/buildMacOS/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/buildMacOS/action.yml b/.github/actions/buildMacOS/action.yml index 72b7c68157..e672b32b5e 100644 --- a/.github/actions/buildMacOS/action.yml +++ b/.github/actions/buildMacOS/action.yml @@ -204,8 +204,8 @@ runs: if [[ "${OS_VER}" -ge 12 ]]; then # For OS versions 12 and above we need to ensure that the ParserDetails.ini is set up. sudo perl -MXML::SAX -e "XML::SAX->add_parser('XML::SAX::PurePerl')->save_parsers()" || true - sudo perl -MXML::SAX -e "XML::SAX->add_parser('XML::LibXML::SAX::Parser')->save_parsers()" - sudo perl -MXML::SAX -e "XML::SAX->add_parser('XML::LibXML::SAX')->save_parsers()" + sudo perl -MXML::SAX -e "XML::SAX->add_parser('XML::LibXML::SAX::Parser')->save_parsers()" || true + sudo perl -MXML::SAX -e "XML::SAX->add_parser('XML::LibXML::SAX')->save_parsers()" || true fi sudo perl -MCPAN -e 'force("install","XML::SAX::ParserFactory")' sudo perl -MCPAN -e 'force("install","XML::Validator::Schema")'