@@ -30,13 +30,6 @@ def unit_normalize(a, order=2, axis=-1):
3030 return a / np .expand_dims (l2 , axis )[0 ][0 ]
3131
3232
33- def float_eq (a , b ):
34- """
35- Test if two floats are almost equal to each other
36- """
37- return abs (a - b ) < 1e-10 * max (1e-5 , abs (a ), abs (b ))
38-
39-
4033def linear_interpol (x , x1 , x2 , y1 , y2 ):
4134 """
4235 Linearly interpolate to point x, between
@@ -353,7 +346,7 @@ def interp_smoothed_array_and_derivatives(
353346 return interps
354347
355348
356- def compare_l2 (depth , calc , obs ):
349+ def l2_norm_profiles (depth , calc , obs ):
357350 """
358351 Computes the L2 norm for N profiles at a time (assumed to be linear between points).
359352
@@ -369,91 +362,85 @@ def compare_l2(depth, calc, obs):
369362 """
370363 err = []
371364 for i in range (len (calc )):
372- err .append (l2 (depth , calc [i ], obs [i ]))
365+ err .append (l2_norm_profile (depth , calc [i ], obs [i ]))
373366
374367 return err
375368
376369
377- def compare_chifactor (calc , obs ):
370+ def chisqr_profiles (calc , obs ):
378371 """
379- Computes the chi factor for N profiles at a time. Assumes a 1% a priori uncertainty on the seismic model.
380-
372+ Computes the chisqr factor for N profiles at a time. Assumes a 1% a priori uncertainty on the seismic model.
381373
382374 :type calc: list of arrays of float
383375 :param calc: N arrays calculated values, e.g. [mat_vs,mat_vphi]
384376 :type obs: list of arrays of float
385- :param obs: N arrays of values (observed or calculated) to compare to , e.g. [seis_vs, seis_vphi]
377+ :param obs: N arrays of values (observed or calculated) to compare to, e.g. [seis_vs, seis_vphi]
386378
387379 :returns: error array of length N
388380 :rtype: array of floats
389381 """
390382 err = []
391383 for i in range (len (calc )):
392- err .append (chi_factor (calc [i ], obs [i ]))
384+ err .append (chisqr_profile (calc [i ], obs [i ]))
393385
394- return err
386+ return np . array ( err )
395387
396388
397- def l2 (x , funca , funcb ):
389+ def l2_norm_profile (x , funca , funcb ):
398390 """
399- Computes the L2 norm for one profile(assumed to be linear between points).
391+ Computes the L2 norm of the difference between two 1D profiles,
392+ assuming linear interpolation between points.
400393
401- :type x: array of float
402- :param x: depths :math:`[m]`.
403- :type funca: list of arrays of float
404- :param funca: array calculated values
405- :type funcb: list of arrays of float
406- :param funcb: array of values (observed or calculated) to compare to
394+ This is equivalent to the square root of the integrated squared
395+ difference between the two functions over the given depth range.
396+ The integration is performed using the trapezoidal rule.
407397
408- :returns: L2 norm
409- :rtype: array of floats
410- """
411- diff = np .array (funca - funcb )
412- diff = diff * diff
398+ :param x: Array of depth values [m], must be 1D and monotonically increasing.
399+ :type x: array-like of float
413400
414- return integrate .trapezoid (diff , x )
401+ :param funca: First profile (e.g., model or predicted values), must be same length as x.
402+ :type funca: array-like of float
415403
404+ :param funcb: Second profile (e.g., observed or reference values), same shape as funca.
405+ :type funcb: array-like of float
416406
417- def nrmse (x , funca , funcb ):
407+ :return: L2 norm (scalar)
408+ :rtype: float
418409 """
419- Normalized root mean square error for one profile
420- :type x: array of float
421- :param x: depths in m.
422- :type funca: list of arrays of float
423- :param funca: array calculated values
424- :type funcb: list of arrays of float
425- :param funcb: array of values (observed or calculated) to compare to
426-
427- :returns: RMS error
428- :rtype: array of floats
410+ diff = np .square (funca - funcb )
411+ return np .sqrt (integrate .trapezoid (diff , x ))
412+
413+
414+ def chisqr_profile (calc , obs , uncertainties = 0.01 ):
429415 """
430- diff = np .array (funca - funcb )
431- diff = diff * diff
432- rmse = np .sqrt (np .sum (diff ) / x )
433- nrmse = rmse / (np .max (funca ) - np .min (funca ))
416+ Computes the :math:`\\ chi^2` factor for a single profile, assuming a 1 %
417+ uncertainty on the reference (observed) values. This provides a normalized
418+ measure of the deviation between calculated and reference values.
434419
435- return nrmse
420+ The :math:` \\ chi^2` factor is calculated as:
436421
422+ .. math::
437423
438- def chi_factor (calc , obs ):
439- """
440- :math:`\\ chi` factor for one profile assuming 1% uncertainty on the reference model (obs)
441- :type calc: list of arrays of float
442- :param calc: array calculated values
443- :type obs: list of arrays of float
444- :param obs: array of reference values to compare to
424+ \\ chi^2 = \\ frac{1}{N} \\ sum_{i=1}^{N}
425+ \\ left( \\ frac{\\ text{calc}_i - \\ text{obs}_i}{0.01 \\ cdot \\ text{mean}(\\ text{obs})} \\ right)^2
445426
446- :returns: :math:`\\ chi` factor
447- :rtype: array of floats
448- """
427+ where :math:`N` is the number of elements in the profile.
449428
450- err = np .empty_like (calc )
451- for i in range (len (calc )):
452- err [i ] = pow ((calc [i ] - obs [i ]) / (0.01 * np .mean (obs )), 2.0 )
429+ :param calc: Array of calculated values (e.g., from a model).
430+ :type calc: array
453431
454- err_tot = np .sum (err ) / len (err )
432+ :param obs: Array of reference or observed values.
433+ :type obs: array
434+
435+ :param uncertainties: Array of uncertainties values.
436+ :type uncertainties: array or float
437+
438+ :return: The :math:`\\ chi^2` factor for the profile.
439+ :rtype: float
440+ """
455441
456- return err_tot
442+ err = np .square ((calc - obs ) / (uncertainties * np .mean (obs )))
443+ return np .sum (err ) / len (err )
457444
458445
459446def independent_row_indices (array ):
@@ -495,27 +482,33 @@ def array_to_rational_matrix(array):
495482
496483def complete_basis (basis , flip_columns = True ):
497484 """
498- Creates a full basis by filling remaining rows with
499- selected rows of the identity matrix that have indices
500- not in the column pivot list of the basis RREF
501-
502- :param basis: A partial basis
503- :type basis: numpy array
504- :param flip_columns: whether to calculate the RREF
505- from a flipped basis. This can be useful, for example,
506- when dependent columns are known to be further to the
507- right in the basis. defaults to True
485+ Extends a partial basis (with fewer rows than columns) to a full basis
486+ by adding rows from the identity matrix that are linearly independent
487+ of the existing rows.
488+
489+ This is done by computing the reduced row echelon form (RREF) of the basis
490+ to identify pivot columns. Identity rows corresponding to non-pivot columns
491+ are added to complete the basis.
492+
493+ :param basis: A 2D NumPy array representing a partial basis, with shape (n, m)
494+ where n < m.
495+ :type basis: numpy.ndarray
496+
497+ :param flip_columns: If True, the basis columns are flipped (reversed) before
498+ computing the RREF. This is helpful if the dependent columns
499+ are expected to appear later in the matrix. Default is True.
508500 :type flip_columns: bool, optional
509- :return: basis
510- :rtype: numpy array
511- """
512501
502+ :return: A completed basis as a NumPy array with shape (m, m), containing the
503+ original rows plus additional rows from the identity matrix.
504+ :rtype: numpy.ndarray
505+ """
513506 n , m = basis .shape
514507 if n < m :
515508 if flip_columns :
516509 pivots = list (m - 1 - np .array (Matrix (np .flip (basis , axis = 1 )).rref ()[1 ]))
517510 else :
518- pivots = list (Matrix (basis )) .rref ()[1 ]
511+ pivots = list (Matrix (basis ).rref () )[1 ]
519512
520513 return np .concatenate (
521514 (basis , np .identity (m )[[i for i in range (m ) if i not in pivots ], :]), axis = 0
0 commit comments