This is a massive update that merges all changes from PsN_2_2_0_patches_serial. It...
[PsN.git] / lib / model_subs.pm
blob6e6e157ee2c3852a5e9b43ea3d942ab4721cc561
1 # TODO: All: 2004-09-06 Fix absolute paths for data and output files. (under both
2 # windows and unix)
4 # {{{ Include
6 start include statements
7 use Digest::MD5 'md5_hex';
8 use Cwd;
9 use File::Copy 'cp';
10 use Config;
11 use OSspecific;
12 use Storable;
13 use Data::Dumper;
14 use POSIX qw(ceil floor);
15 use model::shrinkage_module;
16 end include statements
18 # }}} include statements
20 # {{{ description, synopsis and see_also
22 # No method, just documentation
23 start description
25 =head1 Description
27 PsN::model is a Perl module for parsing and manipulating NONMEM model
28 files.
30 The model class is built around the NONMEM model file. This is an
31 ordinary ASCII text file that, except for the data, holds all
32 information needed for fitting a non-linear mixed effect model using
33 NONMEM. Typically, a model file contains specifications for a
34 pharmacokinetic and/or a pharmacodynamic model, initial estimates of
35 model parameters, boundaries for model parameters as well as details
36 about the data location and format.
38 =cut
40 end description
42 start synopsis
44 =head1 Synopsis
46 C<< use model; >>
48 C<< my $model_object = model -> new ( filename => 'pheno.mod' ); >>
50 =begin html
52 <pre>
54 =end html
56 $model_object -> initial_values ( parameter_type => 'theta',
57 parameter_numbers => [[1,3]],
58 new_values => [[1.2,34]] );
60 =begin html
62 </pre>
64 =end html
66 =cut
68 end synopsis
70 start see_also
72 =head1 See also
74 =begin html
76 <a HREF="data.html">data</a>, <a HREF="output.html">output</a>
78 =end html
80 =begin man
82 data, output
84 =end man
86 =cut
88 end see_also
90 =head1 Methods
92 =cut
94 # }}}
96 # {{{ new
98 =head2 new
100 Usage:
102 =for html <pre>
104 $model = model -> new( filename => 'run1.mod' )
106 =for html </pre>
108 This is the simplest and most common way to create a model
109 object and it requires a file on disk.
111 =for html <pre>
113 $model = model -> new( filename => 'run1.mod',
114 target => 'mem' )
116 =for html </pre>
118 If the target parameter is set to anything other than I<mem>
119 the output object (with file name given by the model
120 attribute I<outputfile>) and the data objects (identified by
121 the data file names in the $DATA NONMEM model file section)
122 will be initialized but will contain no information from
123 their files. If information from them are requiered later
124 on, they are read and parsed and the appropriate attributes
125 of the data and output objects are set.
127 =cut
129 start new
132 if ( defined $parm{'problems'} ) {
133 $this -> {'problems'} = $parm{'problems'};
134 } else {
135 ($this -> {'directory'}, $this -> {'filename'}) =
136 OSspecific::absolute_path( $this -> {'directory'}, $this -> {'filename'} );
137 $this -> _read_problems;
138 $this -> {'synced'} = 1;
141 if ( defined $parm{'active_problems'} ) {
142 $this -> {'active_problems'} = $parm{'active_problems'};
143 } elsif ( defined $this -> {'problems'} ) {
144 my @active = ();
145 for ( @{$this -> {'problems'}} ) {
146 push( @active, 1 );
148 $this -> {'active_problems'} = \@active;
151 if ( defined $this -> {'extra_data_files'} ){
152 for( my $i; $i < scalar @{$this -> {'extra_data_files'}}; $i++ ){
153 my ( $dir, $file ) = OSspecific::absolute_path( $this -> {'directory'}, $this -> {'extra_data_files'} -> [$i]);
154 $this -> {'extra_data_files'} -> [$i] = $dir . $file;
158 my $subroutine_files = $this -> subroutine_files;
159 if( defined $subroutine_files and scalar @{$subroutine_files} > 0 ){
160 push( @{$this -> {'extra_files'}}, @{$subroutine_files} );
163 if ( defined $this -> {'extra_files'} ){
164 for( my $i; $i < scalar @{$this -> {'extra_files'}}; $i++ ){
165 my ( $dir, $file ) = OSspecific::absolute_path( $this -> {'directory'}, $this -> {'extra_files'} -> [$i]);
166 $this -> {'extra_files'} -> [$i] = $dir . $file;
170 # Read datafiles, if any.
171 unless( defined $this -> {'datas'} and not $this -> {'quick_reload'} ){
172 my @idcolumns = @{$this -> idcolumns};
173 my @datafiles = @{$this -> datafiles('absolute_path' => 1)};
174 # my @datafiles = @{$this -> datafiles('absolute_path' => 0)};
175 for ( my $i = 0; $i <= $#datafiles; $i++ ) {
176 my $datafile = $datafiles[$i];
177 my $idcolumn = $idcolumns[$i];
178 my ( $cont_column, $wrap_column ) = $this -> {'problems'} -> [$i] -> cont_wrap_columns;
179 my $ignoresign = defined $this -> ignoresigns ? $this -> ignoresigns -> [$i] : undef;
180 my @model_header = @{$this -> {'problems'} -> [$i] -> header};
181 if ( defined $idcolumn ) {
182 push ( @{$this -> {'datas'}}, data ->
183 new( idcolumn => $idcolumn,
184 filename => $datafile,
185 cont_column => $cont_column,
186 wrap_column => $wrap_column,
187 #model_header => \@model_header,
188 ignoresign => $ignoresign,
189 directory => $this -> {'directory'},
190 ignore_missing_files => $this -> {'ignore_missing_files'} ||
191 $this -> {'ignore_missing_data'},
192 target => $this -> {'target'}) );
193 } else {
194 'debug' -> die( message => "New model to be created from ".$this -> full_name().
195 ". Data file is ".$datafile.
196 ". No id column definition found in the model file." );
201 # Read outputfile, if any.
202 if( ! defined $this -> {'outputs'} ) {
203 unless( defined $this -> {'outputfile'} ){
204 if( $this -> filename() =~ /\.mod$/ ) {
205 ($this -> {'outputfile'} = $this -> {'filename'}) =~ s/\.mod$/.lst/;
206 } else {
207 $this -> outputfile( $this -> filename().'.lst' );
210 push ( @{$this -> {'outputs'}}, output ->
211 new( filename => $this -> {'outputfile'},
212 directory => $this -> {'directory'},
213 ignore_missing_files =>
214 $this -> {'ignore_missing_files'} || $this -> {'ignore_missing_output_files'},
215 target => $this -> {'target'},
216 model_id => $this -> {'model_id'} ) );
219 # Adding mirror_plots module here, since it can add
220 # $PROBLEMS. Also it needs to know wheter an lst file exists
221 # or not.
223 if( $this -> {'mirror_plots'} > 0 ){
224 my $mirror_plot_module = model::mirror_plot_module -> new( base_model => $this,
225 nr_of_mirrors => $this -> {'mirror_plots'},
226 cwres => $this -> {'cwres'},
227 mirror_from_lst => $this -> {'mirror_from_lst'});
228 push( @{$this -> {'mirror_plot_modules'}}, $mirror_plot_module );
231 if( $this -> {'iofv'} > 0 ){
232 my $iofv_module = model::iofv_module -> new( base_model => $this,
233 nm_version => $this -> {'nm_version'});
234 push( @{$this -> {'iofv_modules'}}, $iofv_module );
238 end new
240 # }}} new
242 # {{{ register_in_database
244 start register_in_database
246 if ( $PsN::config -> {'_'} -> {'use_database'} ) {
247 # Backslashes messes up the sql syntax
248 my $file_str = $self->{'filename'};
249 my $dir_str = $self->{'directory'};
250 $file_str =~ s/\\/\//g;
251 $dir_str =~ s/\\/\//g;
253 # md5sum
254 my $md5sum = md5_hex(OSspecific::slurp_file($self-> full_name ));
256 my $dbh = DBI -> connect("DBI:mysql:host=".$PsN::config -> {'_'} -> {'database_server'}.
257 ";databse=".$PsN::config -> {'_'} -> {'project'},
258 $PsN::config -> {'_'} -> {'user'},
259 $PsN::config -> {'_'} -> {'password'},
260 {'RaiseError' => 1});
262 my $sth;
264 my $select_arr = [];
266 if ( not $force ) {
267 my $sth = $dbh -> prepare( "SELECT model_id FROM ".$PsN::config -> {'_'} -> {'project'}.
268 ".model ".
269 "WHERE filename = '$file_str' AND ".
270 "directory = '$dir_str' AND ".
271 "md5sum = '".$md5sum."'" );
272 $sth -> execute or 'debug' -> die( message => $sth->errstr ) ;
274 $select_arr = $sth -> fetchall_arrayref;
277 if ( scalar @{$select_arr} > 0 ) {
278 'debug' -> warn( level => 1,
279 message => "Found an old entry in the database matching the ".
280 "current model file" );
281 if ( scalar @{$select_arr} > 1 ) {
282 'debug' -> warn( level => 1,
283 message => "Found more than one matching entry in database".
284 ", using the first" );
286 $self -> {'model_id'} = $select_arr->[0][0];
287 } else {
288 my ( $date_str, $time_str );
289 if( $Config{osname} eq 'MSWin32' ){
290 $date_str = `date /T`;
291 $time_str = ' '.`time /T`;
292 } else {
293 # Assuming UNIX
294 $date_str = `date`;
296 chomp($date_str);
297 chomp($time_str);
298 my $date_time = $date_str.$time_str;
299 $sth = $dbh -> prepare("INSERT INTO ".$PsN::config -> {'_'} -> {'project'}.
300 ".model (filename,date,directory,md5sum) ".
301 "VALUES ('$file_str', '$date_time', '$dir_str','".
302 $md5sum."' )");
303 $sth -> execute;
304 $self -> {'model_id'} = $sth->{'mysql_insertid'};
306 $sth -> finish if ( defined $sth );
307 $dbh -> disconnect;
309 $model_id = $self -> {'model_id'} # return the model_id;
311 end register_in_database
313 # }}} register_in_database
315 # {{{ shrinkage_stats
317 start shrinkage_stats
319 if ( $#problem_numbers > 0 and ref $enabled eq 'ARRAY' ){
320 if ( $#problem_numbers != ( scalar @{$enabled} - 1 ) ) {
321 'debug' -> die( message => "The number of problem_numbers ".($#problem_numbers+1).
322 "and enabled/disabled shrinkage_stats ".scalar @{$enabled}.
323 " do not match" );
326 unless( $#problem_numbers > 0 ){
327 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
329 my @en_arr;
330 if( ref \$enabled eq 'SCALAR' ) {
331 for ( @problem_numbers ) {
332 push( @en_arr, $enabled );
334 } elsif ( not ref $enabled eq 'ARRAY' ) {
335 debug -> die( message => 'enabled must be a scalar or a reference to an array, '.
336 'not a reference to a '.ref($enabled).'.' );
339 my @problems = @{$self -> {'problems'}};
340 my $j = 0;
341 foreach my $i ( @problem_numbers ) {
342 if ( defined $problems[ $i-1 ] ) {
343 if ( defined $en_arr[ $j ] ) {
344 if( $en_arr[ $j ] ) {
345 $problems[ $i-1 ] -> shrinkage_module -> enable;
346 } else {
347 $problems[ $i-1 ] -> shrinkage_module -> disable;
349 # my $eta_file = $self -> filename.'_'.$i.'.etas';
350 # my $eps_file = $self -> filename.'_'.$i.'.wres';
351 # $problems[ $i-1 ] -> {'eta_shrinkage_table'} = $eta_file;
352 # $problems[ $i-1 ] -> {'wres_shrinkage_table'} = $eps_file;
353 } else {
354 push( @indicators, $problems[ $i-1 ] -> shrinkage_module -> status );
356 } else {
357 'debug' -> die( message => "Problem number $i does not exist!" );
359 $j++;
362 end shrinkage_stats
364 # }}} shrinkage_stats
366 # {{{ wres_shrinkage
368 =head2 wres_shrinkage
370 Usage:
372 =for html <pre>
374 my $wres_shrink = $model_object -> wres_shrinkage();
376 =for html </pre>
378 Description:
380 Calculates wres shrinkage, a table file with wres is necessary. The
381 return value is reference of and array with one an array per problem
382 in it.
384 =cut
386 start wres_shrinkage
388 my @problems = @{$self -> {'problems'}};
389 foreach my $problem ( @problems ) {
390 push( @wres_shrinkage, $problem -> wres_shrinkage );
393 end wres_shrinkage
395 # }}} wres_shrinkage
397 # {{{ eta_shrinkage
399 =head2 eta_shrinkage
401 Usage:
403 =for html <pre>
405 my $eta_shrink = $model_object -> eta_shrinkage();
407 =for html </pre>
409 Description:
411 Calculates eta shrinkage, a table file with eta is necessary. The
412 return value is reference of and array with one an array per problem
413 in it.
415 =cut
417 start eta_shrinkage
419 my @problems = @{$self -> {'problems'}};
420 foreach my $problem ( @problems ) {
421 push( @eta_shrinkage, $problem -> eta_shrinkage );
424 end eta_shrinkage
426 # }}} eta_shrinkage
428 # {{{ nonparametric_code
430 start nonparametric_code
432 if ( $#problem_numbers > 0 and $#enabled > 0 ){
433 if ( $#problem_numbers != $#enabled ) {
434 'debug' -> die( message => "The number of problem_numbers ".($#problem_numbers+1).
435 "and enabled/disabled nonparametric_code ".($#enabled+1).
436 "do not match" );
439 unless( $#problem_numbers > 0 ){
440 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
442 my @problems = @{$self -> {'problems'}};
443 my $j = 0;
444 foreach my $i ( @problem_numbers ) {
445 if ( defined $problems[ $i-1 ] ) {
446 if ( defined $enabled[ $j ] ) {
447 $problems[ $i-1 ] -> nonparametric_code( $enabled[ $j ] );
448 } else {
449 push( @indicators, $problems[ $i-1 ] -> nonparametric_code );
451 } else {
452 'debug' -> die( message => "Problem number $i does not exist!" );
454 $j++;
457 end nonparametric_code
459 # }}} nonparametric_code
461 # {{{ add_nonparametric_code
463 start add_nonparametric_code
465 $self -> set_records( type => 'nonparametric',
466 record_strings => [ 'MARGINALS UNCONDITIONAL' ] );
467 $self -> set_option( record_name => 'estimation',
468 option_name => 'POSTHOC' );
469 my ( $msfo_ref, $junk ) = $self ->
470 _get_option_val_pos( name => 'MSFO',
471 record_name => 'estimation' );
472 my @nomegas = @{$self -> nomegas};
474 for( my $i = 0; $i <= $#nomegas; $i++ ) { # loop the problems
475 my $marg_str = 'ID';
476 for( my $j = 0; $j <= $nomegas[$i]; $j++ ) {
477 $marg_str = $marg_str.' COM('.($j+1).')=MG'.($j+1);
479 $marg_str = $marg_str.' FILE='.$self->filename.'.marginals'.
480 ' NOAPPEND ONEHEADER NOPRINT';
481 $self -> add_records( problem_numbers => [($i+1)],
482 type => 'table',
483 record_strings => [ $marg_str ] );
484 $self -> remove_option( record_name => 'abbreviated',
485 option_name => 'COMRES' );
486 $self -> add_option( record_name => 'abbreviated',
487 option_name => 'COMRES',
488 option_value => ($nomegas[$i]+1),
489 add_record => 1 ); #Add $ABB if not existing
491 $self -> add_marginals_code( problem_numbers => [($i+1)],
492 nomegas => [ $nomegas[$i] ] );
495 if( not defined $msfo_ref ) {
496 for( my $i = 0; $i < $self -> nproblems; $i++ ) {
497 $self -> add_option( record_name => 'estimation',
498 option_name => 'MSFO',
499 option_value => $self -> filename.'.msfo'.($i+1) );
501 } else {
502 for( my $i = 0; $i < scalar @{$msfo_ref}; $i++ ) {
503 if( not defined $msfo_ref->[$i] or not defined $msfo_ref->[$i][0] ) {
504 $self -> add_option( record_name => 'estimation',
505 option_name => 'MSFO',
506 option_value => $self -> filename.'.msfo'.($i+1) );
511 end add_nonparametric_code
513 # }}} add_nonparametric_code
515 # {{{ flush_data
517 =head2 flush_data
519 Usage:
521 =for html <pre>
523 $model_object -> flush_data();
525 =for html </pre>
527 Description:
529 flush data calls the same method on each data object (usually one)
530 which causes it to write data to disk and remove its data from memory.
532 =cut
534 start flush_data
536 if ( defined $self -> {'datas'} ) {
537 foreach my $data ( @{$self -> {'datas'}} ) {
538 $data -> flush;
542 end flush_data
544 # }}} flush_data
546 # {{{ full_name
548 =head2 full_name
550 Usage:
552 C<< my $file_name = $model_object -> full_name(); >>
554 Description:
556 full_name will return the name of the modelfile and its directory in a
557 string. For example: "/users/guest/project/model.mod".
559 =cut
561 start full_name
563 $full_name = $self -> {'directory'} . $self -> {'filename'};
565 end full_name
567 # }}}
569 # {{{ sync_output
571 This function is unused and should probably be removed.
573 # start __sync_output
575 unless( defined $self -> {'outputfile'} ){
576 'debug' -> die( message => "No output file is set, cannot synchronize output" );
578 @{$self -> {'outputs'}} = ();
579 push ( @{$self -> {'outputs'}}, output ->
580 new( filename => $self -> {'outputfile'},
581 ignore_missing_files => $self -> {'ignore_missing_files'},
582 target => $self -> {'target'},
583 model_id => $self -> {'model_id'} ) );
585 # end __sync_output
587 # }}} sync_output
589 # {{{ add_marginals_code
591 start add_marginals_code
593 # add_marginals_code takes two arguments.
595 # - problem_numbers is an array holding the numbers of the problems in
596 # which code should be added.
598 # - nomegas which is an array holding the number of (diagonal-element)
599 # omegas of each problem given by problem_numbers.
601 # For each omega in each problem, verbatim code is added to make the
602 # marginals available for printing (e.g. to a table file). COM(1) will
603 # hold the nonparametric density, COM(2) the marginal cumulative value
604 # for the first eta, COM(2) the marginal cumulative density for the
605 # second eta and so on.
607 unless( $#problem_numbers >= 0 ){
608 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
611 my @problems = @{$self -> {'problems'}};
612 my $j = 0;
613 foreach my $i ( @problem_numbers ) {
614 if ( defined $problems[ $i-1 ] ) {
615 $problems[$i-1] -> add_marginals_code( nomegas => $nomegas[ $j ] );
616 } else {
617 'debug' -> die( message => "Problem number $i does not exist.");
619 $j++;
622 end add_marginals_code
624 # }}} add_marginals_code
626 # {{{ add_records
628 =head2 add_records
630 Usage:
632 =for html <pre>
634 $model_object -> add_records( type => 'THETA',
635 record_strings => ['(0.1,15,23)'] );
637 =for html </pre>
639 Arguments:
641 =over 3
643 =item type
645 string
647 =item record_strings
649 array of strings
651 =item problem_numbers
653 array of integers
655 =back
657 Description:
659 add_records is used to add NONMEM control file records to the model
660 object. The "type" argument is mandatory and must be a valid NONMEM
661 record name, such as "PRED" or "THETA". Otherwise an error will be
662 output and the program terminated (this is object to change, ideally
663 we would only report an error and let the caller deal with it). The
664 "record_strings" argument is a mandatory array of valid NONMEM record
665 code. Each array corresponds to a line of the record code. There
666 "problem_numbers" argument is optional and is an array of problems
667 numbered from 1 for which the record is added, by default the record
668 is added to all problems.
670 Notice that the records are appended to those that allready exists,
671 which makes sence for records that do not exist and for initial
672 values. For records like "DATA" or "PRED" you probably want to use
673 "set_records".
675 =cut
677 start add_records
679 unless( $#problem_numbers >= 0 ){
680 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
683 my @problems = @{$self -> {'problems'}};
684 foreach my $i ( @problem_numbers ) {
685 if ( defined $problems[ $i-1 ] ) {
686 # if( defined $self -> {'problems'} ){
687 # if( defined @{$self -> {'problems'}}[$problem_number - 1] ){
688 # my $problem = @{$self -> {'problems'}}[$problem_number - 1];
689 # $problem -> add_records( 'type' => $type,
690 # 'record_strings' => \@record_strings );
691 $problems[$i-1] -> add_records( 'type' => $type,
692 'record_strings' => \@record_strings );
693 } else {
694 'debug' -> die( message => "Problem number $i does not exist.");
697 # else {
698 # 'debug' -> die( message => "Model -> add_records: No Problems in model object.") ;
701 end add_records
703 # }}} add_records
705 # {{{ set_records
707 =head2 set_records
709 Usage:
711 =for html <pre>
713 $model_object -> set_records( type => 'THETA',
714 record_strings => ['(0.1,15,23)'] );
716 =for html </pre>
718 Arguments:
720 =over 3
722 =item type
724 string
726 =item record_strings
728 array of strings
730 =item problem_numbers
732 array of integers
734 =back
736 Description:
738 set_records works just like add_records but will replace any existing
739 records in the model object.
741 =cut
743 start set_records
745 unless( $#problem_numbers >= 0 ){
746 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
749 my @problems = @{$self -> {'problems'}};
750 foreach my $i ( @problem_numbers ) {
751 if ( defined $problems[ $i-1 ] ) {
752 # if( defined $self -> {'problems'} ){
753 # if( defined @{$self -> {'problems'}}[$problem_number - 1] ){
754 # my $problem = @{$self -> {'problems'}}[$problem_number - 1];
755 # $problem -> set_records( 'type' => $type,
756 # 'record_strings' => \@record_strings );
757 $problems[$i-1] -> set_records( 'type' => $type,
758 'record_strings' => \@record_strings );
759 } else {
760 'debug' -> die( message => "Problem number $i does not exist." );
763 # else {
764 # 'debug' -> die( "No Problems in model object.") ;
767 end set_records
769 # }}} set_records
771 # {{{ remove_records
773 =head2 remove_records
775 Usage:
777 =for html <pre>
779 $model_object -> remove_records( type => 'THETA' )
781 =for html </pre>
783 Arguments:
785 =over 3
787 =item type
789 string
791 =item problem_numbers
793 array of integers
795 =back
797 Description:
799 remove_records removes the record given in the "type" argument which
800 must be a valid NONMEM record name.
802 =cut
804 start remove_records
806 unless( $#problem_numbers >= 0 ){
807 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
810 my @problems = @{$self -> {'problems'}};
811 foreach my $i ( @problem_numbers ) {
812 if ( defined $problems[ $i-1 ] ) {
813 # if( defined $self -> {'problems'} ){
814 # if( defined @{$self -> {'problems'}}[$problem_number - 1] ){
815 # my $problem = @{$self -> {'problems'}}[$problem_number - 1];
816 # $problem -> remove_records( 'type' => $type );
817 $problems[$i-1] -> remove_records( 'type' => $type );
818 } else {
819 'debug' -> die( message => "Problem number $i, does not exist" );
822 # else {
823 # 'debug' -> die( message => "No Problems in model object." );
826 end remove_records
828 # }}} remove_records
830 # {{{ copy
832 =head2 copy
834 Usage:
836 =for html <pre>
838 $model_object -> copy( filename => 'copy.mod',
839 copy_data => 1,
840 copy_output => 0 )
842 =for html </pre>
844 Arguments:
846 =over 3
848 =item filename
850 string
852 =item copy_data
854 boolean
856 =item copy_output
858 boolean
860 =item directory
862 string
864 =item data_file_names
866 array of strings
868 =item target
870 string with value 'disk' or 'mem'
872 =item extra_data_file_names
874 array of strings
876 =item update_shrinkage_tables
878 boolean
880 =back
882 Description:
884 copy produces a new modelfile object and a new file on disk whose name
885 is given by the "filename" argument. To create copies of data file the
886 copy_data options may be set to 1. The values of "data_file_names",
887 unless given, will be the model file name but with '.mod' exchanged
888 for '_$i.dta', where $i is the problem number. If data is not copied,
889 a new data object will be intialized from the same data file as the
890 previous model and "data_file_names" WILL BE IGNORED. This has the
891 side effect that the data file can be modified from both the original
892 model and the copy. The same holds for "extra_data_files". It is
893 possible to set "copy_output" to 1 as well, which then copies the
894 output object instead of reading the output file from disk, which is
895 slower. Since output objects are meant to be read-only, no
896 output_filename can be specified and the output object copy will
897 reside in memory only.
899 The "target" option has no effect.
901 =cut
903 start copy
905 # PP_TODO fix a nice copying of modelfile data
906 # preferably in memory copy. Perhaps flush data ?
908 # Check sanity of the length of data file names argument
909 if ( scalar @data_file_names > 0 ) {
910 'debug' -> die( message => "model -> copy: The number of specified new data file " .
911 "names ". scalar @data_file_names. "must\n match the number".
912 " of data objects connected to the model object".
913 scalar @{$self -> {'datas'}} )
914 unless ( scalar @data_file_names == scalar @{$self -> {'datas'}} );
915 } else {
916 my $d_filename;
917 ($d_filename = $filename) =~ s/\.mod$//;
918 for ( my $i = 1; $i <= scalar @{$self -> {'datas'}}; $i++ ) {
919 # Data filename is created in this directory (no directory needed).
920 push( @data_file_names, $d_filename."_data_".$i."_copy.dta" );
924 # Check sanity of the length of extra_data file names argument
925 if ( scalar @extra_data_file_names > 0 ) {
926 'debug' -> die( message => "The number of specified new extra_data file ".
927 "names ". scalar @extra_data_file_names, "must\n match the number".
928 " of problems (one extra_data file per prolem)".
929 scalar @{$self -> {'extra_data_files'}} )
930 unless( scalar @extra_data_file_names == scalar @{$self -> {'extra_data_files'}} );
931 } else {
932 if ( defined $self -> {'extra_data_files'} ) {
933 my $d_filename;
934 ($d_filename = $filename) =~ s/\.mod$//;
935 for ( my $i = 1; $i <= scalar @{$self -> {'extra_data_files'}}; $i++ ) {
936 # Extra_Data filename is created in this directory (no directory needed).
937 push( @extra_data_file_names, $d_filename."_extra_data_".$i."_copy.dta" );
942 ($directory, $filename) = OSspecific::absolute_path( $directory, $filename );
944 # New copy:
946 # save references to own data and output objects
947 my $datas = $self -> {'datas'};
948 # $Data::Dumper::Maxdepth = 2;
949 # die "MC1: ", Dumper $datas -> [0] -> {'individuals'};
950 my $outputs = $self -> {'outputs'};
951 my %extra_datas;
952 my @problems = @{$self -> {'problems'}};
953 for ( my $i = 0; $i <= $#problems; $i++ ) {
954 if ( defined $problems[$i] -> {'extra_data'} ) {
955 $extra_datas{$i} = $problems[$i] -> {'extra_data'};
959 my ( @new_datas, @new_extra_datas, @new_outputs );
961 $self -> synchronize if not $self -> {'synced'};
963 # remove ref to data and output object to speed up the
964 # cloning
965 $self -> {'datas'} = undef;
966 $self -> {'outputs'} = undef;
967 for ( my $i = 0; $i <= $#problems; $i++ ) {
968 $problems[$i] -> {'extra_data'} = undef;
971 # Copy the data objects if so is requested
972 if ( defined $datas ) {
973 my $i = 0;
974 foreach my $data ( @{$datas} ) {
975 if ( $copy_data == 1 ) {
976 push( @new_datas, $data ->
977 copy( filename => $data_file_names[$i]) );
978 } else {
979 # This line assumes one data per problem! May be a source of error.
980 my ( $cont_column, $wrap_column ) = $self -> problems -> [$i] -> cont_wrap_columns;
981 my $ignoresign = defined $self -> ignoresigns ? $self -> ignoresigns -> [$i] : undef;
982 my @model_header = @{$self -> problems -> [$i] -> header};
983 push @new_datas, data ->
984 new( filename => $data -> filename,
985 directory => $data -> directory,
986 cont_column => $cont_column,
987 wrap_column => $wrap_column,
988 #model_header => \@model_header,
989 target => 'disk',
990 ignoresign => $ignoresign,
991 idcolumn => $data -> idcolumn );
993 $i++;
997 # Copy the extra_data objects if so is requested
998 for ( my $i = 0; $i <= $#problems; $i++ ) {
999 my $extra_data = $extra_datas{$i};
1000 if ( defined $extra_data ) {
1001 if ( $copy_data == 1 ) {
1002 push( @new_extra_datas, $extra_data ->
1003 copy( filename => $extra_data_file_names[$i]) );
1004 } else {
1005 push( @new_extra_datas, extra_data ->
1006 new( filename => $extra_data -> filename,
1007 directory => $extra_data -> directory,
1008 target => 'disk',
1009 idcolumn => $extra_data -> idcolumn ) );
1015 # Clone self into new model object and set synced to 0 for
1016 # the copy
1017 $new_model = Storable::dclone( $self );
1018 $new_model -> {'synced'} = 0;
1020 # $Data::Dumper::Maxdepth = 3;
1021 # die Dumper $new_datas[0] -> {'individuals'};
1023 # Restore the data and output objects for self
1024 $self -> {'datas'} = $datas;
1025 $self -> {'outputs'} = $outputs;
1026 for ( my $i = 0; $i <= $#problems; $i++ ) {
1027 if( defined $extra_datas{$i} ){
1028 $problems[$i] -> {'extra_data'} = $extra_datas{$i};
1032 # Set the new file name for the copy
1033 $new_model -> directory( $directory );
1034 $new_model -> filename( $filename );
1036 # {{{ update the shrinkage modules
1038 my @problems = @{$new_model -> problems};
1039 for( my $i = 1; $i <= scalar @problems; $i++ ) {
1040 $problems[ $i-1 ] -> shrinkage_module -> model( $new_model );
1043 # }}} update the shrinkage modules
1045 # Copy the output object if so is requested (only one output
1046 # object defined per model object)
1047 if ( defined $outputs ) {
1048 foreach my $output ( @{$outputs} ) {
1049 if ( $copy_output == 1 ) {
1050 push( @new_outputs, $output -> copy );
1051 } else {
1052 my $new_out = $filename;
1053 if( $new_out =~ /\.mod$/ ) {
1054 $new_out =~ s/\.mod$/\.lst/;
1055 } else {
1056 $new_out = $new_out.'.lst';
1058 push( @new_outputs, output ->
1059 new ( filename => $new_out,
1060 directory => $directory,
1061 target => 'disk',
1062 ignore_missing_files => 1,
1063 model_id => $new_model -> {'model_id'} ) );
1068 # Add the copied data and output objects to the model copy
1069 $new_model -> datas( \@new_datas );
1071 if ( $#new_extra_datas >= 0 ) {
1072 my @new_problems = @{$new_model -> problems};
1073 for ( my $i = 0; $i <= $#new_problems; $i++ ) {
1074 $new_problems[$i] -> {'extra_data'} = $new_extra_datas[$i];
1075 if ( $copy_data == 1 ){
1076 $new_problems[$i] -> {'extra_data_file_name'} = $extra_data_file_names[$i];
1081 $new_model -> {'outputs'} = \@new_outputs;
1083 $new_model -> _write;
1085 $new_model -> synchronize if $target eq 'disk';
1087 end copy
1089 # }}} copy
1091 # {{{ covariance
1093 =head2 covariance
1095 Usage:
1097 =for html <pre>
1099 my $indicators = $model_object -> covariance( enabled => [1] );
1101 =for html </pre>
1103 Arguments:
1105 =over 3
1107 =item enabled
1109 array of booleans
1111 =item problem_numbers
1113 array of integers
1115 =back
1117 Description:
1119 covariance will let you turn the covariance step on and off per
1120 problem. The "enabled" argument is an array which must have a length
1121 equal to the number of problems. Each element set to 0 will disable
1122 the covariance step for the corresponding problem. And conversely each
1123 element set to nonzero will enable the covariance step.
1125 covariance will return an array with an element for each problem, the
1126 element will indicate whether the covariance step is turned on or not.
1128 =cut
1130 start covariance
1132 if ( $#problem_numbers > 0 ){
1133 if ( $#problem_numbers != $#enabled ) {
1134 'debug' -> die( message => "The number of problem_numbers ".($#problem_numbers+1).
1135 "and enabled/disabled covariance records ".($#enabled+1).
1136 "do not match" );
1139 unless( $#problem_numbers > 0 ){
1140 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
1142 my @problems = @{$self -> {'problems'}};
1143 my $j = 0;
1144 foreach my $i ( @problem_numbers ) {
1145 if ( defined $problems[ $i-1 ] ) {
1146 if ( defined $enabled[ $j ] ) {
1147 $problems[ $i-1 ] -> covariance( enabled => $enabled[ $j ] );
1148 } else {
1149 push( @indicators, $problems[ $i-1 ] -> covariance );
1151 } else {
1152 'debug' -> die( message => "Problem number $i does not exist!" );
1154 $j++;
1157 end covariance
1159 # }}} covariance
1161 # {{{ datas
1163 =head2 datas
1165 Usage:
1167 =for html <pre>
1169 $model_object -> datas( [$data_obj] );
1171 my $data_objects = $model_object -> data;
1173 =for html </pre>
1175 Arguments:
1177 The argument is an unnamed array of data objects.
1179 Description:
1181 If data is used without argument the data objects connected to the
1182 model object is returned. If an argument is given it must be an array
1183 of length equal to the number of problems with data objects. Those
1184 objects will replace any existing data objects and their filenames
1185 will be put in the model files records.
1187 =cut
1189 start datas
1191 my $nprobs = scalar @{$self -> {'problems'}};
1192 if ( defined $parm ) {
1193 if ( ref($parm) eq 'ARRAY' ) {
1194 my @new_datas = @{$parm};
1195 # Check that new_headers and problems match
1196 'debug' -> die( message => "The number of problems $nprobs and".
1197 " new data ". ($#new_datas+1) ." don't match in ".
1198 $self -> full_name ) unless ( $#new_datas + 1 == $nprobs );
1199 if ( defined $self -> {'problems'} ) {
1200 for( my $i = 0; $i < $nprobs; $i++ ) {
1201 $self -> _option_name( position => 0,
1202 record => 'data',
1203 problem_number => $i+1,
1204 new_name => $new_datas[$i] -> filename);
1206 } else {
1207 'debug' -> die( message => "No problems defined in ".
1208 $self -> full_name );
1210 } else {
1211 'debug' -> die( message => "Supplied new value is not an array" );
1215 end datas
1217 # }}}
1219 # {{{ datafile
1221 # TODO 2006-03-22
1222 # I have removed this because it was only used in the bootstrap. I
1223 # fixed the bootstrap to use datafiles instead. Also the bootstrap
1224 # methods who used this was very old and should probably be removed as
1225 # well.
1227 # start datafile
1229 # datafile either retrieves or sets a new name for the datafile in the first problem of the
1230 # model. This method is only here for compatibility reasons. Don't use it. Use L</datafiles> instead.
1232 if( defined $new_name ){
1233 $self -> _option_name( position => 0,
1234 record => 'data',
1235 problem_number => $problem_number,
1236 new_name => $new_name);
1237 my ( $cont_column, $wrap_column ) = $self -> problems -> [$problem_number-1] ->
1238 cont_wrap_columns;
1239 my $ignoresign = defined $self -> ignoresigns ?
1240 $self -> ignoresigns -> [$problem_number-1] : undef;
1241 my @model_header = @{$self -> problems -> [$problem_number-1] -> header};
1242 $self -> {'datas'} -> [$problem_number-1] = data ->
1243 new( idcolumn => $self -> idcolumn( problem_number => $problem_number ),
1244 ignoresign => $ignoresign,
1245 filename => $new_name,
1246 cont_column => $cont_column,
1247 wrap_column => $wrap_column,
1248 #model_header => \@model_header,
1249 ignore_missing_files => $self -> {'ignore_missing_files'},
1250 target => $self -> {'target'} );
1251 } else {
1252 $name = $self -> _option_name( position => 0, record => 'data', problem_number => $problem_number );
1255 # end datafile
1257 # }}} datafile
1259 # {{{ datafiles
1261 =head2 datafiles
1263 Usage:
1265 =for html <pre>
1267 $model_object -> datafiles( new_names => ['datafile.dta'] );
1269 =for html </pre>
1271 Arguments:
1273 =over 2
1275 =item new_names
1277 array of strings
1279 =item problem_numbers
1281 array of integer
1283 =item absolute_path
1285 boolean
1287 =back
1289 Description:
1291 datafiles changes the names of the data files in a model file. The
1292 "new_names" argument is an array of strings, where each string gives
1293 the file name of a problem data file. The length of "new_names" must
1294 be equal to the "problem_numbers" argument. "problem_numbers" is by
1295 default containing all of the models problems numbers. In the example
1296 above we only have one problem in the model file and therefore only
1297 need to give on new file name.
1299 Unless new_names is given datafiles returns the names of the data
1300 files used by the model file. If the optional "absolute_path" argument
1301 is given, the returned file names will have the path to file as well.
1303 =cut
1305 start datafiles
1307 # The datafiles method retrieves or sets the names of the
1308 # datafiles specified in the $DATA record of each problem. The
1309 # problem_numbers argument can be used to control which
1310 # problem that is affected. If absolute_path is set to 1, the
1311 # returned file names are given with absolute paths.
1313 unless( $#problem_numbers > 0 ){
1314 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
1316 if ( scalar @new_names > 0 ) {
1317 my $i = 0;
1318 my @idcolumns = @{$self ->
1319 idcolumns( problem_numbers => \@problem_numbers )};
1320 foreach my $new_name ( @new_names ) {
1321 if ( $absolute_path ) {
1322 my $tmp;
1323 ($tmp, $new_name) = OSspecific::absolute_path('', $new_name );
1324 $new_name = $tmp . $new_name;
1327 $self -> _option_name( position => 0,
1328 record => 'data',
1329 problem_number => $problem_numbers[$i],
1330 new_name => $new_name);
1331 my ( $cont_column, $wrap_column ) = $self -> problems ->
1332 [$problem_numbers[$i]-1] -> cont_wrap_columns;
1333 my $ignoresign = defined $self -> ignoresigns ? $self -> ignoresigns -> [$i] : undef;
1334 my @model_header = @{$self -> problems -> [$i] -> header};
1335 $self -> {'datas'} -> [$problem_numbers[$i]-1] = data ->
1336 new( idcolumn => $idcolumns[$i],
1337 ignoresign => $ignoresign,
1338 filename => $new_name,
1339 cont_column => $cont_column,
1340 wrap_column => $wrap_column,
1341 #model_header => \@model_header,
1342 ignore_missing_files => $self -> {'ignore_missing_files'},
1343 target => $self -> {'target'} );
1344 $i++;
1346 } else {
1347 foreach my $prob_num ( @problem_numbers ) {
1348 if ( $absolute_path ) {
1349 my ($d_dir, $d_name);
1350 ($d_dir, $d_name) =
1351 OSspecific::absolute_path($self -> {'directory'}, $self ->_option_name( position => 0,
1352 record => 'data',
1353 problem_number => $prob_num ) );
1354 push( @names, $d_dir . $d_name );
1355 } else {
1356 my $name = $self -> _option_name( position => 0,
1357 record => 'data',
1358 problem_number => $prob_num );
1359 $name =~ s/.*[\/\\]//;
1360 push( @names, $name );
1365 end datafiles
1367 # }}} datafiles
1369 # {{{ des
1371 # TODO 2006-03-22
1372 # This method is renamed __des in dia but not here. If nothing broke
1373 # until now I think we can safely remove it.
1375 start des
1377 # Returns the des part specified subproblem.
1378 # TODO: Even though new_des can be specified, they wont be set
1379 # in to the object.
1381 my @prob = @{$self -> problems};
1382 my @des = @{$prob[$problem_number - 1] -> get_record('des') -> code}
1383 if ( defined $prob[$problem_number - 1] -> get_record('des') );
1385 end des
1387 # }}} des
1389 # {{{ eigen
1390 start eigen
1392 $self -> {'problems'} -> [0] -> eigen;
1394 end eigen
1395 # }}} eigen
1397 # {{{ error
1399 # TODO 2006-03-22
1400 # This method is renamed __error in dia but not here. If nothing broke
1401 # until now I think we can safely remove it.
1403 start error
1405 # Usage:
1407 # @error = $modelObject -> error;
1409 # Returns the error part specified subproblem.
1410 # TODO: Even though new_error can be specified, they wont be set
1411 # in to the object.
1412 my @prob = @{$self -> problems};
1413 my @error = @{$prob[0] -> get_record('error') -> code}
1414 if ( defined $prob[0] -> get_record('error') );
1416 end error
1418 # }}} error
1420 # {{{ extra_data_files
1422 =head2 extra_data_files
1424 Usage:
1426 =for html <pre>
1428 $model_object -> extra_data_files( ['extra_data.dta'] );
1430 my $extra_file_name = $model_object -> extra_data_files;
1432 =for html </pre>
1434 Arguments:
1436 The argument is an unnamed array of strings
1438 Description:
1440 If extra_data_files is used without argument the names of any extra
1441 data files connected to the model object is returned. If an argument
1442 is given it must be an array of length equal to the number of problems
1443 in the model. Then the names of the extra data files will be changed
1444 to those in the array.
1446 =cut
1448 start extra_data_files
1450 my @file_names;
1451 # Sets or retrieves extra_data_file_name on problem level
1452 my $nprobs = scalar @{$self -> {'problems'}};
1453 if ( defined $parm ) {
1454 if ( ref($parm) eq 'ARRAY' ) {
1455 my @new_file_names = @{$parm};
1456 # Check that new_file_names and problems match
1457 'debug' -> die( message => "model -> extra_data_files: The number of problems $nprobs and" .
1458 " new_file_names " . $#new_file_names+1 . " don't match in ".
1459 $self -> full_name ) unless ( $#new_file_names + 1 == $nprobs );
1460 if ( defined $self -> {'problems'} ) {
1461 for( my $i = 0; $i < $nprobs; $i++ ) {
1462 $self -> {'problems'} -> [$i] -> extra_data_file_name( $new_file_names[$i] );
1464 } else {
1465 'debug' -> die( message => "No problems defined in " .
1466 $self -> full_name );
1468 } else {
1469 'debug' -> die(message => "Supplied new value is not an array.");
1471 } else {
1472 if ( defined $self -> {'problems'} ) {
1473 for( my $i = 0; $i < $nprobs; $i++ ) {
1474 if( defined $self -> {'problems'} -> [$i] -> extra_data_file_name ) {
1475 push ( @file_names ,$self -> {'problems'} -> [$i] -> extra_data_file_name );
1480 return \@file_names;
1482 end extra_data_files
1484 # }}}
1486 # {{{ extra_data_headers
1488 =head2 extra_data_headers
1490 Usage:
1492 =for html <pre>
1494 $model_object -> extra_data_headers( [$data_obj] );
1496 my $data_objects = $model_object -> extra_data_headers;
1498 =for html </pre>
1500 Arguments:
1502 The argument is an unnamed array of arrays of strings.
1504 Description:
1506 If extra_data_files is used without argument the headers of any extra
1507 data files connected to the model object is returned. If an argument
1508 is given it must be an array of length equal to the number of problems
1509 in the model. Then the headers of the extra data files will be changed
1510 to those in the array.
1512 =cut
1514 start extra_data_headers
1516 my @headers;
1517 # Sets or retrieves extra_data_header on problem level
1518 my $nprobs = scalar @{$self -> {'problems'}};
1519 if ( defined $parm ) {
1520 if ( ref($parm) eq 'ARRAY' ) {
1521 my @new_headers = @{$parm};
1522 # Check that new_headers and problems match
1523 'debug' -> die( message => "The number of problems $nprobs and".
1524 " new_headers " . $#new_headers+1 . " don't match in ".
1525 $self -> full_name) unless ( $#new_headers + 1 == $nprobs );
1526 if ( defined $self -> {'problems'} ) {
1527 for( my $i = 0; $i < $nprobs; $i++ ) {
1528 $self -> {'problems'} -> [$i] -> extra_data_header( $new_headers[$i] );
1530 } else {
1531 'debug' -> die( message => "No problems defined in " . $self -> full_name );
1533 } else {
1534 'debug' -> die( message => "Supplied new value is not an array" );
1536 } else {
1537 if ( defined $self -> {'problems'} ) {
1538 for( my $i = 0; $i < $nprobs; $i++ ) {
1539 push ( @headers, $self -> {'problems'} -> [$i] -> extra_data_header );
1543 return \@headers;
1545 end extra_data_headers
1547 # }}} extra_data_headers
1549 # {{{ factors
1551 =head2 factors
1553 Usage:
1555 =for html <pre>
1557 my $factors = $model_object -> factors;
1559 =for html </pre>
1561 Arguments:
1563 =over 2
1565 =item colunm
1567 number
1569 =item column_head
1571 string
1573 =item problem_number
1575 integer
1577 =item return_occurences
1579 boolean
1581 =item unique_in_individual
1583 boolean
1585 =back
1587 Description:
1589 The following text comes from the documentation of
1590 data::factors. model::factors will call data::factors for the given
1591 problem number in the model object. Also it will take try to find
1592 "column_head" in the $INPUT record instead of the data file header.
1594 Either column (number, starting at 1) or column_head must be
1595 specified. The default behaviour is to return a hash with the factors
1596 as keys referencing arrays with the order numbers (not the ID numbers)
1597 of the individuals that contain this factor.
1599 If unique_in_individual is true (1), the returned hash will contain an
1600 element with key 'Non-unique values found' and value 1 if any
1601 individual contain more than one value in the specified column.
1603 Return occurences will calculate the occurence of each factor
1604 value. Several occurences in one individual counts as one
1605 occurence. The elements of the returned hash will have the factors as
1606 keys and the number of occurences as values.
1608 =cut
1610 start factors
1612 # Calls <I>factors</I> on the data object of a specified
1613 # problem. See <I>data -> factors</I> for details.
1614 my $column_number;
1615 my $extra_data_column;
1616 if ( defined $column_head ) {
1617 # Check normal data object first
1618 my ( $values_ref, $positions_ref ) = $self ->
1619 _get_option_val_pos ( problem_numbers => [$problem_number],
1620 name => $column_head,
1621 record_name => 'input',
1622 global_position => 1 );
1623 $column_number = $positions_ref -> [0];
1624 # Next, check extra_data
1625 my $extra_data_headers = $self -> extra_data_headers;
1626 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
1627 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
1628 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
1631 'debug' -> die( message => "Unknown column \"$column_head\"" )
1632 unless ( defined $column_number or defined $extra_data_column );
1633 } else {
1634 $column_number = $column;
1636 if ( defined $column_number) {
1637 %factors = %{$self -> {'datas'} -> [$problem_number-1] ->
1638 factors( column => $column_number,
1639 unique_in_individual => $unique_in_individual,
1640 return_occurences => $return_occurences )};
1641 } else {
1642 %factors = %{$self -> {'problems'} -> [$problem_number-1] -> extra_data
1643 -> factors( column => $extra_data_column,
1644 unique_in_individual => $unique_in_individual,
1645 return_occurences => $return_occurences )};
1648 end factors
1650 # }}}
1652 # {{{ fractions
1654 =head2 fractions
1656 Usage:
1658 =for html <pre>
1660 my $fractions = $model_object -> fractions;
1662 =for html </pre>
1664 Arguments:
1666 =over 2
1668 =item colunm
1670 number
1672 =item column_head
1674 string
1676 =item problem_number
1678 integer
1680 =item return_occurences
1682 boolean
1684 =item ignore_missing
1686 boolean
1688 =back
1690 Description:
1692 fractions will return the fractions from data::fractions. It will find
1693 "column_head" in the $INPUT record instead of that data header as
1694 data::fractions does.
1696 =cut
1698 start fractions
1700 # Calls <I>fractions</I> on the data object of a specified
1701 # problem. See <I>data -> fractions</I> for details.
1702 my $column_number;
1703 my $extra_data_column;
1704 if ( defined $column_head ) {
1705 # Check normal data object first
1706 my ( $values_ref, $positions_ref ) = $self ->
1707 _get_option_val_pos ( problem_numbers => [$problem_number],
1708 name => $column_head,
1709 record_name => 'input',
1710 global_position => 1 );
1711 $column_number = $positions_ref -> [0];
1712 # Next, check extra_data
1713 my $extra_data_headers = $self -> extra_data_headers;
1714 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
1715 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
1716 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
1719 'debug' -> die( "Unknown column \"$column_head\"" )
1720 unless ( defined $column_number or defined $extra_data_column );
1721 } else {
1722 $column_number = $column;
1724 if ( defined $column_number) {
1725 %fractions = %{$self -> {'datas'} -> [$problem_number-1] ->
1726 fractions( column => $column_number,
1727 unique_in_individual => $unique_in_individual,
1728 ignore_missing => $ignore_missing )};
1729 } else {
1730 %fractions = %{$self -> {'problems'} -> [$problem_number-1] -> extra_data
1731 -> fractions( column => $extra_data_column,
1732 unique_in_individual => $unique_in_individual,
1733 ignore_missing => $ignore_missing )};
1736 end fractions
1738 # }}}
1740 # {{{ fixed
1742 =head2 fractions
1744 Usage:
1746 =for html <pre>
1748 my $fractions = $model_object -> fractions;
1750 =for html </pre>
1752 Arguments:
1754 =over 2
1756 =item colunm
1758 number
1760 =item column_head
1762 string
1764 =item problem_number
1766 integer
1768 =item return_occurences
1770 boolean
1772 =item ignore_missing
1774 boolean
1776 =back
1778 Description:
1780 fractions will return the fractions from data::fractions. It will find
1781 "column_head" in the $INPUT record instead of that data header as
1782 data::fractions does.
1784 =cut
1786 start fixed
1788 # Sets or gets the 'fixed' status of a (number of)
1789 # parameter(s). 1 correspond to a parameter being fixed and
1790 # 0 not fixed. The returned parameter is a reference to a
1791 # two-dimensional array, indexed by problems and parameter
1792 # numbers.
1793 # Valid parameter types are 'theta', 'omega' and 'sigma'.
1795 @fixed = @{ $self -> _init_attr
1796 ( parameter_type => $parameter_type,
1797 parameter_numbers => \@parameter_numbers,
1798 problem_numbers => \@problem_numbers,
1799 new_values => \@new_values,
1800 attribute => 'fix')};
1802 end fixed
1804 # }}} fixed
1806 # {{{ have_missing_data
1808 =head2 fractions
1810 Usage:
1812 =for html <pre>
1814 my $fractions = $model_object -> fractions;
1816 =for html </pre>
1818 Arguments:
1820 =over 2
1822 =item colunm
1824 number
1826 =item column_head
1828 string
1830 =item problem_number
1832 integer
1834 =item return_occurences
1836 boolean
1838 =item ignore_missing
1840 boolean
1842 =back
1844 Description:
1846 fractions will return the fractions from data::fractions. It will find
1847 "column_head" in the $INPUT record instead of that data header as
1848 data::fractions does.
1850 =cut
1852 start have_missing_data
1854 # Calls <I>have_missing_data</I> on the data object of a specified
1855 # problem. See <I>data -> have_missing_data</I> for details.
1856 my $column_number;
1857 my $extra_data_column;
1858 if ( defined $column_head ) {
1859 # Check normal data object first
1860 my ( $values_ref, $positions_ref ) = $self ->
1861 _get_option_val_pos ( problem_numbers => [$problem_number],
1862 name => $column_head,
1863 record_name => 'input',
1864 global_position => 1 );
1865 $column_number = $positions_ref -> [0];
1866 # Next, check extra_data
1867 my $extra_data_headers = $self -> extra_data_headers;
1868 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
1869 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
1870 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
1873 'debug' -> die( message => "Unknown column \"$column_head\"" )
1874 unless ( defined $column_number or defined $extra_data_column );
1875 } else {
1876 $column_number = $column;
1878 if ( defined $column_number) {
1879 $return_value = $self -> {'datas'} -> [$problem_number-1] ->
1880 have_missing_data( column => $column_number );
1881 } else {
1882 $return_value = $self -> {'problems'} -> [$problem_number-1] ->
1883 extra_data -> have_missing_data( column => $extra_data_column );
1886 end have_missing_data
1888 # }}}
1890 # {{{ idcolumn
1892 =head2 fractions
1894 Usage:
1896 =for html <pre>
1898 my $fractions = $model_object -> fractions;
1900 =for html </pre>
1902 Arguments:
1904 =over 2
1906 =item colunm
1908 number
1910 =item column_head
1912 string
1914 =item problem_number
1916 integer
1918 =item return_occurences
1920 boolean
1922 =item ignore_missing
1924 boolean
1926 =back
1928 Description:
1930 fractions will return the fractions from data::fractions. It will find
1931 "column_head" in the $INPUT record instead of that data header as
1932 data::fractions does.
1934 =cut
1936 start idcolumn
1938 # Usage:
1940 # @idcolumns = @{$modelObject -> idcolumns( problem_numbers => [2,3] );
1942 # idcolumns returns the idcolumn index in the datafile for the
1943 # specified problem.
1945 my $junk_ref;
1946 ( $junk_ref, $col ) = $self ->
1947 _get_option_val_pos( name => 'ID',
1948 record_name => 'input',
1949 problem_numbers => [$problem_number] );
1951 if ( $problem_number ne 'all' ) {
1952 $col = @{$col}[0];
1955 end idcolumn
1957 # }}} idcolumn
1959 # {{{ idcolumns
1961 =head2 fractions
1963 Usage:
1965 =for html <pre>
1967 my $fractions = $model_object -> fractions;
1969 =for html </pre>
1971 Arguments:
1973 =over 2
1975 =item colunm
1977 number
1979 =item column_head
1981 string
1983 =item problem_number
1985 integer
1987 =item return_occurences
1989 boolean
1991 =item ignore_missing
1993 boolean
1995 =back
1997 Description:
1999 fractions will return the fractions from data::fractions. It will find
2000 "column_head" in the $INPUT record instead of that data header as
2001 data::fractions does.
2003 =cut
2005 start idcolumns
2007 # Usage:
2009 # @column_numbers = @{$modelObject -> idcolumns( problem_numbers => [2] )};
2011 # idcolumns returns the idcolumn indexes in the datafile for the
2012 # specified problems.
2014 my ( $junk_ref, $col_ref ) = $self ->
2015 _get_option_val_pos( name => 'ID',
2016 record_name => 'input',
2017 problem_numbers => \@problem_numbers );
2018 # There should only be one instance of $INPUT and hence we collapse
2019 # the two-dim return from _get_option_pos_val to a one-dim array:
2021 foreach my $prob ( @{$col_ref} ) {
2022 foreach my $inst ( @{$prob} ) {
2023 push( @column_numbers, $inst );
2027 end idcolumns
2029 # }}} idcolumns
2031 # {{{ ignoresigns
2033 =head2 ignoresigns
2035 Usage:
2037 =for html <pre>
2039 $model_object -> ignoresigns( ['#','@'] );
2041 my $ignoresigns = $model_object -> ignoresigns;
2043 =for html </pre>
2045 Arguments:
2047 The argument is an unnamed array of strings
2049 Description:
2051 If ignoresigns is used without argument the string that specifies
2052 which string that is used for comment rows in the data file is
2053 returned. The returned value is an array including the ignore signs
2054 of each problem. If an argument is given it must be an array of
2055 length equal to the number of problems in the model. Then the names of
2056 the extra data files will be changed to those in the array.
2058 =cut
2060 start ignoresigns
2062 # Usage:
2064 # @ignore_signs = @{$modelObject -> ignoresigns( problem_numbers => [2,4] )};
2066 # ignoresigns returns the ignore signs in the datafile for the
2067 # specified problems
2069 foreach my $prob ( @{$self -> {'problems'}} ) {
2070 my @datarecs = @{$prob -> datas};
2071 if ( defined $datarecs[0] ) {
2072 push( @ignore, $datarecs[0] -> ignoresign );
2073 } else {
2074 push( @ignore, '#' );
2078 # print "IGNORE: @ignore\n";
2081 end ignoresigns
2083 # }}} ignoresigns
2085 # {{{ ignore_lists
2087 start ignore_lists
2089 # Usage:
2091 # @ignore_signs = @{$modelObject -> ignore_lists( problem_numbers => [2,4] )};
2093 # ignore_lists returns the ignore signs in the datafile for the
2094 # specified problems
2096 foreach my $prob ( @{$self -> {'problems'}} ) {
2097 my @datarecs = @{$prob -> datas};
2098 if ( defined $datarecs[0] ) {
2099 push( @ignore, $datarecs[0] -> ignore_list );
2100 } else {
2101 push( @ignore, '#' );
2105 # print "IGNORE: @ignore\n";
2108 end ignore_lists
2110 # }}} ignoresigns
2112 # {{{ indexes
2114 =head2 fractions
2116 Usage:
2118 =for html <pre>
2120 my $fractions = $model_object -> fractions;
2122 =for html </pre>
2124 Arguments:
2126 =over 2
2128 =item colunm
2130 number
2132 =item column_head
2134 string
2136 =item problem_number
2138 integer
2140 =item return_occurences
2142 boolean
2144 =item ignore_missing
2146 boolean
2148 =back
2150 Description:
2152 fractions will return the fractions from data::fractions. It will find
2153 "column_head" in the $INPUT record instead of that data header as
2154 data::fractions does.
2156 =cut
2158 start indexes
2160 # Usage:
2162 # @indexArray = @{$modelObject -> indexes( 'parameter_type' => 'omega' )};
2164 # A call to I<indexes> returns the indexes of all parameters
2165 # specified in I<parameter_numbers> from the subproblems
2166 # specified in I<problem_numbers>. The method returns a reference to an array that has
2167 # the same structure as parameter_numbers but for each
2168 # array of numbers is instead an array of indices. The method
2169 # uses a method from the model::problem class to format the
2170 # indices, so here are a few lines from the code comments in
2171 # model/problem.pm that describes the returned value:
2173 # <snip>
2174 # The Indexes method calculates the index for a
2175 # parameter. Off-diagonal elements will get a index 'i_j', where i
2176 # is the row number and j is the column number
2177 # </snip>
2179 unless( $#problem_numbers > 0 ){
2180 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
2182 my @problems = @{$self -> {'problems'}};
2183 foreach my $i ( @problem_numbers ) {
2184 if ( defined $problems[ $i-1 ] ) {
2185 push( @indexes,
2186 $problems[ $i-1 ] ->
2187 indexes( parameter_type => $parameter_type,
2188 parameter_numbers => $parameter_numbers[ $i-1 ] ) );
2189 } else {
2190 'debug' -> die( message => "Problem number $i does not exist!" );
2194 end indexes
2196 # }}} indexes
2198 # {{{ initial_values
2200 =head2 fractions
2202 Usage:
2204 =for html <pre>
2206 my $fractions = $model_object -> fractions;
2208 =for html </pre>
2210 Arguments:
2212 =over 2
2214 =item colunm
2216 number
2218 =item column_head
2220 string
2222 =item problem_number
2224 integer
2226 =item return_occurences
2228 boolean
2230 =item ignore_missing
2232 boolean
2234 =back
2236 Description:
2238 fractions will return the fractions from data::fractions. It will find
2239 "column_head" in the $INPUT record instead of that data header as
2240 data::fractions does.
2242 =cut
2244 start initial_values
2246 # initial_values either sets or gets the initial values of
2247 # the parameter specified in "parameter_type" for each
2248 # problem specified in problem_numbers. For each element
2249 # in problem_numbers there must be a reference in
2250 # parameter_numbers to an array that specify the indices
2251 # of the parameters in the subproblem for which the initial
2252 # values are set, replaced or retrieved.
2254 # The add_if_absent argument tells the method to add an init
2255 # (theta,omega,sigma) if the parameter number points to a
2256 # non-existing parameter with parameter number one higher
2257 # than the highest presently included. Only applicable if
2258 # new_values are set. Valid parameter types are 'theta',
2259 # 'omega' and 'sigma'.
2261 @initial_values = @{ $self -> _init_attr
2262 ( parameter_type => $parameter_type,
2263 parameter_numbers => \@parameter_numbers,
2264 problem_numbers => \@problem_numbers,
2265 new_values => \@new_values,
2266 attribute => 'init',
2267 add_if_absent => $add_if_absent )};
2269 end initial_values
2271 # }}} initial_values
2273 # {{{ is_option_set
2276 =head2 fractions
2278 Usage:
2280 =for html <pre>
2282 my $fractions = $model_object -> fractions;
2284 =for html </pre>
2286 Arguments:
2288 =over 2
2290 =item colunm
2292 number
2294 =item column_head
2296 string
2298 =item problem_number
2300 integer
2302 =item return_occurences
2304 boolean
2306 =item ignore_missing
2308 boolean
2310 =back
2312 Description:
2314 fractions will return the fractions from data::fractions. It will find
2315 "column_head" in the $INPUT record instead of that data header as
2316 data::fractions does.
2318 =cut
2320 start is_option_set
2322 # Usage:
2324 # if( $modelObject -> is_option_set( record => 'recordName', name => 'optionName' ) ){
2325 # print "problem_number 1 has option optionName set in record recordName";
2328 # is_option_set checks if an option is set in a given record in given problem.
2330 my ( @problems, @records, @options );
2331 my $accessor = $record.'s';
2332 if ( defined $self -> {'problems'} ) {
2333 @problems = @{$self -> {'problems'}};
2334 } else {
2335 'debug' -> die( message => "No problems defined in model" );
2337 unless( defined $problems[$problem_number - 1] ){
2338 'debug' -> warn( level => 2,
2339 message => "model -> is_option_set: No problem number $problem_number defined in model" );
2340 return 0; # No option can be set if no problem exists.
2343 if ( defined $problems[$problem_number - 1] -> $accessor ) {
2344 @records = @{$problems[$problem_number - 1] -> $accessor};
2345 } else {
2346 'debug' -> warn( level => 2,
2347 message => "model -> is_option_set: No record $record defined" .
2348 " in problem number $problem_number." );
2349 return 0;
2352 unless(defined $records[$instance - 1] ){
2353 'debug' -> warn( level => 2,
2354 message => "model -> is_option_set: No record instance number $instance defined in model." );
2355 return 0;
2358 if ( defined $records[$instance - 1] -> options ) {
2359 @options = @{$records[$instance - 1] -> options};
2360 } else {
2361 'debug' -> warn( level => 2,
2362 message => "No option defined in record: $record in problem number $problem_number." );
2363 return 0;
2365 foreach my $option ( @options ) {
2366 $found = 1 if ( defined $option and $option -> name eq $name );
2367 if( $fuzzy_match ){
2368 if( index( $name, $option -> name ) > -1 ){
2369 $found = 1;
2374 end is_option_set
2376 # }}} is_option_set
2378 # {{{ is_run
2381 =head2 fractions
2383 Usage:
2385 =for html <pre>
2387 my $fractions = $model_object -> fractions;
2389 =for html </pre>
2391 Arguments:
2393 =over 2
2395 =item colunm
2397 number
2399 =item column_head
2401 string
2403 =item problem_number
2405 integer
2407 =item return_occurences
2409 boolean
2411 =item ignore_missing
2413 boolean
2415 =back
2417 Description:
2419 fractions will return the fractions from data::fractions. It will find
2420 "column_head" in the $INPUT record instead of that data header as
2421 data::fractions does.
2423 =cut
2425 start is_run
2427 # Usage:
2429 # is_run returns true if the outputobject owned by the
2430 # modelobject has valid outpudata either in memory or on disc.
2431 if( defined $self -> {'outputs'} ){
2432 if( @{$self -> {'outputs'}}[0] -> have_output ){
2433 $return_value = 1;
2435 } else {
2436 $return_value = 0;
2439 end is_run
2440 # }}} is_run
2442 # {{{ is_simulation
2445 =head2 fractions
2447 Usage:
2449 =for html <pre>
2451 my $fractions = $model_object -> fractions;
2453 =for html </pre>
2455 Arguments:
2457 =over 2
2459 =item colunm
2461 number
2463 =item column_head
2465 string
2467 =item problem_number
2469 integer
2471 =item return_occurences
2473 boolean
2475 =item ignore_missing
2477 boolean
2479 =back
2481 Description:
2483 fractions will return the fractions from data::fractions. It will find
2484 "column_head" in the $INPUT record instead of that data header as
2485 data::fractions does.
2487 =cut
2489 start is_simulation
2491 my $problems = $self -> {'problems'};
2492 if( defined $problems -> [$problem_number - 1] ) {
2493 my $problem = $problems -> [$problem_number - 1];
2494 # If we don't have an ESTIMATION record we are simulating.
2495 $is_sim = 1 unless( defined $problem -> {'estimations'} and
2496 scalar( @{$problem-> {'estimations'}} ) > 0 );
2498 # If we have a ONLYSIM option in the simulation record.
2499 $is_sim = 1 if( $self -> is_option_set ( name => 'ONLYSIM',
2500 record => 'simulation',
2501 problem_number => $problem_number ));
2503 # If max evaluations is zero we are simulating
2504 $is_sim = 1 if( defined $self -> maxeval(problem_numbers => [$problem_number]) and
2505 defined $self -> maxeval(problem_numbers => [$problem_number])->[0][0] and
2506 $self -> maxeval(problem_numbers => [$problem_number])->[0][0] == 0 );
2508 # Anything else?
2510 # If non of the above is true, we are estimating.
2511 } else {
2512 'debug' -> warn( level => 1,
2513 message => 'Problem nr. $problem_number not defined. Assuming no simulation' );
2514 $is_sim = 0;
2517 end is_simulation
2519 # }}}
2521 # {{{ lower_bounds
2523 =head2 fractions
2525 Usage:
2527 =for html <pre>
2529 my $fractions = $model_object -> fractions;
2531 =for html </pre>
2533 Arguments:
2535 =over 2
2537 =item colunm
2539 number
2541 =item column_head
2543 string
2545 =item problem_number
2547 integer
2549 =item return_occurences
2551 boolean
2553 =item ignore_missing
2555 boolean
2557 =back
2559 Description:
2561 fractions will return the fractions from data::fractions. It will find
2562 "column_head" in the $INPUT record instead of that data header as
2563 data::fractions does.
2565 =cut
2567 start lower_bounds
2569 # lower_bounds either sets or gets the initial values of the
2570 # parameter specified in the argument parameter_type for
2571 # each problem specified in problem_numbers. See L</fixed>.
2573 @lower_bounds = @{ $self -> _init_attr
2574 ( parameter_type => $parameter_type,
2575 parameter_numbers => \@parameter_numbers,
2576 problem_numbers => \@problem_numbers,
2577 new_values => \@new_values,
2578 attribute => 'lobnd')};
2580 end lower_bounds
2582 # }}} lower_bounds
2584 # {{{ labels
2586 =head2 fractions
2588 Usage:
2590 =for html <pre>
2592 my $fractions = $model_object -> fractions;
2594 =for html </pre>
2596 Arguments:
2598 =over 2
2600 =item colunm
2602 number
2604 =item column_head
2606 string
2608 =item problem_number
2610 integer
2612 =item return_occurences
2614 boolean
2616 =item ignore_missing
2618 boolean
2620 =back
2622 Description:
2624 fractions will return the fractions from data::fractions. It will find
2625 "column_head" in the $INPUT record instead of that data header as
2626 data::fractions does.
2628 =cut
2630 start labels
2632 # Usage:
2634 # @labels = @{$modobj -> labels( parameter_type => 'theta' )};
2636 # This basic usage takes one arguments and returns matched names and
2637 # estimated values of the specified parameter. The parameter_type argument
2638 # is mandatory. It returns the labels of all parameters of type given by
2639 # $parameter_type.
2640 # @labels will be a two-dimensional array:
2641 # [[label1][label2][label3]...]
2643 # $labels -> labels( parameter_type => 'theta',
2644 # problem_numbers => [2,4] );
2646 # To get labels of specific problems, the problem_numbers argument can be used.
2647 # It should be a reference to an array containing the numbers
2648 # of all problems whos labels should be retrieved.
2650 # $modobj -> labels( parameter_type => 'theta',
2651 # problem_numbers => [2,4],
2652 # parameter_numbers => [[1,3][4,6]]);
2654 # The retrieval can be even more specific by using the parameter_numbers
2655 # argument. It should be a reference to a two-dimensional array, where
2656 # the inner arrays holds the numbers of the parameters that should be
2657 # fetched. In the example above, parameters one and three from problem two
2658 # plus parameters four and six from problem four are retrieved.
2660 # $modobj -> labels( parameter_type => 'theta',
2661 # problem_numbers => [2,4],
2662 # parameter_numbers => [[1,3][4,6]],
2663 # generic => 1 );
2665 # To get generic labels for the parameters - e.g. OM1, OM2_1, OM2 etc -
2666 # set the generic argument to 1.
2668 # $modobj -> labels( parameter_type => 'theta',
2669 # problem_numbers => [2],
2670 # parameter_numbers => [[1,3]],
2671 # new_values => [['Volume','Clearance']] );
2673 # The new_values argument can be used to give parameters new labels. In
2674 # the above example, parameters one and three in problem two are renamed
2675 # Volume and Clearance.
2678 my ( @index, $idx );
2679 @labels = @{ $self -> _init_attr
2680 ( parameter_type => $parameter_type,
2681 parameter_numbers => \@parameter_numbers,
2682 problem_numbers => \@problem_numbers,
2683 new_values => \@new_values,
2684 attribute => 'label' )};
2686 # foreach my $prl ( @labels ) {
2687 # foreach my $label ( @{$prl} ) {
2688 # print "Label: $label\n";
2693 @index = @{$self -> indexes( parameter_type => $parameter_type,
2694 parameter_numbers => \@parameter_numbers,
2695 problem_numbers => \@problem_numbers )};
2697 for ( my $i = 0; $i <= $#labels; $i++ ) {
2698 for ( my $j = 0; $j < scalar @{$labels[$i]}; $j++ ) {
2699 $idx = $index[$i][$j];
2700 $labels[$i][$j] = uc(substr($parameter_type,0,2)).$idx
2701 unless ( defined $labels[$i][$j] and not $generic );
2705 end labels
2707 # }}} labels
2709 # {{{ maxeval
2711 =head2 fractions
2713 Usage:
2715 =for html <pre>
2717 my $fractions = $model_object -> fractions;
2719 =for html </pre>
2721 Arguments:
2723 =over 2
2725 =item colunm
2727 number
2729 =item column_head
2731 string
2733 =item problem_number
2735 integer
2737 =item return_occurences
2739 boolean
2741 =item ignore_missing
2743 boolean
2745 =back
2747 Description:
2749 fractions will return the fractions from data::fractions. It will find
2750 "column_head" in the $INPUT record instead of that data header as
2751 data::fractions does.
2753 =cut
2755 start maxeval
2757 # Usage:
2759 # @maxev = @{$modobj -> maxeval};
2761 # This basic usage takes no arguments and returns the value of the
2762 # MAXEVAL option in the $ESTIMATION record of each problem.
2763 # @maxev will be a two dimensional array:
2764 # [[maxeval_prob1][maxeval_prob2][maxeval_prob3]...]
2766 # $modobj -> maxeval( new_values => [[0],[999]];
2768 # If the new_values argument of maxeval is given, the values of the
2769 # MAXEVAL options will be changed. In this example, MAXEVAL will be
2770 # set to 0 in the first problem and to 999 in the second.
2771 # The number of elements in new_values must match the number of problems
2772 # in the model object $modobj.
2774 # $modobj -> maxeval( new_values => [[0],[999]],
2775 # problem_numbers => [2,4] );
2777 # To set the MAXEVAL of specific problems, the problem_numbers argument can
2778 # be used. It should be a reference to an array containing the numbers
2779 # of all problems where the MAXEVAL should be changed or retrieved.
2780 # If specified, the size of new_values must be the same as the size
2781 # of problem_numbers.
2786 my ( $val_ref, $junk ) = $self ->
2787 _option_val_pos( name => 'MAX',
2788 record_name => 'estimation',
2789 problem_numbers => \@problem_numbers,
2790 new_values => \@new_values,
2791 exact_match => $exact_match );
2792 @values = @{$val_ref};
2794 end maxeval
2796 # }}} maxeval
2798 # {{{ median
2800 =head2 fractions
2802 Usage:
2804 =for html <pre>
2806 my $fractions = $model_object -> fractions;
2808 =for html </pre>
2810 Arguments:
2812 =over 2
2814 =item colunm
2816 number
2818 =item column_head
2820 string
2822 =item problem_number
2824 integer
2826 =item return_occurences
2828 boolean
2830 =item ignore_missing
2832 boolean
2834 =back
2836 Description:
2838 fractions will return the fractions from data::fractions. It will find
2839 "column_head" in the $INPUT record instead of that data header as
2840 data::fractions does.
2842 =cut
2844 start median
2846 # Calls <I>median</I> on the data object of a specified
2847 # problem. See <I>data -> median</I> for details.
2848 my $column_number;
2849 my $extra_data_column;
2850 if ( defined $column_head ) {
2851 # Check normal data object first
2852 my ( $values_ref, $positions_ref ) = $self ->
2853 _get_option_val_pos ( problem_numbers => [$problem_number],
2854 name => $column_head,
2855 record_name => 'input',
2856 global_position => 1 );
2857 $column_number = $positions_ref -> [0];
2858 if ( not defined $column_number ) {
2859 # Next, check extra_data
2860 my $extra_data_headers = $self -> extra_data_headers;
2861 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
2862 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
2863 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
2867 'debug' -> die( message => "Unknown column \"$column_head\"" )
2868 unless ( defined $column_number or defined $extra_data_column );
2869 } else {
2870 $column_number = $column;
2873 if ( defined $column_number) {
2874 $median = $self -> {'datas'} -> [$problem_number-1] ->
2875 median( column => $column_number,
2876 unique_in_individual => $unique_in_individual );
2877 } else {
2878 $median = $self -> {'problems'} -> [$problem_number-1] -> extra_data ->
2879 median( column => $extra_data_column,
2880 unique_in_individual => $unique_in_individual );
2883 end median
2885 # }}}
2887 # {{{ max
2889 =head2 fractions
2891 Usage:
2893 =for html <pre>
2895 my $fractions = $model_object -> fractions;
2897 =for html </pre>
2899 Arguments:
2901 =over 2
2903 =item colunm
2905 number
2907 =item column_head
2909 string
2911 =item problem_number
2913 integer
2915 =item return_occurences
2917 boolean
2919 =item ignore_missing
2921 boolean
2923 =back
2925 Description:
2927 fractions will return the fractions from data::fractions. It will find
2928 "column_head" in the $INPUT record instead of that data header as
2929 data::fractions does.
2931 =cut
2933 start max
2935 # Calls <I>max</I> on the data object of a specified
2936 # problem. See <I>data -> max</I> for details.
2937 my $column_number;
2938 my $extra_data_column;
2939 if ( defined $column_head ) {
2940 # Check normal data object first
2941 my ( $values_ref, $positions_ref ) = $self ->
2942 _get_option_val_pos ( problem_numbers => [$problem_number],
2943 name => $column_head,
2944 record_name => 'input',
2945 global_position => 1 );
2946 $column_number = $positions_ref -> [0];
2947 if ( not defined $column_number ) {
2948 # Next, check extra_data
2949 my $extra_data_headers = $self -> extra_data_headers;
2950 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
2951 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
2952 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
2956 'debug' -> die( message => "Unknown column \"$column_head\"" )
2957 unless ( defined $column_number or defined $extra_data_column );
2958 } else {
2959 $column_number = $column;
2962 if ( defined $column_number) {
2963 $max = $self -> {'datas'} -> [$problem_number-1] ->
2964 max( column => $column_number );
2965 } else {
2966 $max = $self -> {'problems'} -> [$problem_number-1] -> extra_data ->
2967 max( column => $extra_data_column );
2970 end max
2972 # }}}
2974 # {{{ min
2976 =head2 fractions
2978 Usage:
2980 =for html <pre>
2982 my $fractions = $model_object -> fractions;
2984 =for html </pre>
2986 Arguments:
2988 =over 2
2990 =item colunm
2992 number
2994 =item column_head
2996 string
2998 =item problem_number
3000 integer
3002 =item return_occurences
3004 boolean
3006 =item ignore_missing
3008 boolean
3010 =back
3012 Description:
3014 fractions will return the fractions from data::fractions. It will find
3015 "column_head" in the $INPUT record instead of that data header as
3016 data::fractions does.
3018 =cut
3020 start min
3022 # Calls <I>min</I> on the data object of a specified
3023 # problem. See <I>data -> min</I> for details.
3024 my $column_number;
3025 my $extra_data_column;
3026 if ( defined $column_head ) {
3027 # Check normal data object first
3028 my ( $values_ref, $positions_ref ) = $self ->
3029 _get_option_val_pos ( problem_numbers => [$problem_number],
3030 name => $column_head,
3031 record_name => 'input',
3032 global_position => 1 );
3033 $column_number = $positions_ref -> [0];
3034 if ( not defined $column_number ) {
3035 # Next, check extra_data
3036 my $extra_data_headers = $self -> extra_data_headers;
3037 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
3038 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
3039 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
3043 'debug' -> die( message => "Unknown column \"$column_head\"" )
3044 unless ( defined $column_number or defined $extra_data_column );
3045 } else {
3046 $column_number = $column;
3049 if ( defined $column_number) {
3050 $min = $self -> {'datas'} -> [$problem_number-1] ->
3051 min( column => $column_number );
3052 } else {
3053 $min = $self -> {'problems'} -> [$problem_number-1] -> extra_data ->
3054 min( column => $extra_data_column );
3057 end min
3059 # }}}
3061 # {{{ name_val
3063 =head2 fractions
3065 Usage:
3067 =for html <pre>
3069 my $fractions = $model_object -> fractions;
3071 =for html </pre>
3073 Arguments:
3075 =over 2
3077 =item colunm
3079 number
3081 =item column_head
3083 string
3085 =item problem_number
3087 integer
3089 =item return_occurences
3091 boolean
3093 =item ignore_missing
3095 boolean
3097 =back
3099 Description:
3101 fractions will return the fractions from data::fractions. It will find
3102 "column_head" in the $INPUT record instead of that data header as
3103 data::fractions does.
3105 =cut
3107 start name_val
3109 # Usage:
3111 # @name_val = @{$modobj -> name_val( parameter_type => 'theta' )};
3113 # This basic usage takes one arguments and returns matched names and
3114 # estimated values of the specified parameter. The parameter_type argument
3115 # is mandatory.
3116 # The names are taken from
3117 # the labels of the parameters (se the labels method for specifications of
3118 # default labels) and the values are aquired from the output object bound
3119 # to the model object. If no output exists, the name_val method returns
3120 # undef.
3121 # @name_val will be a two-dimensional array of references to hashes using
3122 # the names from each problem as keys:
3123 # [[ref to hash1 ][ref to hash2][ref to hash3]...]
3125 # $modobj -> name_val( parameter_type => 'theta',
3126 # problem_numbers => [2,4] );
3128 # To get matched names and values of specific problems, the problem_numbers argument
3129 # can be used. It should be a reference to an array containing the numbers
3130 # of all problems whos names and values should be retrieved.
3132 # $modobj -> name_val( parameter_type => 'theta',
3133 # problem_numbers => [2,4],
3134 # parameter_numbers => [[1,3][4,6]]);
3136 # The retrieval can be even more specific by using the parameter_numbers
3137 # argument. It should be a reference to a two-dimensional array, where
3138 # the inner arrays holds the numbers of the parameters that should be
3139 # fetched. In the example above, parameters one and three from problem two
3140 # plus parameters four and six from problem four are retrieved.
3143 unless( $#problem_numbers > 0 ){
3144 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
3146 my @names = @{$self -> labels( parameter_type => $parameter_type,
3147 parameter_numbers => \@parameter_numbers,
3148 problem_numbers => \@problem_numbers )};
3149 my @values;
3150 if ( defined $self -> outputs -> [0] ) {
3151 my $accessor = $parameter_type.'s';
3152 @values = @{$self -> outputs -> [0] ->
3153 $accessor( problems => \@problem_numbers,
3154 parameter_numbers => \@parameter_numbers )};
3155 # my @problems = @{$self -> {'problems'}};
3156 # foreach my $i ( @problem_numbers ) {
3157 # if ( defined $problems[ $i-1 ] ) {
3158 # my $pn_ref = $#parameter_numbers >= 0 ? \@{$parameter_numbers[ $i-1 ]} : [];
3159 # push( @names_values,
3160 # $problems[ $i-1 ] ->
3161 # name_val( parameter_type => $parameter_type,
3162 # parameter_numbers => $pn_ref ) );
3163 # } else {
3164 # die "Model -> name_val: Problem number $i does not exist!\n";
3168 # if ( scalar @{$self -> {'outputs'}} > 0 ) {
3169 # my $outobj = $self -> {'outputs'} -> [0];
3172 'debug' -> die( message => "The number of problems retrieved from the model" .
3173 " do not match the ones retrived from the output" ) unless( $#names == $#values );
3174 for( my $i = 0; $i <= $#names; $i++ ) {
3175 'debug' -> die( message => "Problem " . $i+1 .
3176 " The number of parameters retrieved from the model (".scalar @{$names[$i]}.
3177 ") do not match the ones retrived from the output (".
3178 scalar @{$values[$i][0]}.")" )
3179 unless( scalar @{$names[$i]} == scalar @{$values[$i][0]} );
3180 my @prob_nv = ();
3181 for( my $j = 0; $j < scalar @{$values[$i]}; $j++ ){
3182 my %nv = ();
3183 for( my $k = 0; $k < scalar @{$names[$i]}; $k++ ){
3184 $nv{$names[$i][$k]} = $values[$i][$j][$k];
3186 push( @prob_nv, \%nv );
3188 push( @names_values, \@prob_nv );
3191 end name_val
3193 # }}} name_val
3195 # {{{ nproblems
3197 =head2 fractions
3199 Usage:
3201 =for html <pre>
3203 my $fractions = $model_object -> fractions;
3205 =for html </pre>
3207 Arguments:
3209 =over 2
3211 =item colunm
3213 number
3215 =item column_head
3217 string
3219 =item problem_number
3221 integer
3223 =item return_occurences
3225 boolean
3227 =item ignore_missing
3229 boolean
3231 =back
3233 Description:
3235 fractions will return the fractions from data::fractions. It will find
3236 "column_head" in the $INPUT record instead of that data header as
3237 data::fractions does.
3239 =cut
3241 start nproblems
3243 # nproblems returns the number of problems in the modelobject.
3245 $number_of_problem = scalar @{$self -> {'problems'}};
3247 end nproblems
3249 # }}} nproblems
3251 # {{{ nthetas
3253 =head2 fractions
3255 Usage:
3257 =for html <pre>
3259 my $fractions = $model_object -> fractions;
3261 =for html </pre>
3263 Arguments:
3265 =over 2
3267 =item colunm
3269 number
3271 =item column_head
3273 string
3275 =item problem_number
3277 integer
3279 =item return_occurences
3281 boolean
3283 =item ignore_missing
3285 boolean
3287 =back
3289 Description:
3291 fractions will return the fractions from data::fractions. It will find
3292 "column_head" in the $INPUT record instead of that data header as
3293 data::fractions does.
3295 =cut
3297 start nthetas
3299 # returns the number of thetas in the model for the given
3300 # problem number.
3301 $nthetas = $self -> _parameter_count( 'record' => 'theta', 'problem_number' => $problem_number );
3303 end nthetas
3305 # }}} nthetas
3307 # {{{ nomegas
3309 =head2 fractions
3311 Usage:
3313 =for html <pre>
3315 my $fractions = $model_object -> fractions;
3317 =for html </pre>
3319 Arguments:
3321 =over 2
3323 =item colunm
3325 number
3327 =item column_head
3329 string
3331 =item problem_number
3333 integer
3335 =item return_occurences
3337 boolean
3339 =item ignore_missing
3341 boolean
3343 =back
3345 Description:
3347 fractions will return the fractions from data::fractions. It will find
3348 "column_head" in the $INPUT record instead of that data header as
3349 data::fractions does.
3351 =cut
3353 start nomegas
3355 # returns the number of omegas in the model for the given
3356 # problem number.
3357 # $nomegas = $self -> _parameter_count( 'record' => 'omega', 'problem_number' => $problem_number );
3358 unless( $#problem_numbers >= 0 ){
3359 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
3362 my @problems = @{$self -> {'problems'}};
3363 foreach my $i ( @problem_numbers ) {
3364 if ( defined $problems[ $i-1 ] ) {
3365 push( @nomegas, $problems[ $i-1 ] -> nomegas( with_correlations => $with_correlations ));
3366 } else {
3367 'debug' -> die( "Problem number $i does not exist." );
3371 end nomegas
3373 # }}} nomegas
3375 # {{{ nsigmas
3377 =head2 fractions
3379 Usage:
3381 =for html <pre>
3383 my $fractions = $model_object -> fractions;
3385 =for html </pre>
3387 Arguments:
3389 =over 2
3391 =item colunm
3393 number
3395 =item column_head
3397 string
3399 =item problem_number
3401 integer
3403 =item return_occurences
3405 boolean
3407 =item ignore_missing
3409 boolean
3411 =back
3413 Description:
3415 fractions will return the fractions from data::fractions. It will find
3416 "column_head" in the $INPUT record instead of that data header as
3417 data::fractions does.
3419 =cut
3421 start nsigmas
3423 # returns the number of sigmas in the model for the given problem number.
3425 # $nsigmas = $self -> _parameter_count( 'record' => 'sigma', 'problem_number' => $problem_number );
3427 unless( $#problem_numbers >= 0 ){
3428 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
3431 my @problems = @{$self -> {'problems'}};
3432 foreach my $i ( @problem_numbers ) {
3433 if ( defined $problems[ $i-1 ] ) {
3434 push( @nsigmas, $problems[ $i-1 ] -> nsigmas( with_correlations => $with_correlations ));
3435 } else {
3436 'debug' -> die( "Problem number $i does not exist." );
3440 end nsigmas
3442 # }}} nsigmas
3444 # {{{ outputfile
3446 =head2 fractions
3448 Usage:
3450 =for html <pre>
3452 my $fractions = $model_object -> fractions;
3454 =for html </pre>
3456 Arguments:
3458 =over 2
3460 =item colunm
3462 number
3464 =item column_head
3466 string
3468 =item problem_number
3470 integer
3472 =item return_occurences
3474 boolean
3476 =item ignore_missing
3478 boolean
3480 =back
3482 Description:
3484 fractions will return the fractions from data::fractions. It will find
3485 "column_head" in the $INPUT record instead of that data header as
3486 data::fractions does.
3488 =cut
3490 start outputfile
3492 # Usage:
3494 # This method is a (partially) automatically generated accessor for the
3495 # outputfile attribute of the model class. Since no named argument is needed
3496 # for accessors, the two possible ways of calling outputfile are:
3498 # $modelObject -> outputfile( 'newfilename.lst' );
3500 # $outputfilename = $modelObject -> outputfile;
3502 # The first alternative sets a new name for the output file, and the second
3503 # retrieves the value.
3505 # The extra feature for this accessor, compared to other accessors, is that
3506 # if a new name is given, the accessor tries to create a new output object
3507 # based on this.
3509 if( defined $parm ) {
3510 $self -> {'outputs'} =
3511 [ output ->
3512 new( filename => $parm,
3513 ignore_missing_files => ( $self -> ignore_missing_files() || $self -> ignore_missing_output_files() ),
3514 target => $self -> target(),
3515 model_id => $self -> model_id() ) ];
3518 end outputfile
3520 # }}} outputfile
3522 # {{{ pk
3524 =head2 fractions
3526 Usage:
3528 =for html <pre>
3530 my $fractions = $model_object -> fractions;
3532 =for html </pre>
3534 Arguments:
3536 =over 2
3538 =item colunm
3540 number
3542 =item column_head
3544 string
3546 =item problem_number
3548 integer
3550 =item return_occurences
3552 boolean
3554 =item ignore_missing
3556 boolean
3558 =back
3560 Description:
3562 fractions will return the fractions from data::fractions. It will find
3563 "column_head" in the $INPUT record instead of that data header as
3564 data::fractions does.
3566 =cut
3568 start pk
3570 # sets or gets the pk code for a given problem in the
3571 # model object. The new_pk argument should be an array where
3572 # each element contains a row of a valid NONMEM $PK block,
3574 my @prob = @{$self -> problems};
3576 unless( defined $prob[$problem_number - 1] ){
3577 'debug' -> die( message => "Problem number $problem_number does not exist" );
3580 my $pks = $prob[$problem_number - 1] -> pks;
3581 if( scalar @new_pk > 0 ) {
3582 if( defined $pks and scalar @{$pks} > 0 ){
3583 $prob[$problem_number - 1] -> pks -> [0] -> code(\@new_pk);
3584 } else {
3585 'debug' -> die( message => "No \$PK record" );
3587 } else {
3588 if ( defined $pks and scalar @{$pks} > 0 ) {
3589 @pk = @{$prob[$problem_number - 1] -> pks -> [0] -> code};
3593 end pk
3595 # }}} pk
3597 # {{{ pred
3599 =head2 fractions
3601 Usage:
3603 =for html <pre>
3605 my $fractions = $model_object -> fractions;
3607 =for html </pre>
3609 Arguments:
3611 =over 2
3613 =item colunm
3615 number
3617 =item column_head
3619 string
3621 =item problem_number
3623 integer
3625 =item return_occurences
3627 boolean
3629 =item ignore_missing
3631 boolean
3633 =back
3635 Description:
3637 fractions will return the fractions from data::fractions. It will find
3638 "column_head" in the $INPUT record instead of that data header as
3639 data::fractions does.
3641 =cut
3643 start pred
3645 # Sets or gets the pred code for a given problem in the model
3646 # object. See L</pk> for details.
3647 my @prob = @{$self -> problems};
3649 unless( defined $prob[$problem_number - 1] ){
3650 'debug' -> die( message => "problem number $problem_number does not exist" );
3653 if( scalar @new_pred > 0 ) {
3654 if( defined $prob[$problem_number - 1] -> preds ){
3655 $prob[$problem_number - 1] -> preds -> [0] -> code(\@new_pred);
3656 } else {
3657 'debug' -> die( message => "No \$PRED record" );
3659 } else {
3660 if ( defined $prob[$problem_number - 1] -> preds ) {
3661 @pred = @{$prob[$problem_number - 1] -> preds -> [0] -> code};
3662 } else {
3663 'debug' -> die( message => "No \$PRED record" );
3667 end pred
3669 # }}} pred
3671 # {{{ print
3673 =head2 fractions
3675 Usage:
3677 =for html <pre>
3679 my $fractions = $model_object -> fractions;
3681 =for html </pre>
3683 Arguments:
3685 =over 2
3687 =item colunm
3689 number
3691 =item column_head
3693 string
3695 =item problem_number
3697 integer
3699 =item return_occurences
3701 boolean
3703 =item ignore_missing
3705 boolean
3707 =back
3709 Description:
3711 fractions will return the fractions from data::fractions. It will find
3712 "column_head" in the $INPUT record instead of that data header as
3713 data::fractions does.
3715 =cut
3717 start print
3719 # Prints the formatted model to standard out.
3721 my ( @formatted );
3722 foreach my $problem ( @{$self -> {'problems'}} ) {
3723 push( @formatted, $problem -> format_problem );
3725 for ( @formatted ) {
3726 print;
3729 end print
3731 # }}} print
3733 # {{{ problem_structure
3735 start problem_structure
3737 my ( $val, $pos ) = $self -> _option_val_pos( record_name => 'simulation',
3738 name => 'SUBPROBLEMS' );
3739 if( defined $val ) {
3740 my @vals = @{$val};
3741 for( my $i = 0; $i <= $#vals; $i++ ) {
3742 if( defined $vals[$i] ) {
3743 if( scalar @{$vals[$i]} > 0 ) {
3744 $subproblems[$i] = $vals[$i][0];
3745 } else {
3746 $subproblems[$i] = 1;
3748 } else {
3749 $subproblems[$i] = 1;
3754 end problem_structure
3756 # }}} problem_structure
3758 # {{{ randomize_inits
3760 =head2 fractions
3762 Usage:
3764 =for html <pre>
3766 my $fractions = $model_object -> fractions;
3768 =for html </pre>
3770 Arguments:
3772 =over 2
3774 =item colunm
3776 number
3778 =item column_head
3780 string
3782 =item problem_number
3784 integer
3786 =item return_occurences
3788 boolean
3790 =item ignore_missing
3792 boolean
3794 =back
3796 Description:
3798 fractions will return the fractions from data::fractions. It will find
3799 "column_head" in the $INPUT record instead of that data header as
3800 data::fractions does.
3802 =cut
3804 start randomize_inits
3806 foreach my $prob ( @{$self -> {'problems'}} ) {
3807 $prob -> set_random_inits ( degree => $degree );
3810 end randomize_inits
3812 # }}}
3815 # {{{ record
3817 =head2 fractions
3819 Usage:
3821 =for html <pre>
3823 my $fractions = $model_object -> fractions;
3825 =for html </pre>
3827 Arguments:
3829 =over 2
3831 =item colunm
3833 number
3835 =item column_head
3837 string
3839 =item problem_number
3841 integer
3843 =item return_occurences
3845 boolean
3847 =item ignore_missing
3849 boolean
3851 =back
3853 Description:
3855 fractions will return the fractions from data::fractions. It will find
3856 "column_head" in the $INPUT record instead of that data header as
3857 data::fractions does.
3859 =cut
3861 start record
3863 # If the argument new_data is given, record sets new_data in
3864 # the model objects member specified with record_name. The
3865 # format of new_data is an array of strings, where each
3866 # element corresponds to a line of code as it would have
3867 # looked like in a valid NONMEM modelfile. If new_data is left
3868 # undefined, record returns lines of code belonging to the
3869 # record specified by record_name in a format that is valid in
3870 # a NONMEM modelfile.
3872 my @problems = @{$self -> {'problems'}};
3873 my $records;
3875 if ( defined $problems[ $problem_number - 1 ] ) {
3876 if ( scalar(@new_data) > 0 ){
3877 my $rec_class = "model::problem::$record_name";
3878 my $record = $rec_class -> new('record_arr' => \@new_data );
3879 } else {
3880 $record_name .= 's';
3881 $records = $problems[ $problem_number - 1 ] -> {$record_name};
3882 foreach my $record( @{$records} ){
3883 push(@data, $record -> _format_record);
3888 end record
3890 # }}} record
3892 # {{{ remove_inits
3894 =head2 fractions
3896 Usage:
3898 =for html <pre>
3900 my $fractions = $model_object -> fractions;
3902 =for html </pre>
3904 Arguments:
3906 =over 2
3908 =item colunm
3910 number
3912 =item column_head
3914 string
3916 =item problem_number
3918 integer
3920 =item return_occurences
3922 boolean
3924 =item ignore_missing
3926 boolean
3928 =back
3930 Description:
3932 fractions will return the fractions from data::fractions. It will find
3933 "column_head" in the $INPUT record instead of that data header as
3934 data::fractions does.
3936 =cut
3938 start remove_inits
3940 # Usage
3942 # $model -> remove_inits( type => 'theta',
3943 # indexes => [1,2,5,6] )
3946 # In all cases the type must be set to theta. Removing Omegas in
3947 # Sigmas is not allowed, (If need that feature, send us a
3948 # mail). In the above example the thetas 1, 2, 5 and 6 will be
3949 # removed from the modelfile. Notice that this alters the theta
3950 # numbering, so if you later decide that theta number 7 must be
3951 # removed as well, you must calculate its new position in the
3952 # file. In this case the new number would be 3. Also notice that
3953 # numbering starts with 1.
3955 # $model -> remove_inits( type => 'theta',
3956 # labels => ['V', 'CL'] )
3959 # If you have specified labels in you modelfiles(a label is
3960 # string inside a comment on the same row as the theta) you can
3961 # specify an array with labels, and the corresponding theta, if
3962 # it exists, will be removed. This is a much better approach
3963 # since you don't need to know where in order the theta you wish
3964 # to remove appears. If you specify both labels and indexes, the
3965 # indexes will be ignored.
3967 'debug' -> die( message => 'does not have the functionality for removing $OMEGA or $SIGMA options yet' )
3968 if ( $type eq 'omega' or $type eq 'sigma' );
3969 my $accessor = $type.'s';
3971 # First pick out a referens to the theta records array.
3972 my $inits_ref = $self -> problems -> [$problem_number -1] -> $accessor;
3974 # If we have any thetas at all:
3975 if ( defined $inits_ref ) {
3976 my @inits = @{$inits_ref};
3978 # If labels are specified, we translate the labels into
3979 # indexes.
3980 if ( scalar @labels > 0 ) {
3981 @indexes = ();
3982 my $i = 1;
3983 # Loop over theta records
3984 foreach my $init ( @inits ) {
3985 # Loop over the individual thetas inside
3986 foreach my $option ( @{$init -> options} ) {
3987 # Loop over all given labels.
3988 foreach my $label ( @labels ) {
3989 # Push the index number if a given label match the
3990 # theta label
3991 push( @indexes, $i ) if ( $option -> label eq $label);
3993 # $i is the count of thetas so far
3994 $i++;
3999 # We don't really remove thetas, we do a loop over all thetas
4000 # and recording which we like to keep. We do that by selecting
4001 # an index, from @indexes, that shall be removed and loop over
4002 # the thetas, all thetas that doesn't match the index are
4003 # stored in @keep_options. When we find a theta that matches,
4004 # we pick a new index and continue the loop. So by makeing
4005 # sure that @indexes is sorted, we only need to loop over the
4006 # thetas once.
4008 @indexes = sort {$a <=> $b} @indexes;
4010 my $index = 0;
4011 my $nr_options = 1;
4012 my @keep_records;
4014 # Loop over all records
4015 RECORD_LOOP: foreach my $record ( @inits ){
4016 my @keep_options = ();
4017 # Loop over all thetas
4018 foreach my $option ( @{$record -> options} ) {
4019 if( $indexes[ $index ] == $nr_options ){
4020 # If a theta matches an index, we take the next index
4021 # and forget the theta.
4022 unless( $index > $#indexes ){
4023 $index++;
4025 } else {
4026 # Otherwise we rember it.
4027 push(@keep_options,$option);
4029 $nr_options++;
4031 if( scalar(@keep_options) > 0 ){
4032 # If we remember some thetas, we must also remember the
4033 # record which they are in.
4034 $record -> options( \@keep_options );
4035 push( @keep_records, $record );
4039 # Set the all kept thetas back into the modelobject.
4040 @{$inits_ref} = @keep_records;
4042 } else {
4043 'debug' -> die( message => "No init of type $type defined" );
4046 end remove_inits
4048 # }}}
4050 # {{{ restore_inits
4052 =head2 fractions
4054 Usage:
4056 =for html <pre>
4058 my $fractions = $model_object -> fractions;
4060 =for html </pre>
4062 Arguments:
4064 =over 2
4066 =item colunm
4068 number
4070 =item column_head
4072 string
4074 =item problem_number
4076 integer
4078 =item return_occurences
4080 boolean
4082 =item ignore_missing
4084 boolean
4086 =back
4088 Description:
4090 fractions will return the fractions from data::fractions. It will find
4091 "column_head" in the $INPUT record instead of that data header as
4092 data::fractions does.
4094 =cut
4096 start restore_inits
4098 # restore_inits brings back initial values previously stored
4099 # using store_inits. This method pair allows a user to store
4100 # the currents initial values in a backup, replace them with
4101 # temporary values and later restore them.
4103 if ( defined $self -> {'problems'} ) {
4104 foreach my $problem ( @{$self -> {'problems'}} ){
4105 $problem -> restore_inits;
4109 end restore_inits
4111 # }}} restore_inits
4113 # {{{ store_inits
4115 =head2 fractions
4117 Usage:
4119 =for html <pre>
4121 my $fractions = $model_object -> fractions;
4123 =for html </pre>
4125 Arguments:
4127 =over 2
4129 =item colunm
4131 number
4133 =item column_head
4135 string
4137 =item problem_number
4139 integer
4141 =item return_occurences
4143 boolean
4145 =item ignore_missing
4147 boolean
4149 =back
4151 Description:
4153 fractions will return the fractions from data::fractions. It will find
4154 "column_head" in the $INPUT record instead of that data header as
4155 data::fractions does.
4157 =cut
4159 start store_inits
4161 # store_inits stores initial values that can later be
4162 # brought back using restore_inits. See L</restore_inits>.
4164 if ( defined $self -> {'problems'} ) {
4165 foreach my $problem ( @{$self -> {'problems'}} ){
4166 $problem -> store_inits;
4170 end store_inits
4172 # }}} store_inits
4174 # {{{ synchronize
4176 start synchronize
4178 # Synchronize checks the I<synced> object attribute to see
4179 # if the model is in sync with its corresponding file, given
4180 # by the objetc attribute I<filename>. If not, it checks if
4181 # the model contains any defined problems and if it does, it
4182 # writes the formatted model to disk, overwriting any
4183 # existing file of name I<filename>. If no problem is
4184 # defined, synchronize tries to parse the file I<filename>
4185 # and set the object internals to match it.
4186 unless( $self -> {'synced'} ){
4187 if( defined $self -> {'problems'} and
4188 scalar @{$self -> {'problems'}} > 0 ){
4189 $self -> _write;
4190 } else {
4191 if( -e $self -> full_name ){
4192 $self -> _read_problems;
4193 } else {
4194 return;
4198 $self -> {'synced'} = 1;
4200 end synchronize
4202 # }}} synchronize
4204 # {{{ flush
4205 start flush
4206 # synchronizes the object with the file on disk and empties
4207 # most of the objects attributes to save memory.
4208 if( defined $self -> {'problems'} and
4209 ( !$self -> {'synced'} or $force ) ) {
4210 $self -> _write;
4212 $self -> {'problems'} = undef;
4213 $self -> {'synced'} = 0;
4215 end flush
4216 # }}} flush
4218 # {{{ target
4219 start target
4221 if ( $parm eq 'disk' ) {
4222 $self -> {'target'} = 'disk';
4223 $self -> flush;
4224 } elsif ( $parm eq 'mem' and $self -> {'target'} eq 'disk' ) {
4225 $self -> {'target'} = 'mem';
4226 $self -> synchronize;
4229 end target
4230 # }}}
4232 # {{{ msfi_names
4234 =head2 msfi_names
4236 Usage:
4238 =for html <pre>
4240 my $msfi_names_ref = $model_object -> msfi_names;
4242 =for html </pre>
4244 Arguments:
4246 =over 2
4248 =item new_names
4250 array of strings
4252 =item problem_numbers
4254 array of integers
4256 =item ignore_missing_files
4258 boolean
4260 =back
4262 Description:
4264 msfi_names will return the names of all MSFI= statements in the
4265 $ESTIMATION records in all problems.
4267 =cut
4269 start msfi_names
4270 # Usage:
4272 # @msfiNames = @{$modobj -> msfi_names};
4274 # or better:
4276 # $msfiNamesRef = $modobj -> msfi_names;
4277 # @msfiNames = @{$msfiNamesRef} if (defined $msfiNamesRef);
4279 # This basic usage takes no arguments and returns the value of
4280 # the MSFI option in the $ESTIMATION NONMEM record of each
4281 # problem. @msfiNames will be a two-dimensional array:
4283 # [[msfiName_prob1],[msfiName_prob2],[msfiName_prob3]...]
4286 my @problems;
4287 if ( defined $self -> problems() ) {
4288 @problems = @{$self -> problems()};
4289 } else {
4290 'debug' -> die( message => "No problems defined in model" );
4293 if( scalar @new_names > 0 ) {
4294 my $i = 0;
4295 foreach my $prob ( @problems ) {
4296 $prob -> remove_records( type => 'msfi' );
4297 if( defined $new_names[$i] ) {
4298 $prob -> add_records( type => 'msfi',
4299 record_strings => [$new_names[$i]] );
4302 } else {
4303 foreach my $prob ( @problems ) {
4304 if ( defined $prob -> msfis() ) {
4305 my @instances = @{$prob -> msfis()};
4306 my @prob_names;
4307 foreach my $instance ( @instances ) {
4308 my @options;
4309 if ( defined $instance -> options() ) {
4310 @options = @{$instance -> options()};
4312 if ( defined $options[0] ) {
4313 push( @prob_names, $options[0] -> name );
4314 } else {
4315 push( @prob_names, undef );
4318 push( @names, \@prob_names );
4319 } else {
4320 push( @names, undef );
4325 end msfi_names
4327 # }}} msfi_names
4329 # {{{ msfo_names
4331 =head2 msfo_names
4333 Usage:
4335 =for html <pre>
4337 my $msfo_names_ref = $model_object -> msfo_names;
4339 =for html </pre>
4341 Arguments:
4343 =over 2
4345 =item new_names
4347 array of strings
4349 =item problem_numbers
4351 array of integers
4353 =item ignore_missing_files
4355 boolean
4357 =back
4359 Description:
4361 msfo_names will return the names of all MSFO= statements in the
4362 $ESTIMATION records in all problems.
4364 =cut
4366 start msfo_names
4367 # Usage:
4369 # @msfoNames = @{$modobj -> msfo_names};
4371 # or better:
4373 # $msfoNamesRef = $modobj -> msfo_names;
4374 # @msfoNames = @{$msfoNamesRef} if (defined $msfoNamesRef);
4376 # This basic usage takes no arguments and returns the value of
4377 # the MSFO option in the $ESTIMATION NONMEM record of each
4378 # problem. @msfoNames will be an array:
4380 # [msfoName_prob1,msfoName_prob2,msfoName_prob3...]
4383 # If the I<new_names> argument of msfo_names is given, the
4384 # values of the MSFO options will be changed.
4386 # To set the MSFO of specific problems, the I<problem_numbers>
4387 # argument can be used. It should be a reference to an array
4388 # containing the numbers of all problems where the FILE should
4389 # be changed or retrieved. If specified, the size of
4390 # I<new_names> must be the same as the size of
4391 # I<problem_numbers>.
4393 my ( $name_ref, $junk ) = $self ->
4394 _option_val_pos( name => 'MSFO',
4395 record_name => 'estimation',
4396 problem_numbers => \@problem_numbers,
4397 new_values => \@new_names );
4400 my ( $nonp_name_ref, $junk ) = $self ->
4401 _option_val_pos( name => 'MSFO',
4402 record_name => 'nonparametric',
4403 problem_numbers => \@problem_numbers,
4404 new_values => \@new_names );
4406 if( length( @{$name_ref} > 0 ) ){
4407 push( @names, @{$name_ref} );
4410 if( length( @{$nonp_name_ref} ) ){
4411 push( @names, @{$nonp_name_ref} );
4414 end msfo_names
4416 # }}} msfo_names
4418 # {{{ table_names
4420 =head2 fractions
4422 Usage:
4424 =for html <pre>
4426 my $fractions = $model_object -> fractions;
4428 =for html </pre>
4430 Arguments:
4432 =over 2
4434 =item colunm
4436 number
4438 =item column_head
4440 string
4442 =item problem_number
4444 integer
4446 =item return_occurences
4448 boolean
4450 =item ignore_missing
4452 boolean
4454 =back
4456 Description:
4458 fractions will return the fractions from data::fractions. It will find
4459 "column_head" in the $INPUT record instead of that data header as
4460 data::fractions does.
4462 =cut
4464 start table_names
4466 # Usage:
4468 # @tableNames = @{$modobj -> table_names};
4470 # This basic usage takes no arguments and returns the value of
4471 # the FILE option in the $TABLE NONMEM record of each
4472 # problem. @tableNames will be a two dimensional array:
4474 # [[tableName_prob1][tableName_prob2][tableName_prob3]...]
4477 # If the I<new_names> argument of table_names is given, the
4478 # values of the FILE options will be changed.
4480 # To set the FILE of specific problems, the I<problem_numbers>
4481 # argument can be used. It should be a reference to an array
4482 # containing the numbers of all problems where the FILE should
4483 # be changed or retrieved. If specified, the size of
4484 # I<new_names> must be the same as the size of
4485 # I<problem_numbers>.
4487 # The I<ignore_missing_files> boolean argument can be used to
4488 # set names of table that does not exist yet (e.g. before a
4489 # run has been performed).
4491 my ( $name_ref, $junk ) = $self ->
4492 _option_val_pos( name => 'FILE',
4493 record_name => 'table',
4494 problem_numbers => \@problem_numbers,
4495 new_values => \@new_names );
4496 if ( $#new_names >= 0 ) {
4497 my @problems = @{$self -> {'problems'}};
4498 unless( $#problem_numbers > 0 ){
4499 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
4501 foreach my $i ( @problem_numbers ) {
4502 $problems[$i-1] -> _read_table_files( ignore_missing_files => $ignore_missing_files || $self -> {'ignore_missing_output_files'});
4505 @names = @{$name_ref};
4507 end table_names
4509 # }}} table_names
4511 # {{{ table_files
4513 =head2 fractions
4515 Usage:
4517 =for html <pre>
4519 my $fractions = $model_object -> fractions;
4521 =for html </pre>
4523 Arguments:
4525 =over 2
4527 =item colunm
4529 number
4531 =item column_head
4533 string
4535 =item problem_number
4537 integer
4539 =item return_occurences
4541 boolean
4543 =item ignore_missing
4545 boolean
4547 =back
4549 Description:
4551 fractions will return the fractions from data::fractions. It will find
4552 "column_head" in the $INPUT record instead of that data header as
4553 data::fractions does.
4555 =cut
4557 start table_files
4559 # Usage:
4561 # @table_files = @{$modobj -> table_files};
4563 # This basic usage takes no arguments and returns the table
4564 # files objects for all problems. @table_files will be a
4565 # two dimensional array:
4567 # [[table_file_object_prob1][table_file_object_prob2]...]
4570 # To retrieve the table file objects from specific problems,
4571 # the I<problem_numbers> argument can be used. It should be
4572 # a reference to an array containing the numbers of all
4573 # problems from which the table file objects should be
4574 # retrieved.
4576 unless( $#problem_numbers > 0 ){
4577 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
4579 my @problems = @{$self -> {'problems'}};
4580 foreach my $i ( @problem_numbers ) {
4581 if ( defined $problems[ $i-1 ] ) {
4582 push( @table_files, $problems[$i-1] -> table_files );
4583 } else {
4584 'debug' -> die( message => "Problem number $i does not exist!" );
4588 end table_files
4590 # }}}
4592 # {{{ units
4594 =head2 fractions
4596 Usage:
4598 =for html <pre>
4600 my $fractions = $model_object -> fractions;
4602 =for html </pre>
4604 Arguments:
4606 =over 2
4608 =item colunm
4610 number
4612 =item column_head
4614 string
4616 =item problem_number
4618 integer
4620 =item return_occurences
4622 boolean
4624 =item ignore_missing
4626 boolean
4628 =back
4630 Description:
4632 fractions will return the fractions from data::fractions. It will find
4633 "column_head" in the $INPUT record instead of that data header as
4634 data::fractions does.
4636 =cut
4638 start units
4640 # Sets or gets the units of a (number of) parameter(s). The
4641 # unit is not a proper NONMEM syntax but is recognized by
4642 # the PsN model class. A unit (and a label) can be specified
4643 # as a comments after a parameter definition. e.g.:
4645 # $THETA (0,13.2,100) ; MTT; h
4647 # which will give this theta the label I<MTT> and unit I<h>.
4648 @units = @{ $self -> _init_attr( parameter_type => $parameter_type,
4649 parameter_numbers => \@parameter_numbers,
4650 problem_numbers => \@problem_numbers,
4651 new_values => \@new_values,
4652 type => 'unit')};
4654 end units
4656 # }}} units
4658 # {{{ update_inits
4661 =head2 fractions
4663 Usage:
4665 =for html <pre>
4667 my $fractions = $model_object -> fractions;
4669 =for html </pre>
4671 Arguments:
4673 =over 2
4675 =item colunm
4677 number
4679 =item column_head
4681 string
4683 =item problem_number
4685 integer
4687 =item return_occurences
4689 boolean
4691 =item ignore_missing
4693 boolean
4695 =back
4697 Description:
4699 fractions will return the fractions from data::fractions. It will find
4700 "column_head" in the $INPUT record instead of that data header as
4701 data::fractions does.
4703 =cut
4705 start update_inits
4707 # Usage:
4709 # $modobj -> update_inits ( from_output => $outobj );
4711 # alt
4713 # $modobj -> update_inits ( from_output_file => $outfile );
4715 # This basic usage takes the parameter estimates from the
4716 # output object I<$outobj> or from the output file I<$outfile>
4717 # and updates the initial estimates in the model object
4718 # I<$modobj>. The number of problems and parameters must be
4719 # the same in the model and output objects. If there exist
4720 # more than one subproblem per problem in the output object,
4721 # only the estimates from the first subproblem will be
4722 # transferred.
4724 # $modobj -> update_inits ( from_output => $outobj,
4725 # ignore_missing_parameters => 1 );
4727 # If the ignore_missing_parameters argument is set to 1, the number of
4728 # parameters in the model and output objects do not need to match. The
4729 # parameters that exist in both objects are used for the update of the
4730 # model object.
4732 # $modobj -> update_inits ( from_output => $outobj,
4733 # from_model => $from_modobj );
4735 # If the from_model argument is given, update_inits tries to match the
4736 # parameter names (labels) given in $from_modobj and $modobj and
4737 # and thereafter updating the $modobj object. See L</units> and L</labels>.
4740 my ( %labels, @own_labels, @from_labels );
4741 'debug' -> die( message => "No output object defined and" .
4742 " no output object found through the model object specified." )
4743 unless ( ( defined $from_model and
4744 ( defined $from_model -> outputs and
4745 defined @{$from_model -> outputs}[0] ) ) or
4746 defined $from_output or
4747 defined $from_output_file );
4748 if ( defined $from_output ) {
4749 'debug' -> warn( level => 2,
4750 message => "using output object ".
4751 "specified as argument\n" );
4752 } elsif ( defined $from_output_file ) {
4753 $from_output = output -> new( filename => $from_output_file );
4754 } else {
4755 $from_output = @{$from_model -> outputs}[0];
4758 my @params = ();
4759 if( $update_thetas ){
4760 push( @params, 'theta' );
4762 if( $update_omegas ) {
4763 push( @params, 'omega' );
4765 if( $update_sigmas ) {
4766 push( @params, 'sigma' );
4769 foreach my $param ( @params ) {
4770 # Get own labels and from labels
4771 if ( defined $from_model ) {
4772 @own_labels = @{$self -> labels( parameter_type => $param )};
4774 @from_labels = @{$from_model -> labels( parameter_type => $param )};
4775 'debug' -> die( message => "The number of problems are not the same in from-model ".
4776 $from_model -> full_name." (".
4777 ($#from_labels+1).")".
4778 " and the model to be updated ".
4779 $self -> full_name." (".
4780 ($#own_labels+1).")" ) unless ( $#own_labels == $#from_labels );
4781 } else {
4782 @own_labels = @{$self -> labels( parameter_type => $param,
4783 generic => 1 )};
4784 @from_labels = @{$from_output -> labels( parameter_type => $param )};
4785 'debug' -> die( message => "The number of problems are not the same in from-output ".
4786 $from_output -> full_name." (".
4787 ($#from_labels+1).")".
4788 " and the model to be updated ".
4789 $self -> full_name." (".
4790 ($#own_labels+1).")" ) unless ( $#own_labels == $#from_labels );
4793 # Loop over the problems:
4794 my $accessor = $param.'s';
4795 # Since initial estimates are specified on the problem level and not on
4796 # the subproblem level we use the estimates from the outputs first subproblem
4797 my @from_values = @{$from_output -> $accessor ( subproblems => [1] )};
4798 # {{{ Omega and Sigma update section
4800 # The functionality that has been commented out because it
4801 # fails when omegas are zero. This functionality should be
4802 # moved to output::problem::subproblem (2005-02-09) TODO
4804 # if ($param eq 'omega' or $param eq 'sigma')
4806 # #print "FL: ", Dumper @from_labels;
4807 # #print "OL: ", Dumper @own_labels;
4808 # print "FV: $param Before " . Dumper(@from_values) . "\n";
4809 # #Fix omegas and sigmas so that the correlation between elements <=1
4810 # my $raw_accessor = "raw_" . $accessor;
4811 # my @raw_from_values = @{$from_output -> $raw_accessor(subproblems => [1])};
4812 # my ($i,$j);
4813 # for (my $a=0; $a<scalar(@from_values); $a++)
4815 # my $prob_values = $from_values[$a];
4816 # my $raw_prob_values = $raw_from_values[$a];
4817 # for (my $b=0; $b<scalar(@{$prob_values}); $b++)
4819 # my $values = $prob_values->[$b];
4820 # my $raw_values = $raw_prob_values->[$b];
4821 # my $counter = 0;
4822 # #Find out the n*n-matrix size (pq-formula)
4823 # my $n = int(sqrt(1/4+scalar(@{$raw_values})*2)-1/2);
4824 # for ($i=0; $i<$n; $i++)
4826 # for ($j=0; $j<$n; $j++)
4828 # if ( $j<=$i && $raw_values->[$i*($i+1)/2+$j]!=0 )
4830 # #print "Omega value = " . @other_val[$counter] . "\n";
4831 # $counter++;
4833 # #Only check the low-triangular off-diagonals of the omega matrix
4834 # #omega(i,j)>=sqrt(omega(i,i)*omega(j,j))
4835 # if ($j<=$i && $j!=$i &&
4836 # ($raw_values->[$i*($i+1)/2+$j]>=sqrt(
4837 # $raw_values->[$i*($i+1)/2+$i]*$raw_values->[$j*($j+1)/2+$j])))
4839 # print "Changing raw value at $i, $j: " . $raw_values->[$i*($i+1)/2+$j] ." to ".
4840 # (int(10000*sqrt($raw_values->[$i*($i+1)/2+$i]*$raw_values->[$j*($j+1)/2+$j]))/10000) ."\n";
4841 # #print "At index ($i,$j)\n" if ($self->{'debug'});
4842 # $raw_values->[$i*($i+1)/2+$j]=int(10000*sqrt(
4843 # $raw_values->[$i*($i+1)/2+$i]*$raw_values->[$j*($j+1)/2+$j]))/10000;
4844 # print "Changing omega value " . $values->[$counter-1] . " to " . $raw_values->[$i*($i+1)/2+$j] ."\n";
4845 # $values->[$counter-1] = $raw_values->[$i*($i+1)/2+$j];
4851 # #print "FL: ", Dumper @from_labels;
4852 # #print "OL: ", Dumper @own_labels;
4853 # print "FV: $param After ", Dumper(@from_values), "\n";
4854 # die;
4857 # }}}
4859 for ( my $i = 0; $i <= $#own_labels; $i++ ) {
4861 if( $from_output -> have_user_defined_prior ){
4862 $ignore_missing_parameters = 1;
4864 unless ( $ignore_missing_parameters ) {
4865 my $from_name = defined $from_model ? $from_model -> filename :
4866 $from_output -> filename;
4867 'debug' -> die( message => "Model -> update_inits: The number of ".$param.
4868 "s are not the same in from-model (" . $from_name .
4869 "): " . scalar @{$from_labels[$i]} .
4870 ", and the model to be updated (" . $self -> {'filename'} .
4871 "): " . scalar @{$own_labels[$i]} )
4872 unless ( scalar @{$own_labels[$i]} ==
4873 scalar @{$from_labels[$i]} );
4876 for ( my $j = 0; $j < scalar @{$from_labels[$i]}; $j++ ) {
4877 for ( my $k = 0; $k < scalar @{$own_labels[$i]}; $k++ ) {
4878 if ( $from_labels[$i][$j] eq $own_labels[$i][$k] ){
4879 $labels{$k+1} = $from_values[$i][0][$j];
4884 my @own_idxs = keys( %labels );
4885 my @from_vals;
4886 for(my $i=0; $i <= $#own_idxs; $i++){
4887 @from_vals[$i] = $labels{ $own_idxs[$i] };
4890 $self -> initial_values( problem_numbers => [$i+1],
4891 parameter_type => $param,
4892 parameter_numbers => [\@own_idxs],
4893 new_values => [\@from_vals] );
4897 end update_inits
4899 # }}} update_inits
4901 # {{{ upper_bounds
4903 start upper_bounds
4905 # upper_bounds either sets or gets the initial values of the
4906 # parameter specified in I<parameter_type> for each
4907 # subproblem specified in I<problem_numbers>. For each
4908 # element in I<problem_numbers> there must be an array in
4909 # I<parameter_numbers> that specify the indices of the
4910 # parameters in the subproblem for which the upper bounds
4911 # are set, replaced or retrieved.
4913 @upper_bounds = @{ $self -> _init_attr
4914 ( parameter_type => $parameter_type,
4915 parameter_numbers => \@parameter_numbers,
4916 problem_numbers => \@problem_numbers,
4917 new_values => \@new_values,
4918 attribute => 'upbnd')};
4920 end upper_bounds
4922 # }}} upper_bounds
4924 # {{{ clean_extra_data_code
4925 start clean_extra_data_code
4928 # This method cleans out old code for extra data. It searches
4929 # all subroutine statements in all problems for external
4930 # subroutines named "get_sub" and "reader" which are added by
4931 # "add_extra_data_code".
4933 foreach my $problem( @{$self -> {'problems'}} ){
4934 if ( defined $problem -> subroutines and defined $problem -> subroutines -> [0] -> options) {
4935 foreach my $option ( @{$problem -> subroutines -> [0] -> options} ){
4936 if( lc($option -> name) eq 'other'){
4937 if( lc($option -> value) =~ /get_sub|reader/ ){
4939 # If we find "get_sub" or "reader" we remove
4940 # everything between "IMPORTING COVARIATE DATA" and
4941 # "IMPORTING COVARIATE DATA END" by finding the
4942 # indexes in the code array and and splicing it out.
4944 my $code;
4945 if( $problem -> pks ){
4946 # If the code is in a pk block:
4947 $code = $problem -> pks -> [0] -> code;
4948 } else {
4949 $code = $problem -> preds -> [0] -> code;
4952 my $start_idx;
4953 my $end_idx;
4954 for( my $i = 0; $i <= $#{$code}; $i++ ){
4955 if( $code -> [$i] eq ";***IMPORTING COVARIATE DATA*******\n" ){
4956 $start_idx = $i-1;
4958 if( $code -> [$i] eq ";***IMPORTING COVARIATE DATA END***\n" ){
4959 $end_idx = $i+1;
4962 @{$code} = ( @{$code}[0..$start_idx] , @{$code}[$end_idx..$#{$code}] );
4964 if( $problem -> pks ){
4965 # Put the cut down code back in the right place:
4966 $problem -> pks -> [0] -> code( $code );
4967 } else {
4968 $problem -> preds -> [0] -> code( $code );
4971 last;
4978 end clean_extra_data_code
4979 # }}} clean_extra_data_code
4981 # {{{ add_extra_data_code
4983 start add_extra_data_code
4985 # This method adds fortran code that will handle wide datasets
4986 # (that is data sets with more than 20 columns). It adds code to
4987 # each problems pk or pred.
4989 my @code_lines;
4991 # Get the headers of the columns that have been moved to another
4992 # data file.
4994 # unless( defined $self -> extra_data_headers ){
4995 # die "ERROR model::add_extra_data_code: No headers for the extra data file\n";
4998 # extra_data_headers is a two dimensional array. One array of
4999 # headers for each problem in the modelfile.
5000 for( my $i = 0; $i <= $#{$self -> {'problems'}}; $i++ ){
5001 if ( defined $self -> {'problems'} -> [$i] -> {'extra_data_header'} ) {
5002 my $problem_headers = $self -> {'problems'} -> [$i] -> {'extra_data_header'};
5004 my $length = 0;
5005 my @headers;
5006 my $header_string;
5007 # Loop over the problem specific headers and make a string
5008 # that will go into the fortran code. Assume that the
5009 # first column holds the ID, hence the $i=1
5010 for (my $i = 1; $i <= $#{$problem_headers}; $i++ ) {
5011 my $header = $problem_headers -> [$i];
5012 push( @headers, $header );
5013 # Chopp the string at 40 characters, to be nice to g77 :)
5014 if ( $length + length($header) > 40 ) {
5015 $header_string .= "\n\"& ";
5016 $length = 0
5018 if ( $i < $#{$problem_headers} ) {
5019 $header_string .= 'I' . $header . ', ';
5020 $length += length( 'I' . $header . ', ' );
5021 } else {
5022 $header_string .= 'I' . $header;
5023 $length += length( 'I' . $header );
5027 my @code_lines = ('',
5028 ';***IMPORTING COVARIATE DATA*******',
5029 '" FIRST',
5030 '" REAL CURID, MID,',
5031 '"& '.$header_string,
5032 '" LOGICAL READ',
5033 '"',
5034 '" IF (.NOT.READ) THEN',
5035 '" CALL READER()',
5036 '" CURID = 1',
5037 '" READ = .TRUE.',
5038 '" END IF',
5039 '"',
5040 '" IF (NEWIND.LT.2) THEN',
5041 '" CALL GET_SUB (NEWIND,ID,CURID,MID,',
5042 '"& '.$header_string. ')',
5043 '" END IF',
5044 ' CID = MID',
5045 ' IF (CID.NE.ID) THEN',
5046 ' PRINT *, \'ERROR CHECKING FAILED, CID = \', CID ,\' ID = \', ID',
5047 ' END IF',
5048 '');
5050 foreach my $header ( @headers ) {
5051 push( @code_lines, " $header = I$header" );
5054 push( @code_lines, (';***IMPORTING COVARIATE DATA END***','','') );
5056 my $problem = $self -> {'problems'} -> [$i];
5057 if ( defined $problem -> {'subroutines'} ) {
5058 $problem -> subroutines -> [0] -> _add_option( option_string => 'OTHER=get_sub' . $i );
5059 $problem -> subroutines -> [0] -> _add_option( option_string => 'OTHER=reader' . $i );
5060 } else {
5061 $problem -> add_records( type => 'subroutines', record_strings => ['OTHER=get_sub', 'OTHER=reader'] );
5064 if ( defined $problem -> pks ) {
5065 unshift( @{$problem -> pks -> [0] -> code}, join("\n", @code_lines ));
5066 } else {
5067 unshift( @{$problem -> preds -> [0] -> code},join("\n", @code_lines ));
5072 end add_extra_data_code
5074 # }}}
5076 # {{{ drop_dropped
5078 start drop_dropped
5080 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5081 $self -> {'datas'}[$i] -> drop_dropped( model_header => $self -> {'problems'}[$i] -> header );
5082 $self -> {'problems'}[$i] -> drop_dropped( );
5083 #$self -> {'datas'}[$i] -> model_header( $self -> {'problems'}[$i] -> header );
5086 end drop_dropped
5088 # }}} drop_dropped
5090 # {{{ wrap_data
5092 start wrap_data
5094 my $default_wrap = 18;
5096 $self -> drop_dropped(1);
5098 my ( @wrap_columns, @cont_columns );
5099 if ( not defined $wrap_column ) {
5100 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5101 my $columns = scalar @{$self -> {'problems'}[$i] -> dropped_columns}-1; #skip ID
5102 my $modulus = $columns%($default_wrap-2); # default_wrap-2 to account for ID and CONT
5103 my $rows = (($columns-$modulus)/($default_wrap-2))+1;
5104 if ( $rows == 1 ) {
5105 push( @wrap_columns, undef );
5106 } else {
5107 push( @wrap_columns, (ceil( $columns/$rows )+2) ); #Must use #cols + ID and CONT
5110 } else {
5111 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5112 push( @wrap_columns, $wrap_column );
5116 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5117 next if ( not defined $wrap_columns[$i] );
5118 $wrap_column = $wrap_columns[$i];
5119 $cont_column = $wrap_columns[$i] if( not defined $cont_column );
5120 my ( $prim, $sec ) =
5121 $self -> {'datas'}[$i] -> wrap( cont_column => $cont_column,
5122 wrap_column => $wrap_column,
5123 model_header => $self -> {'problems'}[$i] -> header );
5124 $self -> {'problems'}[$i] -> primary_columns( $prim );
5125 $self -> {'problems'}[$i] -> secondary_columns( $sec );
5126 $self -> {'data_wrapped'}++;
5129 end wrap_data
5131 # }}} wrap_data
5133 # {{{ unwrap_data
5134 start unwrap_data
5136 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5137 $self -> {'datas'}[$i] -> unwrap;
5138 $self -> {'problems'}[$i] -> primary_columns( [] );
5139 $self -> {'problems'}[$i] -> secondary_columns( [] );
5141 $self -> {'data_wrapped'} = 0;
5143 end unwrap_data
5144 # }}} unwrap_data
5146 # {{{ write_get_subs
5148 start write_get_subs
5150 for( my $i = 0; $i <= $#{$self -> {'problems'}}; $i++ ){
5151 if ( defined $self -> {'problems'} -> [$i] -> {'extra_data_header'} and
5152 defined $self -> problems -> [$i] -> extra_data ) {
5153 my @problem_header = @{$self -> {'problems'} -> [$i] -> {'extra_data_header'}};
5154 my @headers;
5155 my $length = 0;
5156 my $header_string;
5158 my $rows = $self -> problems -> [$i] -> extra_data -> count_ind;
5160 # Assume that first column holds the ID. Get rid of it.
5161 shift( @problem_header );
5162 for ( my $i = 0; $i <= $#problem_header; $i++ ) {
5163 my $header = $problem_header[$i];
5164 push( @headers, $header );
5165 # Chop the string at 40 characters, to be nice to g77 :)
5166 if ( $length + length($header) > 40 ) {
5167 $header_string .= "\n & ";
5168 $length = 0
5170 if ( $i < $#problem_header ) {
5171 $header_string .= $header . ', ';
5172 $length += length( $header . ', ' );
5173 } else {
5174 $header_string .= $header;
5175 $length += length( $header );
5179 open( FILE, '>', 'get_sub' . $i . '.f' );
5180 print FILE (" SUBROUTINE GET_SUB (NEWIND,ID,CURID,MID,\n",
5181 " & $header_string)\n",
5182 " COMMON /READ/ TID,TCOV\n",
5183 "\n",
5184 " REAL ID,CURID,MID,\n",
5185 " & $header_string\n",
5186 "\n",
5187 " INTEGER NEWIND\n",
5188 "\n",
5189 " REAL TID($rows), TCOV($rows,",scalar @problem_header,")\n",
5190 " CURID = 1\n",
5191 "\n",
5192 "C START AT TOP EVERY TIME\n",
5193 " IF (NEWIND.EQ.1) THEN \n",
5194 "12 CONTINUE\n",
5195 " IF (CURID.GT.$rows) THEN \n",
5196 " PRINT *, \"Covariate data not found for\", ID\n",
5197 " MID = -9999\n",
5198 " RETURN\n",
5199 " END IF\n",
5200 "\n",
5201 " IF (ID.GT.TID (CURID)) THEN\n",
5202 " CURID = CURID + 1\n",
5203 " GOTO 12\n",
5204 " END IF\n",
5205 " ELSEIF (NEWIND.EQ.0) THEN\n",
5206 " CURID = 1\n",
5207 " END IF\n",
5208 "\n" );
5209 my $length = 0;
5210 for ( my $i = 1; $i <= $#headers+1; $i++ ) {
5211 $length += length("TCOV(I,$i),");
5212 if ( $length > 40 ) {
5213 print FILE "\n";
5214 $length = 0;
5216 print FILE " ".$headers[$i-1] . " = TCOV(CURID,$i)\n";
5219 print FILE (" MID = TID(CURID)\n",
5220 " END\n",
5221 "\n" );
5223 close FILE;
5226 close( FILE );
5228 end write_get_subs
5230 # }}}
5232 # {{{ write_readers
5234 start write_readers
5236 for( my $i = 0; $i <= $#{$self -> {'problems'}}; $i++ ){
5237 if ( defined $self -> {'problems'} -> [$i] -> {'extra_data_header'} and
5238 defined $self -> {'problems'} -> [$i] -> {'extra_data'} ) {
5239 my @problem_header = @{$self -> {'problems'} -> [$i] -> {'extra_data_header'}};
5240 my @headers;
5241 my $length = 0;
5243 my $rows = $self -> problems -> [$i] -> extra_data -> count_ind;
5244 my $filename = $self -> problems -> [$i] -> extra_data -> filename;
5245 # Assume that first column holds the ID. Get rid of it.
5246 shift( @problem_header );
5248 'debug' -> warn( level => 2,
5249 message => "Writing reader".$i.".f to directory".cwd );
5250 open( FILE, '>', 'reader' . $i . '.f' );
5251 print FILE (" SUBROUTINE READER()\n",
5252 "\n",
5253 " COMMON /READ/ TID,TCOV\n",
5254 "\n",
5255 " REAL TID ($rows), TCOV ($rows, ",scalar @problem_header,")\n",
5256 "\n",
5257 " OPEN (UNIT = 77,FILE = '$filename')\n",
5258 " REWIND 77\n",
5259 " DO 11,I = 1,$rows\n",
5260 " READ (77,*) TID(I)," );
5262 my $length = 0;
5263 for ( my $i = 1; $i <= $#problem_header+1; $i++ ) {
5264 $length += length("TCOV(I,$i),");
5265 if ( $length > 40 ) {
5266 print FILE "\n & ";
5267 $length = 0;
5269 if ( $i <= $#problem_header ) {
5270 print FILE "TCOV(I,$i),";
5271 } else {
5272 print FILE "TCOV(I,$i)\n";
5276 print FILE ( "11 CONTINUE\n",
5277 " END\n" );
5281 end write_readers
5283 # }}}
5285 # {{{ _write
5287 start _write
5290 # $model -> _write( filename => 'model.mod' );
5292 # Writes the content of the modelobject to disk. Either to the
5293 # filename given, or to the string returned by model::full_name.
5295 my @formatted;
5297 # An element in the active_problems array is a boolean that
5298 # corresponds to the element with the same index in the problems
5299 # array. If the boolean is true, the problem will be run. All
5300 # other will be commented out.
5301 my @active = @{$self -> {'active_problems'}};
5303 # loop over all problems.
5304 for ( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5305 # Call on the problem object to format it as text. The
5306 # filename and problem numbers are needed to make some
5307 # autogenerated files (msfi, tabels etc...) unique to the
5308 # model and problem
5309 my @preformatted = @{$self -> {'problems'} -> [$i] ->
5310 _format_problem( filename => $self -> filename,
5311 problem_number => ($i+1) ) };
5312 # Check if the problem is NOT active, if so comment it out.
5313 unless ( $active[$i] ) {
5314 for ( my $j = 0; $j <= $#preformatted; $j++ ) {
5315 $preformatted[$j] = '; '.$preformatted[$j];
5318 # Add extra line to avoid problems with execution of NONMEM
5319 push(@preformatted,"\n");
5320 push( @formatted, @preformatted );
5323 # Open a file and print the formatted problems.
5324 # TODO Add some errorchecking.
5325 open( FILE, '>'. $filename );
5326 for ( @formatted ) {
5327 chomp;
5328 print FILE;
5329 print FILE "\n";
5331 close( FILE );
5333 if ( $write_data ) {
5334 foreach my $data ( @{$self -> {'datas'}} ) {
5335 $data -> _write;
5339 if( $self -> {'iofv_modules'} ){
5340 $self -> {'iofv_modules'} -> [0] -> post_process;
5344 end _write
5346 # }}} _write
5348 # {{{ filename
5349 start filename
5351 if ( defined $parm and $parm ne $self -> {'filename'} ) {
5352 $self -> {'filename'} = $parm;
5353 $self -> {'model_id'} = undef;
5354 # $self -> _write;
5357 end filename
5358 # }}} filename
5360 # {{{ _get_option_val_pos
5362 start _get_option_val_pos
5364 # Usage:
5366 # ( $values_ref, $positions_ref ) ->
5367 # _get_option_val_pos ( name => 'ID',
5368 # record_name => 'input' );
5369 # my @values = @{$values_ref};
5370 # my @positions = @{$positions_ref};
5372 # This basic usage returns the name of the third option in the first
5373 # instance of the record specified by I<record_name> for all problems
5375 # If global_position is set to 1, only one value and position
5376 # pair is returned per problem. If there are more than one
5377 # match in the model; the first will be returned for each
5378 # problem.
5380 # Private method, should preferably not be used outside model.pm
5382 # my ( @records, @instances );
5383 my $accessor = $record_name.'s';
5384 my @problems = @{$self -> {'problems'}};
5385 unless( $#problem_numbers > 0 ){
5386 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5388 foreach my $i ( @problem_numbers ) {
5389 my $rec_ref = $problems[ $i-1 ] -> $accessor;
5390 if ( defined $problems[ $i-1 ] and defined $rec_ref ) {
5391 my @records = @{$rec_ref};
5392 unless( $#instances > 0 ){
5393 @instances = (1 .. $#records+1);
5396 my @inst_values = ();
5397 my @inst_positions = ();
5398 my $glob_pos = 1;
5399 my ( $glob_value, $glob_position );
5400 INSTANCES: foreach my $j ( @instances ) {
5401 if ( defined $records[ $j-1 ] ) {
5402 my $k = 1;
5403 my ( $value, $position );
5404 foreach my $option ( @{$records[$j-1] -> {'options'}} ) {
5405 if ( defined $option and $option -> name eq $name) {
5406 if ( $global_position ) {
5407 $glob_value = $option -> value;
5408 $glob_position = $glob_pos;
5409 last INSTANCES;
5410 } else {
5411 $value = $option -> value;
5412 $position = $k;
5415 $k++;
5416 $glob_pos++;
5418 push( @inst_values, $value );
5419 push( @inst_positions, $position );
5420 } else {
5421 'debug' -> die( message => "Instance $j in problem number $i does not exist!" )
5424 if ( $global_position ) {
5425 push( @values, $glob_value );
5426 push( @positions, $glob_position );
5427 } else {
5428 push( @values, \@inst_values );
5429 push( @positions, \@inst_positions );
5431 } else {
5432 'debug' -> die( message => "Problem number $i does not exist!" );
5435 # if( defined $problem_number ) {
5436 # if( $problem_number < 1 or $problem_number > scalar @problems ) {
5437 # die "model -> _get_option_val_pos: No such problem number, ",
5438 # $problem_number,", in this model!\n";
5441 # my $i;
5442 # die "modelfile -> _get_option_val_pos: No problem $problem_number exists\n"
5443 # if( (scalar @problems < 1) and ($problem_number ne 'all') );
5444 # my $j = 1;
5445 # foreach my $problem ( @problems ) {
5446 # @records = @{$problem -> $accessor};
5447 # @records = ($records[$instance-1]) if ( $instance ne 'all' );
5448 # die "modelfile -> _get_option_val_pos: No record instance $instance ".
5449 # "of record $record_name in problem $problem_number exists\n"
5450 # if( (scalar @records < 1) and ($instance ne 'all') );
5451 # foreach my $record ( @records ) {
5452 # $i = 1;
5453 # foreach my $option ( @{$record -> {'options'}} ) {
5454 # if ( defined $option and $option -> name eq $name) {
5455 # print "Found $name at $i\n" if ( $self -> {'debug'} );
5456 # push( @values, $option -> value );
5457 # push( @positions, $i );
5459 # $i++;
5464 end _get_option_val_pos
5466 # }}} _get_option_val_pos
5468 # {{{ _init_attr
5470 start _init_attr
5472 # The I<add_if_absent> argument tells the method to add an init (theta,omega,sigma)
5473 # if the parameter number points to a non-existing parameter with parameter number
5474 # one higher than the highest presently included. Only applicatble if
5475 # I<new_values> are set. Default value = 0;
5477 unless( scalar @problem_numbers > 0 ){
5478 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5480 my @problems = @{$self -> {'problems'}};
5481 if ( $#new_values >= 0 ) {
5482 'debug' -> die( message => "The number of new value sets " .
5483 ($#new_values+1) . " do not" .
5484 " match the number of problems " . ($#problem_numbers+1) . " specified" )
5485 unless(($#new_values == $#problem_numbers) );
5486 if ( $#parameter_numbers > 0 ) {
5487 'debug' -> die( message => "The number of parameter number sets do not" .
5488 " match the number of problems specified" )
5489 unless(($#parameter_numbers == $#problem_numbers) );
5493 my $new_val_idx = 0;
5494 foreach my $i ( @problem_numbers ) {
5495 if ( defined $problems[ $i-1 ] ) {
5496 if ( scalar @new_values > 0) {
5497 # {{{ Update values
5498 # Use attribute parameter_values to collect diagnostic outputs
5499 push( @parameter_values,
5500 $problems[ $i-1 ] ->
5501 _init_attr( parameter_type => $parameter_type,
5502 parameter_numbers => $parameter_numbers[ $new_val_idx ],
5503 new_values => \@{$new_values[ $new_val_idx ]},
5504 attribute => $attribute,
5505 add_if_absent => $add_if_absent ) );
5506 # }}} Update values
5507 } else {
5508 # {{{ Retrieve values
5509 push( @parameter_values,
5510 $problems[ $i-1 ] ->
5511 _init_attr( parameter_type => $parameter_type,
5512 parameter_numbers => $parameter_numbers[ $i-1 ],
5513 attribute => $attribute ) );
5514 # }}} Retrieve values
5516 } else {
5517 'debug' -> die( message => "Problem number $i does not exist!" );
5519 $new_val_idx++;
5522 end _init_attr
5524 # }}} _init_attr
5526 # {{{ _option_name
5528 start _option_name
5530 # Usage:
5532 # $modobj -> _option_name ( record => $record_name,
5533 # position => 3 );
5535 # This basic usage returns the name of the third option in the first
5536 # instance of the record specified by I<record>.
5539 my ( @problems, @records, @options, $i );
5540 my $accessor = $record.'s';
5541 if ( defined $self -> {'problems'} ) {
5542 @problems = @{$self -> {'problems'}};
5543 } else {
5544 'debug' -> die( message => "No problems defined in model" );
5546 if ( defined $problems[$problem_number - 1] -> $accessor ) {
5547 @records = @{$problems[$problem_number - 1] -> $accessor};
5548 } else {
5549 'debug' -> die( message => "No record $record defined in ".
5550 "problem number $problem_number." );
5552 if ( defined $records[$instance - 1] -> options ) {
5553 @options = @{$records[$instance - 1] -> options};
5554 } else {
5555 'debug' -> die( message => "model -> _option_name: No option defined in record ".
5556 "$record in problem number $problem_number." );
5558 $i = 0;
5559 foreach my $option ( @options ) {
5560 if ( $i == $position ) {
5561 if ( defined $new_name ){
5562 $option -> name($new_name) if ( defined $option );
5563 }else{
5564 $name = $option -> name if ( defined $option );
5567 $i++;
5570 end _option_name
5572 # }}} _option_name
5574 # {{{ _parameter_count
5575 start _parameter_count
5577 if( defined $self -> {'problems'} ){
5578 my $problems = $self -> {'problems'};
5579 if( defined @{$problems}[$problem_number - 1] ){
5580 $count = @{$problems}[$problem_number - 1] -> record_count( 'record_name' => $record );
5584 end _parameter_count
5585 # }}} _parameter_count
5587 # {{{ _read_problems
5589 start _read_problems
5592 # To read problems from a modelfile we need its full name
5593 # (meaning filename and path). And we need an array for the
5594 # modelfile lines and an array with indexes telling where
5595 # problems start in the modelfile array.
5598 my $file = $self -> full_name;
5599 my ( @modelfile, @problems );
5600 my ( @problem_start_index );
5602 # Check if the file is missing, and if that is ok.
5603 # TODO Check accessor what happens if the file is missing.
5605 return if( not (-e $file) && $self -> {'ignore_missing_files'} );
5607 # Open the file, slurp it and close it
5608 open( FILE, "$file" ) ||
5609 'debug' -> die( message => "Model -> _read_problems: Could not open $file".
5610 " for reading" );
5611 @modelfile = <FILE>;
5612 close( FILE );
5614 my @extra_data_files = defined $self ->{'extra_data_files'} ?
5615 @{$self -> {'extra_data_files'}} : ();
5616 my @extra_data_headers = defined $self ->{'extra_data_headers'} ?
5617 @{$self -> {'extra_data_headers'}} : ();
5620 # # Find the indexes where the problems start
5621 # for ( my $i = 0; $i <= $#modelfile; $i++ ) {
5622 # push( @problem_start_index, $i )if ( $modelfile[$i] =~ /\$PROB/ );
5625 # # Loop over the number of problems. Copy the each problems lines
5626 # # and create a problem object.
5628 # for( my $i = 0; $i <= $#problem_start_index; $i++ ) {
5629 # my $start_index = $problem_start_index[$i];
5630 # my $end_index = defined $problem_start_index[$i+1] ? $problem_start_index[$i+1] - 1: $#modelfile ;
5631 # # Line copy
5632 # my @problem_lines = @modelfile[$start_index .. $end_index];
5634 # # Problem object creation.
5635 # push( @problems, model::problem -> new ( debug => $self -> {'debug'},
5636 # ignore_missing_files => $self -> {'ignore_missing_files'},
5637 # prob_arr => \@problem_lines,
5638 # extra_data_file_name => $extra_data_files[$i],
5639 # extra_data_header => $extra_data_headers[$i]) );
5641 my $start_index = 0;
5642 my $end_index;
5643 my $first = 1;
5644 my $prob_num = 0;
5646 # It may look like the loop takes one step to much, but its a
5647 # trick that helps parsing the last problem.
5648 for ( my $i = 0; $i <= @modelfile; $i++ ) {
5649 if( $i <= $#modelfile ){
5650 $_ = $modelfile[$i];
5653 # In this if statement we use the lazy evaluation of logical
5654 # or to make sure we only execute search pattern when we have
5655 # a line to search. Which is all cases but the very last loop
5656 # iteration.
5658 if( $i > $#modelfile or /\$PROB/ ){
5659 $end_index = $i;
5661 # The if statement here is only necessary in the first loop
5662 # iteration. When start_index == end_index == 0 we want to
5663 # skip to the next iteration looking for the actual end of
5664 # the first problem.
5666 if( $end_index > $start_index and not $first ){
5667 # extract lines of code:
5668 my @problem_lines = @modelfile[$start_index .. $end_index-1];
5669 # reset the search for problems by moving the problem start
5670 # forwards:
5671 $start_index = $i;
5673 my $sh_mod = model::shrinkage_module -> new ( model => $self,
5674 temp_problem_number => ($#problems+2));
5675 my $prob = model::problem ->
5676 new ( directory => $self -> {'directory'},
5677 ignore_missing_files => $self -> {'ignore_missing_files'},
5678 ignore_missing_output_files => $self -> {'ignore_missing_output_files'},
5679 sde => $self -> {'sde'},
5680 cwres => $self -> {'cwres'},
5681 mirror_plots => $self -> {'mirror_plots'},
5682 nm_version => $self -> {'nm_version'},
5683 prob_arr => \@problem_lines,
5684 extra_data_file_name => $extra_data_files[$prob_num],
5685 extra_data_header => $extra_data_headers[$prob_num],
5686 shrinkage_module => $sh_mod );
5687 push( @problems, $prob );
5688 if ( $self -> cwres() ) {
5689 my @eo;
5690 if ( defined $self -> extra_output() ) {
5691 @eo = @{$self -> extra_output()};
5693 if( $prob -> {'cwres_modules'} ){
5694 push( @eo, @{$prob -> {'cwres_modules'} -> [0] -> cwtab_names()} );
5696 $self -> extra_output( \@eo );
5699 $sh_mod -> problem( $problems[$#problems] );
5700 $prob_num++;
5702 $first = 0;
5706 # Set the problems in the modelobject.
5707 $self -> problems(\@problems);
5709 end _read_problems
5711 # }}} _read_problems
5713 # {{{ set_option
5715 start set_option
5717 unless( $#problem_numbers >= 0 ){
5718 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5721 my @problems = @{$self -> {'problems'}};
5722 foreach my $i ( @problem_numbers ) {
5723 if ( defined $problems[ $i-1 ] ) {
5724 my $found = $self -> is_option_set( 'problem_number' => $i,
5725 'record' => $record_name,
5726 'name' => $option_name,
5727 'fuzzy_match' => $fuzzy_match );
5728 $problems[$i-1] -> remove_option( record_name => $record_name,
5729 option_name => $option_name,
5730 fuzzy_match => $fuzzy_match ) if ( $found );
5731 $problems[$i-1] -> add_option( record_name => $record_name,
5732 option_name => $option_name,
5733 option_value => $option_value );
5737 end set_option
5739 # }}} set_option
5741 # {{{ add_option
5743 start add_option
5745 unless( $#problem_numbers >= 0 ){
5746 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5749 my @problems = @{$self -> {'problems'}};
5750 foreach my $i ( @problem_numbers ) {
5751 if ( defined $problems[ $i-1 ] ) {
5752 $problems[$i-1] -> add_option( record_name => $record_name,
5753 option_name => $option_name,
5754 option_value => $option_value,
5755 add_record => $add_record );
5759 end add_option
5761 # }}} add_option
5763 # {{{ remove_option
5765 start remove_option
5767 unless( $#problem_numbers >= 0 ){
5768 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5771 my @problems = @{$self -> {'problems'}};
5772 foreach my $i ( @problem_numbers ) {
5773 if ( defined $problems[ $i-1 ] ) {
5774 $problems[$i-1] -> remove_option( record_name => $record_name,
5775 option_name => $option_name,
5776 fuzzy_match => $fuzzy_match);
5780 end remove_option
5782 # }}} remove_option
5784 # {{{ _option_val_pos
5786 start _option_val_pos
5788 unless( $#problem_numbers >= 0 ){
5789 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5791 my @problems = @{$self -> {'problems'}};
5792 if ( $#new_values >= 0 ) {
5793 'debug' -> die( message => "Trying to set option $name in record $record_name but the ".
5794 "number of new value sets (".
5795 ($#new_values+1).
5796 "), do not match the number of problems specified (".
5797 ($#problem_numbers+1).")" )
5798 unless(($#new_values == $#problem_numbers) );
5799 if ( $#instance_numbers > 0 ) {
5800 'debug' -> die( message => "The number of instance number sets (".
5801 ($#instance_numbers+1).
5802 "),do not match the number of problems specified (".
5803 ($#problem_numbers+1).")" )
5804 unless(($#instance_numbers == $#problem_numbers) );
5808 foreach my $i ( @problem_numbers ) {
5809 if ( defined $problems[ $i-1 ] ) {
5810 my $rn_ref = $#instance_numbers >= 0 ? \@{$instance_numbers[ $i-1 ]} : [];
5811 if ( scalar @new_values > 0) {
5812 # {{{ Update values
5814 if( not defined $new_values[ $i-1 ] ) {
5815 debug -> die( message => " The specified new_values was undefined for problem $i" );
5818 if( not ref( $new_values[ $i-1 ] ) eq 'ARRAY' ) {
5819 debug -> die( message => " The specified new_values for problem $i is not an array as it should be but a ".
5820 ( defined ref( $new_values[ $i-1 ] ) ?
5821 ref( $new_values[ $i-1 ] ) : 'undef' ) );
5824 $problems[ $i-1 ] ->
5825 _option_val_pos( record_name => $record_name,
5826 instance_numbers => $rn_ref,
5827 new_values => \@{$new_values[ $i-1 ]},
5828 name => $name,
5829 exact_match => $exact_match );
5831 # }}} Update values
5832 } else {
5833 # {{{ Retrieve values
5834 my ( $val_ref, $pos_ref ) =
5835 $problems[ $i-1 ] ->
5836 _option_val_pos( record_name => $record_name,
5837 instance_numbers => $rn_ref,
5838 name => $name,
5839 exact_match => $exact_match );
5840 push( @values, $val_ref );
5841 push( @positions, $pos_ref );
5842 # }}} Retrieve values
5844 } else {
5845 'debug' -> die( message => "Problem number $i does not exist!" );
5849 end _option_val_pos
5851 # }}} _option_val_pos
5853 # {{{ subroutine_files
5855 start subroutine_files
5857 my %fsubs;
5858 foreach my $subr( 'PRED','CRIT', 'CONTR', 'CCONTR', 'MIX', 'CONPAR', 'OTHER', 'PRIOR' ){
5859 my ( $model_fsubs, $junk ) = $self -> _option_val_pos( record_name => 'subroutine',
5860 name => $subr );
5861 if( @{$model_fsubs} > 0 ){
5862 foreach my $prob_fsubs ( @{$model_fsubs} ){
5863 foreach my $fsub( @{$prob_fsubs} ){
5864 $fsubs{$fsub} = 1;
5870 # BUG , nonmem6 might not require the file to be named .f And I've
5871 # seen examples of files named .txt
5873 @fsubs = keys %fsubs;
5874 if( @fsubs > 0 ){
5875 for( my $i = 0; $i <= $#fsubs; $i ++ ){
5876 unless( $fsubs[$i] =~ /\.f$/ ){
5877 $fsubs[$i] .= '.f';
5882 end subroutine_files
5884 # }}}