1 # {{{ include_statements
2 start include statements
17 if (defined $this->{'samples'}){
18 if ( $this->{'samples'} < 20){
19 'debug' -> die(message
=> "Program does not allow less than 20 samples.");
22 'debug' -> die(message
=> "Option -samples is required.");
25 if ( scalar (@
{$this -> {'models'}->[0]-> problems
}) != 1 ){
26 'debug' -> die(message
=> 'Tool can only handle modelfiles with exactly one problem.');
29 unless ($this->{'dv'} =~ /^(IPRED|IWRES|CWRES)$/ ){
30 if (length($this->{'dv'})>4){
31 'debug' -> die(message
=> "The dependent variable name (option -dv) can have at most".
32 " 4 letters, unless it is IPRED/IWRES/CWRES, due to a limitation in NONMEM.");
37 push (@check_cols, $this->{'bin_on'}) if (defined $this->{'bin_on'});
38 push (@check_cols, $this->{'stratify_on'})
39 if ((defined $this->{'stratify_on'}) && ('STRT' ne $this->{'stratify_on'}));
40 foreach my $col (@check_cols){
41 my $var_text = ($col eq $this->{'stratify_on'})?
'stratification' : 'independent';
42 if ($col =~ /^(IPRED|IWRES|IRES|RES|WRES|DV|CWRES)$/){
43 'debug' -> die(message
=> "It is not allowed to use $col as the $var_text ".
44 "variable, since it it is dependent and hence differs between ".
45 "simulations of the same observation.");
48 unless ($col =~ /^(PRED)$/){
50 if ($this -> {'models'}->[0]-> is_option_set
(record
=>'input',name
=>$col)){
51 my $val = $this -> {'models'}->[0]-> get_option_value
(record_name
=> 'input',
53 if ((defined $val) && ($val =~ /(SKIP|DROP)/ )){
54 'debug' -> die(message
=> "Cannot SKIP/DROP the $var_text variable ".
55 "in the \$INPUT record.");
59 my $input_record = $this -> {'models'}->[0]-> record
(record_name
=> 'input' );
61 if( scalar(@
{$input_record}) > 0 ){ #always true
62 foreach my $line ( @
{$input_record -> [0]} ){
63 if ( $line =~ /([\w]+)=([\w]+)[^\w]/ ){
71 'debug' -> die(message
=> "In order to use $col as the $var_text variable, ".
72 "it must be in the \$INPUT record ") if !($found);
78 if ($this->{'dv'} =~ /^(PRED|MDV|TIME|DATE|EVID|AMT|RATE|ID)$/){
79 'debug' -> die(message
=> "It is not allowed to use $this->{'dv'} as the dependent".
80 " variable,\nbecause it".
81 " is the same for all simulations of a single observation.");
84 my @needed_variables=();
85 push (@needed_variables,('IWRES','IPRED','IRES')) if ($this->{'do_estimation'});
86 push (@needed_variables,'STRT') if ($this->{'stratify_on'} eq 'STRT');
87 push (@needed_variables,$this->{'dv'}) unless
88 ($this->{'dv'} =~ /^(IPRED|IWRES|IRES|RES|WRES|DV|CWRES)$/);
90 if (scalar(@needed_variables)>0){
92 push (@line_array,@
{$this ->{'models'}->[0]->problems->[0]->errors->[0]->code})
93 if (defined ($this ->{'models'}->[0]->problems->[0]->errors));
95 push (@line_array,@
{$this ->{'models'}->[0]->problems->[0]->preds->[0]->code})
96 if (defined $this ->{'models'}->[0]->problems->[0]->preds);
98 push (@line_array,@
{$this ->{'models'}->[0]->problems->[0]->pks->[0]->code})
99 if (defined $this ->{'models'}->[0]->problems->[0]->pks);
101 my $missing_variables='';
102 foreach my $var (@needed_variables){
104 foreach my $line (@line_array){
105 #variable must be left hand side, i.e. first set of non-blank characters
106 if ($line =~ /^ *$var[ =]/){
111 $missing_variables = "$missing_variables $var" unless $found;
113 if (length($missing_variables)>0){
114 'debug' -> die(message
=> "The selected input options require the user to define".
115 "$missing_variables in the modelfile,\nbut this was not done in ".
116 "neither \$ERROR, \$PRED nor \$PK.");
120 #check for ICALL .EQ. 4
123 push (@line_array,@
{$this ->{'models'}->[0]->problems->[0]->errors->[0]->code})
124 if (defined ($this ->{'models'}->[0]->problems->[0]->errors));
126 push (@line_array,@
{$this ->{'models'}->[0]->problems->[0]->preds->[0]->code})
127 if (defined $this ->{'models'}->[0]->problems->[0]->preds);
129 push (@line_array,@
{$this ->{'models'}->[0]->problems->[0]->pks->[0]->code})
130 if (defined $this ->{'models'}->[0]->problems->[0]->pks);
132 push (@line_array,@
{$this ->{'models'}->[0]-> record
(record_name
=> 'des')->[0]})
133 if (defined $this ->{'models'}->[0]-> record
(record_name
=> 'des')->[0]);
136 foreach my $line (@line_array){
137 if ($line =~ /ICALL\s?\.EQ\.\s?4/){
144 print "\n\nWarning: String ICALL.EQ.4 found in modelfile. Simulation statements\n".
145 "will influence NPC/VPC simulations and might produce unwanted results.\n\n";
152 if (defined $this->{'mirrors'}){
153 if ( $this->{'mirrors'} > 20){
154 'debug' -> die(message
=> "Program does not allow more than 20 mirror plots.");
158 if ( scalar (@
{$this -> {'models'}->[0]-> record
(record_name
=> 'simulation' )}) > 1 ){
159 'debug' -> die(message
=> "Tool does not allow more than one \$SIMULATION".
160 " record in the modelfile.");
163 unless ( scalar (@
{$this -> {'models'}->[0]-> record
( record_name
=> 'estimation' )}) == 1 ){
164 'debug' -> die(message
=> 'Tool requires exactly one $ESTIMATION record in '.
168 if ( scalar (@
{$this -> {'models'}->[0]-> record
(record_name
=> 'table' )}) > 0 ){
169 'debug' -> warn(level
=> 1,
170 message
=> 'Tool will delete existing $TABLE records in the modelfile.');
173 my $np_record = $this -> {'models'}->[0]-> record
(record_name
=> 'nonparametric' );
174 # if(( scalar(@{$np_record}) > 0 )&&($this->{'dv'} eq 'CWRES')){
175 # 'debug' -> die(message => "CWRES cannot be computed when there is a \$NONPARAMETRIC record".
176 # ' in the modelfile.');
179 if (defined $this->{'msfo_file'}){
180 if (defined $this->{'lst_file'}){
181 'debug' -> die(message
=> 'Tool does not allow using both -lst '.
182 'and -msfo options simultaneously.');
185 # my $np_record = $this -> {'models'}->[0]-> record(record_name => 'nonparametric' );
186 if( scalar(@
{$np_record}) > 0 ){
187 'debug' -> die(message
=> "Tool requires an msfo file when there is a \$NONPARAMETRIC record".
188 ' in the modelfile.');
192 #Synonym forbidden for MDV,ID
194 foreach my $variable ('MDV','ID'){
195 if ($this -> {'models'}->[0]-> is_option_set
(record
=>'input',name
=>$variable)){
196 my $value = $this -> {'models'}->[0]-> get_option_value
(record_name
=> 'input',
197 option_name
=> $variable);
198 if ((defined $value) && !($value =~ /(SKIP|DROP)/ )){
199 'debug' -> die(message
=> "It is forbidden to use a synonym for $variable ".
200 'in the $INPUT record.');
203 my $input_record = $this -> {'models'}->[0]-> record
(record_name
=> 'input' );
204 if( scalar(@
{$input_record}) > 0 ){ #always true
205 foreach my $line ( @
{$input_record -> [0]} ){
206 if ( $line =~ /([\w]+)=(MDV|ID)[^\w]/ ){
207 if (($variable eq $2) && !($1 =~ /(SKIP|DROP)/ )){
208 'debug' -> die(message
=> "It is forbidden to use a synonym ".
209 "for $variable in the \$INPUT record.");
220 if ($this->{'is_vpc'}){
222 unless (defined $this->{'bin_on'}){
223 'debug' -> die(message
=> "VPC requires an independent variable column.");
227 if (defined $this->{'no_of_bins'}){
229 unless (defined $this->{'bin_by_count'}){
230 'debug' -> die(message
=>"Option bin_by_count must be defined when ".
231 "option no_of_bins is used.");
234 if (scalar(@
{$this->{'bin_array'}}>0)){
235 if ($option_count>0){
236 'debug' -> die(message
=>"Incompatible set of binning options. Use vpc -h for help.");
239 unless (defined $this->{'bin_by_count'}){
240 'debug' -> die(message
=>"Option bin_by_count must be defined when ".
241 "option bin_array is used.");
243 if ($this->{'bin_by_count'}==1){
244 #check at least two values and all counts larger than 0
245 unless (scalar(@
{$this->{'bin_array'}}) > 1){
246 'debug' -> die(message
=>"Must define at least two counts in bin_array ".
247 "when binning by count.");
249 foreach my $c ($this->{'bin_array'}){
251 'debug' -> die(message
=>"Number of observations in each bin must ".
256 #check at least one value and sorted in ascending order and increasing
257 unless (scalar(@
{$this->{'bin_array'}}) > 0){
258 'debug' -> die(message
=>"Must define at least one boundary in bin_array ".
259 "when binning by width.");
261 for (my $i=1; $i< scalar(@
{$this->{'bin_array'}}); $i++){
262 unless ($this->{'bin_array'}->[$i] > $this->{'bin_array'}->[$i-1]){
263 'debug' -> die(message
=>"List of bin boundaries must be sorted and ".
271 if (defined $this->{'single_bin_size'}){
272 if ($option_count>0){
273 'debug' -> die(message
=>"Incompatible set of binning options. Use vpc -h for help.");
276 unless ($this->{'single_bin_size'}>0){
277 'debug' -> die(message
=>"Option single_bin_size must be larger than 0.");
279 unless (defined $this->{'bin_by_count'}){
280 'debug' -> die(message
=>"Option bin_by_count must be defined when ".
281 "option single_bin_size is used.");
283 if (defined $this->{'overlap_percent'}){
284 unless ($this->{'overlap_percent'}>0){
285 'debug' -> die(message
=>"Option overlap must be larger than 0\%.");
287 unless ($this->{'overlap_percent'}<100){
288 'debug' -> die(message
=>"Option overlap must be smaller than 100\%.");
291 #else handle by translating to no_of_bins-alternative after know width/no of observations
293 if (defined $this->{'overlap_percent'}){
294 'debug' -> die(message
=>"Option single_bin_size must be defined when ".
295 "option overlap is used.");
299 if (defined $this->{'bin_by_count'}){
300 unless ($option_count > 0){
301 'debug' -> die(message
=>"Option bin_by_count is forbidden without ".
302 "additional binning options.");
304 unless ($this->{'bin_by_count'} eq '0' || $this->{'bin_by_count'} eq '1'){
305 'debug' -> die(message
=>"Option bin_by_count must be either 1 or 0.");
310 my $command_file = $this -> {'directory'}."/command.txt";
311 if ( -e
$command_file ){
312 #this is a restart run, check if calls are compatible
313 open( CMD
, $command_file ) or
314 'debug'->die(message
=> "Could not open command.txt in restart directory.");
317 my $str = $this -> {'models'}->[0]->filename();
318 unless ($row =~ /($str)/){
319 'debug'->die(message
=> "Name of modelfile $str on command line does not match name of ".
320 "modelfile \nin restart directory ".$this -> {'directory'});
322 if (defined $this->{'lst_file'}){
323 unless ($row =~ /($this->{'lst'})/){
324 'debug'->die(message
=> "lst-file on command line was not used in call\n$row in".
325 "restart directory ".$this -> {'directory'});
327 } elsif ($row =~ /-lst=/){
328 'debug'->die(message
=> "No lst-file was specified on command line, but an lst-file was used ".
329 "in call\n$row in restart directory ".$this -> {'directory'});
331 if (defined $this->{'msfo_file'}){
332 unless ($row =~ /($this->{'msfo'})/){
333 'debug'->die(message
=> "msfo-file on command line was not used in call\n$row".
334 "in restart directory ".$this -> {'directory'});
336 } elsif ($row =~ /-msfo=/){
337 'debug'->die(message
=> "No msfo-file was specified on command line, but an msfo-file was used ".
338 "in call\n$row in restart directory ".$this -> {'directory'});
340 if (defined $this->{'samples'}){
341 my $str="-samples=$this->{'samples'}";
342 unless ($row =~ /$str\s/){
343 'debug'->die(message
=> "$str on command line is different from call\n$row".
344 "in restart directory ".$this -> {'directory'});
347 if ($this->{'do_estimation'}){
349 unless (($row =~ /$str/)||($row =~ /=PRED\s/)){
350 'debug'->die(message
=> "Estimation was not requested by call\n$row".
351 "in restart directory ".$this -> {'directory'}.
352 "\n(i.e. neither -dv option used nor binning/stratifying on PRED)".
353 "\nand therefore cannot be used here.");
356 unless ($this->{'dv'} =~ /^(IPRED|IWRES|IRES|RES|WRES|DV)$/ ){
357 my $str="-dv=$this->{'dv'}";
358 unless ($row =~ /$str/){
359 'debug'->die(message
=> "$this->{'dv'} is not part of default variable set from estimation,\n".
360 "nor was $str on command line used in call\n$row".
361 "in restart directory ".$this -> {'directory'}.
362 "\nTherefore $this->{'dv'} is not available.");
376 if ($self->{'is_vpc'}){
378 $self->logfile('vpc.log');
379 $self->results_file('vpc_results.csv');
384 my $model_orig = $self-> {'models'}->[0] -> copy
(filename
=>$type.'_original.mod',
387 #Always force rerun of original vpc model by removing lst file of original model
388 #For NPC only force rerun if are reusing old runs, but want to do stratify,
390 if ($self->{'is_vpc'}){
391 my $oldlst = $self -> {'directory'}."/m1/vpc_original.lst";
393 unlink $self -> {'directory'}."NM_run1/psn-1.lst";
394 unlink $self -> {'directory'}."NM_run1/psn.lst";
396 if (defined $self -> {'stratify_on'}){
397 my $oldlst = $self -> {'directory'}."/m1/npc_original.lst";
399 unlink $self -> {'directory'}."NM_run1/psn-1.lst";
400 unlink $self -> {'directory'}."NM_run1/psn.lst";
404 #logic for use of MDV column as basis for finding which rows are observations
405 #request MDV in $TABLE if no $PRED record or if there is a $PRED record and
407 #if there is a $PRED but no MDV in input then all rows will be observations
410 if (scalar @
{$model_orig-> record
( record_name
=> 'pred' )} < 1){
413 if ($model_orig-> is_option_set
(record
=>'input',name
=>'MDV')){
414 my $mdv_val = $model_orig -> get_option_value
(record_name
=> 'input',
415 option_name
=> 'MDV');
416 #have already checked no synonym. If value defined then SKIP/DROP ->don't include
417 unless (defined $mdv_val){
418 $MDV='MDV'; #MDV in input, no synynom
421 #have already checked no synonym. If value defined then SKIP/DROP ->don't include
424 ######## fix $TABLE record: remove any existing. create a new correct one.
426 #store $TABLE if FILE=cwtab<>.deriv, i.e. dv is CWRES, add it back to models later
427 my @extra_table_record;
428 if ($self->{'dv'} eq 'CWRES'){
429 my $table_record = $model_orig -> record
(record_name
=> 'table',
430 problem_number
=> 0);
432 my $rec_count = scalar(@
{$table_record});
433 if( $rec_count > 0 ){
434 for (my $i=0; $i<$rec_count; $i++){
435 @extra_table_record=();
437 foreach my $table_line ( @
{$table_record -> [$i]} ){
438 push(@extra_table_record,$table_line);
439 if ( $table_line =~ /(cwtab[0-9]*)\.deriv/){
440 $self->dv_table_name($1);
449 $model_orig -> remove_records
(type
=> 'table');
453 my @rec_strings = ('ID',$MDV);
454 if (defined $self->{'stratify_on'}){
455 push (@rec_strings,$self->{'stratify_on'}) unless ($self->{'stratify_on'} eq 'PRED');
457 if ($self->{'is_vpc'}){
458 push (@rec_strings,$self->{'bin_on'}) unless ($self->{'bin_on'} eq 'PRED');
460 if ($self->{'do_estimation'}){
461 unless ($self->{'dv'} =~ /^(IPRED|IWRES|IRES|RES|WRES|DV|CWRES)$/ ){
462 push (@rec_strings,$self->{'dv'});
464 push (@rec_strings,('IPRED','IWRES','IRES','ONEHEADER','NOPRINT'));
466 push (@rec_strings,$self->{'dv'});
467 push (@rec_strings,('NOAPPEND','ONEHEADER','NOPRINT'));
469 push (@rec_strings,('FILE=npctab.dta'));
470 $model_orig -> set_records
(type
=> 'table',
471 record_strings
=> \
@rec_strings);
473 $model_orig -> add_records
(type
=> 'table',
474 record_strings
=> \
@extra_table_record)
475 if (scalar(@extra_table_record)>0);
478 #check if synonyms used for DV/strat/bin. If so, replace reserved variable with synonym.
480 my @reserved_labels=('ID','L1','L2','MDV','RAW_','MRG_','RPT_','TIME','DATE');
481 push (@reserved_labels,('DAT1','DAT2','DAT3','EVID','AMT','RATE','SS','II','ADDL'));
482 push (@reserved_labels,('CMT','PCMT','CALL','CONT','SKIP','DROP'));
485 push (@check_var,'DV') if ($self->{'dv'} eq 'DV');
487 #collect variables to check
489 push (@cvar,$self->{'stratify_on'}) if ((defined $self->{'stratify_on'})
490 && !($self->{'stratify_on'} =~ /(STRT|PRED)/));
491 push (@cvar,$self->{'bin_on'}) if ((defined $self->{'bin_on'})
492 && ($self->{'bin_on'} ne 'PRED'));
493 #check if strat/bin reserved
494 foreach my $var (@cvar){
495 foreach my $lab (@reserved_labels){
497 push (@check_var,$var) ;
503 foreach my $reserved_name (@check_var){
504 my $synonym=$reserved_name;
505 if ($model_orig-> is_option_set
(record
=>'input',name
=>$reserved_name)){
506 my $value = $model_orig -> get_option_value
(record_name
=> 'input',
507 option_name
=> $reserved_name);
509 unless ($value =~ /(SKIP|DROP)/ ){
514 my $input_record = $model_orig -> record
(record_name
=> 'input' );
515 if( scalar(@
{$input_record}) > 0 ){ #always true
516 foreach my $line ( @
{$input_record -> [0]} ){
517 if ( $line =~ /([\w]+)=([\w]+)[^\w]/ ){
518 unless ($1 =~ /(SKIP|DROP)/ ){ #synonym
519 $synonym=$1 if ($2 eq $reserved_name);
526 if ($synonym ne $reserved_name){
528 if ('DV' eq $reserved_name){
529 $self->{'dv'}=$synonym;
530 } elsif ($reserved_name eq $self->{'bin_on'}){
531 $self->{'bin_on'}=$synonym;
532 } elsif ($reserved_name eq $self->{'stratify_on'}){
533 $self->{'stratify_on'}=$synonym;
538 ##### fix $ESTIMATION for original model
540 $model_orig -> set_option
(record_name
=> 'estimation',
541 option_name
=> 'MAXEVALS',
543 option_value
=> '0');
545 $model_orig -> remove_option
(record_name
=> 'estimation',
546 option_name
=> 'MSFO',
549 if ($self->{'do_estimation'}){
550 $model_orig -> set_option
(record_name
=> 'estimation',
551 option_name
=> 'POSTHOC',
556 ##### remove $COVARIANCE
557 $model_orig -> remove_records
(type
=> 'covariance');
559 ###update initial estimates/input data, if given###
561 if (defined $self->{'lst_file'}){
562 #create output object to check that can be parsed correctly, and to
563 #extract data for error checking
564 my $outputObject= output
-> new
(filename
=> '../'.$self -> {'lst_file'});
565 unless ($outputObject->parsed_successfully()){
566 'debug'-> die (message
=>"lst file $self->{'lst_file'} could not be parsed.");
568 #update initial values in model
569 $model_orig -> update_inits
( from_output
=> $outputObject);
571 } elsif (defined $self->{'msfo_file'}){
572 #add msfi record, and remove $THETA, $OMEGA, $SIGMA
573 $model_orig -> set_records
(type
=> 'msfi',
574 record_strings
=> [$self -> {'msfo_file'}]);
575 $model_orig -> remove_records
(type
=> 'theta');
576 $model_orig -> remove_records
(type
=> 'omega');
577 $model_orig -> remove_records
(type
=> 'sigma');
580 ####end update initial estimates############
583 #####Copy to simulation model
585 my $model_sim = $model_orig -> copy
(filename
=>$type.'_simulation.mod',
588 $model_orig -> remove_records
(type
=> 'simulation');
590 unless ($self->{'do_estimation'}){
591 $model_sim -> remove_records
(type
=> 'estimation');
594 ###Create simulation record######
597 #Check if existing simulation record
598 my $sim_record = $model_sim-> record
(record_name
=> 'simulation',problem_number
=> 0);
600 if (scalar (@
{$sim_record}) > 0){
601 #this option will be set below
602 foreach my $altopt ('SUBPROBLEMS','SUBPROBS','NSUBPROBLEMS','NSUBPROBS','NSUBS'){
603 #NONMEM accepts a heck of a lot of alternatives...
604 $model_sim -> remove_option
(record_name
=> 'simulation',
605 option_name
=> $altopt,
609 #unless $do_simulation this option will be set below
610 $model_sim -> remove_option
(record_name
=> 'simulation',
611 option_name
=> 'ONLYSIMULATION',
614 if (defined $self->{'msfo_file'}){ #always if $nonp, but even if not $nonp
615 my $val= $model_sim -> get_option_value
(record_name
=> 'simulation',
616 option_name
=> 'TRUE');
617 unless ((defined $val)&& ($val eq 'FINAL')){
618 'debug'->die(message
=>"Error in \$SIMULATION record in modelfile: when using an msfo-file\n".
619 "the option TRUE=FINAL must be set.");
624 #find and replace seeds
625 my $short_record = $model_sim-> record
(record_name
=> 'simulation',problem_number
=> 0);
628 #Simply look for numbers. Since got rid of NSUBPROBS this is ok.
629 foreach my $sim_line ( @
{$short_record -> [0]} ){
631 while ( $sim_line =~ /(\D*)(\d+)(\D.*)/g ){
632 my $seed = random_uniform_integer
(1,0,2147483560 );
633 $new_line .= "$1$seed";
637 push (@rec_strings,$new_line.$sim_line);
639 if (($set_seeds < 1)||($set_seeds > 2)){
640 'debug'->die(message
=>"Error in \$SIMULATION record in modelfile: wrong number of seeds.");
643 my $seed1 = random_uniform_integer
(1,0,2147483560 );
644 my $seed2 = random_uniform_integer
(1,0,2147483560 );
645 @rec_strings = ('('.$seed1.')');
646 my $np_record = $model_sim -> record
(record_name
=> 'nonparametric' );
647 if( scalar(@
{$np_record}) > 0 ){
648 push (@rec_strings ,'('.$seed2.' NONPARAMETRIC)');
649 $model_sim -> remove_records
(type
=> 'nonparametric');
651 if (defined $self->{'msfo_file'}){ #always if $nonp, but even if not $nonp
652 push (@rec_strings ,'TRUE=FINAL');
656 unless ($self->{'do_estimation'}){
657 push (@rec_strings,('ONLYSIMULATION'));
659 push (@rec_strings,('NSUBPROBLEMS='.$self->{'samples'}));
660 $model_sim -> set_records
(type
=> 'simulation',
661 record_strings
=> \
@rec_strings);
665 ###end simulation record######
668 #det som koer modellerna aer ett modelfit-objekt. Detta maoste skapas explicit.
670 $self->{'original_model'} = $model_orig;
671 $self->{'simulation_model'} = $model_sim;
673 push( @
{$self -> {'tools'}},
675 new
( reference_object
=> $self,
676 models
=> [$model_orig,$model_sim],
678 raw_results
=> undef,
679 prepared_models
=> undef,
681 prepend_model_file_name
=> 1
690 # {{{ _modelfit_raw_results_callback
692 #start _modelfit_raw_results_callback
694 #end _modelfit_raw_results_callback
698 # {{{ create_unique_values_hash
700 start create_unique_values_hash
706 foreach my $val (sort {$a <=> $b} @data_column){
707 if ($value_index == 0){
708 $value_hash{$value_index}=$val;
712 unless ($val == $value_hash{($value_index-1)}){
713 $value_hash{$value_index}=$val;
719 end create_unique_values_hash
723 # {{{ get_bin_boundaries_overlap_count
725 start get_bin_boundaries_overlap_count
728 # overlap_percent and scalar count
729 # data_column, and data_indices
730 # return bin_floors, lower boundary not part of upper bin
731 # and bin_ceilings, list of upperlimits, upperlimit is part of lower bin!!!
734 my $n_values = scalar(keys %value_hash);
735 my @obs_count=(0) x
$n_values;
738 #Count how many values we have in input for each unique value
739 for ($value_index=0; $value_index < $n_values;$value_index++){
740 foreach my $index (@data_indices){
741 if ($data_column[$index] == $value_hash{$value_index}){
742 $obs_count[$value_index] +=1;
748 unless ($check_count == scalar(@data_indices)){
749 'debug'->die(message
=>"Did not find all data values in hash.");
752 my $local_error=-$count;
753 my $overlap=$count*$overlap_percent/100;
755 push(@bin_floors,($value_hash{0}));
757 my $prev_start_index=0;
759 while ($value_index < $n_values ) {
760 if ($obs_count[$value_index] == 0){
761 $value_index++; #no observations for this value, skip to next
762 } elsif ($local_error == -$count){
763 #bin empty since error equals initial error, must add observations
764 $local_error += $obs_count[$value_index];
765 $prev_start_index=$value_index;
767 }elsif (abs($local_error)>abs($local_error+$obs_count[$value_index])){
768 #bin not empty and adding observations will reduce error
769 $local_error += $obs_count[$value_index];
772 #bin not empty and best to switch to new bin
773 push(@bin_ceilings,$value_hash{$value_index-1}); #last index was previous index
774 $local_error=-$count;
775 $overlap_error=-$overlap;
776 #compute overlap error if starting at $prev_start_index+1
777 for (my $k=($value_index-1);$k>$prev_start_index;$k--){
778 $overlap_error += $obs_count[$k];
780 $value_index= $prev_start_index+1; #must have nonzero overlap
781 #check if increasing value_index, i.e. moving start of next bin, will reduce overlap errror
782 while (abs($overlap_error)>abs($overlap_error-$obs_count[$value_index])){
783 $overlap_error -= $obs_count[$value_index];
786 push(@bin_floors,$value_hash{$value_index-1});
789 push(@bin_ceilings,$value_hash{$n_values-1});
792 end get_bin_boundaries_overlap_count
796 # {{{ get_bin_ceilings_from_count
798 start get_bin_ceilings_from_count
801 # n_bins or list_counts or single_bin_size
802 # data_column, and data_indices
803 # return bin_ceilings, list of upperlimits, upperlimit is part of lower bin!!!
807 my $n_values = scalar(keys %value_hash);
808 my @obs_count=(0) x
$n_values;
809 my $nonzero_counts=0;
812 #Count how many values we have in input for each unique value
813 #and how many of the unique values have nonzero count
814 for ($value_index=0; $value_index < $n_values;$value_index++){
815 foreach my $index (@data_indices){
816 if ($data_column[$index] == $value_hash{$value_index}){
817 $obs_count[$value_index] +=1;
821 foreach my $c (@obs_count){
829 if (defined $n_bins){
831 'debug'->die(message
=>"Number of bins must be at least 1.");
833 if (scalar(@list_counts)>0){
834 'debug'->die(message
=>"Cannot input both number of bins and set of bin counts.");
837 if ($n_bins >= $nonzero_counts){#one bin per unique value with nonzero obs => no binning
840 my $count = scalar(@data_indices)/$n_bins;
841 @ideal_count = ($count) x
$n_bins;
843 } elsif (defined $single_bin_size){
844 #translate to $n_bins
845 my $nb = int (scalar(@data_indices)/$single_bin_size); #round down
846 $nb++ if ((scalar(@data_indices)/$single_bin_size)-$nb >= 0.5);
847 if ($nb >= $nonzero_counts){#one bin per unique value with nonzero obs => no binning
850 my $count = scalar(@data_indices)/$nb;
851 @ideal_count = ($count) x
$nb;
852 } elsif (scalar(@list_counts)>0 && scalar(@list_counts)<$nonzero_counts ){
853 #check that requested counts matches total number of observations
855 foreach my $c (@list_counts){
858 unless ($checksum == scalar(@data_indices)){
859 'debug'->die(message
=>"Sum of observations requested in each bin must equal ".
860 "total number of observations (in strata).");
863 push (@ideal_count,@list_counts);
870 my $local_error=-$ideal_count[$bin_index];
872 for ($value_index = 0; $value_index < $n_values; $value_index++) {
873 # print "index=$value_index obs=$obs_count[$value_index] local=$local_error global=$global_error \n";
874 if ($bin_index == $#ideal_count){
875 #have reached last bin
876 #last upper limit is largest unique value, include all remaining observations
877 push(@bin_ceilings,$value_hash{($n_values-1)});
879 }elsif ($local_error == -$ideal_count[$bin_index]){
880 #bin empty since error equals initial error
881 $local_error += $obs_count[$value_index];
882 }elsif ($obs_count[$value_index] == 0){
884 }elsif (abs($global_error+$local_error)>
885 abs($global_error+$local_error+$obs_count[$value_index])
886 && (($n_values-$value_index-1)> ($#ideal_count - $bin_index))){
887 #adding observations will reduce global error
888 #and more than one unique value remaining per remaining bin.
889 $local_error += $obs_count[$value_index];
892 #bin not empty and best add observations to new bin
893 push(@bin_ceilings,$value_hash{$value_index-1});
894 $global_error += $local_error;
896 $local_error=-$ideal_count[$bin_index]+$obs_count[$value_index];
904 end get_bin_ceilings_from_count
908 # {{{ get_bin_boundaries_overlap_value
910 start get_bin_boundaries_overlap_value
912 # @data_column, @data_indices
913 # width, overlap_percent
914 #return bin_floors, bin_ceilings
917 for (my $i=0; $i< scalar(@data_indices); $i++){
918 push(@local_values,$data_column[$data_indices[$i]]);
921 my @temp = sort {$a <=> $b} @local_values;
922 my $minval = $temp[0];
923 my $maxval = $temp[$#temp];
924 my $non_overlap_width=$width*(100-$overlap_percent)/100;
926 my $next_ceiling=$minval+$width;
927 my $next_floor=$minval;
928 while ($next_ceiling < $maxval){
929 push(@bin_floors,$next_floor);
930 push(@bin_ceilings,$next_ceiling);
931 $next_ceiling += $non_overlap_width;
932 $next_floor = $next_ceiling - $width;
934 push(@bin_floors,$next_floor);
935 push(@bin_ceilings,$maxval);
938 end get_bin_boundaries_overlap_value
942 # {{{ get_bin_ceilings_from_value
944 start get_bin_ceilings_from_value
946 # @data_column, @data_indices
947 # n_bins or list_boundaries or single_bin_size
948 #return bin_ceilings, upper limits of intervals, upperlimit part of lower bin
951 for (my $i=0; $i< scalar(@data_indices); $i++){
952 push(@local_values,$data_column[$data_indices[$i]]);
955 my @temp = sort {$a <=> $b} @local_values;
956 my $minval = $temp[0];
957 my $maxval = $temp[$#temp];
959 if (defined $n_bins){
960 if (scalar(@list_boundaries)>0){
961 'debug'->die(message
=>"Cannot input both number of intervals and set of boundaries");
963 my $width = ($maxval-$minval)/$n_bins;
964 for (my $i=1; $i<=$n_bins; $i++){
965 push (@bin_ceilings,($width*$i+$minval));
967 } elsif (defined $single_bin_size){
968 #translate to $n_bins
969 my $nb = int(($maxval-$minval)/$single_bin_size); #round down
970 $nb++ if ((($maxval-$minval)/$single_bin_size)-$nb >= 0.5);
971 my $width = ($maxval-$minval)/$nb;
972 for (my $i=1; $i<=$nb; $i++){
973 push (@bin_ceilings,($width*$i+$minval));
976 } elsif (scalar(@list_boundaries)>0){
977 push (@bin_ceilings,@list_boundaries);
978 if ($maxval > $list_boundaries[$#list_boundaries]){
979 push (@bin_ceilings,$maxval);
984 end get_bin_ceilings_from_value
989 # {{{ index_matrix_binned_values
991 start index_matrix_binned_values
993 #based on either unique values hash or bin_ceilings,
994 #create array of arrays of data matrix row indices
995 #one index array for each unique value
996 #input %value_hash, @data_column, @data_indices,
997 #optional input @bin_ceilings, if empty then unique values
998 #optional input @bin_floors, only allowed if ceilings given.
999 #If floors empty then ceilings are floors , if given then first value is inclusive, the rest exclusive
1000 #output index_matrix
1004 if (scalar(@bin_ceilings)>0){
1005 push(@ceilings,@bin_ceilings);
1006 if (scalar(@bin_floors)>0){
1007 push(@floors,@bin_floors);
1009 push(@floors,$value_hash{0});
1010 for (my $i=0; $i<$#ceilings; $i++){
1011 push(@floors,$ceilings[$i]);
1015 #check that floors not given as input
1016 if (scalar(@bin_floors)>0){
1017 'debug'->die(message
=>"Cannot give bin floor input to index_matrix_binned_values ".
1018 "unless ceilings given.");
1020 #no_binning, base on unique values
1021 my $no_of_values = scalar (keys %value_hash);
1022 for (my $value_index=0; $value_index<$no_of_values; $value_index++){
1023 push(@ceilings,$value_hash{$value_index});
1025 push(@floors,$value_hash{0} - 0.2);
1026 for (my $i=0; $i<$#ceilings; $i++){
1027 push(@floors,$ceilings[$i]);
1031 for (my $bin_index=0; $bin_index<scalar(@ceilings); $bin_index++){
1033 my $this_floor=$floors[$bin_index];
1034 $this_floor -= 0.2 if ($bin_index==0); #first floor is inclusive
1035 foreach my $row_index (@data_indices){
1036 if ($data_column[$row_index]>$this_floor &&
1037 $data_column[$row_index]<=$ceilings[$bin_index] ){
1038 push (@index_row,$row_index);
1041 push (@index_matrix,\
@index_row);
1045 end index_matrix_binned_values
1050 # {{{ get_data_matrix
1052 start get_data_matrix
1054 my $signal_file = $self -> {'directory'}."/m1/".$self -> {'dv'}."_matrix_saved";
1055 my $matrix_saved = ( -e
$signal_file ) ?
1 : 0;
1056 my $no_sim=$self->{'samples'};
1057 my $type = ($self->{'is_vpc'}) ?
'vpc' : 'npc';
1060 open( MATRIX
, $self -> {'directory'}."/m1/".$self -> {'dv'}."_matrix.csv" ) or
1061 'debug'->die(message
=> "Could not find saved matrix.");
1063 while (my $row = <MATRIX
>){
1065 push (@matrix,$row);
1066 $nsim= (split(/,/,$row)) -1 if ($nsim==0);
1069 #check that found correct number of columns in matrix
1070 unless ($nsim == $no_sim){
1071 'debug'->die(message
=> "Number of simulated data sets $nsim in saved matrix\n".
1072 "is different from number $no_sim in input (-samples option).");
1078 my @datearr=localtime;
1079 my $the_time=sprintf "%2.2d:%2.2d:%2.2d",$datearr[2],$datearr[1],$datearr[0];
1080 my $prev_sec=$datearr[2]*3600+$datearr[1]*60+$datearr[0];
1082 ui
-> print (category
=>'npc',
1083 message
=>"\nReading and formatting $self->{'dv'} data. This can take a while...");
1085 my $orig_file = (defined $self->{'dv_table_name'}) ?
$self->{'dv_table_name'}:
1086 $self->{'original_model'}-> get_option_value
(record_name
=> 'table',
1087 option_name
=> 'FILE');
1089 $orig_file = $self->{'original_model'}->directory().$type.'_original.'.$orig_file;
1091 unless ( -e
$orig_file ){
1092 my $file_to_check = $self -> {'directory'}."NM_run1/compute_cwres.Rout";
1093 print "\nCheck installation of R and XPose, check file $file_to_check\n"
1094 if ($self->{'dv'} eq 'CWRES');
1095 $file_to_check = $self -> {'directory'}."NM_run1/psn-1.lst";
1096 'debug'->die(message
=> "File $orig_file \nwith table output for original data does not exist. ".
1097 "It is recommended to check lst-file $file_to_check for NONMEM error messages.");
1099 my $d = data
-> new
(filename
=>$orig_file); #läser in allt
1101 my $no_individuals= scalar(@
{$d->{'individuals'}});
1103 my $filt = $d -> create_row_filter
('no_individuals'=>$no_individuals);
1104 my $all_rows_observations = (scalar(@
{$filt}) > 0)?
0 : 1;
1106 #NONMEM only prints first 4 letters of variable name as header
1107 #exception for CWRES
1108 my $dv_header = ($self->{'dv'} eq 'CWRES') ?
$self->{'dv'} : substr($self->{'dv'},0,4);
1110 @matrix = @
{$d -> column_to_array
('column'=>$dv_header,'filter'=>$filt)};
1111 my $no_observations = scalar(@matrix);
1113 unless ($no_observations >0){
1114 'debug' -> die(message
=> "No $self->{'dv'} values found after filtering original data.");
1117 #want to always read whole simulation, i.e. whole table. Compute how many
1118 #simulations can be read in each round given this condition and a limit of 400000 lines
1119 #count lines in original tablefile
1121 open(ORIG
, $orig_file ) or 'debug'->die(message
=> "Could not open tablefile.");
1126 my $max_read_sim = ($linecount >= 400000) ?
1 : int (400000/$linecount);
1127 my $max_ind=$max_read_sim*$no_individuals; #individuals to read in one round
1132 my $sim_file = (defined $self->{'dv_table_name'}) ?
$self->{'dv_table_name'}:
1133 $self->{'simulation_model'}-> get_option_value
(record_name
=> 'table',
1134 option_name
=> 'FILE');
1136 $sim_file = $self->{'simulation_model'}->directory().$type.'_simulation.'.$sim_file;
1137 unless ( -e
$sim_file ){
1138 my $file_to_check = $self -> {'directory'}."NM_run2/compute_cwres.Rout";
1139 print "\nCheck installation of R and XPose, check file $file_to_check\n"
1140 if ($self->{'dv'} eq 'CWRES');
1141 $file_to_check = $self -> {'directory'}."NM_run2/psn-1.lst";
1142 'debug'->die(message
=> "File $sim_file \nwith table output for original data does not exist. ".
1143 "It is recommended to check lst-file\n$file_to_check \nfor NONMEM error messages.");
1146 $d = data
-> new
(filename
=>$sim_file,target
=>'disk');
1147 $d -> _read_header
();
1149 #read portions of the simdatafiles, until all expected records read
1150 #build data matrix so that there is one column for each simulation
1151 #(real data is first column) and one row for each data point.
1152 #Store as one-dimensional array of rows, each row is comma-separated string of values
1155 while ( $skip_tab<$no_sim){
1158 $the_time=sprintf "%2.2d:%2.2d:%2.2d",$datearr[2],$datearr[1],$datearr[0];
1159 $this_sec=$datearr[2]*3600+$datearr[1]*60+$datearr[0];
1160 unless ($skip_tab == 0){
1161 my $sec_rem = $self->ceil('number'=>(($no_sim-$skip_tab)/$max_read_sim))*
1162 ($this_sec-$prev_sec);
1163 my $percent_done=int(100*$skip_tab/$no_sim);
1164 my $minutes_remaining=$self->ceil('number'=>($sec_rem/60));
1165 my $plural = ($minutes_remaining == 1)?
'' : 's';
1166 my $mess="Time $the_time, $percent_done\% done. ".
1167 "Approximately $minutes_remaining minute$plural of formatting remaining.";
1168 ui
-> print (category
=>'npc', message
=>$mess);
1170 $prev_sec=$this_sec;
1173 # my $mess=sprintf "Time $the_time. Processing %d to %d out of %d simulated datasets...",
1175 # (($skip_tab+$max_read_sim)>$no_sim) ? $no_sim :($skip_tab+$max_read_sim),$no_sim;
1177 $d-> _read_individuals
('skip_tables'=>$skip_tab,'max_individuals'=>$max_ind);
1180 my $tables_to_read= ($max_read_sim > ($no_sim-$skip_tab))?
($no_sim-$skip_tab): $max_read_sim;
1181 my $individuals_expected = $tables_to_read*$no_individuals;
1182 unless (scalar(@
{$d->{'individuals'}}) == $individuals_expected){
1183 my $file_to_check = $self -> {'directory'}."NM_run2/psn-1.lst";
1184 'debug' -> die(message
=> "Did not find the expected number of individuals to read in \n".
1185 "$sim_file. \nA possible cause is that some simulations failed. ".
1186 "Check lst-file\n $file_to_check \nfor error messages. Also check in \n$sim_file \n".
1187 "that number of TABLE rows is equal to -samples ".
1188 "requested on command-line, and that all TABLE sections contain ".
1189 "observations for all individuals.");
1194 if ($skip_tab == 0){ #if first read from simdata, create filter
1195 $filt = $d -> create_row_filter
('no_individuals'=>$no_individuals);
1197 unless ($all_rows_observations){
1199 $test_count++ if ($_ > 0);
1201 unless ($test_count == $no_observations){
1202 'debug' -> die(message
=> "Number of observations $test_count after filtering ".
1203 "simulated data set were not equal to number after ".
1204 "filtering $no_observations original data set.");
1208 my $column_data = $d -> column_to_array
('column'=>$dv_header,'filter'=>$filt);
1210 unless (scalar @
{$column_data} >0){
1211 'debug' -> die(message
=> "No $self->{'dv'} values found after filtering simulated data portion.");
1216 data
-> append_columns_to_matrix
('matrix'=>\
@matrix,'columns'=>$column_data);
1217 $column_data = undef;
1218 $skip_tab += $max_read_sim;
1221 #check simulations read
1222 my $no_read_sim= (split(/,/,$matrix[0])) -1;
1223 unless ($no_sim == $no_read_sim){
1224 'debug'-> die(message
=>"Number of read simulated datasets $no_read_sim is\n".
1225 "different from expected number $no_sim.");
1230 open( MATRIX
, ">".$self -> {'directory'}."/m1/".$self -> {'dv'}."_matrix.csv" ) ;
1231 foreach my $row (@matrix){
1232 print MATRIX
"$row"."\n";
1236 open( DONE
, ">".$signal_file ) ;
1237 my $tmp = $no_sim+1;
1238 print DONE
"Created $no_observations rows by $tmp columns data matrix ".
1239 "and wrote to file $self -> {'dv'}_matrix.csv\n";
1240 print DONE
"First column is original data, columns 2 to $tmp are simulated data.\n";
1244 ui
-> print (category
=>'npc', message
=> "Done reading and formatting $self->{'dv'} data, finishing run.");
1252 # {{{ modelfit_analyze
1253 start modelfit_analyze
1257 if ($self->{'is_vpc'}){
1260 my $matrix = $self -> get_data_matrix
();
1261 my $no_sim= (split(/,/,$matrix ->[0])) -1;
1262 unless ($no_sim == $self->{'samples'}){
1263 'debug'-> die(message
=>"Number of simulated datasets in matrix file $no_sim is\n".
1264 "different from number $self->{'samples'} in input (option -samples).");
1266 print "$no_sim simulations \n" if ($self->{'verbose'});
1268 my $no_of_strata = 1;
1272 my @strata_labels=();
1273 my $no_observations = scalar(@
{$matrix});
1274 my @all_indices= (0 .. ($no_observations-1));
1276 if (defined $self -> {'stratify_on'}){
1277 my $col = $self -> {'stratify_on'};
1278 #NONMEM only prints first 4 letters of variable name as header
1279 #no CWRES exception since not allowed stratify on CWRES
1281 my $strat_header = substr($self->{'stratify_on'},0,4);
1283 #add new: If ((defined $self->{dv_table_name }) && (not $self->{'dv} eq 'CWRES'))
1284 #use dv_table_name instead
1285 #OR require that stratification and binning variables are in vpc-generated table
1287 my $orig_file = $self->{'original_model'}->directory().$type.'_original.'.
1288 $self->{'original_model'}-> get_option_value
(record_name
=> 'table',
1289 option_name
=> 'FILE');
1291 my $d = data
-> new
(filename
=>$orig_file); #läser in allt
1293 my $no_individuals= scalar(@
{$d->{'individuals'}});
1294 my $filt = $d -> create_row_filter
('no_individuals'=>$no_individuals);
1296 $strat_array = $d -> column_to_array
('column'=>$strat_header,'filter'=>$filt);
1297 unless (scalar @
{$strat_array} > 0){
1298 'debug'-> die(message
=>"Could not find column to stratify on in original data file.");
1300 unless (scalar @
{$strat_array} == $no_observations){
1301 'debug'-> die(message
=>"Number of observations in stratification column after filtering ".
1302 "does not match number of observations in matrix file.");
1305 $strat_hash = $self -> create_unique_values_hash
('data_column'=>$strat_array);
1306 #compute strata limits. Currently only no_of_strata based on counts allowed.
1307 #ok with undefined no_of_strata, will return empty array, which
1308 #index_matrix_binned_values interprets as stratify on unique values.
1310 my $strata_ceilings = $self -> get_bin_ceilings_from_count
('data_column'=>$strat_array,
1311 'value_hash'=>$strat_hash,
1312 'data_indices'=>\
@all_indices,
1313 'n_bins'=>$self->{'no_of_strata'});
1314 $strat_matrix = $self -> index_matrix_binned_values
('data_column'=>$strat_array,
1315 'value_hash'=>$strat_hash,
1316 'data_indices'=>\
@all_indices,
1317 'bin_ceilings'=>$strata_ceilings);
1319 #create label array for printed report.
1320 if (defined $self->{'no_of_strata'} && $self->{'no_of_strata'}< scalar(keys %{$strat_hash})){
1321 $no_of_strata=$self->{'no_of_strata'};
1322 my $low= sprintf "[%g;",${$strat_hash}{0};
1323 foreach my $high (@
{$strata_ceilings}){
1324 my $lab = sprintf "strata $col %s %g]",$low,$high;
1325 push (@strata_labels,$lab);
1326 $low=sprintf "(%g;",$high;
1329 $no_of_strata = scalar (keys %{$strat_hash});
1330 for (my $strat_ind=0; $strat_ind<$no_of_strata; $strat_ind++){
1331 my $lab = sprintf "strata $col = %g",${$strat_hash}{$strat_ind};
1332 push (@strata_labels,$lab);
1337 if ($self->{'verbose'}){
1338 print "\n strata $no_of_strata\n";
1339 foreach my $k (keys %{$strat_hash}){
1340 print "key $k and value ${$strat_hash}{$k}\n";
1345 $strat_matrix = [\
@all_indices];
1346 push (@strata_labels," ");
1351 if ($no_of_strata > 10){
1352 ui
-> print (category
=>'npc', message
=>"Warning: The number of stratification levels is $no_of_strata");
1355 if ($self->{'is_vpc'}){
1356 $self->vpc_analyze('matrix'=>$matrix,
1357 'strat_matrix'=>$strat_matrix,
1358 'strata_labels'=>\
@strata_labels,
1359 'strata_variable'=> $strat_array);
1361 $self->npc_analyze('matrix'=>$matrix,
1362 'strat_matrix'=>$strat_matrix,
1363 'strata_labels'=>\
@strata_labels);
1368 end modelfit_analyze
1369 # }}} modelfit_analyze
1374 my $floor=int($number);
1375 my $rem=$number-$floor;
1377 $integer_out = ($rem >= 0.5)?
$floor+1 : $floor;
1379 $integer_out = (abs($rem) >= 0.5)?
$floor-1 : $floor;
1389 my $floor=int($number);
1390 my $rem=$number-$floor;
1392 $integer_out = $floor+1;
1395 $integer_out = $floor;
1405 my $len= scalar( @
{$sorted_array} );
1408 $result = $sorted_array->[($len-1)/2];
1410 $result = ($sorted_array->[$len/2]+$sorted_array->[($len-2)/2])/ 2;
1419 #input refs strat_matrix, strata_labels(fix no_of_strata from labels)
1420 #matrix (fix no_observations and no_sim from matrix)
1422 my $no_sim= (split(/,/,$matrix ->[0])) -1;
1423 my $no_observations = scalar(@
{$matrix});
1424 my $no_of_strata = scalar(@
{$strata_labels});
1427 #Recreate basic observation filter, and hash for binning. Copy paste from modelfit_analyze
1429 my $col = $self -> {'bin_on'};
1430 #NONMEM only prints first 4 letters of variable name as header
1431 #no exception for CWRES since not allowed to bin on CWRES
1432 my $bin_header = substr($self->{'bin_on'},0,4);
1434 #add new: If ((defined $self->{dv_table_name }) && (not $self->{'dv} eq 'CWRES'))
1435 #use dv_table_name instead
1436 #OR require that stratification and binning variables are in vpc-generated table
1438 my $orig_file = $self->{'original_model'}->directory().'vpc_original.'.
1439 $self->{'original_model'}-> get_option_value
(record_name
=> 'table',
1440 option_name
=> 'FILE');
1442 my $d = data
-> new
(filename
=>$orig_file); #läser in allt
1444 my $no_individuals= scalar(@
{$d->{'individuals'}});
1445 my $filter = $d -> create_row_filter
('no_individuals'=>$no_individuals);
1447 my $bin_array = $d -> column_to_array
('column'=>$bin_header,'filter'=>$filter);
1448 unless (scalar @
{$bin_array} > 0){
1449 'debug'-> die(message
=>"Could not find column to bin on in original data file.");
1451 unless (scalar @
{$bin_array} == $no_observations){
1452 'debug'-> die(message
=>"Number of observations in binning column after filtering ".
1453 "does not match number of observations in matrix file.");
1456 ###### print data for VPC plots, prepare mirror parameters
1458 my $id_array = $d -> column_to_array
('column'=>'ID','filter'=>$filter);
1459 unless (scalar @
{$id_array} > 0){
1460 'debug'-> die(message
=>"Could not find ID column in original data file.");
1462 unless (scalar @
{$id_array} == $no_observations){
1463 'debug'-> die(message
=>"Number of observations in ID column after filtering ".
1464 "does not match number of observations in matrix file.");
1467 #add translated stratacol
1468 my @translated_strata = (0) x
$no_observations;
1469 for (my $strat_ind=0; $strat_ind<$no_of_strata; $strat_ind++){
1470 foreach my $j (@
{$strat_matrix->[$strat_ind]}){
1471 $translated_strata[$j] = ($strat_ind +1);
1475 #filename vpctabN - find number N
1477 if ($self -> {'models'}->[0]->filename() =~ /run(\d+)\.mod/){
1484 my @mirror_labels=();
1485 if (defined $self->{'mirrors'}){
1486 my @rand_indices=random_permuted_index
($self -> {'samples'});
1487 @mirror_set = @rand_indices[0 .. ($self->{'mirrors'}-1)];
1488 for my $j (1 .. $self->{'mirrors'}){
1489 push (@mirror_labels,"mirror_$j");
1493 open( ST
, ">".$self -> {'directory'}."/vpctab".$tabno);
1495 print ST
"ID,".$self->{'dv'}.",".$self->{'bin_on'};
1496 print ST
",strata_no,".$self->{'stratify_on'} if (defined $self->{'stratify_on'});
1497 foreach my $j (@mirror_labels){
1502 for (my $i=0;$i<$no_observations;$i++){
1503 my $idno = sprintf "%d",$id_array->[$i] ;
1504 my $row = $matrix->[$i];
1505 my $idv=$bin_array->[$i];
1508 ($orig_value,@tmp) = split(/,/,$row);
1509 print ST
"$idno,$orig_value,$idv";
1510 print ST
",$translated_strata[$i],".$strata_variable->[$i] if (defined $self->{'stratify_on'});
1511 foreach my $j (@mirror_set){
1512 print ST
",$tmp[$j]";
1520 my $bin_hash = $self -> create_unique_values_hash
('data_column'=>$bin_array);
1523 my @pred_int = sort {$a <=> $b} 0,40,80,90,95;
1526 foreach my $pi (@pred_int){
1528 push (@perc_limit,50);
1530 push (@perc_limit,(100-$pi)/2);
1531 push (@perc_limit,(100-(100-$pi)/2));
1535 my $no_perc_limits = scalar(@perc_limit);
1536 my @limit = (0) x
$no_perc_limits;
1537 my @lower_limit_ci = (0) x
$no_perc_limits;
1538 my @upper_limit_ci = (0) x
$no_perc_limits;
1539 my @limit_real = (0) x
$no_perc_limits;
1540 my @limit_index= (0) x
$no_perc_limits;
1541 my @limit_singlesim;
1542 for (my $i=0; $i<$no_perc_limits; $i++){
1543 @
{$limit_singlesim[$i]} = (0) x
($no_sim);
1546 if (defined $self->{'mirrors'}){
1547 for (my $i=0; $i<$no_perc_limits; $i++){
1548 @
{$limit_mirrors[$i]} = (0) x
($self->{'mirrors'});
1554 my $low_ci_ind = $self->round('number'=>((100-$c_i)*($no_sim-1)/200));
1555 # my $low_ci_ind = int(((100-$c_i)*($no_sim-1)/200)+0.5); #index of start of ci % interval
1556 my $high_ci_ind = $no_sim - $low_ci_ind - 1; #index of end of c_i% interval
1559 ## Prepare general run info for output file, and bin labels
1561 $return_section{'name'} = 'VPC run info';
1562 my $modelname=$self-> {'models'}->[0] ->filename();
1563 my $extra_value=$modelname;
1564 if (defined $self->{'msfo_file'}){
1565 $extra_value='msfo-file '.$self->{'msfo_file'};
1566 } elsif (defined $self->{'lst_file'}){
1567 $extra_value='lst-file '.$self->{'lst_file'};
1570 $return_section{'labels'} = [[],['Date','observations','simulations','Modelfile',
1571 'parameter values from','Independent variable','Dependent variable',
1572 'PsN version','NONMEM version']];
1573 my @datearr=localtime;
1574 my $the_date=($datearr[5]+1900).'-'.($datearr[4]+1).'-'.($datearr[3]);
1576 $return_section{'values'} = [[$the_date,$no_observations,$no_sim,$modelname,$extra_value,
1577 $self->{'bin_on'},$self->{'dv'},$PsN::version
,$self->{'nm_version'}]];
1578 push( @
{$self -> {'results'}[0]{'own'}},\
%return_section );
1580 my @result_column_labels=("< $col",'<=','no. of obs');
1581 for (my $i=0; $i<$no_perc_limits; $i++){
1582 push (@result_column_labels,"$perc_limit[$i]\% real");
1583 foreach my $lab (@mirror_labels){
1584 push (@result_column_labels,"$perc_limit[$i]\% ".$lab);
1586 push (@result_column_labels,"$perc_limit[$i]\% sim","$c_i\%CI for $perc_limit[$i]\% from",
1587 "$c_i\%CI for $perc_limit[$i]\% to");
1590 #For VPC diagnostics
1592 my $npc_pi_offset=0;
1593 foreach my $pi (@pred_int){
1597 push (@result_column_labels,"PI $pi\% False pos (\%)","PI $pi\% False neg (\%)")
1601 my ($npc_lower_index,$npc_upper_index,$npc_low_ind,$npc_high_ind);
1603 ($npc_lower_index,$npc_upper_index,$npc_low_ind,$npc_high_ind)=
1604 $self->get_npc_indices('ci' => $c_i,
1605 'no_sim' => $no_sim,
1606 'pred_intervals' => \
@pred_int);
1608 my ($npc_result_column_labels,$npc_result_row_labels);
1609 ($npc_result_column_labels,$npc_result_row_labels) =
1610 $self->get_npc_result_labels('ci' => $c_i,'pred_intervals' => \
@pred_int);
1611 my @npc_result_labels = ($npc_result_row_labels,$npc_result_column_labels);
1612 # my @npc_section_array; have insdie strata loop
1614 #end prep VPC diagnostics
1616 ##done general run info and labels
1619 #Do the binning. Copy paste from modelfit_analyze stratification,
1620 #very similar but more options and parameters...
1622 for (my $strat_ind=0; $strat_ind<$no_of_strata; $strat_ind++){
1623 #report strata header, use labels...
1624 my @result_row_labels = ('first interval is closed');
1626 my @result_values=();
1627 my $no_strata_obs=scalar(@
{$strat_matrix->[$strat_ind]});
1628 my $result_name = "\nVPC results ".$strata_labels -> [$strat_ind].
1629 "\n$no_strata_obs observations out of $no_observations";
1630 $return_section{'name'} = $result_name;
1631 my @npc_section_array; #possibly move out again
1634 my ($bin_floors,$bin_ceilings);
1635 if ($self->{'bin_by_count'} eq '1') {
1636 # print "Binning by count\n";
1637 if (defined $self->{'overlap_percent'}){
1638 ($bin_floors,$bin_ceilings) =
1639 $self -> get_bin_boundaries_overlap_count
('data_column'=>$bin_array,
1640 'value_hash'=>$bin_hash,
1641 'data_indices'=>$strat_matrix->[$strat_ind],
1642 'count'=>$self->{'single_bin_size'},
1643 'overlap_percent' =>$self->{'overlap_percent'});
1645 #add input param single_bin_size
1647 $self -> get_bin_ceilings_from_count
('data_column'=>$bin_array,
1648 'value_hash'=>$bin_hash,
1649 'data_indices'=>$strat_matrix->[$strat_ind],
1650 'n_bins'=>$self->{'no_of_bins'},
1651 'single_bin_size'=>$self->{'single_bin_size'},
1652 'list_counts' =>$self->{'bin_array'});
1654 } elsif ($self->{'bin_by_count'} eq '0') {
1655 if (defined $self->{'overlap_percent'}){
1656 ($bin_floors,$bin_ceilings) =
1657 $self -> get_bin_boundaries_overlap_value
('data_column'=>$bin_array,
1658 'data_indices'=>$strat_matrix->[$strat_ind],
1659 'width'=>$self->{'single_bin_size'},
1660 'overlap_percent' =>$self->{'overlap_percent'});
1662 #add input param single_bin_size
1664 $self -> get_bin_ceilings_from_value
('data_column'=>$bin_array,
1665 'data_indices'=>$strat_matrix->[$strat_ind],
1666 'n_bins'=>$self->{'no_of_bins'},
1667 'single_bin_size'=>$self->{'single_bin_size'},
1668 'list_boundaries' =>$self->{'bin_array'});
1671 my $bin_matrix = $self -> index_matrix_binned_values
('data_column'=>$bin_array,
1672 'value_hash'=>$bin_hash,
1673 'data_indices'=>$strat_matrix->[$strat_ind],
1674 'bin_floors'=>$bin_floors,
1675 'bin_ceilings'=>$bin_ceilings);
1676 my $no_bins = scalar(@
{$bin_matrix});
1679 if (defined $bin_ceilings ){
1680 unless (defined $bin_floors ){
1681 $bin_floors->[0]=${$bin_hash}{0};
1682 for (my $bi=1; $bi<$no_bins; $bi++){
1683 $bin_floors->[$bi]=$bin_ceilings->[$bi-1];
1686 } else{ #unique value binning
1687 for (my $bi=0; $bi<$no_bins; $bi++){
1688 $bin_ceilings->[$bi]=${$bin_hash}{$bi};
1689 # my $lab = sprintf "\n$type results bin $col = %g",${$bin_hash}{$bi};
1690 # push (@bin_labels,$lab);
1699 my @sum_falsepos= (0) x
scalar(@pred_int);
1700 my @sum_falseneg= (0) x
scalar(@pred_int);
1703 for (my $bin_index=0;$bin_index<$no_bins;$bin_index++){
1704 #Loop over bins. Check URS
1706 #push (@result_row_labels,' ') unless ($bin_index==0); #avoid NA in labels
1713 my $no_bin_observations=0;
1715 #a) pool all simulated values in bin
1716 #sort simvalues, compute indices for this particular $no_simvalues;
1718 foreach my $row_index (@
{$bin_matrix->[$bin_index]}){
1719 my $row = $matrix->[$row_index];
1720 ($orig_value,@tmp) = split(/,/,$row);
1721 push(@simvalues,@tmp);
1722 push(@singleset,$orig_value);
1723 $no_simvalues += $no_sim;
1724 $no_bin_observations++;
1726 next if ($no_bin_observations == 0);
1728 my @sorted_sim_values = sort {$a <=> $b} @simvalues;
1729 for (my $i=0; $i<$no_perc_limits; $i++){
1730 if ($perc_limit[$i]==50){
1731 # if (int($limit_index[$i]+0.5)>int($limit_index[$i])){
1733 $limit[$i]= $self->median('sorted_array' => \
@sorted_sim_values);
1734 # ($sorted_sim_values[int($limit_index[$i]+0.5)]+$sorted_sim_values[int($limit_index[$i])])/2;
1736 $limit_index[$i] = $self->round('number'=>$perc_limit[$i]*($no_simvalues-1)/100);
1737 $limit[$i]=$sorted_sim_values[$limit_index[$i]];
1741 for (my $i=0; $i<$no_perc_limits; $i++){
1742 $limit_index[$i] = $self->round('number'=>($perc_limit[$i]*($no_bin_observations-1)/100));
1746 ##VPC diagnostics. Before b,c) because need singleset of real values
1748 #outside bin-loop: call get_npc_indices with correct PI:s and no_sim (and ci)
1749 #here call subset_npc_analyze with this bin
1750 my ($npc_result_values,$npc_realpos,$npc_stats_warnings);
1751 ($npc_result_values,$npc_realpos,$npc_stats_warnings)=
1752 $self->subset_npc_analyze('matrix' => $matrix,
1753 'row_indices' => $bin_matrix->[$bin_index],
1754 'low_ind' => $npc_low_ind,
1755 'high_ind' => $npc_high_ind,
1756 'lower_index' => $npc_lower_index,
1757 'upper_index' => $npc_upper_index,
1758 'pred_intervals' => \
@pred_int);
1759 #realpos has one arrayref per PI, each array one integer per obs. -1 below, 0 in, 1 above
1762 #the offset is to skip interval 50-50 which is of course empty
1763 for (my $i=$npc_pi_offset; $i<scalar(@pred_int); $i++){
1766 for (my $j=0; $j<$no_bin_observations; $j++){
1767 if ($npc_realpos->[$i]->[$j] == 0){
1769 if (($singleset[$j] < $limit[($i*2-$npc_pi_offset)]) ||
1770 ($singleset[$j] > $limit[($i*2-$npc_pi_offset+1)])){
1776 if (($singleset[$j] >= $limit[($i*2-$npc_pi_offset)]) &&
1777 ($singleset[$j] <= $limit[($i*2-$npc_pi_offset+1)])){
1783 push (@diagnostics,($false_pos*100/$no_bin_observations,$false_neg*100/$no_bin_observations));
1784 $sum_falsepos[$i] += $false_pos;
1785 $sum_falseneg[$i] += $false_neg;
1787 $sum_no_obs += $no_bin_observations;
1789 my %npc_return_section;
1790 $npc_return_section{'name'} = "\nNPC results ".$strata_labels -> [$strat_ind].
1791 "\nbin ".($bin_index+1).": ".$no_bin_observations." observations";
1792 $npc_return_section{'labels'} = \
@npc_result_labels;
1793 $npc_return_section{'values'} = $npc_result_values;
1794 push( @npc_section_array,\
%npc_return_section );
1797 #end VPC diagnostics (print below)
1800 #b) compute PI:s for original, sort values and save lower and upper limits
1801 my @sorted_singleset = sort {$a <=> $b} @singleset;
1803 for (my $i=0; $i<$no_perc_limits; $i++){
1804 if ($perc_limit[$i]==50){
1805 $limit_real[$i] = $self->median('sorted_array' => \
@sorted_singleset);
1806 # if (int($limit_index[$i]+0.5)>int($limit_index[$i])){
1808 # ($sorted_singleset[int($limit_index[$i]+0.5)]+$sorted_singleset[int($limit_index[$i])])/2;
1810 $limit_real[$i] = $sorted_singleset[$limit_index[$i]];
1815 #c) compute PI:s for each simset. Use clever indexing in @simvalues to extract values.
1816 #then determine and save ci:s for each PI boundary
1817 for (my $col=0;$col<$no_sim; $col++){
1819 for (my $row=0; $row<$no_bin_observations; $row++){
1820 push(@singleset,$simvalues[$col+$row*$no_sim]);
1822 @sorted_singleset = sort {$a <=> $b} @singleset;
1823 for (my $i=0; $i<$no_perc_limits; $i++){
1824 if ($perc_limit[$i]==50){
1825 $limit_singlesim[$i]->[$col] = $self->median('sorted_array' => \
@sorted_singleset);
1826 # if (int($limit_index[$i]+0.5)>int($limit_index[$i])){
1827 # $limit_singlesim[$i]->[$col] =
1828 # ($sorted_singleset[int($limit_index[$i]+0.5)]+$sorted_singleset[int($limit_index[$i])])/2;
1830 # $limit_singlesim[$i]->[$col] = $sorted_singleset[int($limit_index[$i])];
1831 $limit_singlesim[$i]->[$col] = $sorted_singleset[$limit_index[$i]];
1837 if (defined $self->{'mirrors'}){
1838 for my $mi (0 .. ($self->{'mirrors'}-1)){
1839 my $col = $mirror_set[$mi];
1840 for (my $i=0; $i<$no_perc_limits; $i++){
1841 $limit_mirrors[$i]->[$mi]=$limit_singlesim[$i]->[$col];
1847 for (my $i=0; $i<$no_perc_limits; $i++){
1848 my @val_arr = sort {$a <=> $b} @
{$limit_singlesim[$i]};
1849 $lower_limit_ci[$i] = $val_arr[$low_ci_ind];
1850 $upper_limit_ci[$i] = $val_arr[$high_ci_ind];
1854 $st = $bin_floors->[$bin_index] if (defined $bin_floors );
1855 my @result_row_values=($st,$bin_ceilings->[$bin_index],$no_bin_observations);
1857 for (my $i=0; $i<$no_perc_limits; $i++){
1858 push (@result_row_values,$limit_real[$i]);
1859 for my $mi (0 .. ($self->{'mirrors'}-1)){
1860 push (@result_row_values,$limit_mirrors[$i]->[$mi]);
1862 push (@result_row_values,($limit[$i],$lower_limit_ci[$i],$upper_limit_ci[$i]));
1866 push (@result_row_values,@diagnostics);
1870 push (@result_values,\
@result_row_values);
1872 } #end loop over bins
1874 my @result_labels = (\
@result_row_labels,\
@result_column_labels);
1875 $return_section{'labels'} = \
@result_labels;
1876 $return_section{'values'} = \
@result_values;
1877 push( @
{$self -> {'results'}[0]{'own'}},\
%return_section );
1883 $diag_section{'name'}="\nDiagnostics VPC ".$strata_labels -> [$strat_ind];
1884 for (my $i=$npc_pi_offset; $i<scalar(@pred_int); $i++){
1885 push (@diag_labels,"PI $pred_int[$i]\% ");
1886 push (@diag_vals,[$sum_falsepos[$i]*100/$sum_no_obs,$sum_falseneg[$i]*100/$sum_no_obs]);
1888 $diag_section{'labels'}=[\
@diag_labels,["False pos (\%)","False neg (\%)"]];
1889 $diag_section{'values'}=\
@diag_vals;
1890 push( @
{$self -> {'results'}[0]{'own'}},\
%diag_section );
1891 push( @
{$self -> {'results'}[0]{'own'}},@npc_section_array);
1893 } #end loop over strata
1901 # {{{ subset_npc_analyze
1902 start subset_npc_analyze
1904 #start function, in is row_indices,matrix,lower_index,upper_index,
1905 #pred_intervals,$high_ind,$low_ind
1906 #out is ref to result_values and real_positions and stats_warnings
1907 #npoints not needed, length of input @row_indices
1909 my $no_sim= (split(/,/,$matrix ->[0])) -1;
1910 my $point_counter=scalar(@
{$row_indices});
1911 if ($point_counter < 1){ #empty set of observations
1915 #need to guarantee sorted pred_ints
1916 my @pred_int = sort {$a <=> $b} @
{$pred_intervals};
1917 my $no_pred_ints = scalar(@pred_int);
1918 my @upper_limit = (0) x
$no_pred_ints;
1919 my @lower_limit = (0) x
$no_pred_ints;
1920 my (@values,@sorted_sim_values);
1922 my @sum_warnings = (0) x
($no_sim+1);
1923 my (@upper_count, @lower_count);
1924 for (my $i=0; $i<$no_pred_ints; $i++){
1925 @
{$upper_count[$i]} = (0) x
($no_sim+1);
1926 @
{$lower_count[$i]} = (0) x
($no_sim+1);
1927 @
{$real_positions[$i]} = (0) x
($point_counter);
1933 foreach my $row_index (@
{$row_indices}){
1934 my $row = $matrix->[$row_index];
1935 ($orig_value,@values) = split(/,/,$row);
1937 @sorted_sim_values = sort {$a <=> $b} @values; #sort numerically ascending
1939 if ($self->{'verbose'}){
1940 printf "\n%.3f ",$orig_value;
1941 foreach my $v (@values){
1944 printf "\n%.3f ",$orig_value;
1945 foreach my $v (@sorted_sim_values){
1951 for (my $i=0; $i<$no_pred_ints; $i++){
1952 $lower_limit[$i] = $sorted_sim_values[($lower_index->[$i])];
1953 $upper_limit[$i] = $sorted_sim_values[($upper_index->[$i])];
1956 unshift @values,($orig_value); #put original value back at the beginning
1958 #Since the pred_ints are sorted in ascending order (e.g 80, 90, 95),
1959 #if value is below limit of first prediction interval, cannot be above
1960 #limit of any interval. Then if value is not below limit of 2nd, 3rd...
1961 #interval it cannot be below limit of any of the remaining.
1963 for (my $j=0; $j<= $no_sim; $j++){
1964 if ($values[$j] < $lower_limit[0]){
1965 $lower_count[0]->[$j] +=1;
1966 for (my $i=1; $i<$no_pred_ints; $i++){
1967 if ($values[$j] < $lower_limit[$i]){
1968 $lower_count[$i]->[$j] +=1;
1970 last; #goto next column (next value in @values)
1973 } elsif ($values[$j] > $upper_limit[0]){
1974 $upper_count[0]->[$j] +=1;
1975 for (my $i=1; $i<$no_pred_ints; $i++){
1976 if ($values[$j] > $upper_limit[$i]){
1977 $upper_count[$i]->[$j] +=1;
1979 last; #goto next $value
1987 ##For VPC diagnostics: build integer matrix w/ under/above/in info for real data only
1990 if ($values[0] < $lower_limit[0]){
1991 $real_positions[0]->[$obs_counter]=-1;
1992 for (my $i=1; $i<$no_pred_ints; $i++){
1993 if ($values[0] < $lower_limit[$i]){
1994 $real_positions[$i]->[$obs_counter]=-1;
1999 } elsif ($values[0] > $upper_limit[0]){
2000 $real_positions[0]->[$obs_counter]= 1;
2001 for (my $i=1; $i<$no_pred_ints; $i++){
2002 if ($values[0] > $upper_limit[$i]){
2003 $real_positions[$i]->[$obs_counter]= 1;
2012 ### end VPC diagnostics
2014 if ($self->{'verbose'}){
2015 for (my $i=0; $i<$no_pred_ints; $i++){
2016 printf "%.0f %.3f %.3f\n",$pred_int[$i],$lower_limit[$i],$upper_limit[$i] if ($self->{'verbose'});
2017 for (my $j=0; $j<= $no_sim; $j++){
2018 print "$lower_count[$i]->[$j] ";
2021 for (my $j=0; $j<= $no_sim; $j++){
2022 print "$upper_count[$i]->[$j] ";
2028 } #end foreach rowindex
2030 my $const=100/$point_counter; #conversion from count to percent
2032 print "$low_ind $high_ind $const\n" if ($self->{'verbose'});
2034 #loop over prediction intervals, compute results for each interval
2035 for (my $i=0; $i<$no_pred_ints; $i++){
2037 my $realcount = shift @
{$lower_count[$i]};
2038 my @count_arr = sort {$a <=> $b} @
{$lower_count[$i]};
2040 if (( $realcount<$count_arr[$low_ind]) ||($realcount>$count_arr[$high_ind])){
2042 $sum_warnings[0] += 1; #NPC diagnostics
2045 #For NPC diagnostics:
2046 for (my $si=0; $si<$no_sim; $si++){
2047 if (( $lower_count[$i]->[$si] < $count_arr[$low_ind]) ||($lower_count[$i]->[$si] > $count_arr[$high_ind])){
2048 $sum_warnings[(1+$si)] += 1; # +1 because 0 is real data.
2051 #end NPC diagnostics
2054 my @result_row_values =($realcount,$realcount*$const,$warn,$count_arr[$low_ind]*$const,
2055 $count_arr[$high_ind]*$const);
2056 if ($self->{'verbose'}){
2057 print "$realcount ";
2058 for (my $j=0; $j<= $no_sim; $j++){
2059 print "$lower_count[$i]->[$j] ";
2062 for (my $j=0; $j<$no_sim; $j++){
2063 print "$count_arr[$j] ";
2069 $realcount = shift @
{$upper_count[$i]};
2070 @count_arr = sort {$a <=> $b} @
{$upper_count[$i]};
2071 unless (scalar(@count_arr)==$no_sim){ #kolla no_sim vaerden!
2072 'debug' -> die(message
=> "Crash.");
2075 if (( $realcount<$count_arr[$low_ind]) ||($realcount>$count_arr[$high_ind])){
2077 $sum_warnings[0] += 1; #NPC diagnostics
2079 #For NPC diagnostics:
2080 for (my $si=0; $si<$no_sim; $si++){
2081 if (( $upper_count[$i]->[$si] < $count_arr[$low_ind]) ||($upper_count[$i]->[$si] > $count_arr[$high_ind])){
2082 $sum_warnings[(1+$si)] += 1; # 1+ because 0 is real data
2085 #end NPC diagnostics
2087 push (@result_row_values,($realcount, $realcount*$const,$warn,$count_arr[$low_ind]*$const,
2088 $count_arr[$high_ind]*$const));
2090 if ($self->{'verbose'}){
2091 print "$realcount ";
2092 for (my $j=0; $j<= $no_sim; $j++){
2093 print "$upper_count[$i]->[$j] ";
2096 for (my $j=0; $j<$no_sim; $j++){
2097 print "$count_arr[$j] ";
2102 push (@result_values,\
@result_row_values);
2104 } #end loop over prediction intervals
2107 my $i = shift @sum_warnings; #real count
2108 push(@stats_warnings,$i);
2110 foreach my $i (@sum_warnings){
2113 push(@stats_warnings,$sum_sums/$no_sim); #mean
2114 push(@stats_warnings,($no_pred_ints*2*2*$low_ind/$no_sim)); #theoretical mean
2116 my @sorted_sums = sort {$a <=> $b} @sum_warnings;
2117 # print "\n $sum_sums $low_ind $high_ind\n";
2118 # foreach my $i (@sorted_sums){
2124 push(@stats_warnings,$self->median('sorted_array'=>\
@sorted_sums));
2126 # if( scalar( @sorted_sums ) % 2 ){
2127 # push(@stats_warnings,$sorted_sums[$#sorted_sums/2]);
2129 # push(@stats_warnings,($sorted_sums[@sorted_sums/2]+$sorted_sums[(@sorted_sums-2)/2]) / 2);
2132 push(@stats_warnings,$sorted_sums[$low_ind]); #start 95% CI
2133 push(@stats_warnings,$sorted_sums[$high_ind]); #end 95% CI
2136 end subset_npc_analyze
2137 # }}} subset_npc_analyze
2139 # {{{ get_npc_indices
2140 start get_npc_result_labels
2142 #in pred_intervals ci
2143 #out result_column_labels result_row_labels
2145 my @pred_int = sort {$a <=> $b} @
{$pred_intervals};
2146 my $no_pred_ints = scalar(@pred_int);
2148 @result_column_labels=('points below PI (count)','points below PI (%)','outside CI for below PI',
2149 "$ci\% CI below: from (\%)","$ci\% CI below: to (\%)" );
2150 push (@result_column_labels,('points above PI (count)','points above PI (%)','outside CI for above PI',
2151 "$ci\% CI above: from (\%)","$ci\% CI above: to (\%)"));
2153 for (my $i=0; $i<$no_pred_ints; $i++){
2154 push (@result_row_labels,"$pred_int[$i]% PI");
2158 end get_npc_result_labels
2159 # }}} get_npc_result_labels
2161 # {{{ get_npc_indices
2162 start get_npc_indices
2164 #in pred_intervals ci no_sim
2165 #out lower_index upper_index low_ind high_ind
2167 #For each prediction interval pred_int: Compute lower_index, i.e. index
2168 #of first value in sorted array which is inside this interval.
2169 #Compute upper index, index of last value inside interval
2171 my @pred_int = sort {$a <=> $b} @
{$pred_intervals};
2172 my $no_pred_ints = scalar(@pred_int);
2174 # $low_ind = int(((100-$ci)*($no_sim-1)/200)+0.5); #index of start of ci % interval
2175 $low_ind = $self->round('number'=>((100-$ci)*($no_sim-1)/200)); #index of start of ci % interval
2176 $high_ind = $no_sim - $low_ind - 1; #index of end of c_i% interval
2178 for (my $i=0; $i<$no_pred_ints; $i++){
2179 push (@lower_index, $self->round('number'=>((100-$pred_int[$i])*($no_sim-1)/200)));
2180 push (@upper_index, $no_sim - $lower_index[$i] -1);
2185 # }}} get_npc_indices
2191 #input refs strat_matrix, strata_labels(fix no_of_strata from labels)
2192 #matrix (fix no_observations and no_sim from matrix)
2195 my @pred_int = sort {$a <=> $b} 0,20,40,50,60,80,90,95;
2196 my $no_sim= (split(/,/,$matrix ->[0])) -1;
2197 my $no_observations = scalar(@
{$matrix});
2198 my $no_of_strata = scalar(@
{$strata_labels});
2200 my $no_pred_ints = scalar(@pred_int);
2201 my ($lower_index,$upper_index,$low_ind,$high_ind);
2202 my ($result_column_labels,$result_row_labels);
2204 ## Prepare general run info for output file
2206 $return_sec{'name'} = 'NPC run info';
2207 my $modelname=$self-> {'models'}->[0] ->filename();
2209 my $extra_value=$modelname;
2210 if (defined $self->{'msfo_file'}){
2211 $extra_value='msfo-file '.$self->{'msfo_file'};
2212 } elsif (defined $self->{'lst_file'}){
2213 $extra_value='lst-file '.$self->{'lst_file'};
2216 $return_sec{'labels'} = [[],['Date','observations','simulations','Modelfile',
2217 'parameter values from','Dependent variable','PsN version','NONMEM version']];
2219 my @datearr=localtime;
2220 my $the_date=($datearr[5]+1900).'-'.($datearr[4]+1).'-'.($datearr[3]);
2222 $return_sec{'values'} = [[$the_date,$no_observations,$no_sim,$modelname,$extra_value,
2223 $self->{'dv'},$PsN::version
,$self->{'nm_version'}]];
2225 push( @
{$self -> {'results'}[0]{'own'}},\
%return_sec );
2227 ##done general run info
2229 ($result_column_labels,$result_row_labels) = $self->get_npc_result_labels('ci' => $c_i,
2230 'pred_intervals' => \
@pred_int);
2231 my @result_labels = ($result_row_labels,$result_column_labels);
2234 ($lower_index,$upper_index,$low_ind,$high_ind)= $self->get_npc_indices('ci' => $c_i,
2235 'no_sim' => $no_sim,
2236 'pred_intervals' => \
@pred_int);
2238 if ($self->{'verbose'}){
2239 for (my $i=0; $i<$no_pred_ints; $i++){
2240 print "$pred_int[$i] $lower_index->[$i] $upper_index->[$i]\n";
2245 my $analyzed_points=0;
2247 for (my $strat_ind=0; $strat_ind<$no_of_strata; $strat_ind++){
2249 my ($result_values,$stats_warnings);
2250 ($result_values,$realpos,$stats_warnings)=$self->subset_npc_analyze('matrix' => $matrix,
2251 'row_indices' => $strat_matrix->[$strat_ind],
2252 'low_ind' => $low_ind,
2253 'high_ind' => $high_ind,
2254 'lower_index' => $lower_index,
2255 'upper_index' => $upper_index,
2256 'pred_intervals' => \
@pred_int);
2258 my $point_counter=scalar(@
{$strat_matrix->[$strat_ind]});
2259 my $result_name = "\nNPC results ".$strata_labels -> [$strat_ind].
2260 "\n$point_counter observations out of $no_observations";
2261 $return_section{'name'} = $result_name;
2263 $return_section{'labels'} = \
@result_labels;
2264 $return_section{'values'} = $result_values;
2265 push( @
{$self -> {'results'}[0]{'own'}},\
%return_section );
2268 $diag_section{'name'} = "\nNPC * (warning) statistics";
2269 $diag_section{'labels'} = [[],['Real data * count','Sim. data * count mean','Theoretical mean','Sim. data * count median',
2270 'Sim. data * count 95% CI from','to']];
2271 $diag_section{'values'} = [$stats_warnings];
2272 push( @
{$self -> {'results'}[0]{'own'}},\
%diag_section );
2274 $analyzed_points+=$point_counter;
2277 #check that all individuals were grouped to a strata
2278 unless ($analyzed_points == $no_observations){
2279 'debug' -> die(message
=> "Sum of observations $analyzed_points in each strata does not\n".
2280 "equal total number of observations $no_observations. Something went wrong.");