moved nonpb.pm
[PsN.git] / lib / model_subs.pm
blob88271df62c72c56d6e713c24c9ba1175850f12c1
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 # TODO Remove this if it works
159 #my $subroutine_files = $this -> subroutine_files;
160 #if( defined $subroutine_files and scalar @{$subroutine_files} > 0 ){
161 # push( @{$this -> {'extra_files'}}, @{$subroutine_files} );
164 if ( defined $this -> {'extra_files'} ){
165 for( my $i; $i < scalar @{$this -> {'extra_files'}}; $i++ ){
166 my ( $dir, $file ) = OSspecific::absolute_path( $this -> {'directory'}, $this -> {'extra_files'} -> [$i]);
167 $this -> {'extra_files'} -> [$i] = $dir . $file;
171 # Read datafiles, if any.
172 unless( defined $this -> {'datas'} and not $this -> {'quick_reload'} ){
173 my @idcolumns = @{$this -> idcolumns};
174 my @datafiles = @{$this -> datafiles('absolute_path' => 1)};
175 # my @datafiles = @{$this -> datafiles('absolute_path' => 0)};
176 for ( my $i = 0; $i <= $#datafiles; $i++ ) {
177 my $datafile = $datafiles[$i];
178 my $idcolumn = $idcolumns[$i];
179 my ( $cont_column, $wrap_column ) = $this -> {'problems'} -> [$i] -> cont_wrap_columns;
180 my $ignoresign = defined $this -> ignoresigns ? $this -> ignoresigns -> [$i] : undef;
181 my @model_header = @{$this -> {'problems'} -> [$i] -> header};
182 if ( defined $idcolumn ) {
183 push ( @{$this -> {'datas'}}, data ->
184 new( idcolumn => $idcolumn,
185 filename => $datafile,
186 cont_column => $cont_column,
187 wrap_column => $wrap_column,
188 #model_header => \@model_header,
189 ignoresign => $ignoresign,
190 directory => $this -> {'directory'},
191 ignore_missing_files => $this -> {'ignore_missing_files'} ||
192 $this -> {'ignore_missing_data'},
193 target => $this -> {'target'}) );
194 } else {
195 'debug' -> die( message => "New model to be created from ".$this -> full_name().
196 ". Data file is ".$datafile.
197 ". No id column definition found in the model file." );
202 # Read outputfile, if any.
203 if( ! defined $this -> {'outputs'} ) {
204 unless( defined $this -> {'outputfile'} ){
205 if( $this -> filename() =~ /\.mod$/ ) {
206 ($this -> {'outputfile'} = $this -> {'filename'}) =~ s/\.mod$/.lst/;
207 } else {
208 $this -> outputfile( $this -> filename().'.lst' );
211 push ( @{$this -> {'outputs'}}, output ->
212 new( filename => $this -> {'outputfile'},
213 directory => $this -> {'directory'},
214 ignore_missing_files =>
215 $this -> {'ignore_missing_files'} || $this -> {'ignore_missing_output_files'},
216 target => $this -> {'target'},
217 model_id => $this -> {'model_id'} ) );
220 # Adding mirror_plots module here, since it can add
221 # $PROBLEMS. Also it needs to know wheter an lst file exists
222 # or not.
224 if( $this -> {'mirror_plots'} > 0 ){
225 my $mirror_plot_module = model::mirror_plot_module -> new( base_model => $this,
226 nr_of_mirrors => $this -> {'mirror_plots'},
227 cwres => $this -> {'cwres'},
228 mirror_from_lst => $this -> {'mirror_from_lst'});
229 push( @{$this -> {'mirror_plot_modules'}}, $mirror_plot_module );
232 if( $this -> {'iofv'} > 0 ){
233 my $iofv_module = model::iofv_module -> new( base_model => $this,
234 nm_version => $this -> {'nm_version'});
235 push( @{$this -> {'iofv_modules'}}, $iofv_module );
239 end new
241 # }}} new
243 # {{{ register_in_database
245 start register_in_database
247 if ( $PsN::config -> {'_'} -> {'use_database'} ) {
248 # Backslashes messes up the sql syntax
249 my $file_str = $self->{'filename'};
250 my $dir_str = $self->{'directory'};
251 $file_str =~ s/\\/\//g;
252 $dir_str =~ s/\\/\//g;
254 # md5sum
255 my $md5sum = md5_hex(OSspecific::slurp_file($self-> full_name ));
257 my $dbh = DBI -> connect("DBI:mysql:host=".$PsN::config -> {'_'} -> {'database_server'}.
258 ";databse=".$PsN::config -> {'_'} -> {'project'},
259 $PsN::config -> {'_'} -> {'user'},
260 $PsN::config -> {'_'} -> {'password'},
261 {'RaiseError' => 1});
263 my $sth;
265 my $select_arr = [];
267 if ( not $force ) {
268 my $sth = $dbh -> prepare( "SELECT model_id FROM ".$PsN::config -> {'_'} -> {'project'}.
269 ".model ".
270 "WHERE filename = '$file_str' AND ".
271 "directory = '$dir_str' AND ".
272 "md5sum = '".$md5sum."'" );
273 $sth -> execute or 'debug' -> die( message => $sth->errstr ) ;
275 $select_arr = $sth -> fetchall_arrayref;
278 if ( scalar @{$select_arr} > 0 ) {
279 'debug' -> warn( level => 1,
280 message => "Found an old entry in the database matching the ".
281 "current model file" );
282 if ( scalar @{$select_arr} > 1 ) {
283 'debug' -> warn( level => 1,
284 message => "Found more than one matching entry in database".
285 ", using the first" );
287 $self -> {'model_id'} = $select_arr->[0][0];
288 } else {
289 my ( $date_str, $time_str );
290 if( $Config{osname} eq 'MSWin32' ){
291 $date_str = `date /T`;
292 $time_str = ' '.`time /T`;
293 } else {
294 # Assuming UNIX
295 $date_str = `date`;
297 chomp($date_str);
298 chomp($time_str);
299 my $date_time = $date_str.$time_str;
300 $sth = $dbh -> prepare("INSERT INTO ".$PsN::config -> {'_'} -> {'project'}.
301 ".model (filename,date,directory,md5sum) ".
302 "VALUES ('$file_str', '$date_time', '$dir_str','".
303 $md5sum."' )");
304 $sth -> execute;
305 $self -> {'model_id'} = $sth->{'mysql_insertid'};
307 $sth -> finish if ( defined $sth );
308 $dbh -> disconnect;
310 $model_id = $self -> {'model_id'} # return the model_id;
312 end register_in_database
314 # }}} register_in_database
316 # {{{ shrinkage_stats
318 start shrinkage_stats
320 if ( $#problem_numbers > 0 and ref $enabled eq 'ARRAY' ){
321 if ( $#problem_numbers != ( scalar @{$enabled} - 1 ) ) {
322 'debug' -> die( message => "The number of problem_numbers ".($#problem_numbers+1).
323 "and enabled/disabled shrinkage_stats ".scalar @{$enabled}.
324 " do not match" );
327 unless( $#problem_numbers > 0 ){
328 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
330 my @en_arr;
331 if( ref \$enabled eq 'SCALAR' ) {
332 for ( @problem_numbers ) {
333 push( @en_arr, $enabled );
335 } elsif ( not ref $enabled eq 'ARRAY' ) {
336 debug -> die( message => 'enabled must be a scalar or a reference to an array, '.
337 'not a reference to a '.ref($enabled).'.' );
340 my @problems = @{$self -> {'problems'}};
341 my $j = 0;
342 foreach my $i ( @problem_numbers ) {
343 if ( defined $problems[ $i-1 ] ) {
344 if ( defined $en_arr[ $j ] ) {
345 if( $en_arr[ $j ] ) {
346 $problems[ $i-1 ] -> shrinkage_module -> enable;
347 } else {
348 $problems[ $i-1 ] -> shrinkage_module -> disable;
350 # my $eta_file = $self -> filename.'_'.$i.'.etas';
351 # my $eps_file = $self -> filename.'_'.$i.'.wres';
352 # $problems[ $i-1 ] -> {'eta_shrinkage_table'} = $eta_file;
353 # $problems[ $i-1 ] -> {'wres_shrinkage_table'} = $eps_file;
354 } else {
355 push( @indicators, $problems[ $i-1 ] -> shrinkage_module -> status );
357 } else {
358 'debug' -> die( message => "Problem number $i does not exist!" );
360 $j++;
363 end shrinkage_stats
365 # }}} shrinkage_stats
367 start shrinkage_modules
369 if( defined $parm ){
370 if( ref $parm ne 'ARRAY'
372 not ( scalar @{$parm} == scalar @{$self -> {'problems'}} ) ){
373 'debug' -> die( message => 'New number of shrinkage modules must be equal to number of problems' );
376 foreach my $prob( @{$self -> {'problems'}} ){
377 my $new_module = shift( @{$parm} );
378 $new_module -> model( $self );
379 $prob -> shrinkage_module( shift( @{$parm} ) );
383 } else {
384 my @return_array;
385 foreach my $prob( @{$self -> {'problems'}} ){
386 push( @return_array, $prob -> shrinkage_module );
388 return \@return_array;
391 end shrinkage_modules
393 # {{{ wres_shrinkage
395 =head2 wres_shrinkage
397 Usage:
399 =for html <pre>
401 my $wres_shrink = $model_object -> wres_shrinkage();
403 =for html </pre>
405 Description:
407 Calculates wres shrinkage, a table file with wres is necessary. The
408 return value is reference of and array with one an array per problem
409 in it.
411 =cut
413 start wres_shrinkage
415 my @problems = @{$self -> {'problems'}};
416 foreach my $problem ( @problems ) {
417 push( @wres_shrinkage, $problem -> wres_shrinkage );
420 end wres_shrinkage
422 # }}} wres_shrinkage
424 # {{{ eta_shrinkage
426 =head2 eta_shrinkage
428 Usage:
430 =for html <pre>
432 my $eta_shrink = $model_object -> eta_shrinkage();
434 =for html </pre>
436 Description:
438 Calculates eta shrinkage, a table file with eta is necessary. The
439 return value is reference of and array with one an array per problem
440 in it.
442 =cut
444 start eta_shrinkage
446 my @problems = @{$self -> {'problems'}};
447 foreach my $problem ( @problems ) {
448 push( @eta_shrinkage, $problem -> eta_shrinkage );
451 end eta_shrinkage
453 # }}} eta_shrinkage
455 # {{{ nonparametric_code
457 start nonparametric_code
459 if ( $#problem_numbers > 0 and $#enabled > 0 ){
460 if ( $#problem_numbers != $#enabled ) {
461 'debug' -> die( message => "The number of problem_numbers ".($#problem_numbers+1).
462 "and enabled/disabled nonparametric_code ".($#enabled+1).
463 "do not match" );
466 unless( $#problem_numbers > 0 ){
467 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
469 my @problems = @{$self -> {'problems'}};
470 my $j = 0;
471 foreach my $i ( @problem_numbers ) {
472 if ( defined $problems[ $i-1 ] ) {
473 if ( defined $enabled[ $j ] ) {
474 $problems[ $i-1 ] -> nonparametric_code( $enabled[ $j ] );
475 } else {
476 push( @indicators, $problems[ $i-1 ] -> nonparametric_code );
478 } else {
479 'debug' -> die( message => "Problem number $i does not exist!" );
481 $j++;
484 end nonparametric_code
486 # }}} nonparametric_code
488 # {{{ add_nonparametric_code
490 start add_nonparametric_code
492 $self -> set_records( type => 'nonparametric',
493 record_strings => [ 'MARGINALS UNCONDITIONAL' ] );
494 $self -> set_option( record_name => 'estimation',
495 option_name => 'POSTHOC' );
496 my ( $msfo_ref, $junk ) = $self ->
497 _get_option_val_pos( name => 'MSFO',
498 record_name => 'estimation' );
499 my @nomegas = @{$self -> nomegas};
501 for( my $i = 0; $i <= $#nomegas; $i++ ) { # loop the problems
502 my $marg_str = 'ID';
503 for( my $j = 0; $j <= $nomegas[$i]; $j++ ) {
504 $marg_str = $marg_str.' COM('.($j+1).')=MG'.($j+1);
506 $marg_str = $marg_str.' FILE='.$self->filename.'.marginals'.
507 ' NOAPPEND ONEHEADER NOPRINT';
508 $self -> add_records( problem_numbers => [($i+1)],
509 type => 'table',
510 record_strings => [ $marg_str ] );
511 $self -> remove_option( record_name => 'abbreviated',
512 option_name => 'COMRES' );
513 $self -> add_option( record_name => 'abbreviated',
514 option_name => 'COMRES',
515 option_value => ($nomegas[$i]+1),
516 add_record => 1 ); #Add $ABB if not existing
518 $self -> add_marginals_code( problem_numbers => [($i+1)],
519 nomegas => [ $nomegas[$i] ] );
522 if( not defined $msfo_ref ) {
523 for( my $i = 0; $i < $self -> nproblems; $i++ ) {
524 $self -> add_option( record_name => 'estimation',
525 option_name => 'MSFO',
526 option_value => $self -> filename.'.msfo'.($i+1) );
528 } else {
529 for( my $i = 0; $i < scalar @{$msfo_ref}; $i++ ) {
530 if( not defined $msfo_ref->[$i] or not defined $msfo_ref->[$i][0] ) {
531 $self -> add_option( record_name => 'estimation',
532 option_name => 'MSFO',
533 option_value => $self -> filename.'.msfo'.($i+1) );
538 end add_nonparametric_code
540 # }}} add_nonparametric_code
542 # {{{ flush_data
544 =head2 flush_data
546 Usage:
548 =for html <pre>
550 $model_object -> flush_data();
552 =for html </pre>
554 Description:
556 flush data calls the same method on each data object (usually one)
557 which causes it to write data to disk and remove its data from memory.
559 =cut
561 start flush_data
563 if ( defined $self -> {'datas'} ) {
564 foreach my $data ( @{$self -> {'datas'}} ) {
565 $data -> flush;
569 end flush_data
571 # }}} flush_data
573 # {{{ full_name
575 =head2 full_name
577 Usage:
579 C<< my $file_name = $model_object -> full_name(); >>
581 Description:
583 full_name will return the name of the modelfile and its directory in a
584 string. For example: "/users/guest/project/model.mod".
586 =cut
588 start full_name
590 $full_name = $self -> {'directory'} . $self -> {'filename'};
592 end full_name
594 # }}}
596 # {{{ sync_output
598 This function is unused and should probably be removed.
600 # start __sync_output
602 unless( defined $self -> {'outputfile'} ){
603 'debug' -> die( message => "No output file is set, cannot synchronize output" );
605 @{$self -> {'outputs'}} = ();
606 push ( @{$self -> {'outputs'}}, output ->
607 new( filename => $self -> {'outputfile'},
608 ignore_missing_files => $self -> {'ignore_missing_files'},
609 target => $self -> {'target'},
610 model_id => $self -> {'model_id'} ) );
612 # end __sync_output
614 # }}} sync_output
616 # {{{ add_marginals_code
618 start add_marginals_code
620 # add_marginals_code takes two arguments.
622 # - problem_numbers is an array holding the numbers of the problems in
623 # which code should be added.
625 # - nomegas which is an array holding the number of (diagonal-element)
626 # omegas of each problem given by problem_numbers.
628 # For each omega in each problem, verbatim code is added to make the
629 # marginals available for printing (e.g. to a table file). COM(1) will
630 # hold the nonparametric density, COM(2) the marginal cumulative value
631 # for the first eta, COM(2) the marginal cumulative density for the
632 # second eta and so on.
634 unless( $#problem_numbers >= 0 ){
635 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
638 my @problems = @{$self -> {'problems'}};
639 my $j = 0;
640 foreach my $i ( @problem_numbers ) {
641 if ( defined $problems[ $i-1 ] ) {
642 $problems[$i-1] -> add_marginals_code( nomegas => $nomegas[ $j ] );
643 } else {
644 'debug' -> die( message => "Problem number $i does not exist.");
646 $j++;
649 end add_marginals_code
651 # }}} add_marginals_code
653 # {{{ add_records
655 =head2 add_records
657 Usage:
659 =for html <pre>
661 $model_object -> add_records( type => 'THETA',
662 record_strings => ['(0.1,15,23)'] );
664 =for html </pre>
666 Arguments:
668 =over 3
670 =item type
672 string
674 =item record_strings
676 array of strings
678 =item problem_numbers
680 array of integers
682 =back
684 Description:
686 add_records is used to add NONMEM control file records to the model
687 object. The "type" argument is mandatory and must be a valid NONMEM
688 record name, such as "PRED" or "THETA". Otherwise an error will be
689 output and the program terminated (this is object to change, ideally
690 we would only report an error and let the caller deal with it). The
691 "record_strings" argument is a mandatory array of valid NONMEM record
692 code. Each array corresponds to a line of the record code. There
693 "problem_numbers" argument is optional and is an array of problems
694 numbered from 1 for which the record is added, by default the record
695 is added to all problems.
697 Notice that the records are appended to those that allready exists,
698 which makes sence for records that do not exist and for initial
699 values. For records like "DATA" or "PRED" you probably want to use
700 "set_records".
702 =cut
704 start add_records
706 unless( $#problem_numbers >= 0 ){
707 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
710 my @problems = @{$self -> {'problems'}};
711 foreach my $i ( @problem_numbers ) {
712 if ( defined $problems[ $i-1 ] ) {
713 # if( defined $self -> {'problems'} ){
714 # if( defined @{$self -> {'problems'}}[$problem_number - 1] ){
715 # my $problem = @{$self -> {'problems'}}[$problem_number - 1];
716 # $problem -> add_records( 'type' => $type,
717 # 'record_strings' => \@record_strings );
718 $problems[$i-1] -> add_records( 'type' => $type,
719 'record_strings' => \@record_strings );
720 } else {
721 'debug' -> die( message => "Problem number $i does not exist.");
724 # else {
725 # 'debug' -> die( message => "Model -> add_records: No Problems in model object.") ;
728 end add_records
730 # }}} add_records
732 # {{{ set_records
734 =head2 set_records
736 Usage:
738 =for html <pre>
740 $model_object -> set_records( type => 'THETA',
741 record_strings => ['(0.1,15,23)'] );
743 =for html </pre>
745 Arguments:
747 =over 3
749 =item type
751 string
753 =item record_strings
755 array of strings
757 =item problem_numbers
759 array of integers
761 =back
763 Description:
765 set_records works just like add_records but will replace any existing
766 records in the model object.
768 =cut
770 start set_records
772 unless( $#problem_numbers >= 0 ){
773 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
776 my @problems = @{$self -> {'problems'}};
777 foreach my $i ( @problem_numbers ) {
778 if ( defined $problems[ $i-1 ] ) {
779 # if( defined $self -> {'problems'} ){
780 # if( defined @{$self -> {'problems'}}[$problem_number - 1] ){
781 # my $problem = @{$self -> {'problems'}}[$problem_number - 1];
782 # $problem -> set_records( 'type' => $type,
783 # 'record_strings' => \@record_strings );
784 $problems[$i-1] -> set_records( 'type' => $type,
785 'record_strings' => \@record_strings );
786 } else {
787 'debug' -> die( message => "Problem number $i does not exist." );
790 # else {
791 # 'debug' -> die( "No Problems in model object.") ;
794 end set_records
796 # }}} set_records
798 # {{{ remove_records
800 =head2 remove_records
802 Usage:
804 =for html <pre>
806 $model_object -> remove_records( type => 'THETA' )
808 =for html </pre>
810 Arguments:
812 =over 3
814 =item type
816 string
818 =item problem_numbers
820 array of integers
822 =back
824 Description:
826 remove_records removes the record given in the "type" argument which
827 must be a valid NONMEM record name.
829 =cut
831 start remove_records
833 unless( $#problem_numbers >= 0 ){
834 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
837 my @problems = @{$self -> {'problems'}};
838 foreach my $i ( @problem_numbers ) {
839 if ( defined $problems[ $i-1 ] ) {
840 # if( defined $self -> {'problems'} ){
841 # if( defined @{$self -> {'problems'}}[$problem_number - 1] ){
842 # my $problem = @{$self -> {'problems'}}[$problem_number - 1];
843 # $problem -> remove_records( 'type' => $type );
844 $problems[$i-1] -> remove_records( 'type' => $type );
845 } else {
846 'debug' -> die( message => "Problem number $i, does not exist" );
849 # else {
850 # 'debug' -> die( message => "No Problems in model object." );
853 end remove_records
855 # }}} remove_records
857 # {{{ copy
859 =head2 copy
861 Usage:
863 =for html <pre>
865 $model_object -> copy( filename => 'copy.mod',
866 copy_data => 1,
867 copy_output => 0 )
869 =for html </pre>
871 Arguments:
873 =over 3
875 =item filename
877 string
879 =item copy_data
881 boolean
883 =item copy_output
885 boolean
887 =item directory
889 string
891 =item data_file_names
893 array of strings
895 =item target
897 string with value 'disk' or 'mem'
899 =item extra_data_file_names
901 array of strings
903 =item update_shrinkage_tables
905 boolean
907 =back
909 Description:
911 copy produces a new modelfile object and a new file on disk whose name
912 is given by the "filename" argument. To create copies of data file the
913 copy_data options may be set to 1. The values of "data_file_names",
914 unless given, will be the model file name but with '.mod' exchanged
915 for '_$i.dta', where $i is the problem number. If data is not copied,
916 a new data object will be intialized from the same data file as the
917 previous model and "data_file_names" WILL BE IGNORED. This has the
918 side effect that the data file can be modified from both the original
919 model and the copy. The same holds for "extra_data_files". It is
920 possible to set "copy_output" to 1 as well, which then copies the
921 output object instead of reading the output file from disk, which is
922 slower. Since output objects are meant to be read-only, no
923 output_filename can be specified and the output object copy will
924 reside in memory only.
926 The "target" option has no effect.
928 =cut
930 start copy
932 # PP_TODO fix a nice copying of modelfile data
933 # preferably in memory copy. Perhaps flush data ?
935 # Check sanity of the length of data file names argument
936 if ( scalar @data_file_names > 0 ) {
937 'debug' -> die( message => "model -> copy: The number of specified new data file " .
938 "names ". scalar @data_file_names. "must\n match the number".
939 " of data objects connected to the model object".
940 scalar @{$self -> {'datas'}} )
941 unless ( scalar @data_file_names == scalar @{$self -> {'datas'}} );
942 } else {
943 my $d_filename;
944 ($d_filename = $filename) =~ s/\.mod$//;
945 for ( my $i = 1; $i <= scalar @{$self -> {'datas'}}; $i++ ) {
946 # Data filename is created in this directory (no directory needed).
947 push( @data_file_names, $d_filename."_data_".$i."_copy.dta" );
951 # Check sanity of the length of extra_data file names argument
952 if ( scalar @extra_data_file_names > 0 ) {
953 'debug' -> die( message => "The number of specified new extra_data file ".
954 "names ". scalar @extra_data_file_names, "must\n match the number".
955 " of problems (one extra_data file per prolem)".
956 scalar @{$self -> {'extra_data_files'}} )
957 unless( scalar @extra_data_file_names == scalar @{$self -> {'extra_data_files'}} );
958 } else {
959 if ( defined $self -> {'extra_data_files'} ) {
960 my $d_filename;
961 ($d_filename = $filename) =~ s/\.mod$//;
962 for ( my $i = 1; $i <= scalar @{$self -> {'extra_data_files'}}; $i++ ) {
963 # Extra_Data filename is created in this directory (no directory needed).
964 push( @extra_data_file_names, $d_filename."_extra_data_".$i."_copy.dta" );
969 ($directory, $filename) = OSspecific::absolute_path( $directory, $filename );
971 # New copy:
973 # save references to own data and output objects
974 my $datas = $self -> {'datas'};
975 # $Data::Dumper::Maxdepth = 2;
976 # die "MC1: ", Dumper $datas -> [0] -> {'individuals'};
977 my $outputs = $self -> {'outputs'};
978 my %extra_datas;
979 my @problems = @{$self -> {'problems'}};
980 for ( my $i = 0; $i <= $#problems; $i++ ) {
981 if ( defined $problems[$i] -> {'extra_data'} ) {
982 $extra_datas{$i} = $problems[$i] -> {'extra_data'};
986 my ( @new_datas, @new_extra_datas, @new_outputs );
988 $self -> synchronize if not $self -> {'synced'};
990 # remove ref to data and output object to speed up the
991 # cloning
992 $self -> {'datas'} = undef;
993 $self -> {'outputs'} = undef;
994 for ( my $i = 0; $i <= $#problems; $i++ ) {
995 $problems[$i] -> {'extra_data'} = undef;
998 # Copy the data objects if so is requested
999 if ( defined $datas ) {
1000 my $i = 0;
1001 foreach my $data ( @{$datas} ) {
1002 if ( $copy_data == 1 ) {
1003 push( @new_datas, $data ->
1004 copy( filename => $data_file_names[$i]) );
1005 } else {
1006 # This line assumes one data per problem! May be a source of error.
1007 my ( $cont_column, $wrap_column ) = $self -> problems -> [$i] -> cont_wrap_columns;
1008 my $ignoresign = defined $self -> ignoresigns ? $self -> ignoresigns -> [$i] : undef;
1009 my @model_header = @{$self -> problems -> [$i] -> header};
1010 push @new_datas, data ->
1011 new( filename => $data -> filename,
1012 directory => $data -> directory,
1013 cont_column => $cont_column,
1014 wrap_column => $wrap_column,
1015 #model_header => \@model_header,
1016 target => 'disk',
1017 ignoresign => $ignoresign,
1018 idcolumn => $data -> idcolumn );
1020 $i++;
1024 # Copy the extra_data objects if so is requested
1025 for ( my $i = 0; $i <= $#problems; $i++ ) {
1026 my $extra_data = $extra_datas{$i};
1027 if ( defined $extra_data ) {
1028 if ( $copy_data == 1 ) {
1029 push( @new_extra_datas, $extra_data ->
1030 copy( filename => $extra_data_file_names[$i]) );
1031 } else {
1032 push( @new_extra_datas, extra_data ->
1033 new( filename => $extra_data -> filename,
1034 directory => $extra_data -> directory,
1035 target => 'disk',
1036 idcolumn => $extra_data -> idcolumn ) );
1042 # Clone self into new model object and set synced to 0 for
1043 # the copy
1044 $new_model = Storable::dclone( $self );
1045 $new_model -> {'synced'} = 0;
1047 # $Data::Dumper::Maxdepth = 3;
1048 # die Dumper $new_datas[0] -> {'individuals'};
1050 # Restore the data and output objects for self
1051 $self -> {'datas'} = $datas;
1052 $self -> {'outputs'} = $outputs;
1053 for ( my $i = 0; $i <= $#problems; $i++ ) {
1054 if( defined $extra_datas{$i} ){
1055 $problems[$i] -> {'extra_data'} = $extra_datas{$i};
1059 # Set the new file name for the copy
1060 $new_model -> directory( $directory );
1061 $new_model -> filename( $filename );
1063 # {{{ update the shrinkage modules
1065 my @problems = @{$new_model -> problems};
1066 for( my $i = 1; $i <= scalar @problems; $i++ ) {
1067 $problems[ $i-1 ] -> shrinkage_module -> model( $new_model );
1070 # }}} update the shrinkage modules
1072 # Copy the output object if so is requested (only one output
1073 # object defined per model object)
1074 if ( defined $outputs ) {
1075 foreach my $output ( @{$outputs} ) {
1076 if ( $copy_output == 1 ) {
1077 push( @new_outputs, $output -> copy );
1078 } else {
1079 my $new_out = $filename;
1080 if( $new_out =~ /\.mod$/ ) {
1081 $new_out =~ s/\.mod$/\.lst/;
1082 } else {
1083 $new_out = $new_out.'.lst';
1085 push( @new_outputs, output ->
1086 new ( filename => $new_out,
1087 directory => $directory,
1088 target => 'disk',
1089 ignore_missing_files => 1,
1090 model_id => $new_model -> {'model_id'} ) );
1095 # Add the copied data and output objects to the model copy
1096 $new_model -> datas( \@new_datas );
1098 if ( $#new_extra_datas >= 0 ) {
1099 my @new_problems = @{$new_model -> problems};
1100 for ( my $i = 0; $i <= $#new_problems; $i++ ) {
1101 $new_problems[$i] -> {'extra_data'} = $new_extra_datas[$i];
1102 if ( $copy_data == 1 ){
1103 $new_problems[$i] -> {'extra_data_file_name'} = $extra_data_file_names[$i];
1108 $new_model -> {'outputs'} = \@new_outputs;
1110 $new_model -> _write;
1112 $new_model -> synchronize if $target eq 'disk';
1114 end copy
1116 # }}} copy
1118 # {{{ covariance
1120 =head2 covariance
1122 Usage:
1124 =for html <pre>
1126 my $indicators = $model_object -> covariance( enabled => [1] );
1128 =for html </pre>
1130 Arguments:
1132 =over 3
1134 =item enabled
1136 array of booleans
1138 =item problem_numbers
1140 array of integers
1142 =back
1144 Description:
1146 covariance will let you turn the covariance step on and off per
1147 problem. The "enabled" argument is an array which must have a length
1148 equal to the number of problems. Each element set to 0 will disable
1149 the covariance step for the corresponding problem. And conversely each
1150 element set to nonzero will enable the covariance step.
1152 covariance will return an array with an element for each problem, the
1153 element will indicate whether the covariance step is turned on or not.
1155 =cut
1157 start covariance
1159 if ( $#problem_numbers > 0 ){
1160 if ( $#problem_numbers != $#enabled ) {
1161 'debug' -> die( message => "The number of problem_numbers ".($#problem_numbers+1).
1162 "and enabled/disabled covariance records ".($#enabled+1).
1163 "do not match" );
1166 unless( $#problem_numbers > 0 ){
1167 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
1169 my @problems = @{$self -> {'problems'}};
1170 my $j = 0;
1171 foreach my $i ( @problem_numbers ) {
1172 if ( defined $problems[ $i-1 ] ) {
1173 if ( defined $enabled[ $j ] ) {
1174 $problems[ $i-1 ] -> covariance( enabled => $enabled[ $j ] );
1175 } else {
1176 push( @indicators, $problems[ $i-1 ] -> covariance );
1178 } else {
1179 'debug' -> die( message => "Problem number $i does not exist!" );
1181 $j++;
1184 end covariance
1186 # }}} covariance
1188 # {{{ datas
1190 =head2 datas
1192 Usage:
1194 =for html <pre>
1196 $model_object -> datas( [$data_obj] );
1198 my $data_objects = $model_object -> data;
1200 =for html </pre>
1202 Arguments:
1204 The argument is an unnamed array of data objects.
1206 Description:
1208 If data is used without argument the data objects connected to the
1209 model object is returned. If an argument is given it must be an array
1210 of length equal to the number of problems with data objects. Those
1211 objects will replace any existing data objects and their filenames
1212 will be put in the model files records.
1214 =cut
1216 start datas
1218 my $nprobs = scalar @{$self -> {'problems'}};
1219 if ( defined $parm ) {
1220 if ( ref($parm) eq 'ARRAY' ) {
1221 my @new_datas = @{$parm};
1222 # Check that new_headers and problems match
1223 'debug' -> die( message => "The number of problems $nprobs and".
1224 " new data ". ($#new_datas+1) ." don't match in ".
1225 $self -> full_name ) unless ( $#new_datas + 1 == $nprobs );
1226 if ( defined $self -> {'problems'} ) {
1227 for( my $i = 0; $i < $nprobs; $i++ ) {
1228 $self -> _option_name( position => 0,
1229 record => 'data',
1230 problem_number => $i+1,
1231 new_name => $new_datas[$i] -> filename);
1233 } else {
1234 'debug' -> die( message => "No problems defined in ".
1235 $self -> full_name );
1237 } else {
1238 'debug' -> die( message => "Supplied new value is not an array" );
1242 end datas
1244 # }}}
1246 # {{{ datafile
1248 # TODO 2006-03-22
1249 # I have removed this because it was only used in the bootstrap. I
1250 # fixed the bootstrap to use datafiles instead. Also the bootstrap
1251 # methods who used this was very old and should probably be removed as
1252 # well.
1254 # start datafile
1256 # datafile either retrieves or sets a new name for the datafile in the first problem of the
1257 # model. This method is only here for compatibility reasons. Don't use it. Use L</datafiles> instead.
1259 if( defined $new_name ){
1260 $self -> _option_name( position => 0,
1261 record => 'data',
1262 problem_number => $problem_number,
1263 new_name => $new_name);
1264 my ( $cont_column, $wrap_column ) = $self -> problems -> [$problem_number-1] ->
1265 cont_wrap_columns;
1266 my $ignoresign = defined $self -> ignoresigns ?
1267 $self -> ignoresigns -> [$problem_number-1] : undef;
1268 my @model_header = @{$self -> problems -> [$problem_number-1] -> header};
1269 $self -> {'datas'} -> [$problem_number-1] = data ->
1270 new( idcolumn => $self -> idcolumn( problem_number => $problem_number ),
1271 ignoresign => $ignoresign,
1272 filename => $new_name,
1273 cont_column => $cont_column,
1274 wrap_column => $wrap_column,
1275 #model_header => \@model_header,
1276 ignore_missing_files => $self -> {'ignore_missing_files'},
1277 target => $self -> {'target'} );
1278 } else {
1279 $name = $self -> _option_name( position => 0, record => 'data', problem_number => $problem_number );
1282 # end datafile
1284 # }}} datafile
1286 # {{{ datafiles
1288 =head2 datafiles
1290 Usage:
1292 =for html <pre>
1294 $model_object -> datafiles( new_names => ['datafile.dta'] );
1296 =for html </pre>
1298 Arguments:
1300 =over 2
1302 =item new_names
1304 array of strings
1306 =item problem_numbers
1308 array of integer
1310 =item absolute_path
1312 boolean
1314 =back
1316 Description:
1318 datafiles changes the names of the data files in a model file. The
1319 "new_names" argument is an array of strings, where each string gives
1320 the file name of a problem data file. The length of "new_names" must
1321 be equal to the "problem_numbers" argument. "problem_numbers" is by
1322 default containing all of the models problems numbers. In the example
1323 above we only have one problem in the model file and therefore only
1324 need to give on new file name.
1326 Unless new_names is given datafiles returns the names of the data
1327 files used by the model file. If the optional "absolute_path" argument
1328 is given, the returned file names will have the path to file as well.
1330 =cut
1332 start datafiles
1334 # The datafiles method retrieves or sets the names of the
1335 # datafiles specified in the $DATA record of each problem. The
1336 # problem_numbers argument can be used to control which
1337 # problem that is affected. If absolute_path is set to 1, the
1338 # returned file names are given with absolute paths.
1340 unless( $#problem_numbers > 0 ){
1341 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
1343 if ( scalar @new_names > 0 ) {
1344 my $i = 0;
1345 my @idcolumns = @{$self ->
1346 idcolumns( problem_numbers => \@problem_numbers )};
1347 foreach my $new_name ( @new_names ) {
1348 if ( $absolute_path ) {
1349 my $tmp;
1350 ($tmp, $new_name) = OSspecific::absolute_path('', $new_name );
1351 $new_name = $tmp . $new_name;
1354 $self -> _option_name( position => 0,
1355 record => 'data',
1356 problem_number => $problem_numbers[$i],
1357 new_name => $new_name);
1358 my ( $cont_column, $wrap_column ) = $self -> problems ->
1359 [$problem_numbers[$i]-1] -> cont_wrap_columns;
1360 my $ignoresign = defined $self -> ignoresigns ? $self -> ignoresigns -> [$i] : undef;
1361 my @model_header = @{$self -> problems -> [$i] -> header};
1362 $self -> {'datas'} -> [$problem_numbers[$i]-1] = data ->
1363 new( idcolumn => $idcolumns[$i],
1364 ignoresign => $ignoresign,
1365 filename => $new_name,
1366 cont_column => $cont_column,
1367 wrap_column => $wrap_column,
1368 #model_header => \@model_header,
1369 ignore_missing_files => $self -> {'ignore_missing_files'},
1370 target => $self -> {'target'} );
1371 $i++;
1373 } else {
1374 foreach my $prob_num ( @problem_numbers ) {
1375 if ( $absolute_path ) {
1376 my ($d_dir, $d_name);
1377 ($d_dir, $d_name) =
1378 OSspecific::absolute_path($self -> {'directory'}, $self ->_option_name( position => 0,
1379 record => 'data',
1380 problem_number => $prob_num ) );
1381 push( @names, $d_dir . $d_name );
1382 } else {
1383 my $name = $self -> _option_name( position => 0,
1384 record => 'data',
1385 problem_number => $prob_num );
1386 $name =~ s/.*[\/\\]//;
1387 push( @names, $name );
1392 end datafiles
1394 # }}} datafiles
1396 # {{{ des
1398 # TODO 2006-03-22
1399 # This method is renamed __des in dia but not here. If nothing broke
1400 # until now I think we can safely remove it.
1402 start des
1404 # Returns the des part specified subproblem.
1405 # TODO: Even though new_des can be specified, they wont be set
1406 # in to the object.
1408 my @prob = @{$self -> problems};
1409 my @des = @{$prob[$problem_number - 1] -> get_record('des') -> code}
1410 if ( defined $prob[$problem_number - 1] -> get_record('des') );
1412 end des
1414 # }}} des
1416 # {{{ eigen
1417 start eigen
1419 $self -> {'problems'} -> [0] -> eigen;
1421 end eigen
1422 # }}} eigen
1424 # {{{ error
1426 # TODO 2006-03-22
1427 # This method is renamed __error in dia but not here. If nothing broke
1428 # until now I think we can safely remove it.
1430 start error
1432 # Usage:
1434 # @error = $modelObject -> error;
1436 # Returns the error part specified subproblem.
1437 # TODO: Even though new_error can be specified, they wont be set
1438 # in to the object.
1439 my @prob = @{$self -> problems};
1440 my @error = @{$prob[0] -> get_record('error') -> code}
1441 if ( defined $prob[0] -> get_record('error') );
1443 end error
1445 # }}} error
1447 # {{{ extra_data_files
1449 =head2 extra_data_files
1451 Usage:
1453 =for html <pre>
1455 $model_object -> extra_data_files( ['extra_data.dta'] );
1457 my $extra_file_name = $model_object -> extra_data_files;
1459 =for html </pre>
1461 Arguments:
1463 The argument is an unnamed array of strings
1465 Description:
1467 If extra_data_files is used without argument the names of any extra
1468 data files connected to the model object is returned. If an argument
1469 is given it must be an array of length equal to the number of problems
1470 in the model. Then the names of the extra data files will be changed
1471 to those in the array.
1473 =cut
1475 start extra_data_files
1477 my @file_names;
1478 # Sets or retrieves extra_data_file_name on problem level
1479 my $nprobs = scalar @{$self -> {'problems'}};
1480 if ( defined $parm ) {
1481 if ( ref($parm) eq 'ARRAY' ) {
1482 my @new_file_names = @{$parm};
1483 # Check that new_file_names and problems match
1484 'debug' -> die( message => "model -> extra_data_files: The number of problems $nprobs and" .
1485 " new_file_names " . $#new_file_names+1 . " don't match in ".
1486 $self -> full_name ) unless ( $#new_file_names + 1 == $nprobs );
1487 if ( defined $self -> {'problems'} ) {
1488 for( my $i = 0; $i < $nprobs; $i++ ) {
1489 $self -> {'problems'} -> [$i] -> extra_data_file_name( $new_file_names[$i] );
1491 } else {
1492 'debug' -> die( message => "No problems defined in " .
1493 $self -> full_name );
1495 } else {
1496 'debug' -> die(message => "Supplied new value is not an array.");
1498 } else {
1499 if ( defined $self -> {'problems'} ) {
1500 for( my $i = 0; $i < $nprobs; $i++ ) {
1501 if( defined $self -> {'problems'} -> [$i] -> extra_data_file_name ) {
1502 push ( @file_names ,$self -> {'problems'} -> [$i] -> extra_data_file_name );
1507 return \@file_names;
1509 end extra_data_files
1511 # }}}
1513 # {{{ extra_data_headers
1515 =head2 extra_data_headers
1517 Usage:
1519 =for html <pre>
1521 $model_object -> extra_data_headers( [$data_obj] );
1523 my $data_objects = $model_object -> extra_data_headers;
1525 =for html </pre>
1527 Arguments:
1529 The argument is an unnamed array of arrays of strings.
1531 Description:
1533 If extra_data_files is used without argument the headers of any extra
1534 data files connected to the model object is returned. If an argument
1535 is given it must be an array of length equal to the number of problems
1536 in the model. Then the headers of the extra data files will be changed
1537 to those in the array.
1539 =cut
1541 start extra_data_headers
1543 my @headers;
1544 # Sets or retrieves extra_data_header on problem level
1545 my $nprobs = scalar @{$self -> {'problems'}};
1546 if ( defined $parm ) {
1547 if ( ref($parm) eq 'ARRAY' ) {
1548 my @new_headers = @{$parm};
1549 # Check that new_headers and problems match
1550 'debug' -> die( message => "The number of problems $nprobs and".
1551 " new_headers " . $#new_headers+1 . " don't match in ".
1552 $self -> full_name) unless ( $#new_headers + 1 == $nprobs );
1553 if ( defined $self -> {'problems'} ) {
1554 for( my $i = 0; $i < $nprobs; $i++ ) {
1555 $self -> {'problems'} -> [$i] -> extra_data_header( $new_headers[$i] );
1557 } else {
1558 'debug' -> die( message => "No problems defined in " . $self -> full_name );
1560 } else {
1561 'debug' -> die( message => "Supplied new value is not an array" );
1563 } else {
1564 if ( defined $self -> {'problems'} ) {
1565 for( my $i = 0; $i < $nprobs; $i++ ) {
1566 push ( @headers, $self -> {'problems'} -> [$i] -> extra_data_header );
1570 return \@headers;
1572 end extra_data_headers
1574 # }}} extra_data_headers
1576 # {{{ input_files
1578 =head2 input_files
1580 Usage:
1582 =for html <pre>
1584 my @file_names = $model_object -> input_files();
1586 =for html </pre>
1588 Arguments:
1590 none
1592 Description:
1594 Returns an two dimensional array with filenames to files that are
1595 necessary for a NONMEM run, i.e. all input files.
1597 The first level of the array is the list of files, the second level is
1598 allways of length two and contains the path and then the file.
1600 Example return value:
1602 [ ['/path/to', 'filename'],
1603 ['/another/path/to', 'another_file'] ]
1605 =cut
1607 start input_files
1610 # TODO: Skip the dataset for now, when I [PP] rewrite the
1611 # "model::copy" routine, I will revisit this.
1613 if( 0 ){
1614 foreach my $data ( @{$self -> datas} ) {
1615 my $filename = $data -> filename;
1617 #push( @new_data_names, $filename );
1621 # msfi files
1622 if( scalar @{$self -> msfi_names()} > 0 ){
1623 foreach my $msfi_files( @{$self -> msfi_names()} ){
1624 foreach my $msfi_file( @{$msfi_files} ){
1625 my ( $dir, $filename ) = OSspecific::absolute_path($self -> directory,
1626 $msfi_file );
1627 push( @file_names, [$dir, $filename] );
1630 } else {
1632 # If we don't have $MSFI we can consider $EST MSFO as input.
1634 foreach my $msfo_files( @{$self -> msfo_names()} ){
1635 foreach my $msfo_file( @{$msfo_files} ){
1636 my ( $dir, $filename ) = OSspecific::absolute_path($self -> directory,
1637 $msfo_file );
1638 push( @file_names, [$dir, $filename] );
1643 # TODO: as with data files, revisit this when model::copy is
1644 # rewritten.
1646 if( 0 ){
1647 my @problems = @{$self -> problems};
1648 for ( my $i = 1; $i <= $#problems + 1; $i++ ) {
1649 my $extra_data = $problems[$i-1] -> extra_data;
1650 if ( defined $extra_data ) {
1651 my $filename = $extra_data -> filename;
1653 #push( @, $filename );
1658 # Copy extra fortran files specified in "$SUBROUTINE"
1660 if( defined( $self -> subroutine_files ) ){
1661 foreach my $sub_file ( @{$self -> subroutine_files} ){
1662 my ( $dir, $filename ) = OSspecific::absolute_path( $self -> directory,
1663 $sub_file );
1664 push( @file_names, [$dir, $filename] );
1668 # Copy extra files the user specified.
1670 if( defined $self -> extra_files ){
1671 foreach my $x_file (@{$self -> extra_files}){
1672 my ( $dir, $filename ) = OSspecific::absolute_path( $self -> directory,
1673 $x_file );
1674 push( @file_names, [$dir, $filename] );
1678 end input_files
1680 # }}}
1682 # {{{ output_files
1684 =head2 output_files
1686 Usage:
1688 =for html <pre>
1690 my @file_names = $model_object -> output_files();
1692 =for html </pre>
1694 Arguments:
1696 none
1698 Description:
1700 Returns an array with filenames to files that are produced by a NONMEM
1701 run, i.e. all output files.
1703 Example return value:
1705 [ 'psn.lst',
1706 'patab' ]
1708 =cut
1710 start output_files
1713 push( @file_names, $self -> outputs -> [0] -> filename );
1715 if( defined $self -> table_names ){
1716 foreach my $table_files( @{$self -> table_names} ){
1717 foreach my $table_file( @{$table_files} ){
1718 my ($dir, $filename) = OSspecific::absolute_path( undef,
1719 $table_file );
1720 push( @file_names, $filename );
1725 if( defined $self -> msfo_names() ){
1726 foreach my $msfo_files( @{$self -> msfo_names()} ){
1727 foreach my $msfo_file( @{$msfo_files} ){
1728 my ( $dir, $filename ) = OSspecific::absolute_path( undef,
1729 $msfo_file );
1730 push( @file_names, $filename );
1735 if( defined $self -> {'extra_output'} ){
1736 foreach my $extra_out ( @{$self -> {'extra_output'}} ){
1737 push( @file_names, $extra_out );
1742 my @problems = @{$self -> problems};
1743 for( my $i = 0; $i <= $#problems; $i++ ) {
1744 if( $problems[$i-1] -> shrinkage_module -> enabled ) {
1745 my ( $dir, $eta_filename ) =
1746 OSspecific::absolute_path( undef,
1747 $problems[$i] -> shrinkage_module -> eta_tablename );
1749 push( @file_names, $eta_filename );
1751 my ( $dir, $wres_filename ) =
1752 OSspecific::absolute_path( undef,
1753 $problems[$i] -> shrinkage_module -> wres_tablename );
1755 push( @file_names, $wres_filename );
1760 end output_files
1762 # }}}
1764 # {{{ factors
1766 =head2 factors
1768 Usage:
1770 =for html <pre>
1772 my $factors = $model_object -> factors;
1774 =for html </pre>
1776 Arguments:
1778 =over 2
1780 =item colunm
1782 number
1784 =item column_head
1786 string
1788 =item problem_number
1790 integer
1792 =item return_occurences
1794 boolean
1796 =item unique_in_individual
1798 boolean
1800 =back
1802 Description:
1804 The following text comes from the documentation of
1805 data::factors. model::factors will call data::factors for the given
1806 problem number in the model object. Also it will take try to find
1807 "column_head" in the $INPUT record instead of the data file header.
1809 Either column (number, starting at 1) or column_head must be
1810 specified. The default behaviour is to return a hash with the factors
1811 as keys referencing arrays with the order numbers (not the ID numbers)
1812 of the individuals that contain this factor.
1814 If unique_in_individual is true (1), the returned hash will contain an
1815 element with key 'Non-unique values found' and value 1 if any
1816 individual contain more than one value in the specified column.
1818 Return occurences will calculate the occurence of each factor
1819 value. Several occurences in one individual counts as one
1820 occurence. The elements of the returned hash will have the factors as
1821 keys and the number of occurences as values.
1823 =cut
1825 start factors
1827 # Calls <I>factors</I> on the data object of a specified
1828 # problem. See <I>data -> factors</I> for details.
1829 my $column_number;
1830 my $extra_data_column;
1831 if ( defined $column_head ) {
1832 # Check normal data object first
1833 my ( $values_ref, $positions_ref ) = $self ->
1834 _get_option_val_pos ( problem_numbers => [$problem_number],
1835 name => $column_head,
1836 record_name => 'input',
1837 global_position => 1 );
1838 $column_number = $positions_ref -> [0];
1839 # Next, check extra_data
1840 my $extra_data_headers = $self -> extra_data_headers;
1841 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
1842 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
1843 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
1846 'debug' -> die( message => "Unknown column \"$column_head\"" )
1847 unless ( defined $column_number or defined $extra_data_column );
1848 } else {
1849 $column_number = $column;
1851 if ( defined $column_number) {
1852 %factors = %{$self -> {'datas'} -> [$problem_number-1] ->
1853 factors( column => $column_number,
1854 unique_in_individual => $unique_in_individual,
1855 return_occurences => $return_occurences )};
1856 } else {
1857 %factors = %{$self -> {'problems'} -> [$problem_number-1] -> extra_data
1858 -> factors( column => $extra_data_column,
1859 unique_in_individual => $unique_in_individual,
1860 return_occurences => $return_occurences )};
1863 end factors
1865 # }}}
1867 # {{{ fractions
1869 =head2 fractions
1871 Usage:
1873 =for html <pre>
1875 my $fractions = $model_object -> fractions;
1877 =for html </pre>
1879 Arguments:
1881 =over 2
1883 =item colunm
1885 number
1887 =item column_head
1889 string
1891 =item problem_number
1893 integer
1895 =item return_occurences
1897 boolean
1899 =item ignore_missing
1901 boolean
1903 =back
1905 Description:
1907 fractions will return the fractions from data::fractions. It will find
1908 "column_head" in the $INPUT record instead of that data header as
1909 data::fractions does.
1911 =cut
1913 start fractions
1915 # Calls <I>fractions</I> on the data object of a specified
1916 # problem. See <I>data -> fractions</I> for details.
1917 my $column_number;
1918 my $extra_data_column;
1919 if ( defined $column_head ) {
1920 # Check normal data object first
1921 my ( $values_ref, $positions_ref ) = $self ->
1922 _get_option_val_pos ( problem_numbers => [$problem_number],
1923 name => $column_head,
1924 record_name => 'input',
1925 global_position => 1 );
1926 $column_number = $positions_ref -> [0];
1927 # Next, check extra_data
1928 my $extra_data_headers = $self -> extra_data_headers;
1929 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
1930 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
1931 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
1934 'debug' -> die( "Unknown column \"$column_head\"" )
1935 unless ( defined $column_number or defined $extra_data_column );
1936 } else {
1937 $column_number = $column;
1939 if ( defined $column_number) {
1940 %fractions = %{$self -> {'datas'} -> [$problem_number-1] ->
1941 fractions( column => $column_number,
1942 unique_in_individual => $unique_in_individual,
1943 ignore_missing => $ignore_missing )};
1944 } else {
1945 %fractions = %{$self -> {'problems'} -> [$problem_number-1] -> extra_data
1946 -> fractions( column => $extra_data_column,
1947 unique_in_individual => $unique_in_individual,
1948 ignore_missing => $ignore_missing )};
1951 end fractions
1953 # }}}
1955 # {{{ fixed
1957 =head2 fractions
1959 Usage:
1961 =for html <pre>
1963 my $fractions = $model_object -> fractions;
1965 =for html </pre>
1967 Arguments:
1969 =over 2
1971 =item colunm
1973 number
1975 =item column_head
1977 string
1979 =item problem_number
1981 integer
1983 =item return_occurences
1985 boolean
1987 =item ignore_missing
1989 boolean
1991 =back
1993 Description:
1995 fractions will return the fractions from data::fractions. It will find
1996 "column_head" in the $INPUT record instead of that data header as
1997 data::fractions does.
1999 =cut
2001 start fixed
2003 # Sets or gets the 'fixed' status of a (number of)
2004 # parameter(s). 1 correspond to a parameter being fixed and
2005 # 0 not fixed. The returned parameter is a reference to a
2006 # two-dimensional array, indexed by problems and parameter
2007 # numbers.
2008 # Valid parameter types are 'theta', 'omega' and 'sigma'.
2010 @fixed = @{ $self -> _init_attr
2011 ( parameter_type => $parameter_type,
2012 parameter_numbers => \@parameter_numbers,
2013 problem_numbers => \@problem_numbers,
2014 new_values => \@new_values,
2015 attribute => 'fix')};
2017 end fixed
2019 # }}} fixed
2021 # {{{ have_missing_data
2023 =head2 fractions
2025 Usage:
2027 =for html <pre>
2029 my $fractions = $model_object -> fractions;
2031 =for html </pre>
2033 Arguments:
2035 =over 2
2037 =item colunm
2039 number
2041 =item column_head
2043 string
2045 =item problem_number
2047 integer
2049 =item return_occurences
2051 boolean
2053 =item ignore_missing
2055 boolean
2057 =back
2059 Description:
2061 fractions will return the fractions from data::fractions. It will find
2062 "column_head" in the $INPUT record instead of that data header as
2063 data::fractions does.
2065 =cut
2067 start have_missing_data
2069 # Calls <I>have_missing_data</I> on the data object of a specified
2070 # problem. See <I>data -> have_missing_data</I> for details.
2071 my $column_number;
2072 my $extra_data_column;
2073 if ( defined $column_head ) {
2074 # Check normal data object first
2075 my ( $values_ref, $positions_ref ) = $self ->
2076 _get_option_val_pos ( problem_numbers => [$problem_number],
2077 name => $column_head,
2078 record_name => 'input',
2079 global_position => 1 );
2080 $column_number = $positions_ref -> [0];
2081 # Next, check extra_data
2082 my $extra_data_headers = $self -> extra_data_headers;
2083 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
2084 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
2085 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
2088 'debug' -> die( message => "Unknown column \"$column_head\"" )
2089 unless ( defined $column_number or defined $extra_data_column );
2090 } else {
2091 $column_number = $column;
2093 if ( defined $column_number) {
2094 $return_value = $self -> {'datas'} -> [$problem_number-1] ->
2095 have_missing_data( column => $column_number );
2096 } else {
2097 $return_value = $self -> {'problems'} -> [$problem_number-1] ->
2098 extra_data -> have_missing_data( column => $extra_data_column );
2101 end have_missing_data
2103 # }}}
2105 # {{{ idcolumn
2107 =head2 fractions
2109 Usage:
2111 =for html <pre>
2113 my $fractions = $model_object -> fractions;
2115 =for html </pre>
2117 Arguments:
2119 =over 2
2121 =item colunm
2123 number
2125 =item column_head
2127 string
2129 =item problem_number
2131 integer
2133 =item return_occurences
2135 boolean
2137 =item ignore_missing
2139 boolean
2141 =back
2143 Description:
2145 fractions will return the fractions from data::fractions. It will find
2146 "column_head" in the $INPUT record instead of that data header as
2147 data::fractions does.
2149 =cut
2151 start idcolumn
2153 # Usage:
2155 # @idcolumns = @{$modelObject -> idcolumns( problem_numbers => [2,3] );
2157 # idcolumns returns the idcolumn index in the datafile for the
2158 # specified problem.
2160 my $junk_ref;
2161 ( $junk_ref, $col ) = $self ->
2162 _get_option_val_pos( name => 'ID',
2163 record_name => 'input',
2164 problem_numbers => [$problem_number] );
2166 if ( $problem_number ne 'all' ) {
2167 $col = @{$col}[0];
2170 end idcolumn
2172 # }}} idcolumn
2174 # {{{ idcolumns
2176 =head2 fractions
2178 Usage:
2180 =for html <pre>
2182 my $fractions = $model_object -> fractions;
2184 =for html </pre>
2186 Arguments:
2188 =over 2
2190 =item colunm
2192 number
2194 =item column_head
2196 string
2198 =item problem_number
2200 integer
2202 =item return_occurences
2204 boolean
2206 =item ignore_missing
2208 boolean
2210 =back
2212 Description:
2214 fractions will return the fractions from data::fractions. It will find
2215 "column_head" in the $INPUT record instead of that data header as
2216 data::fractions does.
2218 =cut
2220 start idcolumns
2222 # Usage:
2224 # @column_numbers = @{$modelObject -> idcolumns( problem_numbers => [2] )};
2226 # idcolumns returns the idcolumn indexes in the datafile for the
2227 # specified problems.
2229 my ( $junk_ref, $col_ref ) = $self ->
2230 _get_option_val_pos( name => 'ID',
2231 record_name => 'input',
2232 problem_numbers => \@problem_numbers );
2233 # There should only be one instance of $INPUT and hence we collapse
2234 # the two-dim return from _get_option_pos_val to a one-dim array:
2236 foreach my $prob ( @{$col_ref} ) {
2237 foreach my $inst ( @{$prob} ) {
2238 push( @column_numbers, $inst );
2242 end idcolumns
2244 # }}} idcolumns
2246 # {{{ ignoresigns
2248 =head2 ignoresigns
2250 Usage:
2252 =for html <pre>
2254 $model_object -> ignoresigns( ['#','@'] );
2256 my $ignoresigns = $model_object -> ignoresigns;
2258 =for html </pre>
2260 Arguments:
2262 The argument is an unnamed array of strings
2264 Description:
2266 If ignoresigns is used without argument the string that specifies
2267 which string that is used for comment rows in the data file is
2268 returned. The returned value is an array including the ignore signs
2269 of each problem. If an argument is given it must be an array of
2270 length equal to the number of problems in the model. Then the names of
2271 the extra data files will be changed to those in the array.
2273 =cut
2275 start ignoresigns
2277 # Usage:
2279 # @ignore_signs = @{$modelObject -> ignoresigns( problem_numbers => [2,4] )};
2281 # ignoresigns returns the ignore signs in the datafile for the
2282 # specified problems
2284 foreach my $prob ( @{$self -> {'problems'}} ) {
2285 my @datarecs = @{$prob -> datas};
2286 if ( defined $datarecs[0] ) {
2287 push( @ignore, $datarecs[0] -> ignoresign );
2288 } else {
2289 push( @ignore, '#' );
2293 # print "IGNORE: @ignore\n";
2296 end ignoresigns
2298 # }}} ignoresigns
2300 # {{{ ignore_lists
2302 start ignore_lists
2304 # Usage:
2306 # @ignore_signs = @{$modelObject -> ignore_lists( problem_numbers => [2,4] )};
2308 # ignore_lists returns the ignore signs in the datafile for the
2309 # specified problems
2311 foreach my $prob ( @{$self -> {'problems'}} ) {
2312 my @datarecs = @{$prob -> datas};
2313 if ( defined $datarecs[0] ) {
2314 push( @ignore, $datarecs[0] -> ignore_list );
2315 } else {
2316 push( @ignore, '#' );
2320 # print "IGNORE: @ignore\n";
2323 end ignore_lists
2325 # }}} ignoresigns
2327 # {{{ indexes
2329 =head2 fractions
2331 Usage:
2333 =for html <pre>
2335 my $fractions = $model_object -> fractions;
2337 =for html </pre>
2339 Arguments:
2341 =over 2
2343 =item colunm
2345 number
2347 =item column_head
2349 string
2351 =item problem_number
2353 integer
2355 =item return_occurences
2357 boolean
2359 =item ignore_missing
2361 boolean
2363 =back
2365 Description:
2367 fractions will return the fractions from data::fractions. It will find
2368 "column_head" in the $INPUT record instead of that data header as
2369 data::fractions does.
2371 =cut
2373 start indexes
2375 # Usage:
2377 # @indexArray = @{$modelObject -> indexes( 'parameter_type' => 'omega' )};
2379 # A call to I<indexes> returns the indexes of all parameters
2380 # specified in I<parameter_numbers> from the subproblems
2381 # specified in I<problem_numbers>. The method returns a reference to an array that has
2382 # the same structure as parameter_numbers but for each
2383 # array of numbers is instead an array of indices. The method
2384 # uses a method from the model::problem class to format the
2385 # indices, so here are a few lines from the code comments in
2386 # model/problem.pm that describes the returned value:
2388 # <snip>
2389 # The Indexes method calculates the index for a
2390 # parameter. Off-diagonal elements will get a index 'i_j', where i
2391 # is the row number and j is the column number
2392 # </snip>
2394 unless( $#problem_numbers > 0 ){
2395 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
2397 my @problems = @{$self -> {'problems'}};
2398 foreach my $i ( @problem_numbers ) {
2399 if ( defined $problems[ $i-1 ] ) {
2400 push( @indexes,
2401 $problems[ $i-1 ] ->
2402 indexes( parameter_type => $parameter_type,
2403 parameter_numbers => $parameter_numbers[ $i-1 ] ) );
2404 } else {
2405 'debug' -> die( message => "Problem number $i does not exist!" );
2409 end indexes
2411 # }}} indexes
2413 # {{{ initial_values
2415 =head2 fractions
2417 Usage:
2419 =for html <pre>
2421 my $fractions = $model_object -> fractions;
2423 =for html </pre>
2425 Arguments:
2427 =over 2
2429 =item colunm
2431 number
2433 =item column_head
2435 string
2437 =item problem_number
2439 integer
2441 =item return_occurences
2443 boolean
2445 =item ignore_missing
2447 boolean
2449 =back
2451 Description:
2453 fractions will return the fractions from data::fractions. It will find
2454 "column_head" in the $INPUT record instead of that data header as
2455 data::fractions does.
2457 =cut
2459 start initial_values
2461 # initial_values either sets or gets the initial values of
2462 # the parameter specified in "parameter_type" for each
2463 # problem specified in problem_numbers. For each element
2464 # in problem_numbers there must be a reference in
2465 # parameter_numbers to an array that specify the indices
2466 # of the parameters in the subproblem for which the initial
2467 # values are set, replaced or retrieved.
2469 # The add_if_absent argument tells the method to add an init
2470 # (theta,omega,sigma) if the parameter number points to a
2471 # non-existing parameter with parameter number one higher
2472 # than the highest presently included. Only applicable if
2473 # new_values are set. Valid parameter types are 'theta',
2474 # 'omega' and 'sigma'.
2476 @initial_values = @{ $self -> _init_attr
2477 ( parameter_type => $parameter_type,
2478 parameter_numbers => \@parameter_numbers,
2479 problem_numbers => \@problem_numbers,
2480 new_values => \@new_values,
2481 attribute => 'init',
2482 add_if_absent => $add_if_absent )};
2484 end initial_values
2486 # }}} initial_values
2488 # {{{ is_option_set
2491 =head2 fractions
2493 Usage:
2495 =for html <pre>
2497 my $fractions = $model_object -> fractions;
2499 =for html </pre>
2501 Arguments:
2503 =over 2
2505 =item colunm
2507 number
2509 =item column_head
2511 string
2513 =item problem_number
2515 integer
2517 =item return_occurences
2519 boolean
2521 =item ignore_missing
2523 boolean
2525 =back
2527 Description:
2529 fractions will return the fractions from data::fractions. It will find
2530 "column_head" in the $INPUT record instead of that data header as
2531 data::fractions does.
2533 =cut
2535 start is_option_set
2537 # Usage:
2539 # if( $modelObject -> is_option_set( record => 'recordName', name => 'optionName' ) ){
2540 # print "problem_number 1 has option optionName set in record recordName";
2543 # is_option_set checks if an option is set in a given record in given problem.
2545 my ( @problems, @records, @options );
2546 my $accessor = $record.'s';
2547 if ( defined $self -> {'problems'} ) {
2548 @problems = @{$self -> {'problems'}};
2549 } else {
2550 'debug' -> die( message => "No problems defined in model" );
2552 unless( defined $problems[$problem_number - 1] ){
2553 'debug' -> warn( level => 2,
2554 message => "model -> is_option_set: No problem number $problem_number defined in model" );
2555 return 0; # No option can be set if no problem exists.
2558 if ( defined $problems[$problem_number - 1] -> $accessor ) {
2559 @records = @{$problems[$problem_number - 1] -> $accessor};
2560 } else {
2561 'debug' -> warn( level => 2,
2562 message => "model -> is_option_set: No record $record defined" .
2563 " in problem number $problem_number." );
2564 return 0;
2567 unless(defined $records[$instance - 1] ){
2568 'debug' -> warn( level => 2,
2569 message => "model -> is_option_set: No record instance number $instance defined in model." );
2570 return 0;
2573 if ( defined $records[$instance - 1] -> options ) {
2574 @options = @{$records[$instance - 1] -> options};
2575 } else {
2576 'debug' -> warn( level => 2,
2577 message => "No option defined in record: $record in problem number $problem_number." );
2578 return 0;
2580 foreach my $option ( @options ) {
2581 $found = 1 if ( defined $option and $option -> name eq $name );
2582 if( $fuzzy_match ){
2583 if( index( $name, $option -> name ) > -1 ){
2584 $found = 1;
2589 end is_option_set
2591 # }}} is_option_set
2593 # {{{ is_run
2596 =head2 fractions
2598 Usage:
2600 =for html <pre>
2602 my $fractions = $model_object -> fractions;
2604 =for html </pre>
2606 Arguments:
2608 =over 2
2610 =item colunm
2612 number
2614 =item column_head
2616 string
2618 =item problem_number
2620 integer
2622 =item return_occurences
2624 boolean
2626 =item ignore_missing
2628 boolean
2630 =back
2632 Description:
2634 fractions will return the fractions from data::fractions. It will find
2635 "column_head" in the $INPUT record instead of that data header as
2636 data::fractions does.
2638 =cut
2640 start is_run
2642 # Usage:
2644 # is_run returns true if the outputobject owned by the
2645 # modelobject has valid outpudata either in memory or on disc.
2646 if( defined $self -> {'outputs'} ){
2647 if( @{$self -> {'outputs'}}[0] -> have_output ){
2648 $return_value = 1;
2650 } else {
2651 $return_value = 0;
2654 end is_run
2655 # }}} is_run
2657 # {{{ is_simulation
2660 =head2 fractions
2662 Usage:
2664 =for html <pre>
2666 my $fractions = $model_object -> fractions;
2668 =for html </pre>
2670 Arguments:
2672 =over 2
2674 =item colunm
2676 number
2678 =item column_head
2680 string
2682 =item problem_number
2684 integer
2686 =item return_occurences
2688 boolean
2690 =item ignore_missing
2692 boolean
2694 =back
2696 Description:
2698 fractions will return the fractions from data::fractions. It will find
2699 "column_head" in the $INPUT record instead of that data header as
2700 data::fractions does.
2702 =cut
2704 start is_simulation
2706 my $problems = $self -> {'problems'};
2707 if( defined $problems -> [$problem_number - 1] ) {
2708 my $problem = $problems -> [$problem_number - 1];
2709 # If we don't have an ESTIMATION record we are simulating.
2710 $is_sim = 1 unless( defined $problem -> {'estimations'} and
2711 scalar( @{$problem-> {'estimations'}} ) > 0 );
2713 # If we have a ONLYSIM option in the simulation record.
2714 $is_sim = 1 if( $self -> is_option_set ( name => 'ONLYSIM',
2715 record => 'simulation',
2716 problem_number => $problem_number ));
2718 # If max evaluations is zero we are simulating
2719 $is_sim = 1 if( defined $self -> maxeval(problem_numbers => [$problem_number]) and
2720 defined $self -> maxeval(problem_numbers => [$problem_number])->[0][0] and
2721 $self -> maxeval(problem_numbers => [$problem_number])->[0][0] == 0 );
2723 # Anything else?
2725 # If non of the above is true, we are estimating.
2726 } else {
2727 'debug' -> warn( level => 1,
2728 message => 'Problem nr. $problem_number not defined. Assuming no simulation' );
2729 $is_sim = 0;
2732 end is_simulation
2734 # }}}
2736 # {{{ lower_bounds
2738 =head2 fractions
2740 Usage:
2742 =for html <pre>
2744 my $fractions = $model_object -> fractions;
2746 =for html </pre>
2748 Arguments:
2750 =over 2
2752 =item colunm
2754 number
2756 =item column_head
2758 string
2760 =item problem_number
2762 integer
2764 =item return_occurences
2766 boolean
2768 =item ignore_missing
2770 boolean
2772 =back
2774 Description:
2776 fractions will return the fractions from data::fractions. It will find
2777 "column_head" in the $INPUT record instead of that data header as
2778 data::fractions does.
2780 =cut
2782 start lower_bounds
2784 # lower_bounds either sets or gets the initial values of the
2785 # parameter specified in the argument parameter_type for
2786 # each problem specified in problem_numbers. See L</fixed>.
2788 @lower_bounds = @{ $self -> _init_attr
2789 ( parameter_type => $parameter_type,
2790 parameter_numbers => \@parameter_numbers,
2791 problem_numbers => \@problem_numbers,
2792 new_values => \@new_values,
2793 attribute => 'lobnd')};
2795 end lower_bounds
2797 # }}} lower_bounds
2799 # {{{ labels
2801 =head2 fractions
2803 Usage:
2805 =for html <pre>
2807 my $fractions = $model_object -> fractions;
2809 =for html </pre>
2811 Arguments:
2813 =over 2
2815 =item colunm
2817 number
2819 =item column_head
2821 string
2823 =item problem_number
2825 integer
2827 =item return_occurences
2829 boolean
2831 =item ignore_missing
2833 boolean
2835 =back
2837 Description:
2839 fractions will return the fractions from data::fractions. It will find
2840 "column_head" in the $INPUT record instead of that data header as
2841 data::fractions does.
2843 =cut
2845 start labels
2847 # Usage:
2849 # @labels = @{$modobj -> labels( parameter_type => 'theta' )};
2851 # This basic usage takes one arguments and returns matched names and
2852 # estimated values of the specified parameter. The parameter_type argument
2853 # is mandatory. It returns the labels of all parameters of type given by
2854 # $parameter_type.
2855 # @labels will be a two-dimensional array:
2856 # [[label1][label2][label3]...]
2858 # $labels -> labels( parameter_type => 'theta',
2859 # problem_numbers => [2,4] );
2861 # To get labels of specific problems, the problem_numbers argument can be used.
2862 # It should be a reference to an array containing the numbers
2863 # of all problems whos labels should be retrieved.
2865 # $modobj -> labels( parameter_type => 'theta',
2866 # problem_numbers => [2,4],
2867 # parameter_numbers => [[1,3][4,6]]);
2869 # The retrieval can be even more specific by using the parameter_numbers
2870 # argument. It should be a reference to a two-dimensional array, where
2871 # the inner arrays holds the numbers of the parameters that should be
2872 # fetched. In the example above, parameters one and three from problem two
2873 # plus parameters four and six from problem four are retrieved.
2875 # $modobj -> labels( parameter_type => 'theta',
2876 # problem_numbers => [2,4],
2877 # parameter_numbers => [[1,3][4,6]],
2878 # generic => 1 );
2880 # To get generic labels for the parameters - e.g. OM1, OM2_1, OM2 etc -
2881 # set the generic argument to 1.
2883 # $modobj -> labels( parameter_type => 'theta',
2884 # problem_numbers => [2],
2885 # parameter_numbers => [[1,3]],
2886 # new_values => [['Volume','Clearance']] );
2888 # The new_values argument can be used to give parameters new labels. In
2889 # the above example, parameters one and three in problem two are renamed
2890 # Volume and Clearance.
2893 my ( @index, $idx );
2894 @labels = @{ $self -> _init_attr
2895 ( parameter_type => $parameter_type,
2896 parameter_numbers => \@parameter_numbers,
2897 problem_numbers => \@problem_numbers,
2898 new_values => \@new_values,
2899 attribute => 'label' )};
2901 # foreach my $prl ( @labels ) {
2902 # foreach my $label ( @{$prl} ) {
2903 # print "Label: $label\n";
2908 @index = @{$self -> indexes( parameter_type => $parameter_type,
2909 parameter_numbers => \@parameter_numbers,
2910 problem_numbers => \@problem_numbers )};
2912 for ( my $i = 0; $i <= $#labels; $i++ ) {
2913 for ( my $j = 0; $j < scalar @{$labels[$i]}; $j++ ) {
2914 $idx = $index[$i][$j];
2915 $labels[$i][$j] = uc(substr($parameter_type,0,2)).$idx
2916 unless ( defined $labels[$i][$j] and not $generic );
2920 end labels
2922 # }}} labels
2924 # {{{ maxeval
2926 =head2 fractions
2928 Usage:
2930 =for html <pre>
2932 my $fractions = $model_object -> fractions;
2934 =for html </pre>
2936 Arguments:
2938 =over 2
2940 =item colunm
2942 number
2944 =item column_head
2946 string
2948 =item problem_number
2950 integer
2952 =item return_occurences
2954 boolean
2956 =item ignore_missing
2958 boolean
2960 =back
2962 Description:
2964 fractions will return the fractions from data::fractions. It will find
2965 "column_head" in the $INPUT record instead of that data header as
2966 data::fractions does.
2968 =cut
2970 start maxeval
2972 # Usage:
2974 # @maxev = @{$modobj -> maxeval};
2976 # This basic usage takes no arguments and returns the value of the
2977 # MAXEVAL option in the $ESTIMATION record of each problem.
2978 # @maxev will be a two dimensional array:
2979 # [[maxeval_prob1][maxeval_prob2][maxeval_prob3]...]
2981 # $modobj -> maxeval( new_values => [[0],[999]];
2983 # If the new_values argument of maxeval is given, the values of the
2984 # MAXEVAL options will be changed. In this example, MAXEVAL will be
2985 # set to 0 in the first problem and to 999 in the second.
2986 # The number of elements in new_values must match the number of problems
2987 # in the model object $modobj.
2989 # $modobj -> maxeval( new_values => [[0],[999]],
2990 # problem_numbers => [2,4] );
2992 # To set the MAXEVAL of specific problems, the problem_numbers argument can
2993 # be used. It should be a reference to an array containing the numbers
2994 # of all problems where the MAXEVAL should be changed or retrieved.
2995 # If specified, the size of new_values must be the same as the size
2996 # of problem_numbers.
3001 my ( $val_ref, $junk ) = $self ->
3002 _option_val_pos( name => 'MAX',
3003 record_name => 'estimation',
3004 problem_numbers => \@problem_numbers,
3005 new_values => \@new_values,
3006 exact_match => $exact_match );
3007 @values = @{$val_ref};
3009 end maxeval
3011 # }}} maxeval
3013 # {{{ median
3015 =head2 fractions
3017 Usage:
3019 =for html <pre>
3021 my $fractions = $model_object -> fractions;
3023 =for html </pre>
3025 Arguments:
3027 =over 2
3029 =item colunm
3031 number
3033 =item column_head
3035 string
3037 =item problem_number
3039 integer
3041 =item return_occurences
3043 boolean
3045 =item ignore_missing
3047 boolean
3049 =back
3051 Description:
3053 fractions will return the fractions from data::fractions. It will find
3054 "column_head" in the $INPUT record instead of that data header as
3055 data::fractions does.
3057 =cut
3059 start median
3061 # Calls <I>median</I> on the data object of a specified
3062 # problem. See <I>data -> median</I> for details.
3063 my $column_number;
3064 my $extra_data_column;
3065 if ( defined $column_head ) {
3066 # Check normal data object first
3067 my ( $values_ref, $positions_ref ) = $self ->
3068 _get_option_val_pos ( problem_numbers => [$problem_number],
3069 name => $column_head,
3070 record_name => 'input',
3071 global_position => 1 );
3072 $column_number = $positions_ref -> [0];
3073 if ( not defined $column_number ) {
3074 # Next, check extra_data
3075 my $extra_data_headers = $self -> extra_data_headers;
3076 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
3077 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
3078 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
3082 'debug' -> die( message => "Unknown column \"$column_head\"" )
3083 unless ( defined $column_number or defined $extra_data_column );
3084 } else {
3085 $column_number = $column;
3088 if ( defined $column_number) {
3089 $median = $self -> {'datas'} -> [$problem_number-1] ->
3090 median( column => $column_number,
3091 unique_in_individual => $unique_in_individual );
3092 } else {
3093 $median = $self -> {'problems'} -> [$problem_number-1] -> extra_data ->
3094 median( column => $extra_data_column,
3095 unique_in_individual => $unique_in_individual );
3098 end median
3100 # }}}
3102 # {{{ max
3104 =head2 fractions
3106 Usage:
3108 =for html <pre>
3110 my $fractions = $model_object -> fractions;
3112 =for html </pre>
3114 Arguments:
3116 =over 2
3118 =item colunm
3120 number
3122 =item column_head
3124 string
3126 =item problem_number
3128 integer
3130 =item return_occurences
3132 boolean
3134 =item ignore_missing
3136 boolean
3138 =back
3140 Description:
3142 fractions will return the fractions from data::fractions. It will find
3143 "column_head" in the $INPUT record instead of that data header as
3144 data::fractions does.
3146 =cut
3148 start max
3150 # Calls <I>max</I> on the data object of a specified
3151 # problem. See <I>data -> max</I> for details.
3152 my $column_number;
3153 my $extra_data_column;
3154 if ( defined $column_head ) {
3155 # Check normal data object first
3156 my ( $values_ref, $positions_ref ) = $self ->
3157 _get_option_val_pos ( problem_numbers => [$problem_number],
3158 name => $column_head,
3159 record_name => 'input',
3160 global_position => 1 );
3161 $column_number = $positions_ref -> [0];
3162 if ( not defined $column_number ) {
3163 # Next, check extra_data
3164 my $extra_data_headers = $self -> extra_data_headers;
3165 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
3166 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
3167 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
3171 'debug' -> die( message => "Unknown column \"$column_head\"" )
3172 unless ( defined $column_number or defined $extra_data_column );
3173 } else {
3174 $column_number = $column;
3177 if ( defined $column_number) {
3178 $max = $self -> {'datas'} -> [$problem_number-1] ->
3179 max( column => $column_number );
3180 } else {
3181 $max = $self -> {'problems'} -> [$problem_number-1] -> extra_data ->
3182 max( column => $extra_data_column );
3185 end max
3187 # }}}
3189 # {{{ min
3191 =head2 fractions
3193 Usage:
3195 =for html <pre>
3197 my $fractions = $model_object -> fractions;
3199 =for html </pre>
3201 Arguments:
3203 =over 2
3205 =item colunm
3207 number
3209 =item column_head
3211 string
3213 =item problem_number
3215 integer
3217 =item return_occurences
3219 boolean
3221 =item ignore_missing
3223 boolean
3225 =back
3227 Description:
3229 fractions will return the fractions from data::fractions. It will find
3230 "column_head" in the $INPUT record instead of that data header as
3231 data::fractions does.
3233 =cut
3235 start min
3237 # Calls <I>min</I> on the data object of a specified
3238 # problem. See <I>data -> min</I> for details.
3239 my $column_number;
3240 my $extra_data_column;
3241 if ( defined $column_head ) {
3242 # Check normal data object first
3243 my ( $values_ref, $positions_ref ) = $self ->
3244 _get_option_val_pos ( problem_numbers => [$problem_number],
3245 name => $column_head,
3246 record_name => 'input',
3247 global_position => 1 );
3248 $column_number = $positions_ref -> [0];
3249 if ( not defined $column_number ) {
3250 # Next, check extra_data
3251 my $extra_data_headers = $self -> extra_data_headers;
3252 if ( defined $extra_data_headers and defined $extra_data_headers -> [0] ) {
3253 for ( my $i = 1; $i <= scalar @{$extra_data_headers->[0]}; $i++ ) {
3254 $extra_data_column = $i if ( $column_head eq $extra_data_headers->[0][$i-1] );
3258 'debug' -> die( message => "Unknown column \"$column_head\"" )
3259 unless ( defined $column_number or defined $extra_data_column );
3260 } else {
3261 $column_number = $column;
3264 if ( defined $column_number) {
3265 $min = $self -> {'datas'} -> [$problem_number-1] ->
3266 min( column => $column_number );
3267 } else {
3268 $min = $self -> {'problems'} -> [$problem_number-1] -> extra_data ->
3269 min( column => $extra_data_column );
3272 end min
3274 # }}}
3276 # {{{ name_val
3278 =head2 fractions
3280 Usage:
3282 =for html <pre>
3284 my $fractions = $model_object -> fractions;
3286 =for html </pre>
3288 Arguments:
3290 =over 2
3292 =item colunm
3294 number
3296 =item column_head
3298 string
3300 =item problem_number
3302 integer
3304 =item return_occurences
3306 boolean
3308 =item ignore_missing
3310 boolean
3312 =back
3314 Description:
3316 fractions will return the fractions from data::fractions. It will find
3317 "column_head" in the $INPUT record instead of that data header as
3318 data::fractions does.
3320 =cut
3322 start name_val
3324 # Usage:
3326 # @name_val = @{$modobj -> name_val( parameter_type => 'theta' )};
3328 # This basic usage takes one arguments and returns matched names and
3329 # estimated values of the specified parameter. The parameter_type argument
3330 # is mandatory.
3331 # The names are taken from
3332 # the labels of the parameters (se the labels method for specifications of
3333 # default labels) and the values are aquired from the output object bound
3334 # to the model object. If no output exists, the name_val method returns
3335 # undef.
3336 # @name_val will be a two-dimensional array of references to hashes using
3337 # the names from each problem as keys:
3338 # [[ref to hash1 ][ref to hash2][ref to hash3]...]
3340 # $modobj -> name_val( parameter_type => 'theta',
3341 # problem_numbers => [2,4] );
3343 # To get matched names and values of specific problems, the problem_numbers argument
3344 # can be used. It should be a reference to an array containing the numbers
3345 # of all problems whos names and values should be retrieved.
3347 # $modobj -> name_val( parameter_type => 'theta',
3348 # problem_numbers => [2,4],
3349 # parameter_numbers => [[1,3][4,6]]);
3351 # The retrieval can be even more specific by using the parameter_numbers
3352 # argument. It should be a reference to a two-dimensional array, where
3353 # the inner arrays holds the numbers of the parameters that should be
3354 # fetched. In the example above, parameters one and three from problem two
3355 # plus parameters four and six from problem four are retrieved.
3358 unless( $#problem_numbers > 0 ){
3359 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
3361 my @names = @{$self -> labels( parameter_type => $parameter_type,
3362 parameter_numbers => \@parameter_numbers,
3363 problem_numbers => \@problem_numbers )};
3364 my @values;
3365 if ( defined $self -> outputs -> [0] ) {
3366 my $accessor = $parameter_type.'s';
3367 @values = @{$self -> outputs -> [0] ->
3368 $accessor( problems => \@problem_numbers,
3369 parameter_numbers => \@parameter_numbers )};
3370 # my @problems = @{$self -> {'problems'}};
3371 # foreach my $i ( @problem_numbers ) {
3372 # if ( defined $problems[ $i-1 ] ) {
3373 # my $pn_ref = $#parameter_numbers >= 0 ? \@{$parameter_numbers[ $i-1 ]} : [];
3374 # push( @names_values,
3375 # $problems[ $i-1 ] ->
3376 # name_val( parameter_type => $parameter_type,
3377 # parameter_numbers => $pn_ref ) );
3378 # } else {
3379 # die "Model -> name_val: Problem number $i does not exist!\n";
3383 # if ( scalar @{$self -> {'outputs'}} > 0 ) {
3384 # my $outobj = $self -> {'outputs'} -> [0];
3387 'debug' -> die( message => "The number of problems retrieved from the model" .
3388 " do not match the ones retrived from the output" ) unless( $#names == $#values );
3389 for( my $i = 0; $i <= $#names; $i++ ) {
3390 'debug' -> die( message => "Problem " . $i+1 .
3391 " The number of parameters retrieved from the model (".scalar @{$names[$i]}.
3392 ") do not match the ones retrived from the output (".
3393 scalar @{$values[$i][0]}.")" )
3394 unless( scalar @{$names[$i]} == scalar @{$values[$i][0]} );
3395 my @prob_nv = ();
3396 for( my $j = 0; $j < scalar @{$values[$i]}; $j++ ){
3397 my %nv = ();
3398 for( my $k = 0; $k < scalar @{$names[$i]}; $k++ ){
3399 $nv{$names[$i][$k]} = $values[$i][$j][$k];
3401 push( @prob_nv, \%nv );
3403 push( @names_values, \@prob_nv );
3406 end name_val
3408 # }}} name_val
3410 # {{{ nproblems
3412 =head2 fractions
3414 Usage:
3416 =for html <pre>
3418 my $fractions = $model_object -> fractions;
3420 =for html </pre>
3422 Arguments:
3424 =over 2
3426 =item colunm
3428 number
3430 =item column_head
3432 string
3434 =item problem_number
3436 integer
3438 =item return_occurences
3440 boolean
3442 =item ignore_missing
3444 boolean
3446 =back
3448 Description:
3450 fractions will return the fractions from data::fractions. It will find
3451 "column_head" in the $INPUT record instead of that data header as
3452 data::fractions does.
3454 =cut
3456 start nproblems
3458 # nproblems returns the number of problems in the modelobject.
3460 $number_of_problem = scalar @{$self -> {'problems'}};
3462 end nproblems
3464 # }}} nproblems
3466 # {{{ nthetas
3468 =head2 fractions
3470 Usage:
3472 =for html <pre>
3474 my $fractions = $model_object -> fractions;
3476 =for html </pre>
3478 Arguments:
3480 =over 2
3482 =item colunm
3484 number
3486 =item column_head
3488 string
3490 =item problem_number
3492 integer
3494 =item return_occurences
3496 boolean
3498 =item ignore_missing
3500 boolean
3502 =back
3504 Description:
3506 fractions will return the fractions from data::fractions. It will find
3507 "column_head" in the $INPUT record instead of that data header as
3508 data::fractions does.
3510 =cut
3512 start nthetas
3514 # returns the number of thetas in the model for the given
3515 # problem number.
3516 $nthetas = $self -> _parameter_count( 'record' => 'theta', 'problem_number' => $problem_number );
3518 end nthetas
3520 # }}} nthetas
3522 # {{{ nomegas
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 nomegas
3570 # returns the number of omegas in the model for the given
3571 # problem number.
3572 # $nomegas = $self -> _parameter_count( 'record' => 'omega', 'problem_number' => $problem_number );
3573 unless( $#problem_numbers >= 0 ){
3574 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
3577 my @problems = @{$self -> {'problems'}};
3578 foreach my $i ( @problem_numbers ) {
3579 if ( defined $problems[ $i-1 ] ) {
3580 push( @nomegas, $problems[ $i-1 ] -> nomegas( with_correlations => $with_correlations ));
3581 } else {
3582 'debug' -> die( "Problem number $i does not exist." );
3586 end nomegas
3588 # }}} nomegas
3590 # {{{ nsigmas
3592 =head2 fractions
3594 Usage:
3596 =for html <pre>
3598 my $fractions = $model_object -> fractions;
3600 =for html </pre>
3602 Arguments:
3604 =over 2
3606 =item colunm
3608 number
3610 =item column_head
3612 string
3614 =item problem_number
3616 integer
3618 =item return_occurences
3620 boolean
3622 =item ignore_missing
3624 boolean
3626 =back
3628 Description:
3630 fractions will return the fractions from data::fractions. It will find
3631 "column_head" in the $INPUT record instead of that data header as
3632 data::fractions does.
3634 =cut
3636 start nsigmas
3638 # returns the number of sigmas in the model for the given problem number.
3640 # $nsigmas = $self -> _parameter_count( 'record' => 'sigma', 'problem_number' => $problem_number );
3642 unless( $#problem_numbers >= 0 ){
3643 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
3646 my @problems = @{$self -> {'problems'}};
3647 foreach my $i ( @problem_numbers ) {
3648 if ( defined $problems[ $i-1 ] ) {
3649 push( @nsigmas, $problems[ $i-1 ] -> nsigmas( with_correlations => $with_correlations ));
3650 } else {
3651 'debug' -> die( "Problem number $i does not exist." );
3655 end nsigmas
3657 # }}} nsigmas
3659 # {{{ outputfile
3661 =head2 fractions
3663 Usage:
3665 =for html <pre>
3667 my $fractions = $model_object -> fractions;
3669 =for html </pre>
3671 Arguments:
3673 =over 2
3675 =item colunm
3677 number
3679 =item column_head
3681 string
3683 =item problem_number
3685 integer
3687 =item return_occurences
3689 boolean
3691 =item ignore_missing
3693 boolean
3695 =back
3697 Description:
3699 fractions will return the fractions from data::fractions. It will find
3700 "column_head" in the $INPUT record instead of that data header as
3701 data::fractions does.
3703 =cut
3705 start outputfile
3707 # Usage:
3709 # This method is a (partially) automatically generated accessor for the
3710 # outputfile attribute of the model class. Since no named argument is needed
3711 # for accessors, the two possible ways of calling outputfile are:
3713 # $modelObject -> outputfile( 'newfilename.lst' );
3715 # $outputfilename = $modelObject -> outputfile;
3717 # The first alternative sets a new name for the output file, and the second
3718 # retrieves the value.
3720 # The extra feature for this accessor, compared to other accessors, is that
3721 # if a new name is given, the accessor tries to create a new output object
3722 # based on this.
3724 if( defined $parm ) {
3725 $self -> {'outputs'} =
3726 [ output ->
3727 new( filename => $parm,
3728 ignore_missing_files => ( $self -> ignore_missing_files() || $self -> ignore_missing_output_files() ),
3729 target => $self -> target(),
3730 model_id => $self -> model_id() ) ];
3733 end outputfile
3735 # }}} outputfile
3737 # {{{ pk
3739 =head2 fractions
3741 Usage:
3743 =for html <pre>
3745 my $fractions = $model_object -> fractions;
3747 =for html </pre>
3749 Arguments:
3751 =over 2
3753 =item colunm
3755 number
3757 =item column_head
3759 string
3761 =item problem_number
3763 integer
3765 =item return_occurences
3767 boolean
3769 =item ignore_missing
3771 boolean
3773 =back
3775 Description:
3777 fractions will return the fractions from data::fractions. It will find
3778 "column_head" in the $INPUT record instead of that data header as
3779 data::fractions does.
3781 =cut
3783 start pk
3785 # sets or gets the pk code for a given problem in the
3786 # model object. The new_pk argument should be an array where
3787 # each element contains a row of a valid NONMEM $PK block,
3789 my @prob = @{$self -> problems};
3791 unless( defined $prob[$problem_number - 1] ){
3792 'debug' -> die( message => "Problem number $problem_number does not exist" );
3795 my $pks = $prob[$problem_number - 1] -> pks;
3796 if( scalar @new_pk > 0 ) {
3797 if( defined $pks and scalar @{$pks} > 0 ){
3798 $prob[$problem_number - 1] -> pks -> [0] -> code(\@new_pk);
3799 } else {
3800 'debug' -> die( message => "No \$PK record" );
3802 } else {
3803 if ( defined $pks and scalar @{$pks} > 0 ) {
3804 @pk = @{$prob[$problem_number - 1] -> pks -> [0] -> code};
3808 end pk
3810 # }}} pk
3812 # {{{ pred
3814 =head2 fractions
3816 Usage:
3818 =for html <pre>
3820 my $fractions = $model_object -> fractions;
3822 =for html </pre>
3824 Arguments:
3826 =over 2
3828 =item colunm
3830 number
3832 =item column_head
3834 string
3836 =item problem_number
3838 integer
3840 =item return_occurences
3842 boolean
3844 =item ignore_missing
3846 boolean
3848 =back
3850 Description:
3852 fractions will return the fractions from data::fractions. It will find
3853 "column_head" in the $INPUT record instead of that data header as
3854 data::fractions does.
3856 =cut
3858 start pred
3860 # Sets or gets the pred code for a given problem in the model
3861 # object. See L</pk> for details.
3862 my @prob = @{$self -> problems};
3864 unless( defined $prob[$problem_number - 1] ){
3865 'debug' -> die( message => "problem number $problem_number does not exist" );
3868 if( scalar @new_pred > 0 ) {
3869 if( defined $prob[$problem_number - 1] -> preds ){
3870 $prob[$problem_number - 1] -> preds -> [0] -> code(\@new_pred);
3871 } else {
3872 'debug' -> die( message => "No \$PRED record" );
3874 } else {
3875 if ( defined $prob[$problem_number - 1] -> preds ) {
3876 @pred = @{$prob[$problem_number - 1] -> preds -> [0] -> code};
3877 } else {
3878 'debug' -> die( message => "No \$PRED record" );
3882 end pred
3884 # }}} pred
3886 # {{{ print
3888 =head2 fractions
3890 Usage:
3892 =for html <pre>
3894 my $fractions = $model_object -> fractions;
3896 =for html </pre>
3898 Arguments:
3900 =over 2
3902 =item colunm
3904 number
3906 =item column_head
3908 string
3910 =item problem_number
3912 integer
3914 =item return_occurences
3916 boolean
3918 =item ignore_missing
3920 boolean
3922 =back
3924 Description:
3926 fractions will return the fractions from data::fractions. It will find
3927 "column_head" in the $INPUT record instead of that data header as
3928 data::fractions does.
3930 =cut
3932 start print
3934 # Prints the formatted model to standard out.
3936 my ( @formatted );
3937 foreach my $problem ( @{$self -> {'problems'}} ) {
3938 foreach my $line (@{$problem-> _format_problem}){
3939 print $line;
3943 end print
3945 # }}} print
3947 # {{{ problem_structure
3949 start problem_structure
3951 my ( $val, $pos ) = $self -> _option_val_pos( record_name => 'simulation',
3952 name => 'SUBPROBLEMS' );
3953 if( defined $val ) {
3954 my @vals = @{$val};
3955 for( my $i = 0; $i <= $#vals; $i++ ) {
3956 if( defined $vals[$i] ) {
3957 if( scalar @{$vals[$i]} > 0 ) {
3958 $subproblems[$i] = $vals[$i][0];
3959 } else {
3960 $subproblems[$i] = 1;
3962 } else {
3963 $subproblems[$i] = 1;
3968 end problem_structure
3970 # }}} problem_structure
3972 # {{{ randomize_inits
3974 =head2 fractions
3976 Usage:
3978 =for html <pre>
3980 my $fractions = $model_object -> fractions;
3982 =for html </pre>
3984 Arguments:
3986 =over 2
3988 =item colunm
3990 number
3992 =item column_head
3994 string
3996 =item problem_number
3998 integer
4000 =item return_occurences
4002 boolean
4004 =item ignore_missing
4006 boolean
4008 =back
4010 Description:
4012 fractions will return the fractions from data::fractions. It will find
4013 "column_head" in the $INPUT record instead of that data header as
4014 data::fractions does.
4016 =cut
4018 start randomize_inits
4020 foreach my $prob ( @{$self -> {'problems'}} ) {
4021 $prob -> set_random_inits ( degree => $degree );
4024 end randomize_inits
4026 # }}}
4028 # {{{ record
4030 =head2 fractions
4032 Usage:
4034 =for html <pre>
4036 my $fractions = $model_object -> fractions;
4038 =for html </pre>
4040 Arguments:
4042 =over 2
4044 =item colunm
4046 number
4048 =item column_head
4050 string
4052 =item problem_number
4054 integer
4056 =item return_occurences
4058 boolean
4060 =item ignore_missing
4062 boolean
4064 =back
4066 Description:
4068 fractions will return the fractions from data::fractions. It will find
4069 "column_head" in the $INPUT record instead of that data header as
4070 data::fractions does.
4072 =cut
4074 start record
4076 # If the argument new_data is given, record sets new_data in
4077 # the model objects member specified with record_name. The
4078 # format of new_data is an array of strings, where each
4079 # element corresponds to a line of code as it would have
4080 # looked like in a valid NONMEM modelfile. If new_data is left
4081 # undefined, record returns lines of code belonging to the
4082 # record specified by record_name in a format that is valid in
4083 # a NONMEM modelfile.
4085 my @problems = @{$self -> {'problems'}};
4086 my $records;
4088 if ( defined $problems[ $problem_number - 1 ] ) {
4089 if ( scalar(@new_data) > 0 ){
4090 my $rec_class = "model::problem::$record_name";
4091 my $record = $rec_class -> new('record_arr' => \@new_data );
4092 } else {
4093 $record_name .= 's';
4094 $records = $problems[ $problem_number - 1 ] -> {$record_name};
4095 foreach my $record( @{$records} ){
4096 push(@data, $record -> _format_record);
4101 end record
4103 # }}} record
4105 # {{{ remove_inits
4107 =head2 fractions
4109 Usage:
4111 =for html <pre>
4113 my $fractions = $model_object -> fractions;
4115 =for html </pre>
4117 Arguments:
4119 =over 2
4121 =item colunm
4123 number
4125 =item column_head
4127 string
4129 =item problem_number
4131 integer
4133 =item return_occurences
4135 boolean
4137 =item ignore_missing
4139 boolean
4141 =back
4143 Description:
4145 fractions will return the fractions from data::fractions. It will find
4146 "column_head" in the $INPUT record instead of that data header as
4147 data::fractions does.
4149 =cut
4151 start remove_inits
4153 # Usage
4155 # $model -> remove_inits( type => 'theta',
4156 # indexes => [1,2,5,6] )
4159 # In all cases the type must be set to theta. Removing Omegas in
4160 # Sigmas is not allowed, (If need that feature, send us a
4161 # mail). In the above example the thetas 1, 2, 5 and 6 will be
4162 # removed from the modelfile. Notice that this alters the theta
4163 # numbering, so if you later decide that theta number 7 must be
4164 # removed as well, you must calculate its new position in the
4165 # file. In this case the new number would be 3. Also notice that
4166 # numbering starts with 1.
4168 # $model -> remove_inits( type => 'theta',
4169 # labels => ['V', 'CL'] )
4172 # If you have specified labels in you modelfiles(a label is
4173 # string inside a comment on the same row as the theta) you can
4174 # specify an array with labels, and the corresponding theta, if
4175 # it exists, will be removed. This is a much better approach
4176 # since you don't need to know where in order the theta you wish
4177 # to remove appears. If you specify both labels and indexes, the
4178 # indexes will be ignored.
4180 'debug' -> die( message => 'does not have the functionality for removing $OMEGA or $SIGMA options yet' )
4181 if ( $type eq 'omega' or $type eq 'sigma' );
4182 my $accessor = $type.'s';
4184 # First pick out a referens to the theta records array.
4185 my $inits_ref = $self -> problems -> [$problem_number -1] -> $accessor;
4187 # If we have any thetas at all:
4188 if ( defined $inits_ref ) {
4189 my @inits = @{$inits_ref};
4191 # If labels are specified, we translate the labels into
4192 # indexes.
4193 if ( scalar @labels > 0 ) {
4194 @indexes = ();
4195 my $i = 1;
4196 # Loop over theta records
4197 foreach my $init ( @inits ) {
4198 # Loop over the individual thetas inside
4199 foreach my $option ( @{$init -> options} ) {
4200 # Loop over all given labels.
4201 foreach my $label ( @labels ) {
4202 # Push the index number if a given label match the
4203 # theta label
4204 push( @indexes, $i ) if ( $option -> label eq $label);
4206 # $i is the count of thetas so far
4207 $i++;
4212 # We don't really remove thetas, we do a loop over all thetas
4213 # and recording which we like to keep. We do that by selecting
4214 # an index, from @indexes, that shall be removed and loop over
4215 # the thetas, all thetas that doesn't match the index are
4216 # stored in @keep_options. When we find a theta that matches,
4217 # we pick a new index and continue the loop. So by makeing
4218 # sure that @indexes is sorted, we only need to loop over the
4219 # thetas once.
4221 @indexes = sort {$a <=> $b} @indexes;
4223 my $index = 0;
4224 my $nr_options = 1;
4225 my @keep_records;
4227 # Loop over all records
4228 RECORD_LOOP: foreach my $record ( @inits ){
4229 my @keep_options = ();
4230 # Loop over all thetas
4231 foreach my $option ( @{$record -> options} ) {
4232 if( $indexes[ $index ] == $nr_options ){
4233 # If a theta matches an index, we take the next index
4234 # and forget the theta.
4235 unless( $index > $#indexes ){
4236 $index++;
4238 } else {
4239 # Otherwise we rember it.
4240 push(@keep_options,$option);
4242 $nr_options++;
4244 if( scalar(@keep_options) > 0 ){
4245 # If we remember some thetas, we must also remember the
4246 # record which they are in.
4247 $record -> options( \@keep_options );
4248 push( @keep_records, $record );
4252 # Set the all kept thetas back into the modelobject.
4253 @{$inits_ref} = @keep_records;
4255 } else {
4256 'debug' -> die( message => "No init of type $type defined" );
4259 end remove_inits
4261 # }}}
4263 # {{{ restore_inits
4265 =head2 fractions
4267 Usage:
4269 =for html <pre>
4271 my $fractions = $model_object -> fractions;
4273 =for html </pre>
4275 Arguments:
4277 =over 2
4279 =item colunm
4281 number
4283 =item column_head
4285 string
4287 =item problem_number
4289 integer
4291 =item return_occurences
4293 boolean
4295 =item ignore_missing
4297 boolean
4299 =back
4301 Description:
4303 fractions will return the fractions from data::fractions. It will find
4304 "column_head" in the $INPUT record instead of that data header as
4305 data::fractions does.
4307 =cut
4309 start restore_inits
4311 # restore_inits brings back initial values previously stored
4312 # using store_inits. This method pair allows a user to store
4313 # the currents initial values in a backup, replace them with
4314 # temporary values and later restore them.
4316 if ( defined $self -> {'problems'} ) {
4317 foreach my $problem ( @{$self -> {'problems'}} ){
4318 $problem -> restore_inits;
4322 end restore_inits
4324 # }}} restore_inits
4326 # {{{ store_inits
4328 =head2 fractions
4330 Usage:
4332 =for html <pre>
4334 my $fractions = $model_object -> fractions;
4336 =for html </pre>
4338 Arguments:
4340 =over 2
4342 =item colunm
4344 number
4346 =item column_head
4348 string
4350 =item problem_number
4352 integer
4354 =item return_occurences
4356 boolean
4358 =item ignore_missing
4360 boolean
4362 =back
4364 Description:
4366 fractions will return the fractions from data::fractions. It will find
4367 "column_head" in the $INPUT record instead of that data header as
4368 data::fractions does.
4370 =cut
4372 start store_inits
4374 # store_inits stores initial values that can later be
4375 # brought back using restore_inits. See L</restore_inits>.
4377 if ( defined $self -> {'problems'} ) {
4378 foreach my $problem ( @{$self -> {'problems'}} ){
4379 $problem -> store_inits;
4383 end store_inits
4385 # }}} store_inits
4387 # {{{ synchronize
4389 start synchronize
4391 # Synchronize checks the I<synced> object attribute to see
4392 # if the model is in sync with its corresponding file, given
4393 # by the objetc attribute I<filename>. If not, it checks if
4394 # the model contains any defined problems and if it does, it
4395 # writes the formatted model to disk, overwriting any
4396 # existing file of name I<filename>. If no problem is
4397 # defined, synchronize tries to parse the file I<filename>
4398 # and set the object internals to match it.
4399 unless( $self -> {'synced'} ){
4400 if( defined $self -> {'problems'} and
4401 scalar @{$self -> {'problems'}} > 0 ){
4402 $self -> _write;
4403 } else {
4404 if( -e $self -> full_name ){
4405 $self -> _read_problems;
4406 } else {
4407 return;
4411 $self -> {'synced'} = 1;
4413 end synchronize
4415 # }}} synchronize
4417 # {{{ flush
4418 start flush
4419 # synchronizes the object with the file on disk and empties
4420 # most of the objects attributes to save memory.
4421 if( defined $self -> {'problems'} and
4422 ( !$self -> {'synced'} or $force ) ) {
4423 $self -> _write;
4425 $self -> {'problems'} = undef;
4426 $self -> {'synced'} = 0;
4428 end flush
4429 # }}} flush
4431 # {{{ target
4432 start target
4434 if ( $parm eq 'disk' ) {
4435 $self -> {'target'} = 'disk';
4436 $self -> flush;
4437 } elsif ( $parm eq 'mem' and $self -> {'target'} eq 'disk' ) {
4438 $self -> {'target'} = 'mem';
4439 $self -> synchronize;
4442 end target
4443 # }}}
4445 # {{{ msfi_names
4447 =head2 msfi_names
4449 Usage:
4451 =for html <pre>
4453 my $msfi_names_ref = $model_object -> msfi_names;
4455 =for html </pre>
4457 Arguments:
4459 =over 2
4461 =item new_names
4463 array of strings
4465 =item problem_numbers
4467 array of integers
4469 =item ignore_missing_files
4471 boolean
4473 =back
4475 Description:
4477 msfi_names will return the names of all MSFI= statements in the
4478 $ESTIMATION records in all problems.
4480 =cut
4482 start msfi_names
4483 # Usage:
4485 # @msfiNames = @{$modobj -> msfi_names};
4487 # or better:
4489 # $msfiNamesRef = $modobj -> msfi_names;
4490 # @msfiNames = @{$msfiNamesRef} if (defined $msfiNamesRef);
4492 # This basic usage takes no arguments and returns the value of
4493 # the MSFI option in the $ESTIMATION NONMEM record of each
4494 # problem. @msfiNames will be a two-dimensional array:
4496 # [[msfiName_prob1],[msfiName_prob2],[msfiName_prob3]...]
4499 my @problems;
4500 if ( defined $self -> problems() ) {
4501 @problems = @{$self -> problems()};
4502 } else {
4503 'debug' -> die( message => "No problems defined in model" );
4506 if( scalar @new_names > 0 ) {
4507 my $i = 0;
4508 foreach my $prob ( @problems ) {
4509 $prob -> remove_records( type => 'msfi' );
4510 if( defined $new_names[$i] ) {
4511 $prob -> add_records( type => 'msfi',
4512 record_strings => [$new_names[$i]] );
4515 } else {
4516 foreach my $prob ( @problems ) {
4517 if ( defined $prob -> msfis() ) {
4518 my @instances = @{$prob -> msfis()};
4519 my @prob_names;
4520 foreach my $instance ( @instances ) {
4521 my @options;
4522 if ( defined $instance -> options() ) {
4523 @options = @{$instance -> options()};
4525 if ( defined $options[0] ) {
4526 push( @prob_names, $options[0] -> name );
4527 } else {
4528 push( @prob_names, undef );
4531 push( @names, \@prob_names );
4536 end msfi_names
4538 # }}} msfi_names
4540 # {{{ msfo_names
4542 =head2 msfo_names
4544 Usage:
4546 =for html <pre>
4548 my $msfo_names_ref = $model_object -> msfo_names;
4550 =for html </pre>
4552 Arguments:
4554 =over 2
4556 =item new_names
4558 array of strings
4560 =item problem_numbers
4562 array of integers
4564 =item ignore_missing_files
4566 boolean
4568 =back
4570 Description:
4572 msfo_names will return the names of all MSFO= statements in the
4573 $ESTIMATION records in all problems.
4575 =cut
4577 start msfo_names
4578 # Usage:
4580 # @msfoNames = @{$modobj -> msfo_names};
4582 # or better:
4584 # $msfoNamesRef = $modobj -> msfo_names;
4585 # @msfoNames = @{$msfoNamesRef} if (defined $msfoNamesRef);
4587 # This basic usage takes no arguments and returns the value of
4588 # the MSFO option in the $ESTIMATION NONMEM record of each
4589 # problem. @msfoNames will be an array:
4591 # [msfoName_prob1,msfoName_prob2,msfoName_prob3...]
4594 # If the I<new_names> argument of msfo_names is given, the
4595 # values of the MSFO options will be changed.
4597 # To set the MSFO of specific problems, the I<problem_numbers>
4598 # argument can be used. It should be a reference to an array
4599 # containing the numbers of all problems where the FILE should
4600 # be changed or retrieved. If specified, the size of
4601 # I<new_names> must be the same as the size of
4602 # I<problem_numbers>.
4604 my ( $name_ref, $junk ) = $self ->
4605 _option_val_pos( name => 'MSFO',
4606 record_name => 'estimation',
4607 problem_numbers => \@problem_numbers,
4608 new_values => \@new_names );
4611 my ( $nonp_name_ref, $junk ) = $self ->
4612 _option_val_pos( name => 'MSFO',
4613 record_name => 'nonparametric',
4614 problem_numbers => \@problem_numbers,
4615 new_values => \@new_names );
4617 if( scalar( @{$name_ref -> [0]} > 0 ) ){
4618 push( @names, @{$name_ref} );
4621 if( scalar( @{$nonp_name_ref -> [0]} > 0 ) ){
4622 push( @names, @{$nonp_name_ref} );
4625 end msfo_names
4627 # }}} msfo_names
4629 # {{{ table_names
4631 =head2 fractions
4633 Usage:
4635 =for html <pre>
4637 my $fractions = $model_object -> fractions;
4639 =for html </pre>
4641 Arguments:
4643 =over 2
4645 =item colunm
4647 number
4649 =item column_head
4651 string
4653 =item problem_number
4655 integer
4657 =item return_occurences
4659 boolean
4661 =item ignore_missing
4663 boolean
4665 =back
4667 Description:
4669 fractions will return the fractions from data::fractions. It will find
4670 "column_head" in the $INPUT record instead of that data header as
4671 data::fractions does.
4673 =cut
4675 start table_names
4677 # Usage:
4679 # @tableNames = @{$modobj -> table_names};
4681 # This basic usage takes no arguments and returns the value of
4682 # the FILE option in the $TABLE NONMEM record of each
4683 # problem. @tableNames will be a two dimensional array:
4685 # [[tableName_prob1][tableName_prob2][tableName_prob3]...]
4688 # If the I<new_names> argument of table_names is given, the
4689 # values of the FILE options will be changed.
4691 # To set the FILE of specific problems, the I<problem_numbers>
4692 # argument can be used. It should be a reference to an array
4693 # containing the numbers of all problems where the FILE should
4694 # be changed or retrieved. If specified, the size of
4695 # I<new_names> must be the same as the size of
4696 # I<problem_numbers>.
4698 # The I<ignore_missing_files> boolean argument can be used to
4699 # set names of table that does not exist yet (e.g. before a
4700 # run has been performed).
4702 my ( $name_ref, $junk ) = $self ->
4703 _option_val_pos( name => 'FILE',
4704 record_name => 'table',
4705 problem_numbers => \@problem_numbers,
4706 new_values => \@new_names );
4707 if ( $#new_names >= 0 ) {
4708 my @problems = @{$self -> {'problems'}};
4709 unless( $#problem_numbers > 0 ){
4710 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
4712 foreach my $i ( @problem_numbers ) {
4713 $problems[$i-1] -> _read_table_files( ignore_missing_files => $ignore_missing_files || $self -> {'ignore_missing_output_files'});
4716 @names = @{$name_ref};
4718 end table_names
4720 # }}} table_names
4722 # {{{ table_files
4724 =head2 fractions
4726 Usage:
4728 =for html <pre>
4730 my $fractions = $model_object -> fractions;
4732 =for html </pre>
4734 Arguments:
4736 =over 2
4738 =item colunm
4740 number
4742 =item column_head
4744 string
4746 =item problem_number
4748 integer
4750 =item return_occurences
4752 boolean
4754 =item ignore_missing
4756 boolean
4758 =back
4760 Description:
4762 fractions will return the fractions from data::fractions. It will find
4763 "column_head" in the $INPUT record instead of that data header as
4764 data::fractions does.
4766 =cut
4768 start table_files
4770 # Usage:
4772 # @table_files = @{$modobj -> table_files};
4774 # This basic usage takes no arguments and returns the table
4775 # files objects for all problems. @table_files will be a
4776 # two dimensional array:
4778 # [[table_file_object_prob1][table_file_object_prob2]...]
4781 # To retrieve the table file objects from specific problems,
4782 # the I<problem_numbers> argument can be used. It should be
4783 # a reference to an array containing the numbers of all
4784 # problems from which the table file objects should be
4785 # retrieved.
4787 unless( $#problem_numbers > 0 ){
4788 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
4790 my @problems = @{$self -> {'problems'}};
4791 foreach my $i ( @problem_numbers ) {
4792 if ( defined $problems[ $i-1 ] ) {
4793 push( @table_files, $problems[$i-1] -> table_files );
4794 } else {
4795 'debug' -> die( message => "Problem number $i does not exist!" );
4799 end table_files
4801 # }}}
4803 # {{{ units
4805 =head2 fractions
4807 Usage:
4809 =for html <pre>
4811 my $fractions = $model_object -> fractions;
4813 =for html </pre>
4815 Arguments:
4817 =over 2
4819 =item colunm
4821 number
4823 =item column_head
4825 string
4827 =item problem_number
4829 integer
4831 =item return_occurences
4833 boolean
4835 =item ignore_missing
4837 boolean
4839 =back
4841 Description:
4843 fractions will return the fractions from data::fractions. It will find
4844 "column_head" in the $INPUT record instead of that data header as
4845 data::fractions does.
4847 =cut
4849 start units
4851 # Sets or gets the units of a (number of) parameter(s). The
4852 # unit is not a proper NONMEM syntax but is recognized by
4853 # the PsN model class. A unit (and a label) can be specified
4854 # as a comments after a parameter definition. e.g.:
4856 # $THETA (0,13.2,100) ; MTT; h
4858 # which will give this theta the label I<MTT> and unit I<h>.
4859 @units = @{ $self -> _init_attr( parameter_type => $parameter_type,
4860 parameter_numbers => \@parameter_numbers,
4861 problem_numbers => \@problem_numbers,
4862 new_values => \@new_values,
4863 type => 'unit')};
4865 end units
4867 # }}} units
4869 # {{{ update_inits
4872 =head2 fractions
4874 Usage:
4876 =for html <pre>
4878 my $fractions = $model_object -> fractions;
4880 =for html </pre>
4882 Arguments:
4884 =over 2
4886 =item colunm
4888 number
4890 =item column_head
4892 string
4894 =item problem_number
4896 integer
4898 =item return_occurences
4900 boolean
4902 =item ignore_missing
4904 boolean
4906 =back
4908 Description:
4910 fractions will return the fractions from data::fractions. It will find
4911 "column_head" in the $INPUT record instead of that data header as
4912 data::fractions does.
4914 =cut
4916 start update_inits
4918 # Usage:
4920 # $modobj -> update_inits ( from_output => $outobj );
4922 # alt
4924 # $modobj -> update_inits ( from_output_file => $outfile );
4926 # This basic usage takes the parameter estimates from the
4927 # output object I<$outobj> or from the output file I<$outfile>
4928 # and updates the initial estimates in the model object
4929 # I<$modobj>. The number of problems and parameters must be
4930 # the same in the model and output objects. If there exist
4931 # more than one subproblem per problem in the output object,
4932 # only the estimates from the first subproblem will be
4933 # transferred.
4935 # $modobj -> update_inits ( from_output => $outobj,
4936 # ignore_missing_parameters => 1 );
4938 # If the ignore_missing_parameters argument is set to 1, the number of
4939 # parameters in the model and output objects do not need to match. The
4940 # parameters that exist in both objects are used for the update of the
4941 # model object.
4943 # $modobj -> update_inits ( from_output => $outobj,
4944 # from_model => $from_modobj );
4946 # If the from_model argument is given, update_inits tries to match the
4947 # parameter names (labels) given in $from_modobj and $modobj and
4948 # and thereafter updating the $modobj object. See L</units> and L</labels>.
4951 my ( %labels, @own_labels, @from_labels );
4952 'debug' -> die( message => "No output object defined and" .
4953 " no output object found through the model object specified." )
4954 unless ( ( defined $from_model and
4955 ( defined $from_model -> outputs and
4956 defined @{$from_model -> outputs}[0] ) ) or
4957 defined $from_output or
4958 defined $from_output_file );
4959 if ( defined $from_output ) {
4960 'debug' -> warn( level => 2,
4961 message => "using output object ".
4962 "specified as argument\n" );
4963 } elsif ( defined $from_output_file ) {
4964 $from_output = output -> new( filename => $from_output_file );
4965 } else {
4966 $from_output = @{$from_model -> outputs}[0];
4969 my @params = ();
4970 if( $update_thetas ){
4971 push( @params, 'theta' );
4973 if( $update_omegas ) {
4974 push( @params, 'omega' );
4976 if( $update_sigmas ) {
4977 push( @params, 'sigma' );
4980 foreach my $param ( @params ) {
4981 # Get own labels and from labels
4982 if ( defined $from_model ) {
4983 @own_labels = @{$self -> labels( parameter_type => $param )};
4985 @from_labels = @{$from_model -> labels( parameter_type => $param )};
4986 'debug' -> die( message => "The number of problems are not the same in from-model ".
4987 $from_model -> full_name." (".
4988 ($#from_labels+1).")".
4989 " and the model to be updated ".
4990 $self -> full_name." (".
4991 ($#own_labels+1).")" ) unless ( $#own_labels == $#from_labels );
4992 } else {
4993 @own_labels = @{$self -> labels( parameter_type => $param,
4994 generic => 1 )};
4995 @from_labels = @{$from_output -> labels( parameter_type => $param )};
4996 'debug' -> die( message => "The number of problems are not the same in from-output ".
4997 $from_output -> full_name." (".
4998 ($#from_labels+1).")".
4999 " and the model to be updated ".
5000 $self -> full_name." (".
5001 ($#own_labels+1).")" ) unless ( $#own_labels == $#from_labels );
5004 # Loop over the problems:
5005 my $accessor = $param.'s';
5006 # Since initial estimates are specified on the problem level and not on
5007 # the subproblem level we use the estimates from the outputs first subproblem
5008 my @from_values = @{$from_output -> $accessor ( subproblems => [1] )};
5009 # {{{ Omega and Sigma update section
5011 # The functionality that has been commented out because it
5012 # fails when omegas are zero. This functionality should be
5013 # moved to output::problem::subproblem (2005-02-09) TODO
5015 # if ($param eq 'omega' or $param eq 'sigma')
5017 # #print "FL: ", Dumper @from_labels;
5018 # #print "OL: ", Dumper @own_labels;
5019 # print "FV: $param Before " . Dumper(@from_values) . "\n";
5020 # #Fix omegas and sigmas so that the correlation between elements <=1
5021 # my $raw_accessor = "raw_" . $accessor;
5022 # my @raw_from_values = @{$from_output -> $raw_accessor(subproblems => [1])};
5023 # my ($i,$j);
5024 # for (my $a=0; $a<scalar(@from_values); $a++)
5026 # my $prob_values = $from_values[$a];
5027 # my $raw_prob_values = $raw_from_values[$a];
5028 # for (my $b=0; $b<scalar(@{$prob_values}); $b++)
5030 # my $values = $prob_values->[$b];
5031 # my $raw_values = $raw_prob_values->[$b];
5032 # my $counter = 0;
5033 # #Find out the n*n-matrix size (pq-formula)
5034 # my $n = int(sqrt(1/4+scalar(@{$raw_values})*2)-1/2);
5035 # for ($i=0; $i<$n; $i++)
5037 # for ($j=0; $j<$n; $j++)
5039 # if ( $j<=$i && $raw_values->[$i*($i+1)/2+$j]!=0 )
5041 # #print "Omega value = " . @other_val[$counter] . "\n";
5042 # $counter++;
5044 # #Only check the low-triangular off-diagonals of the omega matrix
5045 # #omega(i,j)>=sqrt(omega(i,i)*omega(j,j))
5046 # if ($j<=$i && $j!=$i &&
5047 # ($raw_values->[$i*($i+1)/2+$j]>=sqrt(
5048 # $raw_values->[$i*($i+1)/2+$i]*$raw_values->[$j*($j+1)/2+$j])))
5050 # print "Changing raw value at $i, $j: " . $raw_values->[$i*($i+1)/2+$j] ." to ".
5051 # (int(10000*sqrt($raw_values->[$i*($i+1)/2+$i]*$raw_values->[$j*($j+1)/2+$j]))/10000) ."\n";
5052 # #print "At index ($i,$j)\n" if ($self->{'debug'});
5053 # $raw_values->[$i*($i+1)/2+$j]=int(10000*sqrt(
5054 # $raw_values->[$i*($i+1)/2+$i]*$raw_values->[$j*($j+1)/2+$j]))/10000;
5055 # print "Changing omega value " . $values->[$counter-1] . " to " . $raw_values->[$i*($i+1)/2+$j] ."\n";
5056 # $values->[$counter-1] = $raw_values->[$i*($i+1)/2+$j];
5062 # #print "FL: ", Dumper @from_labels;
5063 # #print "OL: ", Dumper @own_labels;
5064 # print "FV: $param After ", Dumper(@from_values), "\n";
5065 # die;
5068 # }}}
5070 for ( my $i = 0; $i <= $#own_labels; $i++ ) {
5072 if( $from_output -> have_user_defined_prior ){
5073 $ignore_missing_parameters = 1;
5075 unless ( $ignore_missing_parameters ) {
5076 my $from_name = defined $from_model ? $from_model -> filename :
5077 $from_output -> filename;
5078 'debug' -> die( message => "Model -> update_inits: The number of ".$param.
5079 "s are not the same in from-model (" . $from_name .
5080 "): " . scalar @{$from_labels[$i]} .
5081 ", and the model to be updated (" . $self -> {'filename'} .
5082 "): " . scalar @{$own_labels[$i]} )
5083 unless ( scalar @{$own_labels[$i]} ==
5084 scalar @{$from_labels[$i]} );
5087 for ( my $j = 0; $j < scalar @{$from_labels[$i]}; $j++ ) {
5088 for ( my $k = 0; $k < scalar @{$own_labels[$i]}; $k++ ) {
5089 if ( $from_labels[$i][$j] eq $own_labels[$i][$k] ){
5090 $labels{$k+1} = $from_values[$i][0][$j];
5095 my @own_idxs = keys( %labels );
5096 my @from_vals;
5097 for(my $i=0; $i <= $#own_idxs; $i++){
5098 @from_vals[$i] = $labels{ $own_idxs[$i] };
5101 $self -> initial_values( problem_numbers => [$i+1],
5102 parameter_type => $param,
5103 parameter_numbers => [\@own_idxs],
5104 new_values => [\@from_vals] );
5108 end update_inits
5110 # }}} update_inits
5112 # {{{ upper_bounds
5114 start upper_bounds
5116 # upper_bounds either sets or gets the initial values of the
5117 # parameter specified in I<parameter_type> for each
5118 # subproblem specified in I<problem_numbers>. For each
5119 # element in I<problem_numbers> there must be an array in
5120 # I<parameter_numbers> that specify the indices of the
5121 # parameters in the subproblem for which the upper bounds
5122 # are set, replaced or retrieved.
5124 @upper_bounds = @{ $self -> _init_attr
5125 ( parameter_type => $parameter_type,
5126 parameter_numbers => \@parameter_numbers,
5127 problem_numbers => \@problem_numbers,
5128 new_values => \@new_values,
5129 attribute => 'upbnd')};
5131 end upper_bounds
5133 # }}} upper_bounds
5135 # {{{ clean_extra_data_code
5137 start clean_extra_data_code
5140 # This method cleans out old code for extra data. It searches
5141 # all subroutine statements in all problems for external
5142 # subroutines named "get_sub" and "reader" which are added by
5143 # "add_extra_data_code".
5145 foreach my $problem( @{$self -> {'problems'}} ){
5146 if ( defined $problem -> subroutines and defined $problem -> subroutines -> [0] -> options) {
5147 foreach my $option ( @{$problem -> subroutines -> [0] -> options} ){
5148 if( lc($option -> name) eq 'other'){
5149 if( lc($option -> value) =~ /get_sub|reader/ ){
5151 # If we find "get_sub" or "reader" we remove
5152 # everything between "IMPORTING COVARIATE DATA" and
5153 # "IMPORTING COVARIATE DATA END" by finding the
5154 # indexes in the code array and and splicing it out.
5156 my $code;
5157 if( $problem -> pks ){
5158 # If the code is in a pk block:
5159 $code = $problem -> pks -> [0] -> code;
5160 } else {
5161 $code = $problem -> preds -> [0] -> code;
5164 my $start_idx;
5165 my $end_idx;
5166 for( my $i = 0; $i <= $#{$code}; $i++ ){
5167 if( $code -> [$i] eq ";***IMPORTING COVARIATE DATA*******\n" ){
5168 $start_idx = $i-1;
5170 if( $code -> [$i] eq ";***IMPORTING COVARIATE DATA END***\n" ){
5171 $end_idx = $i+1;
5174 @{$code} = ( @{$code}[0..$start_idx] , @{$code}[$end_idx..$#{$code}] );
5176 if( $problem -> pks ){
5177 # Put the cut down code back in the right place:
5178 $problem -> pks -> [0] -> code( $code );
5179 } else {
5180 $problem -> preds -> [0] -> code( $code );
5183 last;
5190 end clean_extra_data_code
5192 # }}} clean_extra_data_code
5194 # {{{ add_extra_data_code
5196 start add_extra_data_code
5198 # This method adds fortran code that will handle wide datasets
5199 # (that is data sets with more than 20 columns). It adds code to
5200 # each problems pk or pred.
5202 my @code_lines;
5204 # Get the headers of the columns that have been moved to another
5205 # data file.
5207 # unless( defined $self -> extra_data_headers ){
5208 # die "ERROR model::add_extra_data_code: No headers for the extra data file\n";
5211 # extra_data_headers is a two dimensional array. One array of
5212 # headers for each problem in the modelfile.
5213 for( my $i = 0; $i <= $#{$self -> {'problems'}}; $i++ ){
5214 if ( defined $self -> {'problems'} -> [$i] -> {'extra_data_header'} ) {
5215 my $problem_headers = $self -> {'problems'} -> [$i] -> {'extra_data_header'};
5217 my $length = 0;
5218 my @headers;
5219 my $header_string;
5220 # Loop over the problem specific headers and make a string
5221 # that will go into the fortran code. Assume that the
5222 # first column holds the ID, hence the $i=1
5223 for (my $i = 1; $i <= $#{$problem_headers}; $i++ ) {
5224 my $header = $problem_headers -> [$i];
5225 push( @headers, $header );
5226 # Chopp the string at 40 characters, to be nice to g77 :)
5227 if ( $length + length($header) > 40 ) {
5228 $header_string .= "\n\"& ";
5229 $length = 0
5231 if ( $i < $#{$problem_headers} ) {
5232 $header_string .= 'I' . $header . ', ';
5233 $length += length( 'I' . $header . ', ' );
5234 } else {
5235 $header_string .= 'I' . $header;
5236 $length += length( 'I' . $header );
5240 my @code_lines = ('',
5241 ';***IMPORTING COVARIATE DATA*******',
5242 '" FIRST',
5243 '" REAL CURID, MID,',
5244 '"& '.$header_string,
5245 '" LOGICAL READ',
5246 '"',
5247 '" IF (.NOT.READ) THEN',
5248 '" CALL READER()',
5249 '" CURID = 1',
5250 '" READ = .TRUE.',
5251 '" END IF',
5252 '"',
5253 '" IF (NEWIND.LT.2) THEN',
5254 '" CALL GET_SUB (NEWIND,ID,CURID,MID,',
5255 '"& '.$header_string. ')',
5256 '" END IF',
5257 ' CID = MID',
5258 ' IF (CID.NE.ID) THEN',
5259 ' PRINT *, \'ERROR CHECKING FAILED, CID = \', CID ,\' ID = \', ID',
5260 ' END IF',
5261 '');
5263 foreach my $header ( @headers ) {
5264 push( @code_lines, " $header = I$header" );
5267 push( @code_lines, (';***IMPORTING COVARIATE DATA END***','','') );
5269 my $problem = $self -> {'problems'} -> [$i];
5270 if ( defined $problem -> {'subroutines'} ) {
5271 $problem -> subroutines -> [0] -> _add_option( option_string => 'OTHER=get_sub'.$i.'.f' );
5272 $problem -> subroutines -> [0] -> _add_option( option_string => 'OTHER=reader'.$i.'.f');
5273 } else {
5274 $problem -> add_records( type => 'subroutine', record_strings => ['OTHER=get_sub'.$i.'.f', 'OTHER=reader'.$i.'.f'] );
5277 if ( defined $problem -> pks ) {
5278 unshift( @{$problem -> pks -> [0] -> code}, join("\n", @code_lines ));
5279 } else {
5280 unshift( @{$problem -> preds -> [0] -> code},join("\n", @code_lines ));
5285 end add_extra_data_code
5287 # }}}
5289 # {{{ drop_dropped
5291 start drop_dropped
5293 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5294 $self -> {'datas'}[$i] -> drop_dropped( model_header => $self -> {'problems'}[$i] -> header );
5295 $self -> {'problems'}[$i] -> drop_dropped( );
5296 #$self -> {'datas'}[$i] -> model_header( $self -> {'problems'}[$i] -> header );
5299 end drop_dropped
5301 # }}} drop_dropped
5303 # {{{ wrap_data
5305 start wrap_data
5307 my $default_wrap = 18;
5309 $self -> drop_dropped(1);
5311 my ( @wrap_columns, @cont_columns );
5312 if ( not defined $wrap_column ) {
5313 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5314 my $columns = scalar @{$self -> {'problems'}[$i] -> dropped_columns}-1; #skip ID
5315 my $modulus = $columns%($default_wrap-2); # default_wrap-2 to account for ID and CONT
5316 my $rows = (($columns-$modulus)/($default_wrap-2))+1;
5317 if ( $rows == 1 ) {
5318 push( @wrap_columns, undef );
5319 } else {
5320 push( @wrap_columns, (ceil( $columns/$rows )+2) ); #Must use #cols + ID and CONT
5323 } else {
5324 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5325 push( @wrap_columns, $wrap_column );
5329 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5330 next if ( not defined $wrap_columns[$i] );
5331 $wrap_column = $wrap_columns[$i];
5332 $cont_column = $wrap_columns[$i] if( not defined $cont_column );
5333 my ( $prim, $sec ) =
5334 $self -> {'datas'}[$i] -> wrap( cont_column => $cont_column,
5335 wrap_column => $wrap_column,
5336 model_header => $self -> {'problems'}[$i] -> header );
5337 $self -> {'problems'}[$i] -> primary_columns( $prim );
5338 $self -> {'problems'}[$i] -> secondary_columns( $sec );
5339 $self -> {'data_wrapped'}++;
5342 end wrap_data
5344 # }}} wrap_data
5346 # {{{ unwrap_data
5347 start unwrap_data
5349 for( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5350 $self -> {'datas'}[$i] -> unwrap;
5351 $self -> {'problems'}[$i] -> primary_columns( [] );
5352 $self -> {'problems'}[$i] -> secondary_columns( [] );
5354 $self -> {'data_wrapped'} = 0;
5356 end unwrap_data
5357 # }}} unwrap_data
5359 # {{{ write_get_subs
5361 start write_get_subs
5363 for( my $i = 0; $i <= $#{$self -> {'problems'}}; $i++ ){
5364 if ( defined $self -> {'problems'} -> [$i] -> {'extra_data_header'} and
5365 defined $self -> problems -> [$i] -> extra_data ) {
5366 my @problem_header = @{$self -> {'problems'} -> [$i] -> {'extra_data_header'}};
5367 my @headers;
5368 my $length = 0;
5369 my $header_string;
5371 my $rows = $self -> problems -> [$i] -> extra_data -> count_ind;
5373 # Assume that first column holds the ID. Get rid of it.
5374 shift( @problem_header );
5375 for ( my $i = 0; $i <= $#problem_header; $i++ ) {
5376 my $header = $problem_header[$i];
5377 push( @headers, $header );
5378 # Chop the string at 40 characters, to be nice to g77 :)
5379 if ( $length + length($header) > 40 ) {
5380 $header_string .= "\n & ";
5381 $length = 0
5383 if ( $i < $#problem_header ) {
5384 $header_string .= $header . ', ';
5385 $length += length( $header . ', ' );
5386 } else {
5387 $header_string .= $header;
5388 $length += length( $header );
5392 open( FILE, '>', 'get_sub' . $i . '.f' );
5393 print FILE (" SUBROUTINE GET_SUB (NEWIND,ID,CURID,MID,\n",
5394 " & $header_string)\n",
5395 " COMMON /READ/ TID,TCOV\n",
5396 "\n",
5397 " REAL ID,CURID,MID,\n",
5398 " & $header_string\n",
5399 "\n",
5400 " INTEGER NEWIND\n",
5401 "\n",
5402 " REAL TID($rows), TCOV($rows,",scalar @problem_header,")\n",
5403 " CURID = 1\n",
5404 "\n",
5405 "C START AT TOP EVERY TIME\n",
5406 " IF (NEWIND.EQ.1) THEN \n",
5407 "12 CONTINUE\n",
5408 " IF (CURID.GT.$rows) THEN \n",
5409 " PRINT *, \"Covariate data not found for\", ID\n",
5410 " MID = -9999\n",
5411 " RETURN\n",
5412 " END IF\n",
5413 "\n",
5414 " IF (ID.GT.TID (CURID)) THEN\n",
5415 " CURID = CURID + 1\n",
5416 " GOTO 12\n",
5417 " END IF\n",
5418 " ELSEIF (NEWIND.EQ.0) THEN\n",
5419 " CURID = 1\n",
5420 " END IF\n",
5421 "\n" );
5422 my $length = 0;
5423 for ( my $i = 1; $i <= $#headers+1; $i++ ) {
5424 $length += length("TCOV(I,$i),");
5425 if ( $length > 40 ) {
5426 print FILE "\n";
5427 $length = 0;
5429 print FILE " ".$headers[$i-1] . " = TCOV(CURID,$i)\n";
5432 print FILE (" MID = TID(CURID)\n",
5433 " END\n",
5434 "\n" );
5436 close FILE;
5439 close( FILE );
5441 end write_get_subs
5443 # }}}
5445 # {{{ write_readers
5447 start write_readers
5449 for( my $i = 0; $i <= $#{$self -> {'problems'}}; $i++ ){
5450 if ( defined $self -> {'problems'} -> [$i] -> {'extra_data_header'} and
5451 defined $self -> {'problems'} -> [$i] -> {'extra_data'} ) {
5452 my @problem_header = @{$self -> {'problems'} -> [$i] -> {'extra_data_header'}};
5453 my @headers;
5454 my $length = 0;
5456 my $rows = $self -> problems -> [$i] -> extra_data -> count_ind;
5457 my $filename = $self -> problems -> [$i] -> extra_data -> filename;
5458 # Assume that first column holds the ID. Get rid of it.
5459 shift( @problem_header );
5461 'debug' -> warn( level => 2,
5462 message => "Writing reader".$i.".f to directory".cwd );
5463 open( FILE, '>', 'reader' . $i . '.f' );
5464 print FILE (" SUBROUTINE READER()\n",
5465 "\n",
5466 " COMMON /READ/ TID,TCOV\n",
5467 "\n",
5468 " REAL TID ($rows), TCOV ($rows, ",scalar @problem_header,")\n",
5469 "\n",
5470 " OPEN (UNIT = 77,FILE = '$filename')\n",
5471 " REWIND 77\n",
5472 " DO 11,I = 1,$rows\n",
5473 " READ (77,*) TID(I)," );
5475 my $length = 0;
5476 for ( my $i = 1; $i <= $#problem_header+1; $i++ ) {
5477 $length += length("TCOV(I,$i),");
5478 if ( $length > 40 ) {
5479 print FILE "\n & ";
5480 $length = 0;
5482 if ( $i <= $#problem_header ) {
5483 print FILE "TCOV(I,$i),";
5484 } else {
5485 print FILE "TCOV(I,$i)\n";
5489 print FILE ( "11 CONTINUE\n",
5490 " END\n" );
5494 end write_readers
5496 # }}}
5498 # {{{ _write
5500 start _write
5503 # $model -> _write( filename => 'model.mod' );
5505 # Writes the content of the modelobject to disk. Either to the
5506 # filename given, or to the string returned by model::full_name.
5508 my @formatted;
5510 # An element in the active_problems array is a boolean that
5511 # corresponds to the element with the same index in the problems
5512 # array. If the boolean is true, the problem will be run. All
5513 # other will be commented out.
5514 my @active = @{$self -> {'active_problems'}};
5516 # loop over all problems.
5517 for ( my $i = 0; $i < scalar @{$self -> {'problems'}}; $i++ ) {
5518 # Call on the problem object to format it as text. The
5519 # filename and problem numbers are needed to make some
5520 # autogenerated files (msfi, tabels etc...) unique to the
5521 # model and problem
5522 my @preformatted = @{$self -> {'problems'} -> [$i] ->
5523 _format_problem( filename => $self -> filename,
5524 problem_number => ($i+1) ) };
5525 # Check if the problem is NOT active, if so comment it out.
5526 unless ( $active[$i] ) {
5527 for ( my $j = 0; $j <= $#preformatted; $j++ ) {
5528 $preformatted[$j] = '; '.$preformatted[$j];
5531 # Add extra line to avoid problems with execution of NONMEM
5532 push(@preformatted,"\n");
5533 push( @formatted, @preformatted );
5536 # Open a file and print the formatted problems.
5537 # TODO Add some errorchecking.
5538 open( FILE, '>'. $filename );
5539 for ( @formatted ) {
5540 chomp;
5541 print FILE;
5542 print FILE "\n";
5544 close( FILE );
5546 if ( $write_data ) {
5547 foreach my $data ( @{$self -> {'datas'}} ) {
5548 $data -> _write;
5552 if( $self -> {'iofv_modules'} ){
5553 $self -> {'iofv_modules'} -> [0] -> post_process;
5557 end _write
5559 # }}} _write
5561 # {{{ filename
5562 start filename
5564 if ( defined $parm and $parm ne $self -> {'filename'} ) {
5565 $self -> {'filename'} = $parm;
5566 $self -> {'model_id'} = undef;
5567 # $self -> _write;
5570 end filename
5571 # }}} filename
5573 # {{{ _get_option_val_pos
5575 start _get_option_val_pos
5577 # Usage:
5579 # ( $values_ref, $positions_ref ) ->
5580 # _get_option_val_pos ( name => 'ID',
5581 # record_name => 'input' );
5582 # my @values = @{$values_ref};
5583 # my @positions = @{$positions_ref};
5585 # This basic usage returns the name of the third option in the first
5586 # instance of the record specified by I<record_name> for all problems
5588 # If global_position is set to 1, only one value and position
5589 # pair is returned per problem. If there are more than one
5590 # match in the model; the first will be returned for each
5591 # problem.
5593 # Private method, should preferably not be used outside model.pm
5595 # my ( @records, @instances );
5596 my $accessor = $record_name.'s';
5597 my @problems = @{$self -> {'problems'}};
5598 unless( $#problem_numbers > 0 ){
5599 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5601 foreach my $i ( @problem_numbers ) {
5602 my $rec_ref = $problems[ $i-1 ] -> $accessor;
5603 if ( defined $problems[ $i-1 ] and defined $rec_ref ) {
5604 my @records = @{$rec_ref};
5605 unless( $#instances > 0 ){
5606 @instances = (1 .. $#records+1);
5609 my @inst_values = ();
5610 my @inst_positions = ();
5611 my $glob_pos = 1;
5612 my ( $glob_value, $glob_position );
5613 INSTANCES: foreach my $j ( @instances ) {
5614 if ( defined $records[ $j-1 ] ) {
5615 my $k = 1;
5616 my ( $value, $position );
5617 foreach my $option ( @{$records[$j-1] -> {'options'}} ) {
5618 if ( defined $option and $option -> name eq $name) {
5619 if ( $global_position ) {
5620 $glob_value = $option -> value;
5621 $glob_position = $glob_pos;
5622 last INSTANCES;
5623 } else {
5624 $value = $option -> value;
5625 $position = $k;
5628 $k++;
5629 $glob_pos++;
5631 push( @inst_values, $value );
5632 push( @inst_positions, $position );
5633 } else {
5634 'debug' -> die( message => "Instance $j in problem number $i does not exist!" )
5637 if ( $global_position ) {
5638 push( @values, $glob_value );
5639 push( @positions, $glob_position );
5640 } else {
5641 push( @values, \@inst_values );
5642 push( @positions, \@inst_positions );
5644 } else {
5645 'debug' -> die( message => "Problem number $i does not exist!" );
5648 # if( defined $problem_number ) {
5649 # if( $problem_number < 1 or $problem_number > scalar @problems ) {
5650 # die "model -> _get_option_val_pos: No such problem number, ",
5651 # $problem_number,", in this model!\n";
5654 # my $i;
5655 # die "modelfile -> _get_option_val_pos: No problem $problem_number exists\n"
5656 # if( (scalar @problems < 1) and ($problem_number ne 'all') );
5657 # my $j = 1;
5658 # foreach my $problem ( @problems ) {
5659 # @records = @{$problem -> $accessor};
5660 # @records = ($records[$instance-1]) if ( $instance ne 'all' );
5661 # die "modelfile -> _get_option_val_pos: No record instance $instance ".
5662 # "of record $record_name in problem $problem_number exists\n"
5663 # if( (scalar @records < 1) and ($instance ne 'all') );
5664 # foreach my $record ( @records ) {
5665 # $i = 1;
5666 # foreach my $option ( @{$record -> {'options'}} ) {
5667 # if ( defined $option and $option -> name eq $name) {
5668 # print "Found $name at $i\n" if ( $self -> {'debug'} );
5669 # push( @values, $option -> value );
5670 # push( @positions, $i );
5672 # $i++;
5677 end _get_option_val_pos
5679 # }}} _get_option_val_pos
5681 # {{{ _init_attr
5683 start _init_attr
5685 # The I<add_if_absent> argument tells the method to add an init (theta,omega,sigma)
5686 # if the parameter number points to a non-existing parameter with parameter number
5687 # one higher than the highest presently included. Only applicatble if
5688 # I<new_values> are set. Default value = 0;
5690 unless( scalar @problem_numbers > 0 ){
5691 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5693 my @problems = @{$self -> {'problems'}};
5694 if ( $#new_values >= 0 ) {
5695 'debug' -> die( message => "The number of new value sets " .
5696 ($#new_values+1) . " do not" .
5697 " match the number of problems " . ($#problem_numbers+1) . " specified" )
5698 unless(($#new_values == $#problem_numbers) );
5699 if ( $#parameter_numbers > 0 ) {
5700 'debug' -> die( message => "The number of parameter number sets do not" .
5701 " match the number of problems specified" )
5702 unless(($#parameter_numbers == $#problem_numbers) );
5706 my $new_val_idx = 0;
5707 foreach my $i ( @problem_numbers ) {
5708 if ( defined $problems[ $i-1 ] ) {
5709 if ( scalar @new_values > 0) {
5710 # {{{ Update values
5711 # Use attribute parameter_values to collect diagnostic outputs
5712 push( @parameter_values,
5713 $problems[ $i-1 ] ->
5714 _init_attr( parameter_type => $parameter_type,
5715 parameter_numbers => $parameter_numbers[ $new_val_idx ],
5716 new_values => \@{$new_values[ $new_val_idx ]},
5717 attribute => $attribute,
5718 add_if_absent => $add_if_absent ) );
5719 # }}} Update values
5720 } else {
5721 # {{{ Retrieve values
5722 push( @parameter_values,
5723 $problems[ $i-1 ] ->
5724 _init_attr( parameter_type => $parameter_type,
5725 parameter_numbers => $parameter_numbers[ $i-1 ],
5726 attribute => $attribute ) );
5727 # }}} Retrieve values
5729 } else {
5730 'debug' -> die( message => "Problem number $i does not exist!" );
5732 $new_val_idx++;
5735 end _init_attr
5737 # }}} _init_attr
5739 # {{{ _option_name
5741 start _option_name
5743 # Usage:
5745 # $modobj -> _option_name ( record => $record_name,
5746 # position => 3 );
5748 # This basic usage returns the name of the third option in the first
5749 # instance of the record specified by I<record>.
5752 my ( @problems, @records, @options, $i );
5753 my $accessor = $record.'s';
5754 if ( defined $self -> {'problems'} ) {
5755 @problems = @{$self -> {'problems'}};
5756 } else {
5757 'debug' -> die( message => "No problems defined in model" );
5759 if ( defined $problems[$problem_number - 1] -> $accessor ) {
5760 @records = @{$problems[$problem_number - 1] -> $accessor};
5761 } else {
5762 'debug' -> die( message => "No record $record defined in ".
5763 "problem number $problem_number." );
5765 if ( defined $records[$instance - 1] -> options ) {
5766 @options = @{$records[$instance - 1] -> options};
5767 } else {
5768 'debug' -> die( message => "model -> _option_name: No option defined in record ".
5769 "$record in problem number $problem_number." );
5771 $i = 0;
5772 foreach my $option ( @options ) {
5773 if ( $i == $position ) {
5774 if ( defined $new_name ){
5775 $option -> name($new_name) if ( defined $option );
5776 }else{
5777 $name = $option -> name if ( defined $option );
5780 $i++;
5783 end _option_name
5785 # }}} _option_name
5787 # {{{ _parameter_count
5788 start _parameter_count
5790 if( defined $self -> {'problems'} ){
5791 my $problems = $self -> {'problems'};
5792 if( defined @{$problems}[$problem_number - 1] ){
5793 $count = @{$problems}[$problem_number - 1] -> record_count( 'record_name' => $record );
5797 end _parameter_count
5798 # }}} _parameter_count
5800 # {{{ _read_problems
5802 start _read_problems
5805 # To read problems from a modelfile we need its full name
5806 # (meaning filename and path). And we need an array for the
5807 # modelfile lines and an array with indexes telling where
5808 # problems start in the modelfile array.
5811 my $file = $self -> full_name;
5812 my ( @modelfile, @problems );
5813 my ( @problem_start_index );
5815 # Check if the file is missing, and if that is ok.
5816 # TODO Check accessor what happens if the file is missing.
5818 return if( not (-e $file) && $self -> {'ignore_missing_files'} );
5820 # Open the file, slurp it and close it
5821 open( FILE, "$file" ) ||
5822 'debug' -> die( message => "Model -> _read_problems: Could not open $file".
5823 " for reading" );
5824 @modelfile = <FILE>;
5825 close( FILE );
5827 my @extra_data_files = defined $self ->{'extra_data_files'} ?
5828 @{$self -> {'extra_data_files'}} : ();
5829 my @extra_data_headers = defined $self ->{'extra_data_headers'} ?
5830 @{$self -> {'extra_data_headers'}} : ();
5833 # # Find the indexes where the problems start
5834 # for ( my $i = 0; $i <= $#modelfile; $i++ ) {
5835 # push( @problem_start_index, $i )if ( $modelfile[$i] =~ /\$PROB/ );
5838 # # Loop over the number of problems. Copy the each problems lines
5839 # # and create a problem object.
5841 # for( my $i = 0; $i <= $#problem_start_index; $i++ ) {
5842 # my $start_index = $problem_start_index[$i];
5843 # my $end_index = defined $problem_start_index[$i+1] ? $problem_start_index[$i+1] - 1: $#modelfile ;
5844 # # Line copy
5845 # my @problem_lines = @modelfile[$start_index .. $end_index];
5847 # # Problem object creation.
5848 # push( @problems, model::problem -> new ( debug => $self -> {'debug'},
5849 # ignore_missing_files => $self -> {'ignore_missing_files'},
5850 # prob_arr => \@problem_lines,
5851 # extra_data_file_name => $extra_data_files[$i],
5852 # extra_data_header => $extra_data_headers[$i]) );
5854 my $start_index = 0;
5855 my $end_index;
5856 my $first = 1;
5857 my $prob_num = 0;
5859 # It may look like the loop takes one step to much, but its a
5860 # trick that helps parsing the last problem.
5861 for ( my $i = 0; $i <= @modelfile; $i++ ) {
5862 if( $i <= $#modelfile ){
5863 $_ = $modelfile[$i];
5866 if ($first and not /^\s*(;|\$PROB|$)/){
5867 'debug' -> die( message => 'Model -> _read_problems: '.
5868 "First non-comment line in modelfile $file \n".
5869 'is not a $PROB record. NONMEM syntax violation.');
5872 # In this if statement we use the lazy evaluation of logical
5873 # or to make sure we only execute search pattern when we have
5874 # a line to search. Which is all cases but the very last loop
5875 # iteration.
5877 if( $i > $#modelfile or /^\s*\$PROB/ ){
5878 $end_index = $i;
5880 # The if statement here is only necessary in the first loop
5881 # iteration. When start_index == end_index == 0 we want to
5882 # skip to the next iteration looking for the actual end of
5883 # the first problem.
5885 if( $end_index > $start_index and not $first ){
5886 # extract lines of code:
5887 my @problem_lines = @modelfile[$start_index .. $end_index-1];
5888 # reset the search for problems by moving the problem start
5889 # forwards:
5890 $start_index = $i;
5892 my $sh_mod = model::shrinkage_module -> new ( model => $self,
5893 temp_problem_number => ($#problems+2));
5894 my $prob = model::problem ->
5895 new ( directory => $self -> {'directory'},
5896 ignore_missing_files => $self -> {'ignore_missing_files'},
5897 ignore_missing_output_files => $self -> {'ignore_missing_output_files'},
5898 sde => $self -> {'sde'},
5899 cwres => $self -> {'cwres'},
5900 mirror_plots => $self -> {'mirror_plots'},
5901 nm_version => $self -> {'nm_version'},
5902 prob_arr => \@problem_lines,
5903 extra_data_file_name => $extra_data_files[$prob_num],
5904 extra_data_header => $extra_data_headers[$prob_num],
5905 shrinkage_module => $sh_mod );
5906 push( @problems, $prob );
5907 if ( $self -> cwres() ) {
5908 my @eo;
5909 if ( defined $self -> extra_output() ) {
5910 @eo = @{$self -> extra_output()};
5912 if( $prob -> {'cwres_modules'} ){
5913 push( @eo, @{$prob -> {'cwres_modules'} -> [0] -> cwtab_names()} );
5915 $self -> extra_output( \@eo );
5918 $sh_mod -> problem( $problems[$#problems] );
5919 $prob_num++;
5921 $first = 0;
5925 # Set the problems in the modelobject.
5926 if (scalar(@problems)<1){
5927 'debug' -> die( message => 'Model -> _read_problems: '.
5928 "Could not find any problem in modelfile $file");
5930 $self -> problems(\@problems);
5932 end _read_problems
5934 # }}} _read_problems
5936 # {{{ set_option
5938 start set_option
5940 unless( $#problem_numbers >= 0 ){
5941 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5944 my @problems = @{$self -> {'problems'}};
5945 foreach my $i ( @problem_numbers ) {
5946 if ( defined $problems[ $i-1 ] ) {
5947 my $found = $self -> is_option_set( 'problem_number' => $i,
5948 'record' => $record_name,
5949 'name' => $option_name,
5950 'fuzzy_match' => $fuzzy_match );
5951 $problems[$i-1] -> remove_option( record_name => $record_name,
5952 option_name => $option_name,
5953 fuzzy_match => $fuzzy_match ) if ( $found );
5954 $problems[$i-1] -> add_option( record_name => $record_name,
5955 option_name => $option_name,
5956 option_value => $option_value );
5960 end set_option
5962 # }}} set_option
5964 # {{{ add_option
5966 start add_option
5968 unless( $#problem_numbers >= 0 ){
5969 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5972 my @problems = @{$self -> {'problems'}};
5973 foreach my $i ( @problem_numbers ) {
5974 if ( defined $problems[ $i-1 ] ) {
5975 $problems[$i-1] -> add_option( record_name => $record_name,
5976 option_name => $option_name,
5977 option_value => $option_value,
5978 add_record => $add_record );
5982 end add_option
5984 # }}} add_option
5986 # {{{ remove_option
5988 start remove_option
5990 unless( $#problem_numbers >= 0 ){
5991 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
5994 my @problems = @{$self -> {'problems'}};
5995 foreach my $i ( @problem_numbers ) {
5996 if ( defined $problems[ $i-1 ] ) {
5997 $problems[$i-1] -> remove_option( record_name => $record_name,
5998 option_name => $option_name,
5999 fuzzy_match => $fuzzy_match);
6003 end remove_option
6005 # }}} remove_option
6007 # {{{ _option_val_pos
6009 start _option_val_pos
6011 unless( $#problem_numbers >= 0 ){
6012 @problem_numbers = (1 .. $#{$self -> {'problems'}}+1);
6014 my @problems = @{$self -> {'problems'}};
6015 if ( $#new_values >= 0 ) {
6016 'debug' -> die( message => "Trying to set option $name in record $record_name but the ".
6017 "number of new value sets (".
6018 ($#new_values+1).
6019 "), do not match the number of problems specified (".
6020 ($#problem_numbers+1).")" )
6021 unless(($#new_values == $#problem_numbers) );
6022 if ( $#instance_numbers > 0 ) {
6023 'debug' -> die( message => "The number of instance number sets (".
6024 ($#instance_numbers+1).
6025 "),do not match the number of problems specified (".
6026 ($#problem_numbers+1).")" )
6027 unless(($#instance_numbers == $#problem_numbers) );
6031 foreach my $i ( @problem_numbers ) {
6032 if ( defined $problems[ $i-1 ] ) {
6033 my $rn_ref = $#instance_numbers >= 0 ? \@{$instance_numbers[ $i-1 ]} : [];
6034 if ( scalar @new_values > 0) {
6035 # {{{ Update values
6037 if( not defined $new_values[ $i-1 ] ) {
6038 debug -> die( message => " The specified new_values was undefined for problem $i" );
6041 if( not ref( $new_values[ $i-1 ] ) eq 'ARRAY' ) {
6042 debug -> die( message => " The specified new_values for problem $i is not an array as it should be but a ".
6043 ( defined ref( $new_values[ $i-1 ] ) ?
6044 ref( $new_values[ $i-1 ] ) : 'undef' ) );
6047 $problems[ $i-1 ] ->
6048 _option_val_pos( record_name => $record_name,
6049 instance_numbers => $rn_ref,
6050 new_values => \@{$new_values[ $i-1 ]},
6051 name => $name,
6052 exact_match => $exact_match );
6054 # }}} Update values
6055 } else {
6056 # {{{ Retrieve values
6057 my ( $val_ref, $pos_ref ) =
6058 $problems[ $i-1 ] ->
6059 _option_val_pos( record_name => $record_name,
6060 instance_numbers => $rn_ref,
6061 name => $name,
6062 exact_match => $exact_match );
6063 push( @values, $val_ref );
6064 push( @positions, $pos_ref );
6065 # }}} Retrieve values
6067 } else {
6068 'debug' -> die( message => "Problem number $i does not exist!" );
6072 end _option_val_pos
6074 # }}} _option_val_pos
6076 # {{{ subroutine_files
6078 start subroutine_files
6080 my %fsubs;
6081 foreach my $subr( 'PRED','CRIT', 'CONTR', 'CCONTR', 'MIX', 'CONPAR', 'OTHER', 'PRIOR' ){
6082 my ( $model_fsubs, $junk ) = $self -> _option_val_pos( record_name => 'subroutine',
6083 name => $subr );
6084 if( @{$model_fsubs} > 0 ){
6085 foreach my $prob_fsubs ( @{$model_fsubs} ){
6086 foreach my $fsub( @{$prob_fsubs} ){
6087 $fsubs{$fsub} = 1;
6093 # BUG , nonmem6 might not require the file to be named .f And I've
6094 # seen examples of files named .txt
6096 @fsubs = keys %fsubs;
6097 if( @fsubs > 0 ){
6098 for( my $i = 0; $i <= $#fsubs; $i ++ ){
6099 unless( $fsubs[$i] =~ /\.f$/ ){
6100 $fsubs[$i] .= '.f';
6105 end subroutine_files
6107 # }}}
6109 # {{{ get_option_value
6110 start get_option_value
6112 #$modelObject -> get_option_value(record_name => 'recordName', option_name => 'optionName',
6113 # problem_index => <index>, record_index => <index>/'all',
6114 # option_index => <index>/'all')
6115 # record_name and option_name are required. All other have default 0.
6116 #record_index and option_index may either be scalar integer or string 'all'.
6117 # Depending on input parameters the return value can be
6118 # Case 1. a scalar for record_index => integer, option_index => integer
6119 # Case 2. a reference to an array of scalars for (record_index=>'all',option_index => integer)
6120 # Case 3. a reference to an array of scalars for (record_index=>integer,option_index => 'all')
6121 # Case 4. a reference to an array of references to arrays for (record_index=>'all',option_index => 'all')
6122 my ( @problems, @records, @options );
6123 my $accessor = $record_name.'s';
6124 my @rec_arr;
6125 my $fail;
6127 # print "start get option\n";
6129 #Basic error checking. Error return type is undef for Case 1
6130 #and reference to empty array for Case 2 and 3 and 4.
6132 if (lc($record_index) eq 'all' || lc($option_index) eq 'all' ){
6133 $fail = [];
6134 } else {
6135 $fail = undef;
6138 if ( defined $self -> {'problems'} ) {
6139 @problems = @{$self -> {'problems'}};
6140 } else {
6141 'debug' -> warn( level => 2,message => "No problems defined in model" );
6142 return $fail;
6144 unless( defined $problems[$problem_index] ){
6145 'debug' -> warn( level => 2,
6146 message => "model -> get_option_value: No problem with ".
6147 "index $problem_index defined in model" );
6148 return $fail;
6151 if ( defined $problems[$problem_index] -> $accessor ) {
6152 @records = @{$problems[$problem_index] -> $accessor};
6153 } else {
6154 'debug' -> warn( level => 2,
6155 message => "model -> get_option_value: No record $record_name defined" .
6156 " in problem with index $problem_index." );
6157 return $fail;
6160 #go through all records, whole array is of correct type.
6161 #if current record is the single we want, investigare option values and break out of loop
6162 #if we want to look at all records, investigare option values and continue with loop
6163 REC: for (my $ri=0; $ri<scalar(@records); $ri++){
6164 if ((lc($record_index) eq 'all') || $record_index==$ri){
6165 my @val_arr = ();
6166 unless ((defined $records[$ri]) &&( defined $records[$ri] -> options )){
6167 'debug' -> warn( level => 2,
6168 message => "model -> get_option_value: No options for record index ".
6169 "$record_index defined in problem." );
6170 if (lc($record_index) eq 'all'){
6171 if (lc($option_index) eq 'all'){
6172 push(@rec_arr,[]); #Case 4
6173 } else {
6174 push(@rec_arr,undef); #Case 2
6176 next REC;
6177 } else {
6178 if (lc($option_index) eq 'all'){
6179 $return_value = []; #Case 3
6180 } else {
6181 $return_value = undef; #Case 1
6183 last REC; #we are done
6186 @options = @{$records[$ri] -> options};
6187 my $oi=-1;
6188 my $val;
6189 #go through all options (array contains all options, regardless of name).
6190 # For each check if it the correct type, if so
6191 #increase counter $oi after possibly storing the option value
6192 #if current correct option is the single we want value for, then
6193 #store value and break out of loop. If want to store values for
6194 #all correct options, store value and then continue with loop
6195 foreach my $option ( @options ) {
6196 if (defined $option and
6197 (($option->name eq $option_name) || (index($option_name,$option ->name ) > -1))){
6198 $oi++; #first is 0
6199 if (lc($option_index) eq 'all' || $option_index == $oi){
6200 if ( (defined $option -> {'value'}) and ($option -> {'value'} ne '')){
6201 $val = $option -> {'value'};
6202 } else {
6203 $val = undef;
6205 if (lc($option_index) eq 'all'){
6206 push(@val_arr,$val); #Case 3 and 4
6207 } else {
6208 last; #Case 1 and 2. Take care of $val outside loop over options
6213 if (lc($record_index) eq 'all'){
6214 if (lc($option_index) eq 'all'){
6215 push(@rec_arr,\@val_arr); #Case 4
6216 } else {
6217 push(@rec_arr,$val); #Case 2
6219 next REC;
6220 } else {
6221 if (lc($option_index) eq 'all'){
6222 $return_value = \@val_arr; #Case 3
6223 } else {
6224 $return_value = $val; #Case 1
6226 last REC;
6230 if (lc($record_index) eq 'all'){
6231 $return_value = \@rec_arr; #Case 2 and 4
6235 end get_option_value
6237 # }}} get_option_value