in reply to Re^3: Closures and undefined subs
in thread Closures and undefined subs

The package is called from another file. $level_iii_ref will be calculated by another package in the main file or it has to call the package itself.

Theres where I tried to make local or lexicla and failed.. but of course all of the _equations_... should be "local".
sub _equation_air { my ( $args_ref, $level_iii_ref, $y ) = @_; # my $_equation_air = sub { # my $y = shift; # local *_equation_air = sub { # my $y = shift; ...
Well I hope you still that enthusiastic...
package Levels::Level_IV; #-------------------------------------------------------------- #Heading: Level_VI.pl #Author: Anonymous #Purpose: Level_VI calculations. #Usage: It's a library. Use only level_iv subroutine. #References: Don Mackay. Multimedia Environmental Models # The Fugacity Approach Second Edition #File formats: No files needed or printed. #Restrictions: Reasonal input. #Notes: This module is free software; you can redistribute it # and/or modify it under the same terms as Perl itself. #-------------------------------------------------------------- use strict; use warnings; #use diagnostics; use Carp; use Exporter; #use List::Util; use List::MoreUtils qw(zip); use Scalar::Util qw(reftype); #use Math::ODE; #Solve N-th Order (O)rdinary (D)ifferential (E)quation +s #use Math::Calculus::Differentiate; #Algebraic Differentiation Engine use Math::RungeKutta; #Runge-Kutta numeric algo. for Differential Equa +tions use Term::Clui; use FileHandle; use Smart::Comments; use Contextual::Return; use Levels::Level_III; our ( @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION ); $VERSION = 0.9; @ISA = qw(Exporter); @EXPORT = qw(level_iv); #non equilibrium unsteady-state flow system sub level_iv { my ( $args_ref, $R, $factor, $level_iii_ref ) = @_; no warnings qw(closure); #'variable will not stay shared' -> switc +hed off #see end of file for possible solution #call level_iii subroutine to generate difusivities and fugacities $level_iii_ref = level_iii($args_ref, $R, $factor) unless $level_i +ii_ref; #choose differentiation algorithm print "\n"; my $routine = choose( 'Algorithm: (use arrow keys and <Return>, or q to qu +it)', 'rk4', 'rk4_auto' ); #initialize y's for the different mediums my @y_med; INPUTY: while (1) { my @try = split m/\s*,\s*/, ask( "Initialize ya, yw, ys and yse: (separate y's with ', +')" ); if ( scalar @try < 4 ) { print "Four (4) arguments needed. Your input was: '@try'.\ +n"; redo INPUTY; } elsif ( "$try[0]$try[1]$try[2]$try[3]" !~ m/ \A \d+ \z /xms ) +{ print "Arguments are not numeric. Your input was: '@try'.\ +n"; redo INPUTY; } else { @y_med = @try; last INPUTY; } } #choose time step, starting and end time my $dt = choose( 'Time step: (use arrow keys and <Return>, or q to + quit)', '0.005', '0.01', '0.02', '0.05', '0.1', '0.2' ); my $t = 0; my $t_final = 1 / $dt; # from 0+step to 1 in that many steps #open file for printing runge-kutta-merson results open my $fh, '>', 'Level_IVa_Caculations.txt' or croak $!; $fh->autoflush(1); #Runge-Kutta-Merson 4th-order method my @iterations; my @output_merson; if ( $routine eq 'rk4_auto' ) { #choose error for the steps in auto mode. my $eps = choose( 'epsilon: (use arrow keys and <Return>, or q to +quit)', '0.000001', '0.00001', '0.0001' ); #invoke runge kutta algorithm and store calculations RK4_AUTO: for my $i ( $t..$t_final ) { ### Differentiating:... % do +ne #print initialisation if ( $i == 0 ) { printf {$fh} "i = %3d t = %16s dt = %16s ya = %20s + " . "yw = %20s ys = %20s yse = %20s\n", $i, $t, $d +t, $y_med[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med +[3] ]; next RK4_AUTO; } #begin calculations after initial print ( $t, $dt, @y_med ) = rk4_auto( \@y_med, \&_dydt, $t, $dt, + $eps ); printf {$fh} "i = %3d t = %16s dt = %16s ya = %20s yw += %20s" . " ys = %20s yse = %20s\n", $i, $t, $dt, $y_med +[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med[3] +]; } } else { #invoke runge kutta algorithm and store calculations RK4: for my $i ( $t..$t_final ) { ### Differentiating:... % do +ne #print initialisation if ( $i == 0 ) { printf {$fh} "i = %3d t = %.3f dt = %.3f ya = %20s + " . "yw = %20s ys = %20s yse = %20s\n", $i, $t, $d +t, $y_med[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med +[3] ]; next RK4; } #begin calculations after initial print ( $t, @y_med ) = rk4( \@y_med, \&_dydt, $t, $dt ); printf {$fh} "i = %3d t = %.3f dt = %.3f ya = %20s yw += %20s" . " ys = %20s yse = %20s\n", $i, $t, $dt, $y_med +[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med[3] +]; } } print "File Level_IVa_Caculations.txt written.\n"; close $fh or croak $!; #_equation and _dydt_* have to be declared in the main routine or +they #would not have access to the $args_ref and $level_iii_ref (closur +es) #level_iv '_equation' for mass is used as helper equation in dydt +function sub _equation_air { my ( $args_ref, $level_iii_ref, $y ) = @_; # my $_equation_air = sub { # my $y = shift; # local *_equation_air = sub { # my $y = shift; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Ea'} and exists $args_ref->{'-Ga'} and exists $args_ref->{'-Cba'} and exists $args_ref->{'-Va'} and exists $args_ref->{'-Za'} ) { $Ei = $args_ref->{'-Ea'}; $Gi = $args_ref->{'-Ga'}; $Cbi = $args_ref->{'-Cba'}; $Vi = $args_ref->{'-Va'}; $Zi = $args_ref->{'-Za'}; } else { croak "No parameter '-Ea', '-Ga', '-Cba', '-Va' or '-Za' f +ound. " . "Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'air'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; }; #helper _equation for water medium/compartment sub _equation_water { my ( $args_ref, $level_iii_ref, $y ) = @_; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Ew'} and exists $args_ref->{'-Gw'} and exists $args_ref->{'-Cbw'} and exists $args_ref->{'-Vw'} and exists $args_ref->{'-Zw'} ) { $Ei = $args_ref->{'-Ew'}; $Gi = $args_ref->{'-Gw'}; $Cbi = $args_ref->{'-Cbw'}; $Vi = $args_ref->{'-Vw'}; $Zi = $args_ref->{'-Zw'}; } else { croak "No parameter '-Ew', '-Gw', '-Cbw', '-Vw' or '-Zw' f +ound. " . "Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'water'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; } #helper _equation for soil medium/compartment sub _equation_soil { my ( $args_ref, $level_iii_ref, $y ) = @_; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Es'} and exists $args_ref->{'-Gs'} and exists $args_ref->{'-Cbs'} and exists $args_ref->{'-Vs'} and exists $args_ref->{'-Zs'} ) { $Ei = $args_ref->{'-Es'}; $Gi = $args_ref->{'-Gs'}; $Cbi = $args_ref->{'-Cbs'}; $Vi = $args_ref->{'-Vs'}; $Zi = $args_ref->{'-Zs'}; } else { croak "No parameter '-Es', '-Gs', '-Cbs', '-Vs' or '-Zs' f +ound. " . "Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'soil'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; } #helper _equation for sediment medium/compartment sub _equation_sediment { my ( $args_ref, $level_iii_ref, $y ) = @_; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Ese'} and exists $args_ref->{'-Gse'} and exists $args_ref->{'-Cbse'} and exists $args_ref->{'-Vse'} and exists $args_ref->{'-Zse'} ) { $Ei = $args_ref->{'-Ese'}; $Gi = $args_ref->{'-Gse'}; $Cbi = $args_ref->{'-Cbse'}; $Vi = $args_ref->{'-Vse'}; $Zi = $args_ref->{'-Zse'}; } else { croak "No parameter '-Ese', '-Ges', '-Cbse', '-Vse' or '-Z +se' " . "found. Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'sediment'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; } #differential equation for fugacity at start and end times sub _dydt { my ( $t, @y ) = @_; my @dydt; #e.g.: dy/dt = 4 -> y'(t) = 4 -> y(t) = 4t #two different stating points are accepted in this implementat +ion #so two different starting scenarios can be calculated in orde +r to #show how the system runs against a boundary and balances itse +lf #start differentiation at point y0 (air) $dydt[0] = _equation_air( $args_ref, $level_iii_ref, $y[0] ); #$dydt[0] = _equation_air($y[0]); #local #$dydt[0] = $_equation_air->($y[0]);#lexical #start again at a different point y1 (water) $dydt[1] = _equation_water( $args_ref, $level_iii_ref, $y[1] ) +; #start again at a different point y2 (soil) $dydt[2] = _equation_soil( $args_ref, $level_iii_ref, $y[2] ); #start again at a different point y3 (sediment) $dydt[3] = _equation_sediment( $args_ref, $level_iii_ref, $y[3 +] ); return @dydt; } #build resulthahes my @hash_pairs = zip @iterations, @output_merson ; my %res_hash = ( air => { @hash_pairs }, water => { @hash_pairs }, soil => { @hash_pairs }, sediment => { @hash_pairs }, ); #my %res_hash_parameter = ( ); # return wantarray # ? ( \%res_hash, $level_iii_ref ) # : [ \%res_hash, $level_iii_ref ]; return SCALAR { [ \%res_hash, $level_iii_ref ] } BOOL { scalar keys %res_hash > 0 } NUM { keys %res_hash } STR { reftype [] } LIST { \%res_hash, $level_iii_ref } ARRAYREF { [ \%res_hash, $level_iii_ref ] } CODEREF { croak " > Don't use this result as code! < "; } ; } 1; #not correct #sub aus { # my $x = $_[0] + 35; # sub in { return $x * 19 } #beachte ; bei local # return $x + in(); #} #correct #sub aussen { # my $x = $_[0] + 35; # local *innen = sub { return $x * 19 }; # return $x + innen(); #}