Skip to content

Commit

Permalink
Merge pull request #43 from lowderchris/parallelized-wind-script
Browse files Browse the repository at this point in the history
Parallelized wind script
  • Loading branch information
lowderchris authored Oct 26, 2023
2 parents 32a5d72 + c0ae772 commit f7b68a7
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 388 deletions.
223 changes: 166 additions & 57 deletions pdl/PDL/map_fluxon_flow.pdl
Original file line number Diff line number Diff line change
@@ -1,88 +1,197 @@
=head1 NAME

Fluxon Flow Mapper - Parallelized Solar Wind Flow Mapping Along Fluxon Structures

=cut

use strict;
use warnings;
use PDL;
use PDL::NiceSlice;
use PDL::Options;
use Parallel::ForkManager;
use PDL::IO::Storable;
use File::Path qw(make_path);
use Time::HiRes qw(clock_gettime);
use Data::Dumper;

=head2 map_fluxon_flow
# Control Flags
$PDL::verbose = 0;

=head1 DESCRIPTION

This Perl module provides functionality to map the solar wind flow along fluxon structures in a parallelized manner. It uses the Parallel::ForkManager library to manage concurrent processes and PDL (Perl Data Language) for numerical computations.

=head1 AUTHOR

=for ref
Gilly <[email protected]>
Chris Lowder

Given a world and list of fluxons, generates a mapping of the solar wind flow along these fluxon structures.
=head1 LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

=cut

=head2 map_fluxon_flow

=over

