.lmfit.normal
author A.M. Thurnherr <athurnherr@yahoo.com>
Sat, 24 Jul 2021 09:38:16 -0400
changeset 46 70e566505a12
parent 39 56bdfe65a697
permissions -rw-r--r--
V7.3
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
39
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     1
#======================================================================
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     2
#                    . L M F I T . N O R M A L 
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     3
#                    doc: Wed Feb 24 09:40:06 1999
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     4
#                    dlm: Fri Jul 28 13:35:24 2006
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     5
#                    (c) 1999 A.M. Thurnherr
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     6
#                    uE-Info: 34 51 NIL 0 0 72 2 2 4 NIL ofnI
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     7
#======================================================================
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     8
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
     9
# What you need to provide if you wanna fit a different
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    10
# model function to your data:
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    11
#	- a number of global variables to be set during loading
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    12
#	- a number of subs to perform admin tasks (usage, init, ...)
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    13
#	- a sub to evaluate the model function which is to be fitted using
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    14
#	  a number of pararams which are all stored in @A (beginning at
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    15
#	  A[1]!!!). You also need to return the partial derivatives of
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    16
#	  the model function wrt all params.
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    17
#	- the interface is documented between +++++++ lines
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    18
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    19
# check if a given distribution is normal
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    20
# NB:
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    21
#	- fitting is based on gauss curve fitting [.lmfit.gauss]
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    22
#	- heuristics are taken from there and scaled for the normal
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    23
#	  parameter choices
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    24
#	- simplified, e.g. y-shift is removed (does not make sense for
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    25
#	  distribution)
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    26
#	- added chi^2 significance testing to &modelCleanup() on -x
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    27
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    28
# HISTORY:
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    29
#	Oct 04, 1999: - created from [.lmfit.gauss]
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    30
#	Oct 05, 1999: - added chi^2 significance test
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    31
#				  - removed -y
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    32
#				  - improved heuristics
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    33
#   Mar 17, 2001: - param->arg
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    34
#	Jul 28, 2006: - Version 3.3 [HISTORY]; &isnan()
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    35
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    36
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    37
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    38
# THE FOLLOWING VARIABLES MUST BE SET GLOBALLY (i.e. during loading)
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    39
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    40
#	$modelOpts			string of allowed options
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    41
#	$modelOptsUsage		usage information string for options
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    42
#	$modelMinArgs		min # of arguments of model
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    43
#	$modelArgsUsage		usage information string for arguments
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    44
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    45
# The following variables may be set later but not after &modelInit()
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    46
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    47
#	$modelNFit			number of params to fit in model
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    48
#	@nameA				symbolic names of model parameters
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    49
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    50
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    51
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    52
$modelOpts = "x";
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    53
$modelOptsUsage = "[-x chi^2 test]";
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    54
$modelMinArgs = 0;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    55
$modelArgsUsage = "[area guess [mean guess [sigma guess]]]";
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    56
$modelNFit = 3;			
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    57
$nameA[1] = "area";
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    58
$nameA[2] = "mean";		
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    59
$nameA[3] = "sigma";	
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    60
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    61
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    62
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    63
# &modelUsage()		mangle parameters; NB: there may be `infinite' # of
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    64
#					filenames after model arguments; this usually sets
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    65
#					@A (the model parameters) but these can later be
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    66
#					calculated heuristically during &modelInit()
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    67
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    68
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    69
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    70
sub modelUsage()
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    71
{
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    72
	$A[1] = nan; $A[2] = nan; $A[3] = nan;				# usage
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    73
	$A[1] = &antsFloatArg() if ($#ARGV >= 0 && ! -r $ARGV[0]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    74
	$A[2] = &antsFloatArg() if ($#ARGV >= 0 && ! -r $ARGV[0]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    75
	$A[3] = &antsFloatArg() if ($#ARGV >= 0 && ! -r $ARGV[0]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    76
	&antsUsageError() unless ($#ARGV < 0 || -r $ARGV[0]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    77
}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    78
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    79
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    80
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    81
# &modelInit()		initializes model after reading of data
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    82
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    83
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    84
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    85
sub modelInit()
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    86
{
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    87
	my($i,$j,$ymin,$ymax,$xatymax);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    88
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    89
#	--------------------------------------------------
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    90
#	heuristics for initial model param values
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    91
#	--------------------------------------------------
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    92
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    93
	$ymin = 1e33, $ymax = -1e33, $xatymax = 0;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    94
	for ($i=0; $i<=$#ants_; $i++) {
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    95
		next if ($antsFlagged[$i]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    96
		$ymin = $ants_[$i][$yfnr]
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    97
			if ($ants_[$i][$yfnr] < $ymin);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    98
		$ymax = $ants_[$i][$yfnr], $xatymax = $ants_[$i][$xfnr]
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
    99
			if ($ants_[$i][$yfnr] > $ymax);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   100
	}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   101
	$A[1] = $ymax - $ymin if isnan($A[1]);			# peak guess
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   102
	$A[2] = $xatymax if isnan($A[2]);				# mean guess
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   103
	if (isnan($A[3])) {								# e-scale guess
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   104
		for ($i=1;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   105
			 $i<=$#ants_ && !$antsFlagged[$i]
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   106
						 && $ants_[$i][$yfnr]-$ymin<0.36*$A[1];
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   107
			 $i++) {}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   108
		for ($j=$#ants_;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   109
			 $j>=1 && !$antsFlagged[$i]
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   110
				   && $ants_[$j][$yfnr]-$ymin < 0.36*$A[1];
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   111
			 $j--) {}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   112
		$A[3] = abs($ants_[$i][$xfnr]-$ants_[$j][$xfnr]) / 2.0;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   113
		if ($A[3] == 0.0) {
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   114
			&antsInfo("$model: sigma heuristic failed (set to 1)!");
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   115
			$A[3] = 1.0;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   116
	    }
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   117
	}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   118
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   119
	$A[1] *= 1.77 * $A[3]							# gauss -> normal
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   120
		unless (isnan($A[1]) || isnan($A[3]));
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   121
	$A[3] *= 0.71 unless isnan($A[3]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   122
}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   123
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   124
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   125
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   126
# &modelEvaluate(x,A,dyda)	evaluate Normal distribution curve at x
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   127
#		x					x value (NOT xfnr)
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   128
#		A					reference to @A
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   129
#		dyda				reference to array for partial derivatives
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   130
#							(wrt individual params in @A)
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   131
#		<ret val>			y value
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   132
#
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   133
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   134
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   135
sub modelEvaluate($$$)
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   136
{
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   137
	my($x,$AR,$dydaR) = @_;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   138
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   139
	my($peak) = $AR->[1] / (2.506628274631 * $AR->[3]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   140
	my($dx  ) = $x - $AR->[2];
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   141
	my($sig2) = $AR->[3] * $AR->[3];
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   142
	my($expo) = exp(-$dx*$dx/(2*$sig2));
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   143
	my($norm) = $peak * $expo;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   144
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   145
	if (defined($dydaR)) {
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   146
		$dydaR->[1] = $norm / $AR->[1];
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   147
		$dydaR->[2] = $norm * $dx / $sig2;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   148
	    $dydaR->[3] = $norm/$AR->[3] * ($dx*$dx/$sig2 - 1);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   149
	}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   150
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   151
	return $norm;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   152
}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   153
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   154
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   155
# &modelCleanup()	cleans up after fitting but before output
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   156
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   157
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   158
sub modelCleanup()
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   159
{
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   160
	return unless ($opt_x);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   161
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   162
	require "$ANTS/libfuns.pl";
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   163
	my($chisq) = 0;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   164
	my($nval,$prob,$sign);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   165
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   166
	for ($i=0; $i<=$#ants_; $i++) {
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   167
		next if ($antsFlagged[$i]);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   168
#		next if ($ants_[$i][$yfnr] <= 1);	# IGNORE TAIL HEURISTICS
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   169
		$nval = &modelEvaluate($ants_[$i][$xfnr],\@A);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   170
		$chisq += ($ants_[$i][$yfnr] - $nval)**2 / $nval;
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   171
	}
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   172
	$prob = &gammq(($ndata-3)/2,$chisq/2);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   173
	$sign = int($prob*100);
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   174
	&antsInfo("$model: normal-distr. hypothesis disproved at $sign%% sign. level");
A.M. Thurnherr <athurnherr@yahoo.com>
parents:
diff changeset
   175
}