File Coverage

blib/lib/Simulation/Sensitivity.pm
Criterion Covered Total %
statement 44 44 100.0
branch 4 4 100.0
condition n/a
subroutine 10 10 100.0
pod 4 4 100.0
total 62 62 100.0


line stmt bran cond sub pod time code
1             package Simulation::Sensitivity;
2 1     1   979 use strict;
  1         2  
  1         51  
3 1     1   5 use warnings;
  1         3  
  1         55  
4             # ABSTRACT: A general-purpose sensitivity analysis tool for user-supplied calculations and parameters
5             our $VERSION = '0.12'; # VERSION
6              
7             # Required modules
8 1     1   6 use Carp;
  1         1  
  1         101  
9 1     1   1091 use Params::Validate ':all';
  1         18173  
  1         280  
10              
11             # ISA
12 1     1   9 use base qw( Class::Accessor::Fast );
  1         2  
  1         863  
13              
14             #--------------------------------------------------------------------------#
15             # main pod documentation #####
16             #--------------------------------------------------------------------------#
17              
18              
19             #--------------------------------------------------------------------------#
20             # new()
21             #--------------------------------------------------------------------------#
22              
23              
24             {
25             my $param_spec = {
26             calculation => { type => CODEREF },
27             parameters => { type => HASHREF },
28             delta => { type => SCALAR }
29             };
30              
31             __PACKAGE__->mk_accessors( keys %$param_spec );
32              
33             sub new {
34 3     3 1 1345 my $class = shift;
35 3         378 my %params = validate( @_, $param_spec );
36 2         18 my $self = bless( {%params}, $class );
37 2         11 return $self;
38             }
39              
40             }
41              
42              
43             #--------------------------------------------------------------------------#
44             # base()
45             #--------------------------------------------------------------------------#
46              
47              
48             sub base {
49 4     4 1 10 my ($self) = @_;
50 4         7 return $self->calculation->( { %{ $self->parameters } } );
  4         15  
51             }
52              
53             #--------------------------------------------------------------------------#
54             # run()
55             #--------------------------------------------------------------------------#
56              
57              
58             sub run {
59 1     1 1 686 my ($self) = @_;
60 1         2 my $results;
61              
62 1         3 for my $key ( keys %{ $self->parameters } ) {
  1         4  
63 2         22 $results->{$key} = {};
64 2         5 for my $mult ( 1, -1 ) {
65 4         46 my $p = { %{ $self->parameters } };
  4         12  
66 4         31 $p->{$key} = ( 1 + $mult * $self->delta ) * $self->parameters->{$key};
67 4         42 $results->{$key}->{ $self->_case($mult) } =
68             $self->calculation->($p);
69             }
70             }
71 1         15 return $results;
72             }
73              
74             #--------------------------------------------------------------------------#
75             # _case ($mult, $result, $base)
76             #
77             # private helper function to turn a +/-1 into a case label using the delta
78             #--------------------------------------------------------------------------#
79              
80             sub _case {
81 10     10   69 my ( $self, $mult ) = @_;
82 10 100       32 return ( ( $mult == 1 ) ? "+" : "-" ) . ( $self->delta * 100 ) . "%";
83             }
84              
85             #--------------------------------------------------------------------------#
86             # text_report()
87             #--------------------------------------------------------------------------#
88              
89              
90             sub text_report {
91 2     2 1 588 my ( $self, $results ) = @_;
92 2         6 my $base = $self->base;
93 2 100       254 croak "Simulation base case is zero/undefined. Cannot generate report."
94             unless $base;
95 1         11 my $report =
96             sprintf( "%12s %9s %9s\n", "Parameter", $self->_case(1), $self->_case(-1) );
97 1         12 $report .= sprintf( "-" x 36 . "\n" );
98 1         7 for my $param ( sort keys %$results ) {
99 2         31 my $cases = $results->{$param};
100 2         5 $report .= sprintf(
101             "%12s %+9.2f%% %+9.2f%%\n",
102             $param,
103             ( $cases->{ $self->_case(1) } / $base - 1 ) * 100,
104             ( $cases->{ $self->_case(-1) } / $base - 1 ) * 100,
105             );
106             }
107 1         18 return $report;
108             }
109              
110             1;
111              
112             __END__