diff --git a/.github/workflows/all_tests_nnpdf.yml b/.github/workflows/all_tests_nnpdf.yml index f61f4764c1..ea0f882457 100644 --- a/.github/workflows/all_tests_nnpdf.yml +++ b/.github/workflows/all_tests_nnpdf.yml @@ -103,7 +103,11 @@ jobs: sudo rm -rf /opt/hostedtoolcache/Python/{3.9*} sudo rm -rf /opt/hostedtoolcache/CodeQL sudo rm -rf /usr/local/lib/android/sdk - pip install .[nolha,torch] + # torch 2.12.0 pulls triton 3.7.0, whose libtriton C extension segfaults + # at import on CPU-only Linux + CPython 3.13. Pinning torch<2.12 also + # pins triton to 3.6.x. Remove this pin once the upstream issue is + # resolved. + pip install ".[nolha,torch]" "torch<2.12" # Since there is no LHAPDF in the system, initialize the folder and download pdfsets.index lhapdf-management update --init - name: Test we can run one runcard diff --git a/doc/sphinx/source/n3fit/runcard_detailed.rst b/doc/sphinx/source/n3fit/runcard_detailed.rst index f5ea1643eb..0db00dfaad 100644 --- a/doc/sphinx/source/n3fit/runcard_detailed.rst +++ b/doc/sphinx/source/n3fit/runcard_detailed.rst @@ -429,6 +429,12 @@ according to their experiment. Additionally, the union of these two is saved in ``/replica_/datacuts_theory_fitting_pseudodata_table.csv`` if one is not interested in the exact nature of the splitting. +When ``diagonal_basis: true`` is used (by default), the saved pseudodata indices are labeled as +``eigenmode `` corresponding to the diagonal basis used in the fit. ``vp-setupfit`` writes one +file with the diagonal-basis elements under: +``/tables/diagonal_basis_rotation.csv``. +This file stores both the eigenvalues and eigenvectors used for the rotation. + Imposing sum rules ^^^^^^^^^^^^^^^^^^ diff --git a/n3fit/src/n3fit/scripts/vp_setupfit.py b/n3fit/src/n3fit/scripts/vp_setupfit.py index 8ed0d8766a..a5ba367d10 100644 --- a/n3fit/src/n3fit/scripts/vp_setupfit.py +++ b/n3fit/src/n3fit/scripts/vp_setupfit.py @@ -25,6 +25,7 @@ # top. +import copy import hashlib import logging import pathlib @@ -54,9 +55,10 @@ 'validphys.results', 'validphys.theorycovariance.construction', 'validphys.photon.compute', + 'validphys.n3fit_data', ] -SETUPFIT_DEFAULTS = dict(use_cuts='internal') +SETUPFIT_DEFAULTS = dict(use_cuts='internal', use_t0=True) log = logging.getLogger(__name__) @@ -141,6 +143,9 @@ class SetupFitConfig(Config): @classmethod def from_yaml(cls, o, *args, **kwargs): + # Create a fresh copy of the fixed config to avoid in-place modifications + fixed_config = copy.deepcopy(SETUPFIT_FIXED_CONFIG) + try: file_content = yaml_safe.load(o) except error.YAMLError as e: @@ -156,10 +161,10 @@ def from_yaml(cls, o, *args, **kwargs): # Use faketheoryid to create the L0 data to be stored into the filter folder # (L1 data is stored if fakedata is True) if 'faketheoryid' in closuredict: - # make sure theory key exists in SETUPFIT_FIXED_CONFIG - SETUPFIT_FIXED_CONFIG.setdefault('theory', {}) + # make sure theory key exists in fixed_config + fixed_config.setdefault('theory', {}) # overwrite theoryid with the faketheoryid - SETUPFIT_FIXED_CONFIG['theory']['theoryid'] = closuredict['faketheoryid'] + fixed_config['theory']['theoryid'] = closuredict['faketheoryid'] # download theoryid since it will be used in the fit try: loader.check_theoryID(file_content['theory']['theoryid']) @@ -171,8 +176,14 @@ def from_yaml(cls, o, *args, **kwargs): filter_action = 'datacuts::theory::fitting filter' check_n3fit_action = 'datacuts::theory::fitting n3fit_checks_action' + # Add rotation action for the total covariance matrix + if file_content.get('theorycovmatconfig') is not None: + rotation_action = 'datacuts::theory::theorycovmatconfig fitting_covmat_table' + else: + rotation_action = 'datacuts::theory fitting_covmat_table' + # The settings for these actions depend on the presence of closuretest - SETUPFIT_FIXED_CONFIG['actions_'] += [check_n3fit_action, filter_action] + fixed_config['actions_'] += [check_n3fit_action, filter_action, rotation_action] # Check theory covariance matrix configuration thconfig = file_content.get('theorycovmatconfig', {}) @@ -184,7 +195,7 @@ def from_yaml(cls, o, *args, **kwargs): "`point_prescriptions: ['9 point', '3 point']`" ) if thconfig: - SETUPFIT_FIXED_CONFIG['actions_'].append( + fixed_config['actions_'].append( 'datacuts::theory::theorycovmatconfig nnfit_theory_covmat' ) @@ -214,14 +225,14 @@ def from_yaml(cls, o, *args, **kwargs): if compute_in_setupfit: log.info("Forcing photon computation with FiatLux during setupfit.") # Since the photon will be computed, check that the luxset and additional_errors exist - SETUPFIT_FIXED_CONFIG['actions_'].append('fiatlux check_luxset_exists') + fixed_config['actions_'].append('fiatlux check_luxset_exists') if fiatlux.get("additional_errors"): - SETUPFIT_FIXED_CONFIG['actions_'].append('fiatlux check_additional_errors') - SETUPFIT_FIXED_CONFIG['actions_'].append('fiatlux::theory compute_photon_to_disk') + fixed_config['actions_'].append('fiatlux check_additional_errors') + fixed_config['actions_'].append('fiatlux::theory compute_photon_to_disk') # Check positivity bound if file_content.get('positivity_bound') is not None: - SETUPFIT_FIXED_CONFIG['actions_'].append('positivity_bound check_unpolarized_bc') + fixed_config['actions_'].append('positivity_bound check_unpolarized_bc') # Check hyperscan trials_config = file_content.get('trial_specs', {}) @@ -233,7 +244,7 @@ def from_yaml(cls, o, *args, **kwargs): file_content.setdefault(k, v) # Update file content with fixed configuration - file_content.update(SETUPFIT_FIXED_CONFIG) + file_content.update(fixed_config) return cls(file_content, *args, **kwargs) diff --git a/n3fit/src/n3fit/tests/test_fit.py b/n3fit/src/n3fit/tests/test_fit.py index c7f10e3faf..088c797000 100644 --- a/n3fit/src/n3fit/tests/test_fit.py +++ b/n3fit/src/n3fit/tests/test_fit.py @@ -283,8 +283,11 @@ def test_parallel_against_sequential(tmp_path, rep_from=6, rep_to=8): "ATLAS_TTBAR_8TEV_TOT_X-SEC", "CMS_SINGLETOP_13TEV_TCHANNEL-XSEC", ] - dataset_inputs = [{"dataset": d, "frac": 0.6, "variant": "legacy"} for d in datasets] + dataset_inputs = [{"dataset": d, "variant": "legacy"} for d in datasets] n3fit_input["dataset_inputs"] = dataset_inputs + # Using diaogonal basis + n3fit_input["diagonal_basis"] = True + n3fit_input["diagonal_frac"] = 0.5 # Exit inmediately n3fit_input["parameters"]["epochs"] = 1 # Save pseudodata @@ -311,8 +314,9 @@ def test_parallel_against_sequential(tmp_path, rep_from=6, rep_to=8): for csvfile_seq in folder_seq.glob("*/*.csv"): csvfile_par = folder_par / csvfile_seq.relative_to(folder_seq) - result_seq = pd.read_csv(csvfile_seq, sep="\t", index_col=[0, 1, 2], header=0) - result_par = pd.read_csv(csvfile_par, sep="\t", index_col=[0, 1, 2], header=0) + # Diagonal basis writes single-index csv files + result_seq = pd.read_csv(csvfile_seq, sep="\t", index_col=[0], header=0) + result_par = pd.read_csv(csvfile_par, sep="\t", index_col=[0], header=0) pd.testing.assert_frame_equal(result_seq, result_par) # Check the rest of the fit, while numerical differences are expected between sequential diff --git a/validphys2/src/validphys/config.py b/validphys2/src/validphys/config.py index 910fc1fd7b..0d841bd6ad 100644 --- a/validphys2/src/validphys/config.py +++ b/validphys2/src/validphys/config.py @@ -812,10 +812,11 @@ def produce_dataset_inputs_fitting_covmat(self, use_thcovmat_in_fitting=False): separate the multiplcative errors and whether to compute the experimental covmat using the t0 prescription. """ + from validphys import covmats if use_thcovmat_in_fitting: - return covmats.dataset_inputs_t0_total_covmat + return covmats.dataset_load_inputs_t0_total_covmat return covmats.dataset_inputs_t0_exp_covmat def produce_sep_mult(self, separate_multiplicative=False): @@ -851,9 +852,9 @@ def produce_dataset_inputs_sampling_covmat( if use_t0_sampling: if use_thcovmat_in_sampling: if sep_mult: - return covmats.dataset_inputs_t0_total_covmat_separate + return covmats.dataset_load_inputs_t0_total_covmat_separate else: - return covmats.dataset_inputs_t0_total_covmat + return covmats.dataset_load_inputs_t0_total_covmat else: if sep_mult: return covmats.dataset_inputs_t0_exp_covmat_separate @@ -863,9 +864,9 @@ def produce_dataset_inputs_sampling_covmat( else: if use_thcovmat_in_sampling: if sep_mult: - return covmats.dataset_inputs_total_covmat_separate + return covmats.dataset_load_inputs_total_covmat_separate else: - return covmats.dataset_inputs_total_covmat + return covmats.dataset_load_inputs_total_covmat else: if sep_mult: return covmats.dataset_inputs_exp_covmat_separate @@ -885,6 +886,7 @@ def produce_loaded_theory_covmat( Loads the theory covmat from the correct file according to how it was generated by vp-setupfit. """ + if not use_thcovmat_in_sampling and not use_thcovmat_in_fitting: return 0.0 # Load correct file according to how the thcovmat was generated by vp-setupfit @@ -1328,6 +1330,7 @@ def produce_nnfit_theory_covmat( This function is only used in vp-setupfit to store the necessary covmats as .csv files in the tables directory. """ + if point_prescriptions is not None: if user_covmat_path is not None: # Both scalevar and user uncertainties diff --git a/validphys2/src/validphys/covmats.py b/validphys2/src/validphys/covmats.py index 195371ad5d..7de450dcc0 100644 --- a/validphys2/src/validphys/covmats.py +++ b/validphys2/src/validphys/covmats.py @@ -225,6 +225,7 @@ def dataset_inputs_covmat_from_systematics( covmat = (covmat / sqrt_weights).T / sqrt_weights if norm_threshold is not None: covmat = regularize_covmat(covmat, norm_threshold=norm_threshold) + return covmat @@ -405,7 +406,7 @@ def dataset_inputs_t0_covmat_from_systematics( ) -def dataset_inputs_t0_total_covmat_separate( +def dataset_load_inputs_t0_total_covmat_separate( dataset_inputs_t0_exp_covmat_separate, loaded_theory_covmat ): """ @@ -416,6 +417,17 @@ def dataset_inputs_t0_total_covmat_separate( return dataset_inputs_t0_exp_covmat_separate + loaded_theory_covmat +def dataset_inputs_t0_total_covmat_separate( + dataset_inputs_t0_exp_covmat_separate, nnfit_theory_covmat +): + """ + Function to compute the covmat to be used for the sampling by make_replica. + In this case the t0 prescription is used for the experimental covmat and the multiplicative + errors are separated. Moreover, the theory covmat is added to experimental covmat. + """ + return dataset_inputs_t0_exp_covmat_separate + nnfit_theory_covmat + + def dataset_inputs_t0_exp_covmat_separate( dataset_inputs_loaded_cd_with_cuts, *, @@ -440,7 +452,9 @@ def dataset_inputs_t0_exp_covmat_separate( return covmat -def dataset_inputs_total_covmat_separate(dataset_inputs_exp_covmat_separate, loaded_theory_covmat): +def dataset_load_inputs_total_covmat_separate( + dataset_inputs_exp_covmat_separate, loaded_theory_covmat +): """ Function to compute the covmat to be used for the sampling by make_replica. In this case the t0 prescription is not used for the experimental covmat and the multiplicative @@ -449,6 +463,15 @@ def dataset_inputs_total_covmat_separate(dataset_inputs_exp_covmat_separate, loa return dataset_inputs_exp_covmat_separate + loaded_theory_covmat +def dataset_inputs_total_covmat_separate(dataset_inputs_exp_covmat_separate, nnfit_theory_covmat): + """ + Function to compute the covmat to be used for the sampling by make_replica. + In this case the t0 prescription is not used for the experimental covmat and the multiplicative + errors are separated. Moreover, the theory covmat is added to experimental covmat. + """ + return dataset_inputs_exp_covmat_separate + nnfit_theory_covmat + + def dataset_inputs_exp_covmat_separate( dataset_inputs_loaded_cd_with_cuts, *, @@ -472,7 +495,17 @@ def dataset_inputs_exp_covmat_separate( return covmat -def dataset_inputs_t0_total_covmat(dataset_inputs_t0_exp_covmat, loaded_theory_covmat): +def dataset_inputs_t0_total_covmat(dataset_inputs_t0_exp_covmat, nnfit_theory_covmat): + """ + Function to compute the covmat to be used for the sampling by make_replica and for the chi2 + by fitting_data_dict. In this case the t0 prescription is used for the experimental covmat + and the multiplicative errors are included in it. Moreover, the theory covmat is added to experimental covmat. + """ + + return dataset_inputs_t0_exp_covmat + nnfit_theory_covmat + + +def dataset_load_inputs_t0_total_covmat(dataset_inputs_t0_exp_covmat, loaded_theory_covmat): """ Function to compute the covmat to be used for the sampling by make_replica and for the chi2 by fitting_data_dict. In this case the t0 prescription is used for the experimental covmat @@ -502,10 +535,11 @@ def dataset_inputs_t0_exp_covmat( dataset_inputs_t0_predictions, False, ) + return covmat -def dataset_inputs_total_covmat(dataset_inputs_exp_covmat, loaded_theory_covmat): +def dataset_load_inputs_total_covmat(dataset_inputs_exp_covmat, loaded_theory_covmat): """ Function to compute the covmat to be used for the sampling by make_replica and for the chi2 by fitting_data_dict. In this case the t0 prescription is not used for the experimental covmat @@ -514,6 +548,15 @@ def dataset_inputs_total_covmat(dataset_inputs_exp_covmat, loaded_theory_covmat) return dataset_inputs_exp_covmat + loaded_theory_covmat +def dataset_inputs_total_covmat(dataset_inputs_exp_covmat, nnfit_theory_covmat): + """ + Function to compute the covmat to be used for the sampling by make_replica and for the chi2 + by fitting_data_dict. In this case the t0 prescription is not used for the experimental covmat + and the multiplicative errors are included in it. Moreover, the theory covmat is added to experimental covmat. + """ + return dataset_inputs_exp_covmat + nnfit_theory_covmat + + def dataset_inputs_exp_covmat( dataset_inputs_loaded_cd_with_cuts, *, diff --git a/validphys2/src/validphys/n3fit_data.py b/validphys2/src/validphys/n3fit_data.py index d49df31f07..c49ef0e461 100644 --- a/validphys2/src/validphys/n3fit_data.py +++ b/validphys2/src/validphys/n3fit_data.py @@ -171,12 +171,12 @@ def __init__(self, group_name, seed, tr_masks, vl_masks): super().__init__(group_name, seed) -def diagonal_masks(data, replica_trvlseed, dataset_inputs_fitting_covmat, diagonal_frac=0.75): +def diagonal_masks(data, replica_trvlseed, dataset_inputs_covmat_t0_considered, diagonal_frac=0.75): nameseed = int(hashlib.sha256(str(data).encode()).hexdigest(), 16) % 10**8 nameseed += replica_trvlseed rng = np.random.Generator(np.random.PCG64(nameseed)) - ndata = len(dataset_inputs_fitting_covmat) + ndata = len(dataset_inputs_covmat_t0_considered) # construct training mask by selecting a fraction of the eigenvalues trmax = int(ndata * diagonal_frac) @@ -319,18 +319,96 @@ def _hashed_dataset_inputs_fitting_covmat(dataset_inputs_fitting_covmat) -> Hash @functools.lru_cache -def _inv_covmat_prepared(_hashed_dataset_inputs_fitting_covmat, diagonal_basis=True): - """Returns the inverse covmats for training, validation and total - attending to the right masks and whether it is diagonal or not. +def _inv_covmat_prepared( + _hashed_dataset_inputs_fitting_covmat, + output_path, + use_thcovmat_in_fitting=False, + diagonal_basis=True, +): + """Prepare the covariance matrix and its inverse, optionally transforming to diagonal basis. - Since the masks and number of datapoints need to be treated for 1-point datasets - it also returns the right ndata and masks for training and validation: + Parameters + ---------- + _hashed_dataset_inputs_fitting_covmat : Hashrray + Wrapped covariance matrix for caching purposes. + output_path : Path + Path to output directory containing diagonal basis data if needed. + diagonal_basis : bool, optional + If True, load pre-computed diagonal basis from tables. If False, use the + covariance matrix directly and compute the inverse via correlation matrix + inversion. Default is True. + Returns + ------- + covmat : np.ndarray + The covariance matrix (diagonal if diagonal_basis=True, full otherwise). + inv_total : np.ndarray + The inverse of the covariance matrix. + diag_rot : np.ndarray or None + The rotation matrix (eigenvectors transposed) for diagonal basis transformation. + Only returned when diagonal_basis=True, otherwise None. + eig_vals : np.ndarray or None + The eigenvalues of the correlation matrix. Only returned when + diagonal_basis=True, otherwise None. """ log.info( - f"_inv_covmat_prepared called with covmat hash={hash(_hashed_dataset_inputs_fitting_covmat)}, diagonal_basis={diagonal_basis}" + f"_inv_covmat_prepared called with covmat hash={hash(_hashed_dataset_inputs_fitting_covmat)}" ) - covmat = _hashed_dataset_inputs_fitting_covmat.array + + diag_rot = None + eig_vals = None + + if diagonal_basis: + if use_thcovmat_in_fitting: + diagonal_basis_saved = "datacuts_theory_theorycovmatconfig_fitting_covmat_table.csv" + else: + diagonal_basis_saved = "datacuts_theory_fitting_covmat_table.csv" + path_diagonal_basis = output_path / "tables" / diagonal_basis_saved + eigensystem = pd.read_csv( + path_diagonal_basis, index_col=[0], header=[0], sep="\t|,", engine="python" + ) + diag_rot = eigensystem.iloc[:, 1:].values + eig_vals = eigensystem["eig_val"].values + covmat = np.diag(eig_vals) + inv_total = np.diag(1 / eig_vals) + else: + covmat = _hashed_dataset_inputs_fitting_covmat.array + diag_inv_sqrt_total = 1 / np.sqrt(np.diag(covmat)) + cormat_total = np.einsum("i, ij, j -> ij", diag_inv_sqrt_total, covmat, diag_inv_sqrt_total) + inv_total = ( + np.diag(diag_inv_sqrt_total) + @ np.linalg.inv(cormat_total) + @ np.diag(diag_inv_sqrt_total) + ) + + return covmat, inv_total, diag_rot, eig_vals + + +def _fiting_covmat(dataset_inputs_fitting_covmat, diagonal_basis=True): + """Prepare the fitting covariance matrix by optionally adding theory contributions + and transforming to diagonal basis. + + Parameters + ---------- + dataset_inputs_fitting_covmat : np.ndarray + The experimental covariance matrix from the datasets. + diagonal_basis : bool, optional + If True, transform the covariance matrix to diagonal basis by extracting + eigenvalues and eigenvectors of the correlation matrix. Default is True. + + Returns + ------- + covmat : np.ndarray + The prepared covariance matrix (sum of experimental and theory covmats). + diagonal_rotation : np.ndarray or None + The rotation matrix (transposed eigenvectors) to transform data to diagonal basis. + Only returned if diagonal_basis=True, otherwise None. + eig_vals : np.ndarray or None + The eigenvalues of the correlation matrix in diagonal basis. + Only returned if diagonal_basis=True, otherwise None. + """ + + covmat = dataset_inputs_fitting_covmat diagonal_rotation = None eig_vals = None @@ -346,21 +424,7 @@ def _inv_covmat_prepared(_hashed_dataset_inputs_fitting_covmat, diagonal_basis=T uT = np.einsum("i, ik -> ik", diag_inv_sqrt, uT) diagonal_rotation = uT.T - ndata = len(eig_vals) - - inv_total = np.diag(1 / eig_vals) - - else: - - diag_inv_sqrt_total = 1 / np.sqrt(np.diag(covmat)) - cormat_total = np.einsum("i, ij, j -> ij", diag_inv_sqrt_total, covmat, diag_inv_sqrt_total) - inv_total = ( - np.diag(diag_inv_sqrt_total) - @ np.linalg.inv(cormat_total) - @ np.diag(diag_inv_sqrt_total) - ) - - return (covmat, inv_total, diagonal_rotation, eig_vals) + return covmat, diagonal_rotation, eig_vals def fitting_data_dict( @@ -371,7 +435,9 @@ def fitting_data_dict( _inv_covmat_prepared, kfold_masks, fittable_datasets_masked, + output_path, threshold=0.0, + diagonal_basis=True, ): """ Provider which takes the information from validphys ``data``. @@ -420,7 +486,7 @@ def fitting_data_dict( expdata = make_replica fittable_datasets = fittable_datasets_masked - # all covmat manipulation is shared across the replicas for memory purposes + # load covmat stored at the time of vp-setupfit covmat, inv_true, diag_rot, eig_vals = _inv_covmat_prepared # get the masks - different for each replica so fine to call here @@ -548,6 +614,27 @@ def fitting_data_dict( exps_fitting_data_dict = collect("fitting_data_dict", ("group_dataset_inputs_by_metadata",)) +@table +def fitting_covmat_table(output_path, _fiting_covmat, data_index, diagonal_basis=True): + """ + Stores the fitting covariance matrix if diagonal_basis is False, else store the rotation matrix and eigenvalues + """ + covmat, diagonal_rotation, eig_vals = _fiting_covmat + + if not diagonal_basis: + log.info("Saving fitting covmat") + if not hasattr(covmat, "index"): + return pd.DataFrame(covmat, index=data_index, columns=data_index) + else: + return covmat + + df_rotation = pd.DataFrame(diagonal_rotation) + df_rotation.insert(0, "eig_val", eig_vals) + df_rotation.index = pd.Index([f"eigenmode {i}" for i in range(len(eig_vals))]) + log.info("Saving diagonal-basis rotation table") + return df_rotation + + def replica_nnseed_fitting_data_dict(replica, exps_fitting_data_dict, replica_nnseed): """For a single replica return a tuple of the inputs to this function. Used with `collect` over replicas to avoid having to perform multiple @@ -575,7 +662,17 @@ def replica_nnseed_fitting_data_dict(replica, exps_fitting_data_dict, replica_nn ) -def replica_pseudodata(experiment_indexed_make_replica, replica): +def diagonal_indexed_make_replica(indexed_make_replica, fitting_data_dict): + """Rotate one group pseudodata block to the diagonal basis.""" + values = indexed_make_replica.iloc[:, 0].to_numpy() + diag_rot = fitting_data_dict.get("data_transformation") + rotated_values = values if diag_rot is None else diag_rot @ values + return pd.DataFrame(rotated_values, columns=["data"]) + + +def replica_pseudodata( + experiment_indexed_make_replica, diagonal_indexed_make_replica, replica, diagonal_basis=True +): """Creates a pandas DataFrame containing the generated pseudodata. The index is :py:func:`validphys.results.experiments_index` and the columns is the replica numbers. @@ -586,8 +683,16 @@ def replica_pseudodata(experiment_indexed_make_replica, replica): `fitting::savepseudodata` is `true` (as per the default setting) The table can be found in the replica folder i.e. /nnfit/replica_*/ """ - df = pd.concat(experiment_indexed_make_replica) - df.columns = [f"replica {replica}"] + replica_column = f"replica {replica}" + + if not diagonal_basis: + df = pd.concat(experiment_indexed_make_replica) + df.columns = [replica_column] + return df + + df = diagonal_indexed_make_replica.copy() + df.columns = [replica_column] + df.index = pd.Index([f"eigenmode {i}" for i in range(len(df))]) return df diff --git a/validphys2/src/validphys/pseudodata.py b/validphys2/src/validphys/pseudodata.py index de7dd36c69..96126f9974 100644 --- a/validphys2/src/validphys/pseudodata.py +++ b/validphys2/src/validphys/pseudodata.py @@ -195,8 +195,7 @@ def make_replica( # Set random seed rng = np.random.default_rng(seed=group_replica_mcseed) # construct covmat - covmat = dataset_inputs_sampling_covmat - covmat_sqrt = sqrt_covmat(covmat) + covmat_sqrt = sqrt_covmat(dataset_inputs_sampling_covmat) full_mask = ( group_positivity_mask @@ -224,7 +223,7 @@ def make_replica( mult_shifts.append(mult_shift) # If sep_mult is true then the multiplicative shifts were not included in the covmat - shifts = covmat_sqrt @ rng.normal(size=covmat.shape[1]) + shifts = covmat_sqrt @ rng.normal(size=dataset_inputs_sampling_covmat.shape[1]) mult_part = 1.0 if sep_mult: special_mult_errors = group_multiplicative_errors["special_mult"] @@ -432,11 +431,17 @@ def make_level1_data(data, level0_commondata_wc, filterseed, data_index, sep_mul ) # ================== generation of Level1 data ======================# - central_vals= central_values_array(level0_commondata_wc) + central_vals = central_values_array(level0_commondata_wc) group_mult_errs = group_multiplicative_errors(level0_commondata_wc, sep_mult=sep_mult) group_pos_mask = group_positivity_mask(level0_commondata_wc) level1_data = make_replica( - central_vals, filterseed, covmat, group_multiplicative_errors=group_mult_errs, group_positivity_mask=group_pos_mask, sep_mult=sep_mult, genrep=True, + central_vals, + filterseed, + covmat, + group_multiplicative_errors=group_mult_errs, + group_positivity_mask=group_pos_mask, + sep_mult=sep_mult, + genrep=True, ) indexed_level1_data = indexed_make_replica(data_index, level1_data)