Removed Parallel::Forkmanager in modelfit
[PsN.git] / lib / output_subs.pm
blobc277693e68380abcfafa5a9c3da28ab5b48575bf
1 # {{{ include
3 start include statements
4 # A Perl module for parsing NONMEM output files
5 use Digest::MD5 'md5_hex';
6 use OSspecific;
7 use Storable;
8 use Config;
9 use ext::Math::SigFigs;
10 use Data::Dumper;
11 end include statements
13 # }}} include statements
15 # {{{ description
17 # No method, just documentation
18 start description
19 # The PsN output class is built to ease the (often trivial,
20 # but still time consuming) task of gathering and structuring the
21 # information contained in NONMEM output files. The major parts of a
22 # NONMEM output file are parsed and in the L</methods> section
23 # you can find a listing of the routines that are available.
24 end description
26 # }}} description
28 # {{{ synopsis
30 start synopsis
31 # use output;
33 # my $out_obj = output -> new ( filename => 'run1.lst' );
35 # my @thetas = @{$out_obj -> thetas};
36 # my @omegas = @{$out_obj -> omegas};
37 # my @ofvs = @{$out_obj -> ofvs};
38 end synopsis
40 # }}} synopsis
42 # {{{ see_also
44 start see_also
45 # =begin html
47 # <a HREF="data.html">data</a>, <a HREF="model.html">model</a>
48 # <a HREF="tool/modelfit.html">tool::modelfit</a>,
49 # <a HREF="tool.html">tool</a>
51 # =end html
53 # =begin man
55 # data, model, tool::modelfit, tool
57 # =end man
58 end see_also
60 # }}} see_also
62 # {{{ new
64 start new
66 # Usage:
68 # $outputObject -> new( filename => 'run1.lst' );
70 # The basic usage above creates a output object with the data
71 # in file.out parsed into memory.
73 # $outputObject -> new( filename => 'run1.lst',
74 # target => 'disk' );
76 # If I<target> is set to 'disk', the data in "run1.lst" will
77 # be left on disk in an effort to preserve memory. The file
78 # will be read if needed.
80 if ( defined $this -> {'filename'} and $this -> {'filename'} ne '' ) {
81 ( $this -> {'directory'}, $this -> {'filename'} ) =
82 OSspecific::absolute_path( $this -> {'directory'},$this->{'filename'} );
83 if( -e $this -> full_name ){
84 if($this -> {'target'} eq 'mem'){
85 $this -> _read_problems;
87 } else {
88 debug -> die( message => "The NONMEM output file ".
89 $this -> full_name." does not exist" )
90 unless $this -> {'ignore_missing_files'};
92 } else {
93 debug -> die( message => "No filename specified or filename equals empty string!" );
96 end new
98 # }}} new
100 # {{{ register_in_database
102 start register_in_database
103 if ( $PsN::config -> {'_'} -> {'use_database'} ) {
104 my $md5sum;
105 if( -e $self -> full_name ){
106 # md5sum
107 $md5sum = md5_hex(OSspecific::slurp_file($self-> full_name ));
109 # Backslashes messes up the sql syntax
110 my $file_str = $self->{'filename'};
111 my $dir_str = $self->{'directory'};
112 $file_str =~ s/\\/\//g;
113 $dir_str =~ s/\\/\//g;
115 my $dbh = DBI -> connect("DBI:mysql:host=".$PsN::config -> {'_'} -> {'database_server'}.
116 ";databse=".$PsN::config -> {'_'} -> {'project'},
117 $PsN::config -> {'_'} -> {'user'},
118 $PsN::config -> {'_'} -> {'password'},
119 {'RaiseError' => 1});
121 my $sth;
122 my $select_arr = [];
124 if ( not $force ) {
125 my $sth = $dbh -> prepare( "SELECT output_id FROM ".$PsN::config -> {'_'} -> {'project'}.
126 ".output ".
127 "WHERE filename = '$file_str' AND ".
128 "directory = '$dir_str' AND ".
129 "md5sum = '".$md5sum."'" );
130 $sth -> execute or debug -> die( message => $sth->errstr ) ;
132 $select_arr = $sth -> fetchall_arrayref;
135 if ( scalar @{$select_arr} > 0 ) {
136 debug -> warn( level => 1,
137 message => "Found an old entry in the database matching the ".
138 "current output file" );
139 if ( scalar @{$select_arr} > 1 ) {
140 debug -> warn( level => 1,
141 message => "Found more than one matching entry in database".
142 ", using the first" );
144 $self -> {'output_id'} = $select_arr->[0][0];
145 # Maybe we should update the table with a new model_id if such is supplied to us?
146 $self -> {'model_id'} = $select_arr->[0][1];
147 } else {
148 my ( $date_str, $time_str );
149 if ( $Config{osname} eq 'MSWin32' ) {
150 $date_str = `date /T`;
151 $time_str = ' '.`time /T`;
152 } else {
153 # Assuming UNIX
154 $date_str = `date`;
156 chomp($date_str);
157 chomp($time_str);
158 my $date_time = $date_str.$time_str;
159 my @mod_str = ('','');
160 if ( defined $model_id ) {
161 @mod_str = ('model_id, ',"$model_id, ");
163 $sth = $dbh -> prepare("INSERT INTO ".$PsN::config -> {'_'} -> {'project'}.
164 ".output ".
165 "( ".$mod_str[0].
166 "filename, date, directory, md5sum ) ".
167 "VALUES (".$mod_str[1].
168 "'$file_str', '$date_time', ".
169 "'$dir_str', '".$md5sum."' )");
171 $sth -> execute;
172 $self -> {'output_id'} = $sth->{'mysql_insertid'};
173 $self -> {'model_id'} = $model_id;
175 $sth -> finish;
176 $dbh -> disconnect;
177 if ( defined $self -> {'output_id'} ) {
178 foreach my $problem ( @{$self -> {'problems'}} ) {
179 $problem -> register_in_database( output_id => $self -> {'output_id'},
180 model_id => $model_id );
184 end register_in_database
186 # }}} register_in_database
188 # {{{ full_name
189 start full_name
191 $full_name = $self -> {'directory'} . $self -> {'filename'};
193 end full_name
195 # }}} full_name
197 # {{{ copy
198 start copy
200 $new_output = Storable::dclone( $self );
202 end copy
203 # }}} copy
205 # {{{ Definitions and help text for all accessors
207 start comegas
208 # Since PsN output objects are read-only, once they are
209 # initialized (probably through parsing a NONMEM output file) the
210 # methods of the output class are only used to extract
211 # information, not to set any.
213 # The general structure of the values returned by the methods
214 # reflect the level where the attributes belong (problems or sub
215 # problems) and of course also the structure of the attribute
216 # itself (scalar (ofv), array (thetas) or matrix
217 # (raw_cormatrix)). Taking ofv as example, this means that the
218 # returned variable will be a (reference to a) two-dimensional
219 # array, with the indexes problem and subproblem since ofv is a
220 # scalar on the sub problem level.
222 # Most methods take two optional arguments, I<problems> and
223 # I<subproblems>. These can be used to specify which problem or sub
224 # problem that the method should extract the required information
225 # from. problems and subproblems should be references to arrays of
226 # numbers. Some methods that return information related to model
227 # parameters also take I<parameter_numbers> as another optional
228 # argument and this can be used to specify a subset of parameters.
230 # Example:
232 # Return the standard errors for omega 1 and 3 (in all problems
233 # and sub problems)
235 # @seomega = @{$output_object -> seomegas( parameter_numbers => [1,3] )};
238 # comegas returns the standard deviation for elements on the
239 # diagonal and correlation coefficients for off-diagonal elements.
240 end comegas
242 start condition_number
243 # condition_number returns the 2-norm condition number for the correlation matrix, i.e.
244 # the largest eigen value divided by the smallest.
245 # See L</comegas> for details of the method arguments.
247 # Level: Sub problem
248 end condition_number
250 start covariance_step_run
251 # Returns 1 if the covariance step was run, 0 otherwise. See
252 # L</comegas> for details.
254 # Level: Problem
255 end covariance_step_run
257 start covariance_step_successful
258 # Returns 1 if the covariance step was successful, 0
259 # otherwise. See L</comegas> for details on the method arguments.
261 # Level: Sub problem
262 end covariance_step_successful
264 start covariance_step_warnings
265 # Returns 0 if there were no warnings or errors printed during the
266 # covariance step, 1 otherwise. See L</comegas> for details on the
267 # method arguments.
269 # Level: Sub problem
270 end covariance_step_warnings
272 start csigmas
273 # csigmas returns the standard deviation for elements on the
274 # diagonal and correlation coefficients for off-diagonal elements.
275 # See L</comegas> for details on the method arguments.
277 # Level: Sub problem
278 end csigmas
280 start cvseomegas
281 # cvseomegas returns the relative standard error for the omegas, i.e. SE/estimate.
282 # See L</comegas> for details on the method arguments.
284 # Level: Sub problem
285 end cvseomegas
287 start cvsesigmas
288 # cvsesigmas returns the relative standard error for the sigmas, i.e. SE/estimate.
289 # See L</comegas> for details on the method arguments.
291 # Level: Sub problem
292 end cvsesigmas
294 start cvsethetas
295 # cvsethetas returns the relative standard error for the thetas, i.e. SE/estimate.
296 # See L</comegas> for details on the method arguments.
298 # Level: Sub problem
299 end cvsethetas
301 start eigens
302 # eigens returns the eigen values.
303 # See L</comegas> for details of the method arguments.
305 # Level: Sub problem
306 end eigens
308 start etabar
309 # etabar returns the ETABAR estimates.
310 # See L</comegas> for details of the method arguments.
312 # Level: Sub problem
313 end etabar
315 start feval
316 # feval returns the number of function evaluations.
317 # See L</comegas> for details of the method arguments.
319 # Level: Sub problem
320 end feval
322 start finalparam
323 # finalparam returns the final parameter vector as it appears in the monitoring of search section.
324 # See L</comegas> for details of the method arguments.
326 # Level: Sub problem
327 end finalparam
329 start final_gradients
330 # final_gradients returns the final gradient vector as it appears in the monitoring of search section.
331 # See L</comegas> for details of the method arguments.
333 # Level: Sub problem
334 end final_gradients
336 start fixedomegas
337 # fixedomegas returns the a vector of booleans; 1's if
338 # the parameters were fixed during the model fit, 0's
339 # if they were not.
340 # See L</comegas> for details of the method arguments.
342 # Level: Sub problem
343 end fixedomegas
345 start fixedsigmas
346 # fixedsigmas returns the a vector of booleans; 1's if
347 # the parameters were fixed during the model fit, 0's
348 # if they were not.
349 # See L</comegas> for details of the method arguments.
351 # Level: Sub problem
352 end fixedsigmas
354 start fixedthetas
355 # fixedthetas returns the a vector of booleans; 1's if
356 # the parameters were fixed during the model fit, 0's
357 # if they were not.
358 # See L</comegas> for details of the method arguments.
360 # Level: Sub problem
361 end fixedthetas
363 start funcevalpath
364 # funcevalpath returns the number of function evaluations for each printed iteration in the monitoring of search section.
365 # See L</comegas> for details of the method arguments.
367 # Level: Sub problem
368 end funcevalpath
370 start gradient_path
371 # gradient_path returns the gradients for each printed iteration in the monitoring of search section (returns a matrix for each sub problem).
372 # See L</comegas> for details of the method arguments.
374 # Level: Sub problem
375 end gradient_path
377 start have_output
378 # Returns 1 if the output object is initialized, i.e. if the I<problems>
379 # or I<filename> attributes are set. Returns 0 otherwise.
380 end have_output
382 start initgrad
383 # initgrad returns the initial gradient vector in the monitoring of search section.
384 # See L</comegas> for details of the method arguments.
386 # Level: Sub problem
387 end initgrad
389 start initomegas
390 # initomegas returns the initial omega values.
391 # See L</comegas> for details of the method arguments.
393 # Level: Sub problem
394 end initomegas
396 start initsigmas
397 # initsigmas returns the initial sigma values.
398 # See L</comegas> for details of the method arguments.
400 # Level: Sub problem
401 end initsigmas
403 start initthetas
404 # initthetas returns the initial theta values.
405 # See L</comegas> for details of the method arguments.
407 # Level: Sub problem
408 end initthetas
410 start iternum
411 # iternum returns a vector of the iteration numbers in the monitoring of search section.
412 # See L</comegas> for details of the method arguments.
414 # Level: Sub problem
415 end iternum
417 start nind
418 # nind returns the number of individuals.
419 # See L</comegas> for details of the method arguments.
421 # Level: Problem
422 end nind
424 start nobs
425 # nobs returns the number of observations.
426 # See L</comegas> for details of the method arguments.
428 # Level: Problem
429 end nobs
431 start npofv
432 # npofv returns the non-parametric objective function value.
433 # See L</comegas> for details of the method arguments.
435 # Level: Sub problem
436 end npofv
438 start nrecs
439 # nrecs returns the number of records.
440 # See L</comegas> for details of the method arguments.
442 # Level: Problem
443 end nrecs
445 start npomegas
446 # npomegas returns the non-parametric omega estimates.
447 # See L</comegas> for details of the method arguments.
449 # Level: Sub problem
450 end npomegas
452 start npthetas
453 # npthetas returns the non-parametric theta estimates.
454 # See L</comegas> for details of the method arguments.
456 # Level: Sub problem
457 end npthetas
459 start nth
460 # nth returns the number of thetas.
461 # See L</comegas> for details of the method arguments.
463 # Level: Sub problem
464 end nth
466 start ofvpath
467 # ofvpath returns the objective [function] values in the monitoring of search section.
468 # See L</comegas> for details of the method arguments.
470 # Level: Sub problem
471 end ofvpath
473 start ofv
474 # ofv returns the objective function value(s).
475 # See L</comegas> for details of the method arguments.
477 # Level: Sub problem
478 end ofv
480 start omega_block_structure
481 # omega_block_structure returns the block structure for
482 # the omega parameters in a lower triangular matrix form
483 # as in the OMEGA HAS BLOCK FORM section in the NONMEM output file.
484 # See L</comegas> for details of the method arguments.
486 # Level: Sub problem
487 end omega_block_structure
489 start omeganameval
490 # omeganameval returns (at the sub problem level) a hash
491 # with default parameter names , i.e. OM1, OM1_2 etc as keys
492 # and parameter estimates as values.
493 # See L</comegas> for details of the method arguments.
495 # Level: Sub problem
496 end omeganameval
498 start omeganames
499 # omeganames returns the default parameter names, e.g. OM1, OM1_2, OM2, etc
500 # See L</comegas> for details of the method arguments.
502 # Level: Sub problem
503 end omeganames
505 start omegas
506 # omegas returns the omega parameter estimates.
507 # See L</comegas> for details of the method arguments.
509 # Level: Sub problem
510 end omegas
512 start parameter_path
513 # parameter_path returns the (normalized) parameter estimates for each iteration in the monitoring of search section (Matrix returned).
514 # See L</comegas> for details of the method arguments.
516 # Level: Sub problem
517 end parameter_path
519 start pval
520 # pval returns the P VAL (reflects the probability that the etas are not centered around zero).
521 # See L</comegas> for details of the method arguments.
523 # Level: Sub problem
524 end pval
526 start raw_covmatrix
527 # raw_covmatrix returns the (raw) covariance matrix including empty matrix elements marked as '.........'.
528 # See L</comegas> for details of the method arguments.
530 # Level: Sub problem
531 end raw_covmatrix
533 start raw_invcovmatrix
534 # raw_invcovmatrix returns the (raw) inverse covariance matrix including empty matrix elements marked as '.........'.
535 # See L</comegas> for details of the method arguments.
537 # Level: Sub problem
538 end raw_invcovmatrix
540 start raw_cormatrix
541 # raw_cormatrix returns the (raw) correlation matrix including empty matrix elements marked as '.........'.
542 # See L</comegas> for details of the method arguments.
544 # Level: Sub problem
545 end raw_cormatrix
547 start raw_omegas
548 # raw_omegas returns the (raw) omegas.
549 # See L</comegas> for details of the method arguments.
551 # Level: Sub problem
552 end raw_omegas
554 start raw_seomegas
555 # raw_seomegas returns the (raw) omega standard error estimates.
556 # See L</comegas> for details of the method arguments.
558 # Level: Sub problem
559 end raw_seomegas
561 start raw_sesigmas
562 # raw_sesigmas returns the (raw) sigma standard error estimates.
563 # See L</comegas> for details of the method arguments.
565 # Level: Sub problem
566 end raw_sesigmas
568 start raw_sigmas
569 # raw_sigmas returns the (raw) sigmas.
570 # See L</comegas> for details of the method arguments.
572 # Level: Sub problem
573 end raw_sigmas
575 start raw_tmatrix
576 # raw_tmatrix returns the (raw) T-matrix.
577 # See L</comegas> for details of the method arguments.
579 # Level: Sub problem
580 end raw_tmatrix
582 start seomegas
583 # seomegas returns the omega standard error estimates.
584 # See L</comegas> for details of the method arguments.
586 # Level: Sub problem
587 end seomegas
589 start sesigmas
590 # sesigmas returns the sigma standard error estimates.
591 # See L</comegas> for details of the method arguments.
593 # Level: Sub problem
594 end sesigmas
596 start sethetas
597 # sethetas returns the theta standard error estimates.
598 # See L</comegas> for details of the method arguments.
600 # Level: Sub problem
601 end sethetas
603 start significant_digits
604 # significant_digits returns the number of significant digits for the model fit.
605 # See L</comegas> for details of the method arguments.
607 # Level: Sub problem
608 end significant_digits
610 start sigma_block_structure
611 # sigma_block_structure returns the block structure for
612 # the sigma parameters in a lower triangular matrix form
613 # as in the sigma HAS BLOCK FORM section in the NONMEM output file.
614 # See L</csigmas> for details of the method arguments.
616 # Level: Sub problem
617 end sigma_block_structure
619 start sigmanameval
620 # sigmanameval returns (at the sub problem level) a hash
621 # with default parameter names , i.e. SI1, SI1_2 etc as keys
622 # and parameter estimates as values.
623 # See L</comegas> for details of the method arguments.
625 # Level: Sub problem
626 end sigmanameval
628 start sigmanames
629 # sigmanames returns the default parameter names, i.e. SI1, SI1_2, SI2 etc.
630 # See L</comegas> for details of the method arguments.
632 # Level: Sub problem
633 end sigmanames
635 start sigmas
636 # sigmas returns the sigma parameter estimates.
637 # See L</comegas> for details of the method arguments.
639 # Level: Sub problem
640 end sigmas
642 start simulationstep
643 # simulationstep returns a boolean value 1 or 0, reflecting
644 # whether a simulation was performed or not. See L</comegas> for
645 # Details of the method arguments.
647 # Level: Sub Problem
648 end simulationstep
650 start minimization_successful
651 # minimization_successful returns a boolean value 1 or 0,
652 # reflecting whether the minimization was successful or not. See
653 # L</comegas> for details of the method arguments.
655 # Level: Sub Problem
656 end minimization_successful
658 start minimization_message
659 # minimization_message returns the minimization message, i.e
660 # MINIMIZATION SUCCESSFUL...
661 # See L</comegas> for details of the method arguments.
663 # Level: Sub problem
664 end minimization_message
666 start thetanameval
667 # thetanameval returns (at the sub problem level) a hash
668 # with default parameter names , i.e. TH1, TH2 etc as keys
669 # and parameter estimates as values.
670 # See L</comegas> for details of the method arguments.
672 # Level: Sub problem
673 end thetanameval
675 start thetanames
676 # thetanames returns the default theta parameter names, TH1, TH2 etc.
677 # See L</comegas> for details of the method arguments.
679 # Level: Sub problem
680 end thetanames
682 start thetas
683 # thetas returns the theta parameter estimates.
684 # See L</comegas> for details of the method arguments.
686 # Level: Sub problem
687 end thetas
689 # }}} Definitions and help text for all accessors
691 # {{{ have_output
692 start have_output
694 # have_output returns true if the output files exits or if there
695 # is output data in memory.
696 if( -e $self -> full_name || defined @{$self -> {'problems'}}){
697 return 1;
698 } else {
699 return 0;
702 end have_output
703 # }}} have_output
705 # {{{ _read_problems
707 start _read_problems
709 # This is a private method, and should not be used outside
710 # this file.
712 @{$self -> {'lstfile'}} = OSspecific::slurp_file($self-> full_name ) ;
713 $self -> {'lstfile_pos'} = 0;
715 # {{{ Old db code. Keep for now
716 # if ( $PsN::config -> {'_'} -> {'use_database'} and
717 # $self -> {'register_in_database'} and
718 # defined $self -> {'output_id'} ) {
719 # my $md5sum = md5_hex(@{$self -> {'lstfile'}});
720 # my $dbh = DBI -> connect("DBI:mysql:host=".$PsN::config -> {'_'} -> {'database_server'}.
721 # ";databse=".$PsN::config -> {'_'} -> {'project'},
722 # $PsN::config -> {'_'} -> {'user'},
723 # $PsN::config -> {'_'} -> {'password'},
724 # {'RaiseError' => 1});
725 # my $sth;
726 # my $sth = $dbh -> prepare( "UPDATE ".$PsN::config -> {'_'} -> {'project'}.
727 # ".output SET md5sum='$md5sum' ".
728 # "WHERE output_id = ".$self -> {'output_id'});
729 # $sth -> execute or debug -> die( message => $sth->errstr ) ;
730 # $sth -> finish;
732 # $dbh -> disconnect;
734 # }}}
736 my $problem_start;
737 my $success = 0;
738 while ( $_ = @{$self -> {'lstfile'}}[ $self -> {'lstfile_pos'} ++ ] ) {
739 if ( /^ PROBLEM NO\.:\s+\d+\s+$/ or $self -> {'lstfile_pos'} >
740 $#{$self -> {'lstfile'}} ) {
741 if ( defined $problem_start ) {
742 my @problem_lstfile =
743 @{$self -> {'lstfile'} } [$problem_start .. ($self ->
744 {'lstfile_pos'} - 2)];
745 $self -> add_problem ( init_data =>
746 { lstfile => \@problem_lstfile,
747 output_id => $self -> {'output_id'},
748 model_id => $self -> {'model_id'} } );
749 @problem_lstfile = undef;
750 $success = 1;
752 $problem_start = $self -> {'lstfile_pos' };
755 $self -> {'lstfile'} = undef;
756 unless( $success ){
757 if( $self -> {'abort_on_fail'} ){
758 debug -> die( message => 'The listfile "' . $self -> full_name . '" seems malformatted or is missing.' );
759 } else {
760 debug -> warn( level => 1,
761 message => 'The listfile "' . $self -> full_name . '" seems malformatted or is missing.' );
762 return 0;
764 } else {
765 $self -> {'parsed_successfully'} = 1;
767 $self -> {'parsed'} = 1;
769 end _read_problems
771 # }}} _read_problems
773 # {{{ access_any
775 start access_any
777 # You should not really use access_any but instead the
778 # specific selector for the information you want, such as
779 # L</sigmas>, L</raw_tmatrix> or similar.
782 # TODO: Add sanity checking of parameter values (more than
783 # the automatic). e.g check that parameter_numbers is a two-
784 # dimensional array.
786 if ( $self -> have_output ) {
787 unless ( defined $self -> {'problems'} and
788 scalar @{$self -> {'problems'}} > 0) {
789 $self -> _read_problems;
791 } else {
792 debug -> die( message => "Trying to access output object, that have no data on file(".
793 $self->full_name.") or in memory" );
795 unless( $#problems > 0 ){
796 debug -> warn(level => 2,
797 message => "Problems undefined, using all" );
798 @problems = (1 .. scalar @{$self -> {'problems'}});
800 my @own_problems = @{$self -> {'problems'}};
801 foreach my $i ( @problems ) {
802 if ( defined $own_problems[$i-1] ) {
803 if ( defined( $own_problems[$i-1] -> can( $attribute ) ) ) {
804 debug -> warn(level => 2,
805 message => "method $attribute defined on the problem level" );
806 my $meth_ret = $own_problems[$i-1] -> $attribute;
807 if ( ref ($meth_ret) ) {
808 my @prob_attr = @{$meth_ret};
809 if ( scalar @parameter_numbers > 0 ) {
810 my @tmp_arr = ();
811 foreach my $num ( @parameter_numbers ) {
812 if ( $num > 0 and $num <= scalar @prob_attr ) {
813 push( @tmp_arr, $prob_attr[$num-1] );
814 } else {
815 debug -> die( message => "( $attribute ): no such parameter number $num!".
816 "(".scalar @prob_attr." exists)" );
819 @prob_attr = @tmp_arr;
821 push( @return_value, \@prob_attr );
822 } else {
823 push( @return_value, $meth_ret ) if defined $meth_ret;
825 } else {
826 debug -> warn(level => 2,
827 message => "method $attribute defined on the subproblem level" );
828 my $problem_ret =
829 $own_problems[$i-1] ->
830 access_any( attribute => $attribute,
831 subproblems => \@subproblems,
832 parameter_numbers => \@parameter_numbers );
833 push( @return_value, $problem_ret ) if defined $problem_ret;
835 } else {
836 debug -> die( message => "No such problem ".($i-1) );
839 # Check the return_value to see if we have empty arrays
840 # if ( $#return_value == 0 and ref $return_value[0] and scalar @{$return_value[0]} < 1 ) {
841 # @return_value = ();
844 end access_any
846 # }}} access_any
848 # {{{ high_correlations
849 start high_correlations
851 my $correlation_matrix = $self -> correlation_matrix( problems => \@problems,
852 subproblems => \@subproblems );
853 my @thetanames = @{$self -> thetanames( problems => \@problems,
854 subproblems => \@subproblems )};
855 my @omeganames = @{$self -> omeganames( problems => \@problems,
856 subproblems => \@subproblems )};
857 my @sigmanames = @{$self -> sigmanames( problems => \@problems,
858 subproblems => \@subproblems )};
859 my @estimated_thetas = @{$self -> estimated_thetas( problems => \@problems,
860 subproblems => \@subproblems )};
861 my @estimated_omegas = @{$self -> estimated_omegas( problems => \@problems,
862 subproblems => \@subproblems )};
863 my @estimated_sigmas = @{$self -> estimated_sigmas( problems => \@problems,
864 subproblems => \@subproblems )};
866 for ( my $i = 0; $i < scalar @{$correlation_matrix}; $i++ ) {
867 my ( @prob_corr, @pf_corr );
868 my @names = ( @{$thetanames[$i]}, @{$omeganames[$i]}, @{$sigmanames[$i]} );
869 my @estimated = ( @{$estimated_thetas[$i]}, @{$estimated_omegas[$i]}, @{$estimated_sigmas[$i]} );
870 for ( my $j = 0; $j < scalar @{$correlation_matrix -> [$i]}; $j++ ) {
871 my ( @sp_corr, @spf_corr );;
872 my $idx = 0;
873 for ( my $row = 1; $row <= scalar @names; $row++ ) {
874 for ( my $col = 1; $col <= $row; $col++ ) {
875 if ( ( $estimated[$row-1] and $estimated[$col-1] ) ) {
876 if ( not ( $row == $col ) and
877 $correlation_matrix -> [$i][$j][$idx] > $limit or
878 $correlation_matrix -> [$i][$j][$idx] < -$limit ) {
879 push( @sp_corr, $names[$row-1]."-".$names[$col-1] );
880 push( @spf_corr, $correlation_matrix -> [$i][$j][$idx] );
882 $idx++;
887 # my @names = ( @{$thetanames[$i]}, @{$omeganames[$i]}, @{$sigmanames[$i]} );
888 # my ( @sp_corr, @spf_corr );;
889 # my ( $row, $col ) = ( 1, 1 );
890 # foreach my $element ( @{$correlation_matrix -> [$i][$j]} ) {
891 # if ( $col == $row ) {
892 # $row++;
893 # $col = 1;
894 # } else {
895 # if ( $element > $limit or $element < -$limit ) {
896 # push( @sp_corr, $names[$row-1]."-".$names[$col-1] );
897 # push( @spf_corr, $element );
899 # $col++;
903 push( @prob_corr, \@sp_corr );
904 push( @pf_corr, \@spf_corr );
906 push( @high_correlations, \@prob_corr );
907 push( @found_correlations, \@pf_corr );
910 end high_correlations
911 # }}} high_correlations
913 # {{{ large_standard_errors
914 start large_standard_errors
916 foreach my $param ( 'theta', 'omega', 'sigma' ) {
917 my @names = eval( '@{$self -> '.$param.'names( problems => \@problems,'.
918 'subproblems => \@subproblems )}' );
919 my @cvs = eval( '@{$self -> cvse'.$param.'s( problems => \@problems,'.
920 'subproblems => \@subproblems )}' );
921 for ( my $i = 0; $i <= $#cvs; $i++ ) {
922 if ( $param eq 'theta' ) {
923 $large_standard_errors[$i] = [];
924 $found_cv[$i] = [];
926 for ( my $j = 0; $j < scalar @{$cvs[$i]}; $j++ ) {
927 if ( $param eq 'theta' ) {
928 $large_standard_errors[$i][$j] = [];
929 $found_cv[$i][$j] = [];
931 for ( my $k = 0; $k < scalar @{$cvs[$i][$j]}; $k++ ) {
932 if ( abs($cvs[$i][$j][$k]) > eval('$'.$param.'_cv_limit') ) {
933 push( @{$large_standard_errors[$i][$j]}, $names[$i][$k] );
934 push( @{$found_cv[$i][$j]}, $cvs[$i][$j][$k] );
941 end large_standard_errors
942 # }}} large_standard_errors
944 # {{{ near_bounds
946 start near_bounds
948 sub test_sigdig {
949 my ( $number, $goal, $sigdig, $zerolim ) = @_;
950 $number = &FormatSigFigs($number, $sigdig );
951 my $test;
952 if ( $goal == 0 ) {
953 $test = abs($number) < $zerolim ? 1 : 0;
954 } else {
955 $goal = &FormatSigFigs($goal, $sigdig );
956 $test = $number eq $goal ? 1 : 0;
958 return $test;
961 my @thetanames = @{$self -> thetanames};
962 my @omeganames = @{$self -> omeganames};
963 my @sigmanames = @{$self -> sigmanames};
966 my @indexes;
967 foreach my $param ( 'theta', 'omega', 'sigma' ) {
968 my @estimates = eval( '@{$self -> '.$param.'s}' );
969 my @bounds = eval( '@{$self -> '.$param.'s}' );
970 @indexes = eval( '@{$self -> '.$param.'_indexes}' ) unless ( $param eq 'theta' );
971 for ( my $i = 0; $i <= $#estimates; $i++ ) {
972 if ( $param eq 'theta' ) {
973 $near_bounds[$i] = [];
974 $found_bounds[$i] = [];
975 $found_estimates[$i] = [];
977 for ( my $j = 0; $j < scalar @{$estimates[$i]}; $j++ ) {
978 if ( $param eq 'theta' ) {
979 $near_bounds[$i][$j] = [];
980 $found_bounds[$i][$j] = [];
981 $found_estimates[$i][$j] = [];
983 for ( my $k = 0; $k < scalar @{$estimates[$i][$j]}; $k++ ) {
984 # Unless the parameter is fixed:
985 if ( not eval( '$self -> fixed'.$param.'s->[$i][$k]' ) ) {
986 if ( $param eq 'theta' ) {
987 if ( test_sigdig( $estimates[$i][$j][$k],
988 $self -> lower_theta_bounds -> [$i][$k],
989 $significant_digits, $zero_limit ) ) {
990 push( @{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]") );
991 push( @{$found_bounds[$i][$j]}, $self -> lower_theta_bounds -> [$i][$k] );
992 push( @{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
994 if ( test_sigdig( $estimates[$i][$j][$k],
995 $self -> upper_theta_bounds -> [$i][$k],
996 $significant_digits, $zero_limit ) ) {
997 push( @{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]") );
998 push( @{$found_bounds[$i][$j]}, $self -> upper_theta_bounds -> [$i][$k] );
999 push( @{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
1001 } else {
1002 my ( $upper, $lower, $sigdig );
1003 if ( $indexes[$i][$k][0] == $indexes[$i][$k][1] ) { # on diagonal
1004 ( $lower, $upper, $sigdig ) = ( 0, 1000000, $significant_digits );
1005 } else {
1006 ( $lower, $upper, $sigdig ) = ( -1, 1, $off_diagonal_sign_digits );
1008 if ( test_sigdig( $estimates[$i][$j][$k], $lower, $sigdig, $zero_limit ) ) {
1009 push( @{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]" ) );
1010 push( @{$found_bounds[$i][$j]}, $lower );
1011 push( @{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
1013 if ( test_sigdig( $estimates[$i][$j][$k], $upper, $sigdig, $zero_limit ) ) {
1014 push( @{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]" ) );
1015 push( @{$found_bounds[$i][$j]}, $upper );
1016 push( @{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
1025 end near_bounds
1027 # }}} near_bounds
1029 # {{{ problem_structure
1030 start problem_structure
1032 my $flush = 0;
1033 unless( defined $self -> {'problems'} ) {
1034 # Try to read from disk
1035 $self -> _read_problems;
1036 $flush = 1;
1038 if( defined $self -> {'problems'} ) {
1039 for(my $problem = 0; $problem < @{$self -> {'problems'}}; $problem++ ){
1040 $structure[$problem] = scalar @{$self -> {'problems'} -> [$problem] -> {'subproblems'}};
1042 $self -> flush if( $flush );
1045 end problem_structure
1046 # }}}
1048 # {{{ labels
1049 start labels
1050 # labels is this far only a wrap-around for L</thetanames>,
1051 # L</omeganames> and L</sigmanames>
1052 # The functionality of these could be moved here later on.
1054 if ( not defined $parameter_type or
1055 $parameter_type eq '' ) {
1056 my @thetanames = @{$self -> thetanames};
1057 my @omeganames = @{$self -> omeganames};
1058 my @sigmanames = @{$self -> sigmanames};
1059 for ( my $i = 0; $i <= $#thetanames; $i++ ) {
1060 if( defined $thetanames[$i] ){
1061 push( @{$labels[$i]}, @{$thetanames[$i]} );
1063 if( defined $omeganames[$i] ){
1064 push( @{$labels[$i]}, @{$omeganames[$i]} );
1066 if( defined $sigmanames[$i] ){
1067 push( @{$labels[$i]}, @{$sigmanames[$i]} );
1070 } else {
1071 my $accessor = $parameter_type.'names';
1072 @labels = @{$self -> $accessor};
1075 end labels
1076 # }}} labels
1078 # {{{ flush
1079 start flush
1081 # flush is not an accessor method. As its name implies it flushes the
1082 # output objects memory by setting the I<problems> attribute to undef.
1083 # This method can be useful when many output objects are handled and
1084 # the memory is limited.
1086 # Flushes the object to save memory. There is no need to
1087 # synchronize the ouptut object before this since they are read-
1088 # only.
1091 $self -> {'problems'} = undef;
1093 end flush
1094 # }}} flush