sub map_fluxon_flow {
my $before = clock_gettime();
=item B<Description>

my $fn = shift;
my $fluxons = shift;
my @fluxons = @{$fluxons};
Given a world and list of fluxons, this function generates a mapping of the solar wind flow along these fluxon structures. It uses parallel processing to speed up the calculations.

=item B<Parameters>

=over

=item C<$file_name>: The name of the output file where the results will be saved.

# Generate some blank storage arrays
my @fps = (); # Fluxon array position
my @phb = (); # Begining coordinates
my @thb = ();
my @phe = (); # End coordinates
my @the = ();
my @vrb = (); # Beginning and end wind velocity
my @vre = ();
my @frb = (); # Beginning and end expansion factors
my @fre = ();
my @fre2 = ();
=item C<$fluxons>: A reference to an array containing the fluxons to be mapped.

# Loop through open fluxons and generate wind profiles
for my $fid(0..scalar(@fluxons)-1){
=item C<$max_processes>: (Optional) The maximum number of parallel processes to use. Defaults to the value of C<$concurrency>.

=back

# if ($fid>0){
# print "\r", ' Calculating fluxon:', $fid, '/', scalar(@fluxons);
# }
my $me = $fluxons[$fid];
=item B<Returns>

# Check for open fieldlines
my $st_open = ($me->{fc_start}->{label}==-1);
my $en_open = ($me->{fc_end}->{label}==-2);
if ($me->{plasmoid} || ($st_open + $en_open != 1)){
The function writes the results to disk and returns nothing.

next;
}
=back

# Find the transonic wind solution
(my $farr, my $fr, my $bth, my $bph) = gen_fluxon_tflow($me);

# Append any needed values and move along home
# Note to distinguish between fluxons ends...
push(@fps, $fid);
push(@phb, squeeze($bph(0,0)));
push(@thb, squeeze($bth(0,0)));
push(@phe, squeeze($bph(0,1)));
push(@the, squeeze($bth(0,1)));
push(@vrb, $farr(1,0));
push(@vre, $farr(1,-1));
push(@frb, $fr(1,1));
push(@fre, $fr(-2,1));
push(@fre2, $fr(-1,1));
=cut

my $after = clock_gettime();
my $elapsed = $after - $before;
my $round_elapsed = rint($elapsed*10) / 10;
print "\r", ' Calculated fluxons:', $fid, '/', scalar(@fluxons), ", ", $round_elapsed, "(s) elapsed";

sub map_fluxon_flow {
my $file_name = shift;
my $fluxons = shift;
my @fluxons = @{$fluxons};
my $max_processes = shift || 6; # Set the number of parallel processes
my $highest_fid_done = 0;
my $before = clock_gettime();

# Output this data to disk
wcols pdl(@fps), pdl(@phb), pdl(@thb), pdl(@phe), pdl(@the), squeeze(pdl(@vrb)), squeeze(pdl(@vre)), squeeze(pdl(@frb)), squeeze(pdl(@fre)), squeeze(pdl(@fre2)), $fn;
my $n_choke = 12;
my $choke = 0;

# Count the number of open and closed fluxons
my $n_closed = 0;
my @open_inds = ();
my $n_open = 0;
for my $fid ( 0 .. scalar(@fluxons) - 1 ) {
## Condition the Input ####
my $me = $fluxons[$fid];

# Check for open fieldline, and skip if not
my $st_open = ( $me->{fc_start}->{label} == -1 );
my $en_open = ( $me->{fc_end}->{label} == -2 );
if ( $me->{plasmoid} || ( $st_open + $en_open != 1 ) ) {
$n_closed = $n_closed + 1;
} else {
$n_open = $n_open + 1;
push(@open_inds, $fid);
}
}

}
my $itercount = -1;
my $fork_manager = Parallel::ForkManager->new( $max_processes );

# Generate a blank storage array
my @results = ();

# Set the finish callback to update $highest_fid_done and print it
$fork_manager->run_on_finish(sub {
$itercount = $itercount + 1;
my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $result) = @_;
if ($exit_code == 0) {
push(@results, $result);
my $this_fid = $result->{fps}+1;

if ($this_fid > $highest_fid_done) {
$highest_fid_done = $this_fid;

# Print timing information
my $after = clock_gettime();
my $elapsed = $after - $before;
my $round_elapsed = rint($elapsed*10) / 10;
my $remaining = $n_open - $highest_fid_done;
my $time_each = $elapsed / $highest_fid_done;
my $time_remaining = $remaining * $time_each;
my $round_remain = rint($time_remaining*10) / 10;
my $round_minutes = rint($round_remain / 6)/10;

print "\r", "\t\t\tCalculated fluxons: ", $highest_fid_done, ' of ', $n_open, ", ", $round_elapsed, "(s) elapsed, ", $round_remain, "(s) [$round_minutes mins] remaining......";
}
}
});

my $n_tot = scalar(@fluxons);
my $n_act = 2*($n_tot - $n_open) + $n_open;
print "\n\t\tRunning with $max_processes Cores on $n_open open Fluxons out of $n_tot total Fluxons from $n_act footpoints!\n\n\t\tBeginning Calculation...\n\n";

$PDL::verbose = 0;
no warnings;

my $max_fid = scalar(@open_inds) - 1;
if ($choke){
if ($n_choke < $max_fid){
$max_fid = $n_choke;
}
}
for my $fid ( 0 .. $max_fid ) {
## Inside the Loop ##################################################
# Start a new process and proceed to the next iteration
$fork_manager->start and next;

## Condition the Input ####
my $me = $fluxons[$fid];

## Run the Main Algorithm ####
# Find the transonic wind solution
(my $farr, my $fr, my $bth, my $bph) = gen_fluxon_tflow($me);


## Report the Results ####
# Create a result hash
my $result = {
fps => $fid, # Fluxon ID
phb => squeeze( $bph ( 0, 0 ) ), # Phi at the base
thb => squeeze( $bth ( 0, 0 ) ), # Theta at the base
phe => squeeze( $bph ( 0, 1 ) ), # Phi at the end
the => squeeze( $bth ( 0, 1 ) ), # Theta at the end
vrb => $farr ( 1, 0 ), # Radial velocity at the base
vre => $farr ( 1, -1 ), # Radial velocity at the end
frb => $fr ( 1, 1 ), # flux expansion at the base
fre => $fr ( -2, 1 ), # flux expansion at the end
fre2 => $fr ( -1, 1 ), # flux expansion at the middle
};

# Finish the process and return the result
$fork_manager->finish( 0, $result );
}

# Output this data to disk
wcols pdl(@fps), pdl(@phb), pdl(@thb), pdl(@phe), pdl(@the), squeeze(pdl(@vrb)), squeeze(pdl(@vre)), squeeze(pdl(@frb)), squeeze(pdl(@fre)), squeeze(pdl(@fre2)), $fn;
## Outside of the Loop ## #############################################
$fork_manager->wait_all_children; # Wait for all processes to finish

my $after = clock_gettime();
my $elapsed = $after - $before;
my $round_elapsed = rint($elapsed*10) / 10;
print "\n\n\t\tWind Calculation Complete\n\n";
## Output the Results ##
# Sort the results by fps
@results = sort { $a->{fps} <=> $b->{fps} } @results;

# Write the results to disk
wcols pdl( map { $_->{fps} } @results ),
pdl( map { $_->{phb} } @results ),
pdl( map { $_->{thb} } @results ),
pdl( map { $_->{phe} } @results ),
pdl( map { $_->{the} } @results ),
squeeze( pdl( map { $_->{vrb} } @results ) ),
squeeze( pdl( map { $_->{vre} } @results ) ),
squeeze( pdl( map { $_->{frb} } @results ) ),
squeeze( pdl( map { $_->{fre} } @results ) ),
squeeze( pdl( map { $_->{fre2} } @results ) ),
$file_name;
}

__END__
1;
__END__
81 changes: 0 additions & 81 deletions pdl/PDL/map_fluxon_flow_parallel.pdl

This file was deleted.

Loading

0 comments on commit f7b68a7

Please sign in to comment.