问:
Problem implementing parallel fill of an array after ~4 hours of the code running (C++/ROOT)
I am trying to implement parallel processing to fill an array with results from a function that runs an mcmc. Every test (using less loops in the chain, and less parameters to fit) I've done indicates that everything is working, but for some reason I get the following error after ~4 hours of the code running (this has happened twice):

root.exe(821,0x700001891000) malloc: *** error for object 0x6000015f3690: pointer being freed was not allocated root.exe(821,0x700001685000) malloc: *** error for object 0x6000015f3600: pointer being freed was not allocated

Here is the snippet where the parallel processing is being implemented (please note that filling the array with the mh_mcmc function worked perfectly before, so I don't think that is the issue). I can post more of the code as well if that would help:

```<code>Mat<double> mcmc_results[paramBins][paramBins][paramBins]; // array to store output of MCMC
// now we fill the mcmc_results array using multiple threads
// parallelization follows this: https://root.cern/doc/master/mt201__parallelHistoFill_8C.html`

gROOT->SetBatch(); // Avoid unnecessary output
ROOT::EnableThreadSafety(); // Make ROOT thread-safe
const int nWorkers = 4; // Match number of threads to what the hardware can do (my laptop has 4 cores

auto workFunction = [&](int k){

    arma::Mat<double> paramVals(paramBins, 3); paramVals = getParamVals();
    arma::Col<double> t23_col = paramVals.col(0);
    arma::Col<double> dmsq31_col = paramVals.col(1);
    arma::Col<double> dCP_col = paramVals.col(2);

    arma::Col<double> E_nu = getEnergyVals();

    for(int i=0; i<paramBins; i++){ // theta23
        cout << "i = " << i << endl;
        for(int j=0; j<paramBins; j++){ // dmsq31
            cout << "j = " << j << endl;

            arma::Col<double> params_obs = {t23_col(i),dmsq31_col(j),dCP_col(k)};
            mcmc_results[i][j][k] = mh_mcmc(params_obs, params_obs, E_nu, nu_flavor, NuOrAnti, muon_polarization, N_loops, param_cov);

        }
    }
};

// Create worker threads
std::vector<std::thread> workers;
for (auto k : ROOT::TSeqI(paramBins)){
    workers.emplace_back(workFunction, k);
}
// Make sure workers are done
for (auto &&worker : workers){
    worker.join();
}
</code>```

I am a physicist, NOT a programmer (this will likely be the first and last time I ever have to do this sort of thing) so I am not sure what is going wrong. I have tried googling my problem, but haven't seen anything similar. Could this mean that my laptop isn't capable of storing all of this information (like not enough RAM or something)? Or could someone point me in the correct direction?

EDIT: The code worked perfectly fine before I tried to implement parallelization, so I dont think the problem is in the mh_mcmc function (the function performs a metropolis hastings mcmc). Here is the entire code:

```    ''''
//
//  MH_MCMC.cpp
//
//
//  Created by Grace Reesman on 12/5/22.
//

#include "NeutrinoFactory_MCMC.hpp"
#include "/Users/greesman/Desktop/NeutrinoFactory/Code/NeutrinoFactory.hpp"

#include <stdio.h>
#include <cmath> // math stuff
#include <complex>
#include <algorithm>
#include <cassert> // use the "assert" function
#include <cstddef>
#include <tgmath.h>
#include <vector> // to define std::vec
#include <iostream> // for cout/endl stuff (i think)
#include <fstream> // for cout/endl stuff (i think)
#include </opt/local/include/armadillo>
#include <limits> // this is to "define" infinity
//#include </Users/greesman/opt/anaconda3/pkgs/llvm-openmp-12.0.0-h0dcd299_1/include/omp.h> // parallel processing

// ROOT stuff to include
#include <TH3D.h> // 2D histograms
#include <TH2D.h> // 2D histograms
#include <TH1D.h> // 1D histograms
#include <TF1.h> // 1D functions
#include <TF2.h> // 2D functions
#include <TRandom3.h> // random numbers
#include <TLatex.h>
#include <TCanvas.h>
#include <TLegend.h>
#include <TStyle.h>
#include <TFile.h>
#include <TGraph.h> // 1D graphs
#include <TGraph2D.h> // 2D graphs
#include <TFrame.h>
//#include <ROOT/TProcessExecutor.hxx> // parallel processing
#include <ROOT/TSeq.hxx> // for sequences
//#include <ROOT/TExecutor.hxx> // executing parallel processing
//#include <TThread.h>
#include <ROOT/RDataFrame.hxx>
#include <ROOT/RVec.hxx>

using namespace std;
using namespace arma;

Mat<double> getParamVals(){
    //std::cout << "Getting column vectors of parameter values..." << std::endl;
    // defining column vectors that will have paramBins entries each, where the values are uniform over the 3sigma nuFit estimates
    Col<double> dCP_col(paramBins, fill::zeros), t23_col(paramBins, fill::zeros), dmsq31_col(paramBins, fill::zeros);

    // setting minimum values
    dCP_col(0) = deltaCP_min;
    t23_col(0) = t23_min;
    dmsq31_col(0) = dmsq31_min;

    for(int i=1; i<paramBins; i++){ // filling the column vectors
        dCP_col(i) = dCP_col(i-1) + (deltaCP_max-deltaCP_min)/paramBins;
        t23_col(i) = t23_col(i-1) + (t23_max-t23_min)/paramBins;
        dmsq31_col(i) = dmsq31_col(i-1) + (dmsq31_max-dmsq31_min)/paramBins;
    }

    Mat<double> paramVals(paramBins, 3); // define a matrix that is MxN where M = number of parameters and N = number of param bins
    paramVals.col(0) = t23_col;
    paramVals.col(1) = dmsq31_col;
    paramVals.col(2) = dCP_col;

    return paramVals;
}

Col<double> getEnergyVals(){
    //std::cout << "Getting column vector of neutrino energies..." << std::endl;
    Col<double> E_nu(energyBins, fill::zeros); // defining and initializing a column vector to store energy values
    E_nu(0) = minEnergy; // setting the starting energy to the minimum energy
    for(int i = 1; i<energyBins; i++){
        E_nu(i) = E_nu(i-1) + step_size; // writing to neutrino energy column
    }
    return E_nu;
}

double radians(double y){ // degrees to radians
    return y * (M_PI / 180);
}

double normal_pdf(double x, double sigma, double x0) {
       double tmp = (x-x0)/sigma;
       return (1.0/(std::sqrt(2 * M_PI) * std::fabs(sigma))) * std::exp(-tmp*tmp/2);
    }

// function that returns the model predictions
double get_model_predictions(Col<double> theta, double energy, int nu_flavor, int NuOrAntiNu, int mu_pol){
    // theta contains values of oscillation parameters of interest: theta(0) = theta23, theta(1) = delta m^2_{31}, theta(2) = delta_{CP}
    // energy is neutrino energy
    // nu_flavor is the neutrino flavor (or rather, the corresponding lepton) we want to look for in the far detector
    // NuOrAntiNu is 1 if neutrino, -1 if anti neutrino
    // mu_pol is muon polarization

    assert (nu_flavor >= 0 && nu_flavor <= 2); // nu_flavor valid for 0 (electron flavored), 1 (muon flavored), 2 (tau flavored)
    assert (NuOrAntiNu == -1 || NuOrAntiNu == 1); // NuOrAntiNu valid for -1 (anti-neutrino), 1 (neutrino)
    assert (mu_pol >= -1 && mu_pol <= 1); // muon polarization valid between -1 and 1

    double matter_potential = NuOrAntiNu*Yrho*Y_to_a*energy;

    // calculate the expected flux each neutrino flavor
    double ExpectFlux_NuE = Flux::diffFlux(0, NuOrAntiNu,mu_pol,energy)*Exact::Palphabeta(0,nu_flavor,matter_potential,L,energy,t12,theta(0),t13,Dmsq21,theta(1),NuOrAntiNu*theta(2));
    double ExpectFlux_NuMu = Flux::diffFlux(1, NuOrAntiNu, mu_pol, energy)*Exact::Palphabeta(1,nu_flavor,matter_potential,L,energy,t12,theta(0),t13,Dmsq21,theta(1),NuOrAntiNu*theta(2));
    double ExpectFlux_NuTau = Flux::diffFlux(2, NuOrAntiNu, mu_pol, energy)*Exact::Palphabeta(2,nu_flavor,matter_potential,L,energy,t12,theta(0),t13,Dmsq21,theta(1),NuOrAntiNu*theta(2)); // should be zero

    double ExpectCCXSec = CrossSection::sigma_nu(energy, NuOrAntiNu);
    return ExpectCCXSec*(ExpectFlux_NuE+ExpectFlux_NuMu+ExpectFlux_NuTau);
}

// function that returns the log of the likelihood
double lnlikelihood(Col<double> params_theory, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol){

    double lnl = 0; // initializing the log likelihood

    assert(params_theory.n_elem == params_obs.n_elem); // make sure the two column vectors containing the parameters are the same size

    for(uword i=0; i<x_energy.n_elem; i++){

        double model_pred_theory = get_model_predictions(params_theory,x_energy(i),nu_flavor,NuOrAntiNu,mu_pol);
        double model_pred_obs = get_model_predictions(params_obs,x_energy(i),nu_flavor,NuOrAntiNu,mu_pol);

        lnl +=  -0.5*pow((model_pred_obs-model_pred_theory),2)/pow(sqrt(model_pred_obs),2); // add term to log likelihood
    }

    return lnl; // return the log of the likelihood
}

// function that calculates the log of the prior
double lnprior(Col<double> theta){

    double t23_input = theta(0);
    double dmsq31_input = theta(1);
    double dCP_input = theta(2);

    double lnp;

    double t23_prior = normal_pdf(t23_input,3*t23_1sig,t23);
    double dmsq31_prior = normal_pdf(dmsq31_input,3*dmsq31_1sig,Dmsq31);
    //+0.3*normal_pdf(-dmsq31_input,3*dmsq31_1sig,Dmsq31); // this is broken up into two parts so that we can see if we get any info about inverted ordering
    double dCP_prior = normal_pdf(dCP_input,3*dCP_1sig,deltaCP);

    if((t23_input<t23_zeroBelow)||(t23_input>t23_zeroAbove)||(dmsq31_input<dmsq31_zeroBelow)||(dmsq31_input>dmsq31_zeroAbove)||(dCP_input<dCP_zeroBelow)||(dCP_input>dCP_zeroAbove)){
        lnp = -infty;
    }
    else{
        lnp = log(t23_prior)+log(dmsq31_prior)+log(dCP_prior);
    }
    return lnp;
}

// test function that calculates the log of the unnormalized posterior
double lnposterior(Col<double> params_theory, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol){

    double lnl = lnlikelihood(params_theory,params_obs,x_energy,nu_flavor,NuOrAntiNu,mu_pol);
    double lnp = lnprior(params_theory);
    double lnpost;

    if((lnp<=-infty/(10e15))||(lnl<=-infty/(10e15))){
        lnpost = -infty;
    }
    else{
        lnpost = lnl + lnp;
    }
    return lnpost;
}

// function to calculate the Hastings ratio
double hastings_ratio(Col<double> params_theory1, Col<double> params_theory2, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol){

    double lnpost1 = lnposterior(params_theory1, params_obs, x_energy, nu_flavor, NuOrAntiNu, mu_pol);
    double lnpost2 = lnposterior(params_theory2, params_obs, x_energy, nu_flavor, NuOrAntiNu, mu_pol);
    double h_ratio;

    if((lnpost1 <= -infty/(10e15)) || (lnpost2 <= -infty/(10e15))){
        h_ratio =  -infty;
    }
    else{
        h_ratio = exp(lnpost1-lnpost2);
    }
    //cout << "ln posteriors to compare: " << lnpost1 << "and" << lnpost2 << endl;
    return h_ratio;
}

// function to generate a proposed new position for MCMC chain
Mat<double> propose_jump(Col<double> theta, Mat<double> cov){

    arma::arma_rng::set_seed_random();
    const int N = theta.n_elem;
    Col<double> proposed_position(N);
    proposed_position= mvnrnd(theta, cov); // generate a matrix w/ random column vectors from a multivariate Gaussian (normal) distribution

    while((proposed_position(0)<t23_zeroBelow)||(proposed_position(0)>t23_zeroAbove)||(proposed_position(1)<dmsq31_zeroBelow)||(proposed_position(1)>dmsq31_zeroAbove)||(proposed_position(2)<dCP_zeroBelow)||(proposed_position(2)>dCP_zeroAbove)){
        proposed_position = mvnrnd(theta, cov);
    }
    return proposed_position;
}

Mat<double> mh_mcmc(Col<double> params_theory, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol, int N_steps, Mat<double> cov){
    //arma::arma_rng::set_seed_random();

    // here we will define/initialize some matrices/col vecs that we want to return
    Mat<double> positions(N_steps+1,params_theory.n_elem); // define a matrix that is MxN where M = number of steps to take in MCMC chain and N = number of model parameters
    Col<double> lnpost_at_pos(N_steps+1); // column vector that stores log-posterior value at the position of the MCMC chain
    Col<double> acceptance_ratio(N_steps+1); // column vector that stores acceptance ratio of all previous steps in the chain

    positions.row(0) = trans(params_theory);
    lnpost_at_pos(0) = lnposterior(params_theory,params_obs,x_energy,nu_flavor,NuOrAntiNu,mu_pol);
    int accepted = 0;

    for(uword step=0; step<N_steps; step++){
        //bool check = FALSE;

        Col<double> theta_propose = propose_jump(trans(positions.row(step)),cov);
        //cout << "proposed step: " << endl; theta_propose.print();

        double hastings = hastings_ratio(theta_propose, trans(positions.row(step)), params_theory, x_energy, nu_flavor,NuOrAntiNu,mu_pol);
        //cout << "Hastings ratio for proposed step: " << hastings << endl;

        Col<double> rand_colvec(1,fill::randu); double p_rand = rand_colvec(0); // generating a random number in (0,1)
        //cout << "Random # to compare to hastings: " << p_rand << endl;

        if(hastings>=p_rand){
            positions.row(step+1) = trans(propose_jump(trans(positions.row(step)),cov));
            lnpost_at_pos(step+1) = lnposterior(trans(positions.row(step+1)),params_obs,x_energy,nu_flavor,NuOrAntiNu,mu_pol);
            accepted += 1;
            acceptance_ratio(step+1) = accepted/(step+1);
            //check = TRUE;
        }
        else{
            positions.row(step+1) = positions.row(step);
            lnpost_at_pos.row(step+1) = lnpost_at_pos(step);
            acceptance_ratio(step+1) = accepted/(step+1);
        }
        //cout << check << endl;
    }

    //cout << "Number of accepted positions: " << accepted << endl;
    Mat<double> returnMat(N_steps+1,5);
    returnMat.col(0) = positions.col(0);
    returnMat.col(1) = positions.col(1);
    returnMat.col(2) = positions.col(2);
    returnMat.col(3) = lnpost_at_pos;
    returnMat.col(4) = acceptance_ratio;

    return returnMat;
}

TGraph2D* mcmcPositions_graph(Mat<double> MCMC_results, int Nloops, int name1, int name2, int name3){
    assert(MCMC_results.n_rows == Nloops+1);

    Mat<double> MCMC_positions = MCMC_results.head_cols(3);

    double t23_mcmc_arr[Nloops+1], dmsq31_mcmc_arr[Nloops+1], dCP_mcmc_arr[Nloops+1];
    for(int i=0; i<Nloops+1; i++){
        t23_mcmc_arr[i] = 0;
        dmsq31_mcmc_arr[i] = 0;
        dCP_mcmc_arr[i] = 0;
    }
    for(int i=0; i<Nloops+1; i++){
        t23_mcmc_arr[i] = MCMC_positions(i,0);
        dmsq31_mcmc_arr[i] = MCMC_positions(i,1);
        dCP_mcmc_arr[i] = MCMC_positions(i,2);
    }

    auto param_mcmc_gr = new TGraph2D(Nloops+1,t23_mcmc_arr, dmsq31_mcmc_arr, dCP_mcmc_arr);
    param_mcmc_gr->SetName(Form("MCMCPositions%d%d%d",name1,name2,name3));
    param_mcmc_gr->SetTitle(Form("MCMCPositions%d%d%d",name1,name2,name3));
    param_mcmc_gr->GetXaxis()->SetTitle("#theta_{23}");
    param_mcmc_gr->GetYaxis()->SetTitle("#Delta m^2_{31}");
    param_mcmc_gr->GetZaxis()->SetTitle("#delta_{CP}");
    param_mcmc_gr->SetMarkerColorAlpha(4,0.25);
    param_mcmc_gr->SetMarkerStyle(21);

    return param_mcmc_gr;
}

TH3D* mcmcPositions_hist(Mat<double> MCMC_results, int Nloops){

    TGraph2D* mcmc_gr = mcmcPositions_graph(MCMC_results,Nloops,0,0,0);
    TH3D* mcmc_hist = new TH3D("mcmc_hist", Form("%s;%s;%s;%s", mcmc_gr->GetTitle(), mcmc_gr->GetXaxis()->GetTitle(), mcmc_gr->GetYaxis()->GetTitle(), mcmc_gr->GetZaxis()->GetTitle()),
                               paramBins, t23_min, t23_max,
                               paramBins, dmsq31_min, dmsq31_max,
                               paramBins, deltaCP_min, deltaCP_max);

    for (int i=0; i < mcmc_gr->GetN(); i++){ // setting bin contents to the TGraph values
        double t23_pt,dmsq31_pt,dCP_pt;
        mcmc_gr->GetPoint(i,t23_pt,dmsq31_pt,dCP_pt);
        mcmc_hist->Fill(t23_pt,dmsq31_pt,dCP_pt);
    }
    mcmc_hist->Scale(1/mcmc_hist->Integral("width")); // normalizing our histogram
    return mcmc_hist;
}

TH2D* TwoParam_pdf(Mat<double> MCMC_results, int Nloops, int margeParam){

    assert(0<=margeParam && margeParam<=2); // margParam is the parameter we want to marginalize over (0 is t23, 1 is dmsq31, 2 is deltaCP)

    TH3D* ThreeParHist = mcmcPositions_hist(MCMC_results,Nloops);
    TH2D* TwoParamHist = new TH2D();

    if(margeParam==0){ //marginalize over t23
        TwoParamHist = static_cast<TH2D*>(ThreeParHist->Project3D("yz"));
    }
    else if(margeParam==1){ //marginalize over dmsq31
        TwoParamHist = static_cast<TH2D*>(ThreeParHist->Project3D("xz"));
    }
    else if(margeParam==2){ //marginalize over dCP
        TwoParamHist = static_cast<TH2D*>(ThreeParHist->Project3D("xy"));
    }
    else{
        cout << "problem marginalizing over one parameter" << endl;
    }
    return TwoParamHist;
}

TH1D* OneParam_pdf(Mat<double> MCMC_results, int Nloops, int param){

    assert(0<=param && param<=2); // param is the only parameter we won't marginalize over (0 is t23, 1 is dmsq31, 2 is deltaCP)

    TH3D* ThreeParHist = mcmcPositions_hist(MCMC_results,Nloops);
    TH1D* OneParamHist = new TH1D();

    if(param==0){ //marginalize over t23
        OneParamHist = static_cast<TH1D*>(ThreeParHist->Project3D("x"));
    }
    else if(param==1){ //marginalize over dmsq31
        OneParamHist = static_cast<TH1D*>(ThreeParHist->Project3D("y"));
    }
    else if(param==2){ //marginalize over dCP
        OneParamHist = static_cast<TH1D*>(ThreeParHist->Project3D("z"));
    }
    else{
        cout << "problem marginalizing over two parameters" << endl;
    }
    return OneParamHist;
}

void plot_mh_summary(Mat<double> MCMC_results, int Nloops){

    // one dimensional histograms
    TH1D* t23_hist = OneParam_pdf(MCMC_results,Nloops,0);
    TH1D* dmsq31_hist = OneParam_pdf(MCMC_results,Nloops,1);
    TH1D* dCP_hist = OneParam_pdf(MCMC_results,Nloops,2);

    // canvas
    auto OneD_canvas = new TCanvas("OneD_canvas","",200,10,700,500);
    //OneD_canvas->SetFillColor(42);
    OneD_canvas->SetGrid();
    OneD_canvas->GetFrame()->SetFillColor(21);
    OneD_canvas->GetFrame()->SetBorderSize(12);
    OneD_canvas->Divide(3);

    OneD_canvas->cd(1);
    t23_hist->Draw("hist");
    OneD_canvas->cd(2);
    dmsq31_hist->Draw("hist");
    OneD_canvas->cd(3);
    dCP_hist->Draw("hist");

    // two dimensional histograms
    TH2D* t23_dmsq31_hist = TwoParam_pdf(MCMC_results,Nloops,2);
    TH2D* t23_dCP_hist = TwoParam_pdf(MCMC_results,Nloops,1);
    TH2D* dmsq31_dCP_hist = TwoParam_pdf(MCMC_results,Nloops,0);

    // canvas
    auto TwoD_canvas = new TCanvas("TwoD_canvas","",200,10,700,500);
    //TwoD_canvas->SetFillColor(42);
    TwoD_canvas->SetGrid();
    TwoD_canvas->GetFrame()->SetFillColor(21);
    TwoD_canvas->GetFrame()->SetBorderSize(12);
    TwoD_canvas->Divide(3);

    TwoD_canvas->cd(1);
    t23_dmsq31_hist->Draw();
    TwoD_canvas->cd(2);
    t23_dCP_hist->Draw();
    TwoD_canvas->cd(3);
    dmsq31_dCP_hist->Draw();

}

TH1D* Col2TH1D(Col<double> col_vec, int name1, int name2, int name3){

    int N = col_vec.n_elem;
    double min_val = min(col_vec);
    double max_val = max(col_vec);
    TH1D* hist = new TH1D("hist","",N,min_val,max_val);
    hist->SetName(Form("MCMCPositions%d%d%d",name1,name2,name3));

    for(uword i=0; i<N; i++){
        hist->Fill(col_vec(i));
    }
    return hist;
}

Mat<double> mcmc_results[paramBins][paramBins][paramBins]; // array to store output of MCMC

// NOTE: this function assumes a muon beam (=> muon polarization = +1 and wrong sign muon signal will be antimuons)
void eventSpecific_mcmc(int lep_flavor, int lep_antilep){
    // variables indicate whether the lepton flavor and whether we have a lepton or antilepton
    // lep_flavor key: 0~electron, 1~muon, 2~tauon
    // lep_antilep key: 1~lepton, -1~anti-lepton

    assert (lep_flavor >= 0 && lep_flavor <= 2); // make sure lep_flavor is in the correct range
    assert (lep_antilep == 1 || lep_antilep == -1); // make sure lep_flavor is in the correct range

    string eventType; // variable to store the type of event we are doing the MCMC for in string form
    if(lep_flavor == 1){
        if(lep_antilep == -1){
            eventType = "wMu";
        }
        else if(lep_antilep == 1){
            eventType = "rMu";
        }
    }
    else if(lep_flavor == 0){
        if(lep_antilep == -1){
            eventType = "rElec";
        }
        else if(lep_antilep == 1){
            eventType = "wElec";
        }
    }
    else{
        if(lep_antilep == -1){
            eventType = "antiTau";
        }
        else if(lep_antilep == 1){
            eventType = "Tau";
        }
    }

    Mat<double> mcmc_results[paramBins][paramBins][paramBins]; // array to store output of MCMC
    // now we fill the mcmc_results array using multiple threads
    // parallelization follows this: https://root.cern/doc/master/mt201__parallelHistoFill_8C.html

    gROOT->SetBatch(); // Avoid unnecessary output
    ROOT::EnableThreadSafety(); // Make ROOT thread-safe
    const int nWorkers = 4; // Match number of threads to what the hardware can do (my laptop has 4 cores

    auto workFunction = [&](int k){

        Mat<double> paramVals(paramBins, 3); paramVals = getParamVals();
        Col<double> t23_col = paramVals.col(0);
        Col<double> dmsq31_col = paramVals.col(1);
        Col<double> dCP_col = paramVals.col(2);

        Col<double> E_nu = getEnergyVals();

        for(int i=0; i<paramBins; i++){ // theta23
            cout << "i = " << i << endl;
            for(int j=0; j<paramBins; j++){ // dmsq31
                cout << "j = " << j << endl;

                Col<double> params_obs = {t23_col(i),dmsq31_col(j),dCP_col(k)};
                mcmc_results[i][j][k] = mh_mcmc(params_obs, params_obs, E_nu, nu_flavor, NuOrAnti, muon_polarization, N_loops, param_cov);

            }
        }
    };

    // Create worker threads
    std::vector<std::thread> workers;
    for (auto k : ROOT::TSeqI(paramBins)){
        workers.emplace_back(workFunction, k);
    }
    // Make sure workers are done
    for (auto &&worker : workers){
        worker.join();
    }

    // files to save the output of MCMC
    TFile* Positions_outFile = new TFile(Form("/Users/greesman/Desktop/NeutrinoFactory/OutputFiles/Positions/%s/%s_mcmcPositions.root",eventType.c_str(),eventType.c_str()),"RECREATE");
    for(int i=0; i<paramBins; i++){
        for(int j=0; j<paramBins; j++){
            for(int k=0; k<paramBins; k++){
                mcmcPositions_graph(mcmc_results[i][j][k],N_loops,i,j,k)->Write();
            }
        }
    }

    TFile* Posteriors_outFile = new TFile(Form("/Users/greesman/Desktop/NeutrinoFactory/OutputFiles/Posteriors/%s/%s_mcmcPosteriors.root",eventType.c_str(),eventType.c_str()),"RECREATE");
    for(int i=0; i<paramBins; i++){
        for(int j=0; j<paramBins; j++){
            for(int k=0; k<paramBins; k++){
                Col2TH1D(mcmc_results[i][j][k].col(3),i,j,k)->Write();
            }
        }
    }

    TFile* AccRatio_outFile = new TFile(Form("/Users/greesman/Desktop/NeutrinoFactory/OutputFiles/AcceptanceRatios/%s/%s_mcmcAcceptanceRatios.root",eventType.c_str(),eventType.c_str()),"RECREATE");
    for(int i=0; i<paramBins; i++){
        for(int j=0; j<paramBins; j++){
            for(int k=0; k<paramBins; k++){
                Col2TH1D(mcmc_results[i][j][k].col(4),i,j,k)->Write();
            }
        }
    }

}

void NeutrinoFactory_MCMC(){

    std::cout << "Starting..." << std::endl;

    std::cout << "performing MH MCMC for wrong-sign muons" << std::endl;
    eventSpecific_mcmc(1,-1); //wMus
    //std::cout << "performing MH MCMC for right-sign muons" << std::endl;
    //eventSpecific_mcmc(1,1); //rMus
    //std::cout << "performing MH MCMC for wrong-sign electrons" << std::endl;
    //eventSpecific_mcmc(0,1); //wElec
    //std::cout << "performing MH MCMC for right-sign electrons" << std::endl;
    //eventSpecific_mcmc(0,-1); //rElec

}
''''
```

Body:
I am trying to implement parallel processing to fill an array with results from a function that runs an mcmc. Every test (using less loops in the chain, and less parameters to fit) I've done indicates that everything is working, but for some reason I get the following error after ~4 hours of the code running (this has happened twice):

root.exe(821,0x700001891000) malloc: *** error for object 0x6000015f3690: pointer being freed was not allocated root.exe(821,0x700001685000) malloc: *** error for object 0x6000015f3600: pointer being freed was not allocated

Here is the snippet where the parallel processing is being implemented (please note that filling the array with the mh_mcmc function worked perfectly before, so I don't think that is the issue). I can post more of the code as well if that would help:

Mat<double> mcmc_results[paramBins][paramBins][paramBins]; // array to store output of MCMC
// now we fill the mcmc_results array using multiple threads
// parallelization follows this: https://root.cern/doc/master/mt201__parallelHistoFill_8C.html`

gROOT->SetBatch(); // Avoid unnecessary output
ROOT::EnableThreadSafety(); // Make ROOT thread-safe
const int nWorkers = 4; // Match number of threads to what the hardware can do (my laptop has 4 cores

auto workFunction = [&](int k){

    arma::Mat<double> paramVals(paramBins, 3); paramVals = getParamVals();
    arma::Col<double> t23_col = paramVals.col(0);
    arma::Col<double> dmsq31_col = paramVals.col(1);
    arma::Col<double> dCP_col = paramVals.col(2);

    arma::Col<double> E_nu = getEnergyVals();

    for(int i=0; i<paramBins; i++){ // theta23
        cout << "i = " << i << endl;
        for(int j=0; j<paramBins; j++){ // dmsq31
            cout << "j = " << j << endl;

            arma::Col<double> params_obs = {t23_col(i),dmsq31_col(j),dCP_col(k)};
            mcmc_results[i][j][k] = mh_mcmc(params_obs, params_obs, E_nu, nu_flavor, NuOrAnti, muon_polarization, N_loops, param_cov);

        }
    }
};

// Create worker threads
std::vector<std::thread> workers;
for (auto k : ROOT::TSeqI(paramBins)){
    workers.emplace_back(workFunction, k);
}
// Make sure workers are done
for (auto &&worker : workers){
    worker.join();
}

I am a physicist, NOT a programmer (this will likely be the first and last time I ever have to do this sort of thing) so I am not sure what is going wrong. I have tried googling my problem, but haven't seen anything similar. Could this mean that my laptop isn't capable of storing all of this information (like not enough RAM or something)? Or could someone point me in the correct direction?

EDIT: The code worked perfectly fine before I tried to implement parallelization, so I dont think the problem is in the mh_mcmc function (the function performs a metropolis hastings mcmc). Here is the entire code:

    ''''
//
//  MH_MCMC.cpp
//
//
//  Created by Grace Reesman on 12/5/22.
//

#include "NeutrinoFactory_MCMC.hpp"
#include "/Users/greesman/Desktop/NeutrinoFactory/Code/NeutrinoFactory.hpp"

#include <stdio.h>
#include <cmath> // math stuff
#include <complex>
#include <algorithm>
#include <cassert> // use the "assert" function
#include <cstddef>
#include <tgmath.h>
#include <vector> // to define std::vec
#include <iostream> // for cout/endl stuff (i think)
#include <fstream> // for cout/endl stuff (i think)
#include </opt/local/include/armadillo>
#include <limits> // this is to "define" infinity
//#include </Users/greesman/opt/anaconda3/pkgs/llvm-openmp-12.0.0-h0dcd299_1/include/omp.h> // parallel processing

// ROOT stuff to include
#include <TH3D.h> // 2D histograms
#include <TH2D.h> // 2D histograms
#include <TH1D.h> // 1D histograms
#include <TF1.h> // 1D functions
#include <TF2.h> // 2D functions
#include <TRandom3.h> // random numbers
#include <TLatex.h>
#include <TCanvas.h>
#include <TLegend.h>
#include <TStyle.h>
#include <TFile.h>
#include <TGraph.h> // 1D graphs
#include <TGraph2D.h> // 2D graphs
#include <TFrame.h>
//#include <ROOT/TProcessExecutor.hxx> // parallel processing
#include <ROOT/TSeq.hxx> // for sequences
//#include <ROOT/TExecutor.hxx> // executing parallel processing
//#include <TThread.h>
#include <ROOT/RDataFrame.hxx>
#include <ROOT/RVec.hxx>

using namespace std;
using namespace arma;

Mat<double> getParamVals(){
    //std::cout << "Getting column vectors of parameter values..." << std::endl;
    // defining column vectors that will have paramBins entries each, where the values are uniform over the 3sigma nuFit estimates
    Col<double> dCP_col(paramBins, fill::zeros), t23_col(paramBins, fill::zeros), dmsq31_col(paramBins, fill::zeros);

    // setting minimum values
    dCP_col(0) = deltaCP_min;
    t23_col(0) = t23_min;
    dmsq31_col(0) = dmsq31_min;

    for(int i=1; i<paramBins; i++){ // filling the column vectors
        dCP_col(i) = dCP_col(i-1) + (deltaCP_max-deltaCP_min)/paramBins;
        t23_col(i) = t23_col(i-1) + (t23_max-t23_min)/paramBins;
        dmsq31_col(i) = dmsq31_col(i-1) + (dmsq31_max-dmsq31_min)/paramBins;
    }

    Mat<double> paramVals(paramBins, 3); // define a matrix that is MxN where M = number of parameters and N = number of param bins
    paramVals.col(0) = t23_col;
    paramVals.col(1) = dmsq31_col;
    paramVals.col(2) = dCP_col;

    return paramVals;
}

Col<double> getEnergyVals(){
    //std::cout << "Getting column vector of neutrino energies..." << std::endl;
    Col<double> E_nu(energyBins, fill::zeros); // defining and initializing a column vector to store energy values
    E_nu(0) = minEnergy; // setting the starting energy to the minimum energy
    for(int i = 1; i<energyBins; i++){
        E_nu(i) = E_nu(i-1) + step_size; // writing to neutrino energy column
    }
    return E_nu;
}

double radians(double y){ // degrees to radians
    return y * (M_PI / 180);
}

double normal_pdf(double x, double sigma, double x0) {
       double tmp = (x-x0)/sigma;
       return (1.0/(std::sqrt(2 * M_PI) * std::fabs(sigma))) * std::exp(-tmp*tmp/2);
    }

// function that returns the model predictions
double get_model_predictions(Col<double> theta, double energy, int nu_flavor, int NuOrAntiNu, int mu_pol){
    // theta contains values of oscillation parameters of interest: theta(0) = theta23, theta(1) = delta m^2_{31}, theta(2) = delta_{CP}
    // energy is neutrino energy
    // nu_flavor is the neutrino flavor (or rather, the corresponding lepton) we want to look for in the far detector
    // NuOrAntiNu is 1 if neutrino, -1 if anti neutrino
    // mu_pol is muon polarization

    assert (nu_flavor >= 0 && nu_flavor <= 2); // nu_flavor valid for 0 (electron flavored), 1 (muon flavored), 2 (tau flavored)
    assert (NuOrAntiNu == -1 || NuOrAntiNu == 1); // NuOrAntiNu valid for -1 (anti-neutrino), 1 (neutrino)
    assert (mu_pol >= -1 && mu_pol <= 1); // muon polarization valid between -1 and 1

    double matter_potential = NuOrAntiNu*Yrho*Y_to_a*energy;

    // calculate the expected flux each neutrino flavor
    double ExpectFlux_NuE = Flux::diffFlux(0, NuOrAntiNu,mu_pol,energy)*Exact::Palphabeta(0,nu_flavor,matter_potential,L,energy,t12,theta(0),t13,Dmsq21,theta(1),NuOrAntiNu*theta(2));
    double ExpectFlux_NuMu = Flux::diffFlux(1, NuOrAntiNu, mu_pol, energy)*Exact::Palphabeta(1,nu_flavor,matter_potential,L,energy,t12,theta(0),t13,Dmsq21,theta(1),NuOrAntiNu*theta(2));
    double ExpectFlux_NuTau = Flux::diffFlux(2, NuOrAntiNu, mu_pol, energy)*Exact::Palphabeta(2,nu_flavor,matter_potential,L,energy,t12,theta(0),t13,Dmsq21,theta(1),NuOrAntiNu*theta(2)); // should be zero

    double ExpectCCXSec = CrossSection::sigma_nu(energy, NuOrAntiNu);
    return ExpectCCXSec*(ExpectFlux_NuE+ExpectFlux_NuMu+ExpectFlux_NuTau);
}

// function that returns the log of the likelihood
double lnlikelihood(Col<double> params_theory, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol){

    double lnl = 0; // initializing the log likelihood

    assert(params_theory.n_elem == params_obs.n_elem); // make sure the two column vectors containing the parameters are the same size

    for(uword i=0; i<x_energy.n_elem; i++){

        double model_pred_theory = get_model_predictions(params_theory,x_energy(i),nu_flavor,NuOrAntiNu,mu_pol);
        double model_pred_obs = get_model_predictions(params_obs,x_energy(i),nu_flavor,NuOrAntiNu,mu_pol);

        lnl +=  -0.5*pow((model_pred_obs-model_pred_theory),2)/pow(sqrt(model_pred_obs),2); // add term to log likelihood
    }

    return lnl; // return the log of the likelihood
}

// function that calculates the log of the prior
double lnprior(Col<double> theta){

    double t23_input = theta(0);
    double dmsq31_input = theta(1);
    double dCP_input = theta(2);

    double lnp;

    double t23_prior = normal_pdf(t23_input,3*t23_1sig,t23);
    double dmsq31_prior = normal_pdf(dmsq31_input,3*dmsq31_1sig,Dmsq31);
    //+0.3*normal_pdf(-dmsq31_input,3*dmsq31_1sig,Dmsq31); // this is broken up into two parts so that we can see if we get any info about inverted ordering
    double dCP_prior = normal_pdf(dCP_input,3*dCP_1sig,deltaCP);

    if((t23_input<t23_zeroBelow)||(t23_input>t23_zeroAbove)||(dmsq31_input<dmsq31_zeroBelow)||(dmsq31_input>dmsq31_zeroAbove)||(dCP_input<dCP_zeroBelow)||(dCP_input>dCP_zeroAbove)){
        lnp = -infty;
    }
    else{
        lnp = log(t23_prior)+log(dmsq31_prior)+log(dCP_prior);
    }
    return lnp;
}

// test function that calculates the log of the unnormalized posterior
double lnposterior(Col<double> params_theory, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol){

    double lnl = lnlikelihood(params_theory,params_obs,x_energy,nu_flavor,NuOrAntiNu,mu_pol);
    double lnp = lnprior(params_theory);
    double lnpost;

    if((lnp<=-infty/(10e15))||(lnl<=-infty/(10e15))){
        lnpost = -infty;
    }
    else{
        lnpost = lnl + lnp;
    }
    return lnpost;
}

// function to calculate the Hastings ratio
double hastings_ratio(Col<double> params_theory1, Col<double> params_theory2, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol){

    double lnpost1 = lnposterior(params_theory1, params_obs, x_energy, nu_flavor, NuOrAntiNu, mu_pol);
    double lnpost2 = lnposterior(params_theory2, params_obs, x_energy, nu_flavor, NuOrAntiNu, mu_pol);
    double h_ratio;

    if((lnpost1 <= -infty/(10e15)) || (lnpost2 <= -infty/(10e15))){
        h_ratio =  -infty;
    }
    else{
        h_ratio = exp(lnpost1-lnpost2);
    }
    //cout << "ln posteriors to compare: " << lnpost1 << "and" << lnpost2 << endl;
    return h_ratio;
}

// function to generate a proposed new position for MCMC chain
Mat<double> propose_jump(Col<double> theta, Mat<double> cov){

    arma::arma_rng::set_seed_random();
    const int N = theta.n_elem;
    Col<double> proposed_position(N);
    proposed_position= mvnrnd(theta, cov); // generate a matrix w/ random column vectors from a multivariate Gaussian (normal) distribution

    while((proposed_position(0)<t23_zeroBelow)||(proposed_position(0)>t23_zeroAbove)||(proposed_position(1)<dmsq31_zeroBelow)||(proposed_position(1)>dmsq31_zeroAbove)||(proposed_position(2)<dCP_zeroBelow)||(proposed_position(2)>dCP_zeroAbove)){
        proposed_position = mvnrnd(theta, cov);
    }
    return proposed_position;
}

Mat<double> mh_mcmc(Col<double> params_theory, Col<double> params_obs, Col<double> x_energy, int nu_flavor, int NuOrAntiNu, int mu_pol, int N_steps, Mat<double> cov){
    //arma::arma_rng::set_seed_random();

    // here we will define/initialize some matrices/col vecs that we want to return
    Mat<double> positions(N_steps+1,params_theory.n_elem); // define a matrix that is MxN where M = number of steps to take in MCMC chain and N = number of model parameters
    Col<double> lnpost_at_pos(N_steps+1); // column vector that stores log-posterior value at the position of the MCMC chain
    Col<double> acceptance_ratio(N_steps+1); // column vector that stores acceptance ratio of all previous steps in the chain

    positions.row(0) = trans(params_theory);
    lnpost_at_pos(0) = lnposterior(params_theory,params_obs,x_energy,nu_flavor,NuOrAntiNu,mu_pol);
    int accepted = 0;

    for(uword step=0; step<N_steps; step++){
        //bool check = FALSE;

        Col<double> theta_propose = propose_jump(trans(positions.row(step)),cov);
        //cout << "proposed step: " << endl; theta_propose.print();

        double hastings = hastings_ratio(theta_propose, trans(positions.row(step)), params_theory, x_energy, nu_flavor,NuOrAntiNu,mu_pol);
        //cout << "Hastings ratio for proposed step: " << hastings << endl;

        Col<double> rand_colvec(1,fill::randu); double p_rand = rand_colvec(0); // generating a random number in (0,1)
        //cout << "Random # to compare to hastings: " << p_rand << endl;

        if(hastings>=p_rand){
            positions.row(step+1) = trans(propose_jump(trans(positions.row(step)),cov));
            lnpost_at_pos(step+1) = lnposterior(trans(positions.row(step+1)),params_obs,x_energy,nu_flavor,NuOrAntiNu,mu_pol);
            accepted += 1;
            acceptance_ratio(step+1) = accepted/(step+1);
            //check = TRUE;
        }
        else{
            positions.row(step+1) = positions.row(step);
            lnpost_at_pos.row(step+1) = lnpost_at_pos(step);
            acceptance_ratio(step+1) = accepted/(step+1);
        }
        //cout << check << endl;
    }

    //cout << "Number of accepted positions: " << accepted << endl;
    Mat<double> returnMat(N_steps+1,5);
    returnMat.col(0) = positions.col(0);
    returnMat.col(1) = positions.col(1);
    returnMat.col(2) = positions.col(2);
    returnMat.col(3) = lnpost_at_pos;
    returnMat.col(4) = acceptance_ratio;

    return returnMat;
}

TGraph2D* mcmcPositions_graph(Mat<double> MCMC_results, int Nloops, int name1, int name2, int name3){
    assert(MCMC_results.n_rows == Nloops+1);

    Mat<double> MCMC_positions = MCMC_results.head_cols(3);

    double t23_mcmc_arr[Nloops+1], dmsq31_mcmc_arr[Nloops+1], dCP_mcmc_arr[Nloops+1];
    for(int i=0; i<Nloops+1; i++){
        t23_mcmc_arr[i] = 0;
        dmsq31_mcmc_arr[i] = 0;
        dCP_mcmc_arr[i] = 0;
    }
    for(int i=0; i<Nloops+1; i++){
        t23_mcmc_arr[i] = MCMC_positions(i,0);
        dmsq31_mcmc_arr[i] = MCMC_positions(i,1);
        dCP_mcmc_arr[i] = MCMC_positions(i,2);
    }

    auto param_mcmc_gr = new TGraph2D(Nloops+1,t23_mcmc_arr, dmsq31_mcmc_arr, dCP_mcmc_arr);
    param_mcmc_gr->SetName(Form("MCMCPositions%d%d%d",name1,name2,name3));
    param_mcmc_gr->SetTitle(Form("MCMCPositions%d%d%d",name1,name2,name3));
    param_mcmc_gr->GetXaxis()->SetTitle("#theta_{23}");
    param_mcmc_gr->GetYaxis()->SetTitle("#Delta m^2_{31}");
    param_mcmc_gr->GetZaxis()->SetTitle("#delta_{CP}");
    param_mcmc_gr->SetMarkerColorAlpha(4,0.25);
    param_mcmc_gr->SetMarkerStyle(21);

    return param_mcmc_gr;
}

TH3D* mcmcPositions_hist(Mat<double> MCMC_results, int Nloops){

    TGraph2D* mcmc_gr = mcmcPositions_graph(MCMC_results,Nloops,0,0,0);
    TH3D* mcmc_hist = new TH3D("mcmc_hist", Form("%s;%s;%s;%s", mcmc_gr->GetTitle(), mcmc_gr->GetXaxis()->GetTitle(), mcmc_gr->GetYaxis()->GetTitle(), mcmc_gr->GetZaxis()->GetTitle()),
                               paramBins, t23_min, t23_max,
                               paramBins, dmsq31_min, dmsq31_max,
                               paramBins, deltaCP_min, deltaCP_max);

    for (int i=0; i < mcmc_gr->GetN(); i++){ // setting bin contents to the TGraph values
        double t23_pt,dmsq31_pt,dCP_pt;
        mcmc_gr->GetPoint(i,t23_pt,dmsq31_pt,dCP_pt);
        mcmc_hist->Fill(t23_pt,dmsq31_pt,dCP_pt);
    }
    mcmc_hist->Scale(1/mcmc_hist->Integral("width")); // normalizing our histogram
    return mcmc_hist;
}

TH2D* TwoParam_pdf(Mat<double> MCMC_results, int Nloops, int margeParam){

    assert(0<=margeParam && margeParam<=2); // margParam is the parameter we want to marginalize over (0 is t23, 1 is dmsq31, 2 is deltaCP)

    TH3D* ThreeParHist = mcmcPositions_hist(MCMC_results,Nloops);
    TH2D* TwoParamHist = new TH2D();

    if(margeParam==0){ //marginalize over t23
        TwoParamHist = static_cast<TH2D*>(ThreeParHist->Project3D("yz"));
    }
    else if(margeParam==1){ //marginalize over dmsq31
        TwoParamHist = static_cast<TH2D*>(ThreeParHist->Project3D("xz"));
    }
    else if(margeParam==2){ //marginalize over dCP
        TwoParamHist = static_cast<TH2D*>(ThreeParHist->Project3D("xy"));
    }
    else{
        cout << "problem marginalizing over one parameter" << endl;
    }
    return TwoParamHist;
}

TH1D* OneParam_pdf(Mat<double> MCMC_results, int Nloops, int param){

    assert(0<=param && param<=2); // param is the only parameter we won't marginalize over (0 is t23, 1 is dmsq31, 2 is deltaCP)

    TH3D* ThreeParHist = mcmcPositions_hist(MCMC_results,Nloops);
    TH1D* OneParamHist = new TH1D();

    if(param==0){ //marginalize over t23
        OneParamHist = static_cast<TH1D*>(ThreeParHist->Project3D("x"));
    }
    else if(param==1){ //marginalize over dmsq31
        OneParamHist = static_cast<TH1D*>(ThreeParHist->Project3D("y"));
    }
    else if(param==2){ //marginalize over dCP
        OneParamHist = static_cast<TH1D*>(ThreeParHist->Project3D("z"));
    }
    else{
        cout << "problem marginalizing over two parameters" << endl;
    }
    return OneParamHist;
}

void plot_mh_summary(Mat<double> MCMC_results, int Nloops){

    // one dimensional histograms
    TH1D* t23_hist = OneParam_pdf(MCMC_results,Nloops,0);
    TH1D* dmsq31_hist = OneParam_pdf(MCMC_results,Nloops,1);
    TH1D* dCP_hist = OneParam_pdf(MCMC_results,Nloops,2);

    // canvas
    auto OneD_canvas = new TCanvas("OneD_canvas","",200,10,700,500);
    //OneD_canvas->SetFillColor(42);
    OneD_canvas->SetGrid();
    OneD_canvas->GetFrame()->SetFillColor(21);
    OneD_canvas->GetFrame()->SetBorderSize(12);
    OneD_canvas->Divide(3);

    OneD_canvas->cd(1);
    t23_hist->Draw("hist");
    OneD_canvas->cd(2);
    dmsq31_hist->Draw("hist");
    OneD_canvas->cd(3);
    dCP_hist->Draw("hist");

    // two dimensional histograms
    TH2D* t23_dmsq31_hist = TwoParam_pdf(MCMC_results,Nloops,2);
    TH2D* t23_dCP_hist = TwoParam_pdf(MCMC_results,Nloops,1);
    TH2D* dmsq31_dCP_hist = TwoParam_pdf(MCMC_results,Nloops,0);

    // canvas
    auto TwoD_canvas = new TCanvas("TwoD_canvas","",200,10,700,500);
    //TwoD_canvas->SetFillColor(42);
    TwoD_canvas->SetGrid();
    TwoD_canvas->GetFrame()->SetFillColor(21);
    TwoD_canvas->GetFrame()->SetBorderSize(12);
    TwoD_canvas->Divide(3);

    TwoD_canvas->cd(1);
    t23_dmsq31_hist->Draw();
    TwoD_canvas->cd(2);
    t23_dCP_hist->Draw();
    TwoD_canvas->cd(3);
    dmsq31_dCP_hist->Draw();

}

TH1D* Col2TH1D(Col<double> col_vec, int name1, int name2, int name3){

    int N = col_vec.n_elem;
    double min_val = min(col_vec);
    double max_val = max(col_vec);
    TH1D* hist = new TH1D("hist","",N,min_val,max_val);
    hist->SetName(Form("MCMCPositions%d%d%d",name1,name2,name3));

    for(uword i=0; i<N; i++){
        hist->Fill(col_vec(i));
    }
    return hist;
}

Mat<double> mcmc_results[paramBins][paramBins][paramBins]; // array to store output of MCMC

// NOTE: this function assumes a muon beam (=> muon polarization = +1 and wrong sign muon signal will be antimuons)
void eventSpecific_mcmc(int lep_flavor, int lep_antilep){
    // variables indicate whether the lepton flavor and whether we have a lepton or antilepton
    // lep_flavor key: 0~electron, 1~muon, 2~tauon
    // lep_antilep key: 1~lepton, -1~anti-lepton

    assert (lep_flavor >= 0 && lep_flavor <= 2); // make sure lep_flavor is in the correct range
    assert (lep_antilep == 1 || lep_antilep == -1); // make sure lep_flavor is in the correct range

    string eventType; // variable to store the type of event we are doing the MCMC for in string form
    if(lep_flavor == 1){
        if(lep_antilep == -1){
            eventType = "wMu";
        }
        else if(lep_antilep == 1){
            eventType = "rMu";
        }
    }
    else if(lep_flavor == 0){
        if(lep_antilep == -1){
            eventType = "rElec";
        }
        else if(lep_antilep == 1){
            eventType = "wElec";
        }
    }
    else{
        if(lep_antilep == -1){
            eventType = "antiTau";
        }
        else if(lep_antilep == 1){
            eventType = "Tau";
        }
    }

    Mat<double> mcmc_results[paramBins][paramBins][paramBins]; // array to store output of MCMC
    // now we fill the mcmc_results array using multiple threads
    // parallelization follows this: https://root.cern/doc/master/mt201__parallelHistoFill_8C.html

    gROOT->SetBatch(); // Avoid unnecessary output
    ROOT::EnableThreadSafety(); // Make ROOT thread-safe
    const int nWorkers = 4; // Match number of threads to what the hardware can do (my laptop has 4 cores

    auto workFunction = [&](int k){

        Mat<double> paramVals(paramBins, 3); paramVals = getParamVals();
        Col<double> t23_col = paramVals.col(0);
        Col<double> dmsq31_col = paramVals.col(1);
        Col<double> dCP_col = paramVals.col(2);

        Col<double> E_nu = getEnergyVals();

        for(int i=0; i<paramBins; i++){ // theta23
            cout << "i = " << i << endl;
            for(int j=0; j<paramBins; j++){ // dmsq31
                cout << "j = " << j << endl;

                Col<double> params_obs = {t23_col(i),dmsq31_col(j),dCP_col(k)};
                mcmc_results[i][j][k] = mh_mcmc(params_obs, params_obs, E_nu, nu_flavor, NuOrAnti, muon_polarization, N_loops, param_cov);

            }
        }
    };

    // Create worker threads
    std::vector<std::thread> workers;
    for (auto k : ROOT::TSeqI(paramBins)){
        workers.emplace_back(workFunction, k);
    }
    // Make sure workers are done
    for (auto &&worker : workers){
        worker.join();
    }

    // files to save the output of MCMC
    TFile* Positions_outFile = new TFile(Form("/Users/greesman/Desktop/NeutrinoFactory/OutputFiles/Positions/%s/%s_mcmcPositions.root",eventType.c_str(),eventType.c_str()),"RECREATE");
    for(int i=0; i<paramBins; i++){
        for(int j=0; j<paramBins; j++){
            for(int k=0; k<paramBins; k++){
                mcmcPositions_graph(mcmc_results[i][j][k],N_loops,i,j,k)->Write();
            }
        }
    }

    TFile* Posteriors_outFile = new TFile(Form("/Users/greesman/Desktop/NeutrinoFactory/OutputFiles/Posteriors/%s/%s_mcmcPosteriors.root",eventType.c_str(),eventType.c_str()),"RECREATE");
    for(int i=0; i<paramBins; i++){
        for(int j=0; j<paramBins; j++){
            for(int k=0; k<paramBins; k++){
                Col2TH1D(mcmc_results[i][j][k].col(3),i,j,k)->Write();
            }
        }
    }

    TFile* AccRatio_outFile = new TFile(Form("/Users/greesman/Desktop/NeutrinoFactory/OutputFiles/AcceptanceRatios/%s/%s_mcmcAcceptanceRatios.root",eventType.c_str(),eventType.c_str()),"RECREATE");
    for(int i=0; i<paramBins; i++){
        for(int j=0; j<paramBins; j++){
            for(int k=0; k<paramBins; k++){
                Col2TH1D(mcmc_results[i][j][k].col(4),i,j,k)->Write();
            }
        }
    }

}

void NeutrinoFactory_MCMC(){

    std::cout << "Starting..." << std::endl;

    std::cout << "performing MH MCMC for wrong-sign muons" << std::endl;
    eventSpecific_mcmc(1,-1); //wMus
    //std::cout << "performing MH MCMC for right-sign muons" << std::endl;
    //eventSpecific_mcmc(1,1); //rMus
    //std::cout << "performing MH MCMC for wrong-sign electrons" << std::endl;
    //eventSpecific_mcmc(0,1); //wElec
    //std::cout << "performing MH MCMC for right-sign electrons" << std::endl;
    //eventSpecific_mcmc(0,-1); //rElec

}
''''


来源: stackexchange

问:
scalafmt: How to disable indentation for trailing single-line comments
I am doing migration scalafmt "2.0.1" => "3.6.1".
It is a huge legacy repo and I'd like to keep code changes caused by new formatting rules to the minimum.

I have one case, which I cannot find a configuration setting as a counter-measure.
Trailing single-line comments got indented as well, which undesirable.

```<code>-val v1: String = "text1" // comment1
-val v2: String = "text2_longer" // comment2
+val v1: String = "text1"         // comment1 <-- indented
+val v2: String = "text2_longer"  // comment2 <-- indented
</code>```

I have setting
align.preset = more

I have found following
https://scalameta.org/scalafmt/docs/configuration.html#aligntokens ,
which says The special code // is used for single-line comments.

So I added

```<code>align.tokens.add = [
  { code = "//", owner = ".*" }
]
</code>```

and it doesn't seem to work.

ContentLicense: CC BY-SA 4.0

Body:
I am doing migration scalafmt "2.0.1" => "3.6.1".
It is a huge legacy repo and I'd like to keep code changes caused by new formatting rules to the minimum.

I have one case, which I cannot find a configuration setting as a counter-measure.
Trailing single-line comments got indented as well, which undesirable.

-val v1: String = "text1" // comment1
-val v2: String = "text2_longer" // comment2
+val v1: String = "text1"         // comment1 <-- indented
+val v2: String = "text2_longer"  // comment2 <-- indented

I have setting
align.preset = more

I have found following
https://scalameta.org/scalafmt/docs/configuration.html#aligntokens ,
which says The special code // is used for single-line comments.

So I added

align.tokens.add = [
  { code = "//", owner = ".*" }
]

and it doesn't seem to work.


问:
KeyboardInterrupt not instant, I need to input an other key, using cmd.Cmd.cmdloop() in python
I'm trying to make a good handling of KeyboardInterruptey, I want it to clear the console, but when I press Ctrl+C, it doesnt raise the exception, I have to input an other key so it raise it, here is my cmdloop() :

```<code>import cmd

class MyCommandPrompt(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)
        self.stop = False

    def emptyline(self) -> None:
        """Do nothing on empty input line"""
        pass

    def cmdloop(self, intro=None):
        """Boucle de commandes"""
        while not self.stop:
            try:
                super().cmdloop(intro="")
                self.postloop()
            except KeyboardInterrupt:
                os.system("cls")

if __name__ == "__main__":
    MyCommandPrompt().cmdloop()
</code>```

I have no idea what is wrong with it. I you have any question about about information that you would need I will give them to you, but I think I wrote everything.

I tryed for that to add try except block but it didn't change anythings.

Body:
I'm trying to make a good handling of KeyboardInterruptey, I want it to clear the console, but when I press Ctrl+C, it doesnt raise the exception, I have to input an other key so it raise it, here is my cmdloop() :

import cmd

class MyCommandPrompt(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)
        self.stop = False

    def emptyline(self) -> None:
        """Do nothing on empty input line"""
        pass

    def cmdloop(self, intro=None):
        """Boucle de commandes"""
        while not self.stop:
            try:
                super().cmdloop(intro="")
                self.postloop()
            except KeyboardInterrupt:
                os.system("cls")

if __name__ == "__main__":
    MyCommandPrompt().cmdloop()

I have no idea what is wrong with it. I you have any question about about information that you would need I will give them to you, but I think I wrote everything.

I tryed for that to add try except block but it didn't change anythings.


问:
How to stabilize Everit Schema serialization?
n my experience, an output of Schema#toString() can be different for equal objects. Particularly, order of dictionary keys can be different.

Can this be stabilized?

Or is it possible to use other method to convert Schema to String to get stable results?


问:
Slider for date filter in matplotlib
I have number of dates and i want to show only current five dates plots on bar. I required slider for looking the dates other than current five dates.

My data is huge and when plotted, it is so messy to see. So I am trying to use X axis slider, so that, an user can slide over the x axis and visualize it easily .

import matplotlib.pyplot as plt
import numpy as np
import ipywidgets as wg

conn = pyodbc.connect("Driver={SQL Server Native Client 11.0};" "Server=RUSHABH\RUSHABHPC;" "Database=SCADA;" "Trusted_Connection=yes;")
daily_data = pd.read_sql_query('SELECT * FROM [SCADA].[dbo].[TOTALIZER] order by SDATETIME ASC', conn)

class Dashboard:
def init(self, window):
self.window = window
self.window.title('Dashboard')
self.window.geometry('1366x768')
self.window.state('zoomed')
self.window.config(background='#eff5f6')

```<code>     datadaily = daily_data.groupby([pd.Grouper(key="SDATETIME", freq="D")]).sum()#daily_data.groupby(pd.to_datetime(daily_data['SDATETIME']).dt.strftime('%y-%m-%d'))['FE014CPV', 'CCC'].last().reset_index()
    datadaily.index = datadaily.index.strftime("%d-%m")#lastdayfrom = daily_data['SDATETIME'].max()
</code>```

sliders do not support datetime display, but it is possible to display timestamps. Here is a full example (I didn't base it off of your code, because you did not provide any data
M = max(datadaily['FE014CPV'])

```<code>    N = 5

    figure3 = Figure(dpi=100)
    ax3 = figure3.add_subplot(111)
    ax3.set_title('Daily Steam Generation (Ton) Vs Coal Consumption (Ton)')
    z = np.arange(len(datadaily.index))#date2num(datadaily.index)
    ax3.bar(z - BarWidth/4, datadaily['FE014CPV'], width=BarWidth/2, facecolor='indianred', align='center')
    ax3.bar(z + BarWidth/4, datadaily['CCC'], width=BarWidth/2, facecolor='#7eb54e', align='center')
    ax3.set_ylabel('Steam Generation(Ton)')
    ax3.set_xticks(z)
    ax6 = ax3.twinx()  # Create another axes that shares the same x-axis as ax.
    ax6.set_ylim(*ax3.get_ylim())
    ax6.set_ylabel('Coal Consumption(Ton)')
    ax3.set_xticklabels(datadaily.index, rotation=90, fontsize=6)
    ax3.legend(['Steam Generation', 'Coal Consumption'])
    #ax3.xaxis_date()
    #ax3.autoscale(tight=True)
    bar3 = FigureCanvasTkAgg(figure3, self.window)
    bar3.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    bar3.get_tk_widget().place(x=760, y=400, width=600, height=300)

    ax_time = bar3.add_axes([0.12, 0.1, 0.78, 0.03])
    s_time = Slider(ax_time, 'Channels', 0, len(z) - N, valinit=0, valstep=1)

    def update(val):
        N = 5
        pos = s_time.val
        ax3.axis([pos - 1 / 2, pos + N - 1 / 2, 0, M + 1])
        bar3.canvas.draw_idle()

    s_time.on_changed(update)
</code>```

I'm trying to put a slider right under the x-axis of a subplot in matplotlib

Title: Slider for date filter in matplotlib

Body:
I have number of dates and i want to show only current five dates plots on bar. I required slider for looking the dates other than current five dates.

My data is huge and when plotted, it is so messy to see. So I am trying to use X axis slider, so that, an user can slide over the x axis and visualize it easily .

import matplotlib.pyplot as plt
import numpy as np
import ipywidgets as wg

conn = pyodbc.connect("Driver={SQL Server Native Client 11.0};" "Server=RUSHABH\RUSHABHPC;" "Database=SCADA;" "Trusted_Connection=yes;")
daily_data = pd.read_sql_query('SELECT * FROM [SCADA].[dbo].[TOTALIZER] order by SDATETIME ASC', conn)

class Dashboard:
def init(self, window):
self.window = window
self.window.title('Dashboard')
self.window.geometry('1366x768')
self.window.state('zoomed')
self.window.config(background='#eff5f6')

     datadaily = daily_data.groupby([pd.Grouper(key="SDATETIME", freq="D")]).sum()#daily_data.groupby(pd.to_datetime(daily_data['SDATETIME']).dt.strftime('%y-%m-%d'))['FE014CPV', 'CCC'].last().reset_index()
    datadaily.index = datadaily.index.strftime("%d-%m")#lastdayfrom = daily_data['SDATETIME'].max()

sliders do not support datetime display, but it is possible to display timestamps. Here is a full example (I didn't base it off of your code, because you did not provide any data
M = max(datadaily['FE014CPV'])

    N = 5

    figure3 = Figure(dpi=100)
    ax3 = figure3.add_subplot(111)
    ax3.set_title('Daily Steam Generation (Ton) Vs Coal Consumption (Ton)')
    z = np.arange(len(datadaily.index))#date2num(datadaily.index)
    ax3.bar(z - BarWidth/4, datadaily['FE014CPV'], width=BarWidth/2, facecolor='indianred', align='center')
    ax3.bar(z + BarWidth/4, datadaily['CCC'], width=BarWidth/2, facecolor='#7eb54e', align='center')
    ax3.set_ylabel('Steam Generation(Ton)')
    ax3.set_xticks(z)
    ax6 = ax3.twinx()  # Create another axes that shares the same x-axis as ax.
    ax6.set_ylim(*ax3.get_ylim())
    ax6.set_ylabel('Coal Consumption(Ton)')
    ax3.set_xticklabels(datadaily.index, rotation=90, fontsize=6)
    ax3.legend(['Steam Generation', 'Coal Consumption'])
    #ax3.xaxis_date()
    #ax3.autoscale(tight=True)
    bar3 = FigureCanvasTkAgg(figure3, self.window)
    bar3.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    bar3.get_tk_widget().place(x=760, y=400, width=600, height=300)

    ax_time = bar3.add_axes([0.12, 0.1, 0.78, 0.03])
    s_time = Slider(ax_time, 'Channels', 0, len(z) - N, valinit=0, valstep=1)

    def update(val):
        N = 5
        pos = s_time.val
        ax3.axis([pos - 1 / 2, pos + N - 1 / 2, 0, M + 1])
        bar3.canvas.draw_idle()

    s_time.on_changed(update)

I'm trying to put a slider right under the x-axis of a subplot in matplotlib


问:
Can't switch SetMkeyState for G13 via mouse G600
I'm trying to assighn

SetMkeyState M1 "lhc" to G18

SetMkeyState M2 "lhc" to G19

SetMkeyState M3 "lhc" to G20

Here my code

```<code>function OnEvent(event, arg)
if (event == "G_PRESSED" and arg == 18) then
SetMKeyState(2,"lhc");
end
end
</code>```

the problem is, there no reaction of G13 :(

Body:
I'm trying to assighn

SetMkeyState M1 "lhc" to G18

SetMkeyState M2 "lhc" to G19

SetMkeyState M3 "lhc" to G20

Here my code

function OnEvent(event, arg)
if (event == "G_PRESSED" and arg == 18) then
SetMKeyState(2,"lhc");
end
end

the problem is, there no reaction of G13 :(


问:
Node Schedule - Cancelling and schedluling a job makes the job run many times (instead of just once)
I'm running into issues with the node-schedule package.

I'm trying to run it with GCP cloud functions. The case where a job is scheduled and fired normally works fine. Cancelling a job also works.

However, when I try to reschedule it (by cancelling the job and scheduling a new one with the same id), it fires many times instead of just once.

Eg.: It is reschedule three times, but fires 15 times.

This is the code I have in my GCP function:

```<code>const functions = require('firebase-functions');
var schedule = require('node-schedule');
const {stringify} = require('flatted');

exports.jobScheduler = functions.https.onRequest(async (req, res) => {
    try {
      const jobId = req.body.id?.toString();
      const type = req.body.type;
      const date = new Date(req.body.date);

      if (type === 'list_jobs') {
        const scheduledJobs = schedule.scheduledJobs;
        res.status(200).send(stringify(scheduledJobs));
      } else {
        if(type === 'schedule_job') {
          const scheduledJob = schedule.scheduleJob(jobId, date, () => {
            // API CALL
            console.log(`SCHEDULED JOB IS RUNNING FOR ${jobId}`);
            }
          );

          functions.logger.log(`Job scheduled for ${jobId}.`);
        }

        if (type === 'reschedule_job') {
          const jobToReschedule = schedule.scheduledJobs[jobId];
          if (jobToReschedule) {
            jobToReschedule.cancel();
            functions.logger.log(`Job canceled for a reschedule for ${jobId}.`);
            const rescheduledJob = schedule.scheduleJob(jobId, date, () => {
              //API CALL
              console.log(`Rescheduled job is running for ${jobId}`);
              }
            );

            functions.logger.log(`[Job rescheduled for ${jobId}.`);

          } else {
            functions.logger.log(`No pending job to reschedule for ${jobId}.`);
          }
        }

        if (type === 'cancel') {
          const jobToCancel = schedule.scheduledJobs[jobId];
          if (jobToCancel) {
            jobToCancel.cancel();
            functions.logger.log(`Job canceled for ${jobId}.`);
          } else {
            functions.logger.log(`No pending job for ${jobId}.`);
          }
        }
        res.status(200).send(`Job to ${type} notification for ${jobId} was successful.`);
      }
    } catch (error) {
      functions.logger.log(error);
      res.status(400).json(error);
    }
});
</code>```

I tried schedule.reschedule(), cancelling and creating a new schedule. I expect the job to be canceled and rescheduled for the new date, and for the job to fire only once (at the rescheduled date). There are some cases where a job might be rescheduled a lot of times. I expect it to only fire once (the last reschedule). However, the job fires more than once. In fact, it fires more than the number of times it was rescheduled.

I appreciate the help!

Body:
I'm running into issues with the node-schedule package.

I'm trying to run it with GCP cloud functions. The case where a job is scheduled and fired normally works fine. Cancelling a job also works.

However, when I try to reschedule it (by cancelling the job and scheduling a new one with the same id), it fires many times instead of just once.

Eg.: It is reschedule three times, but fires 15 times.

This is the code I have in my GCP function:

const functions = require('firebase-functions');
var schedule = require('node-schedule');
const {stringify} = require('flatted');

exports.jobScheduler = functions.https.onRequest(async (req, res) => {
    try {
      const jobId = req.body.id?.toString();
      const type = req.body.type;
      const date = new Date(req.body.date);

      if (type === 'list_jobs') {
        const scheduledJobs = schedule.scheduledJobs;
        res.status(200).send(stringify(scheduledJobs));
      } else {
        if(type === 'schedule_job') {
          const scheduledJob = schedule.scheduleJob(jobId, date, () => {
            // API CALL
            console.log(`SCHEDULED JOB IS RUNNING FOR ${jobId}`);
            }
          );

          functions.logger.log(`Job scheduled for ${jobId}.`);
        }

        if (type === 'reschedule_job') {
          const jobToReschedule = schedule.scheduledJobs[jobId];
          if (jobToReschedule) {
            jobToReschedule.cancel();
            functions.logger.log(`Job canceled for a reschedule for ${jobId}.`);
            const rescheduledJob = schedule.scheduleJob(jobId, date, () => {
              //API CALL
              console.log(`Rescheduled job is running for ${jobId}`);
              }
            );

            functions.logger.log(`[Job rescheduled for ${jobId}.`);

          } else {
            functions.logger.log(`No pending job to reschedule for ${jobId}.`);
          }
        }

        if (type === 'cancel') {
          const jobToCancel = schedule.scheduledJobs[jobId];
          if (jobToCancel) {
            jobToCancel.cancel();
            functions.logger.log(`Job canceled for ${jobId}.`);
          } else {
            functions.logger.log(`No pending job for ${jobId}.`);
          }
        }
        res.status(200).send(`Job to ${type} notification for ${jobId} was successful.`);
      }
    } catch (error) {
      functions.logger.log(error);
      res.status(400).json(error);
    }
});

I tried schedule.reschedule(), cancelling and creating a new schedule. I expect the job to be canceled and rescheduled for the new date, and for the job to fire only once (at the rescheduled date). There are some cases where a job might be rescheduled a lot of times. I expect it to only fire once (the last reschedule). However, the job fires more than once. In fact, it fires more than the number of times it was rescheduled.

I appreciate the help!


问:
Postgres db index not being used on Heroku
I'm trying to debug a slow query for a model that looks like:

```<code>class Employee(TimeStampMixin):
    title = models.TextField(blank=True,db_index=True)
    seniority = models.CharField(blank=True,max_length=128,db_index=True)
</code>```

The query is: Employee.objects.exclude(seniority='').filter(title__icontains=title).order_by('seniority').values_list('seniority')

When I run it locally it takes ~0.3 seconds (same database size). An explain locally shows:

```<code>Limit  (cost=1000.58..196218.23 rows=7 width=1) (actual time=299.016..300.366 rows=1 loops=1)
  Output: seniority
  Buffers: shared hit=2447163 read=23669
  ->  Gather Merge  (cost=1000.58..196218.23 rows=7 width=1) (actual time=299.015..300.364 rows=1 loops=1)
        Output: seniority
        Workers Planned: 2
        Workers Launched: 2
        Buffers: shared hit=2447163 read=23669
        ->  Parallel Index Only Scan using companies_e_seniori_12ac68_idx on public.companies_employee  (cost=0.56..195217.40 rows=3 width=1) (actual time=293.195..293.200 rows=0 loops=3)
              Output: seniority
              Filter: (((companies_employee.seniority)::text <> ''::text) AND (upper(companies_employee.title) ~~ '%INFORMATION SPECIALIST%'::text))
              Rows Removed by Filter: 2697599
              Heap Fetches: 2819
              Buffers: shared hit=2447163 read=23669
              Worker 0:  actual time=291.087..291.088 rows=0 loops=1
                Buffers: shared hit=820222 read=7926
              Worker 1:  actual time=291.056..291.056 rows=0 loops=1
                Buffers: shared hit=812538 read=7888
Planning Time: 0.209 ms
Execution Time: 300.400 ms
</code>```

however when I run the same code on Heroku I get execution times of 3s+, possibly because the former is using an index while the second is not:

```<code>Limit  (cost=216982.74..216983.39 rows=6 width=1) (actual time=988.738..1018.964 rows=1 loops=1)
  Output: seniority
  Buffers: shared hit=199527 dirtied=5
  ->  Gather Merge  (cost=216982.74..216983.39 rows=6 width=1) (actual time=980.932..1011.157 rows=1 loops=1)
        Output: seniority
        Workers Planned: 2
        Workers Launched: 2
        Buffers: shared hit=199527 dirtied=5
        ->  Sort  (cost=215982.74..215982.74 rows=3 width=1) (actual time=959.233..959.234 rows=0 loops=3)
              Output: seniority
              Sort Key: companies_employee.seniority
              Sort Method: quicksort  Memory: 25kB
              Buffers: shared hit=199527 dirtied=5
              Worker 0:  actual time=957.414..957.414 rows=0 loops=1
                Sort Method: quicksort  Memory: 25kB
                JIT:
                  Functions: 4
                  Options: Inlining false, Optimization false, Expressions true, Deforming true
                  Timing: Generation 1.179 ms, Inlining 0.000 ms, Optimization 0.879 ms, Emission 9.714 ms, Total 11.771 ms
                Buffers: shared hit=54855 dirtied=2
              Worker 1:  actual time=939.591..939.592 rows=0 loops=1
                Sort Method: quicksort  Memory: 25kB
                JIT:
                  Functions: 4
                  Options: Inlining false, Optimization false, Expressions true, Deforming true
                  Timing: Generation 0.741 ms, Inlining 0.000 ms, Optimization 0.654 ms, Emission 6.531 ms, Total 7.926 ms
                Buffers: shared hit=87867 dirtied=1
              ->  Parallel Seq Scan on public.companies_employee  (cost=0.00..215982.73 rows=3 width=1) (actual time=705.244..959.146 rows=0 loops=3)
                    Output: seniority
                    Filter: (((companies_employee.seniority)::text <> ''::text) AND (upper(companies_employee.title) ~~ '%INFORMATION SPECIALIST%'::text))
                    Rows Removed by Filter: 2939330
                    Buffers: shared hit=199449 dirtied=5
                    Worker 0:  actual time=957.262..957.262 rows=0 loops=1
                      Buffers: shared hit=54816 dirtied=2
                    Worker 1:  actual time=939.491..939.491 rows=0 loops=1
                      Buffers: shared hit=87828 dirtied=1
Query Identifier: 2827140323627869732
Planning:
  Buffers: shared hit=293 read=1 dirtied=1
  I/O Timings: read=0.021
Planning Time: 1.078 ms
JIT:
  Functions: 13
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 2.746 ms, Inlining 0.000 ms, Optimization 2.224 ms, Emission 23.189 ms, Total 28.160 ms
Execution Time: 1050.493 ms
</code>```

I confirmed the model indexes are identical for my local database and on Heroku, this is what they are:

```<code>  indexname                   |                                                             indexdef
----------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------
 companies_employee_pkey                      | CREATE UNIQUE INDEX companies_employee_pkey ON public.companies_employee USING btree (id)
 companies_employee_company_id_c24081a8       | CREATE INDEX companies_employee_company_id_c24081a8 ON public.companies_employee USING btree (company_id)
 companies_employee_person_id_936e5c6a        | CREATE INDEX companies_employee_person_id_936e5c6a ON public.companies_employee USING btree (person_id)
 companies_employee_role_8772f722             | CREATE INDEX companies_employee_role_8772f722 ON public.companies_employee USING btree (role)
 companies_employee_role_8772f722_like        | CREATE INDEX companies_employee_role_8772f722_like ON public.companies_employee USING btree (role text_pattern_ops)
 companies_employee_seniority_b10393ff        | CREATE INDEX companies_employee_seniority_b10393ff ON public.companies_employee USING btree (seniority)
 companies_employee_seniority_b10393ff_like   | CREATE INDEX companies_employee_seniority_b10393ff_like ON public.companies_employee USING btree (seniority varchar_pattern_ops)
 companies_employee_title_78009330            | CREATE INDEX companies_employee_title_78009330 ON public.companies_employee USING btree (title)
 companies_employee_title_78009330_like       | CREATE INDEX companies_employee_title_78009330_like ON public.companies_employee USING btree (title text_pattern_ops)
 companies_employee_institution_75d6c7e9      | CREATE INDEX companies_employee_institution_75d6c7e9 ON public.companies_employee USING btree (institution)
 companies_employee_institution_75d6c7e9_like | CREATE INDEX companies_employee_institution_75d6c7e9_like ON public.companies_employee USING btree (institution text_pattern_ops)
 companies_e_seniori_12ac68_idx               | CREATE INDEX companies_e_seniori_12ac68_idx ON public.companies_employee USING btree (seniority, title)
 title_seniority                              | CREATE INDEX title_seniority ON public.companies_employee USING btree (upper(title), seniority)
</code>```

Body:
I'm trying to debug a slow query for a model that looks like:

class Employee(TimeStampMixin):
    title = models.TextField(blank=True,db_index=True)
    seniority = models.CharField(blank=True,max_length=128,db_index=True)

The query is: Employee.objects.exclude(seniority='').filter(title__icontains=title).order_by('seniority').values_list('seniority')

When I run it locally it takes ~0.3 seconds (same database size). An explain locally shows:

Limit  (cost=1000.58..196218.23 rows=7 width=1) (actual time=299.016..300.366 rows=1 loops=1)
  Output: seniority
  Buffers: shared hit=2447163 read=23669
  ->  Gather Merge  (cost=1000.58..196218.23 rows=7 width=1) (actual time=299.015..300.364 rows=1 loops=1)
        Output: seniority
        Workers Planned: 2
        Workers Launched: 2
        Buffers: shared hit=2447163 read=23669
        ->  Parallel Index Only Scan using companies_e_seniori_12ac68_idx on public.companies_employee  (cost=0.56..195217.40 rows=3 width=1) (actual time=293.195..293.200 rows=0 loops=3)
              Output: seniority
              Filter: (((companies_employee.seniority)::text <> ''::text) AND (upper(companies_employee.title) ~~ '%INFORMATION SPECIALIST%'::text))
              Rows Removed by Filter: 2697599
              Heap Fetches: 2819
              Buffers: shared hit=2447163 read=23669
              Worker 0:  actual time=291.087..291.088 rows=0 loops=1
                Buffers: shared hit=820222 read=7926
              Worker 1:  actual time=291.056..291.056 rows=0 loops=1
                Buffers: shared hit=812538 read=7888
Planning Time: 0.209 ms
Execution Time: 300.400 ms

however when I run the same code on Heroku I get execution times of 3s+, possibly because the former is using an index while the second is not:

Limit  (cost=216982.74..216983.39 rows=6 width=1) (actual time=988.738..1018.964 rows=1 loops=1)
  Output: seniority
  Buffers: shared hit=199527 dirtied=5
  ->  Gather Merge  (cost=216982.74..216983.39 rows=6 width=1) (actual time=980.932..1011.157 rows=1 loops=1)
        Output: seniority
        Workers Planned: 2
        Workers Launched: 2
        Buffers: shared hit=199527 dirtied=5
        ->  Sort  (cost=215982.74..215982.74 rows=3 width=1) (actual time=959.233..959.234 rows=0 loops=3)
              Output: seniority
              Sort Key: companies_employee.seniority
              Sort Method: quicksort  Memory: 25kB
              Buffers: shared hit=199527 dirtied=5
              Worker 0:  actual time=957.414..957.414 rows=0 loops=1
                Sort Method: quicksort  Memory: 25kB
                JIT:
                  Functions: 4
                  Options: Inlining false, Optimization false, Expressions true, Deforming true
                  Timing: Generation 1.179 ms, Inlining 0.000 ms, Optimization 0.879 ms, Emission 9.714 ms, Total 11.771 ms
                Buffers: shared hit=54855 dirtied=2
              Worker 1:  actual time=939.591..939.592 rows=0 loops=1
                Sort Method: quicksort  Memory: 25kB
                JIT:
                  Functions: 4
                  Options: Inlining false, Optimization false, Expressions true, Deforming true
                  Timing: Generation 0.741 ms, Inlining 0.000 ms, Optimization 0.654 ms, Emission 6.531 ms, Total 7.926 ms
                Buffers: shared hit=87867 dirtied=1
              ->  Parallel Seq Scan on public.companies_employee  (cost=0.00..215982.73 rows=3 width=1) (actual time=705.244..959.146 rows=0 loops=3)
                    Output: seniority
                    Filter: (((companies_employee.seniority)::text <> ''::text) AND (upper(companies_employee.title) ~~ '%INFORMATION SPECIALIST%'::text))
                    Rows Removed by Filter: 2939330
                    Buffers: shared hit=199449 dirtied=5
                    Worker 0:  actual time=957.262..957.262 rows=0 loops=1
                      Buffers: shared hit=54816 dirtied=2
                    Worker 1:  actual time=939.491..939.491 rows=0 loops=1
                      Buffers: shared hit=87828 dirtied=1
Query Identifier: 2827140323627869732
Planning:
  Buffers: shared hit=293 read=1 dirtied=1
  I/O Timings: read=0.021
Planning Time: 1.078 ms
JIT:
  Functions: 13
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 2.746 ms, Inlining 0.000 ms, Optimization 2.224 ms, Emission 23.189 ms, Total 28.160 ms
Execution Time: 1050.493 ms

I confirmed the model indexes are identical for my local database and on Heroku, this is what they are:

  indexname                   |                                                             indexdef
----------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------
 companies_employee_pkey                      | CREATE UNIQUE INDEX companies_employee_pkey ON public.companies_employee USING btree (id)
 companies_employee_company_id_c24081a8       | CREATE INDEX companies_employee_company_id_c24081a8 ON public.companies_employee USING btree (company_id)
 companies_employee_person_id_936e5c6a        | CREATE INDEX companies_employee_person_id_936e5c6a ON public.companies_employee USING btree (person_id)
 companies_employee_role_8772f722             | CREATE INDEX companies_employee_role_8772f722 ON public.companies_employee USING btree (role)
 companies_employee_role_8772f722_like        | CREATE INDEX companies_employee_role_8772f722_like ON public.companies_employee USING btree (role text_pattern_ops)
 companies_employee_seniority_b10393ff        | CREATE INDEX companies_employee_seniority_b10393ff ON public.companies_employee USING btree (seniority)
 companies_employee_seniority_b10393ff_like   | CREATE INDEX companies_employee_seniority_b10393ff_like ON public.companies_employee USING btree (seniority varchar_pattern_ops)
 companies_employee_title_78009330            | CREATE INDEX companies_employee_title_78009330 ON public.companies_employee USING btree (title)
 companies_employee_title_78009330_like       | CREATE INDEX companies_employee_title_78009330_like ON public.companies_employee USING btree (title text_pattern_ops)
 companies_employee_institution_75d6c7e9      | CREATE INDEX companies_employee_institution_75d6c7e9 ON public.companies_employee USING btree (institution)
 companies_employee_institution_75d6c7e9_like | CREATE INDEX companies_employee_institution_75d6c7e9_like ON public.companies_employee USING btree (institution text_pattern_ops)
 companies_e_seniori_12ac68_idx               | CREATE INDEX companies_e_seniori_12ac68_idx ON public.companies_employee USING btree (seniority, title)
 title_seniority                              | CREATE INDEX title_seniority ON public.companies_employee USING btree (upper(title), seniority)


问:
How do I prevent Google Cloud Functions caching results to calls?
I have a simple flask app in a Google Cloud Function that returns different data based on the user's authorization, specified by a token in the header:

@functions_framework.http
def main(request):
    token = request.headers['Authorization']
    data: List[str] = my_store.get_authorized_data(token)
    print(data)
    return data
```
<p>This is deployed using:</p>
```gcloud functions deploy myfunc \
--entry-point main \
--project=myproj \
--trigger-http \
--runtime=python39 \
--allow-unauthenticated \
--timeout=540 \
--memory=1024MB \
--min-instances 1
```
<p>I then have a React/TypeScript front-end deployed to Firebase hosting that calls the function:</p>
<pre class="lang-js prettyprint-override"><code>axios.get(`cloud/function/url`, {
  headers: {
    Accept: "application/json, text/plain, */*",
    Authorization: `Bearer ${token}`,
  },
})
.then((result) => {
  console.log(result.data);
  return result.data;
});
</code>```

The cloud functions are regular Google Cloud Functions, not Cloud Functions for Firebase.

The problem

If I send a request with a token authorized for all data ['a', 'b', 'c'], everything works fine:

Cloud function log: ['a', 'b', 'c']

Front-end log: ['a', 'b', 'c']

If I then switch to a user with less data access, just ['a', 'b'], it also works:

Cloud function log: ['a', 'b']

Front-end log: ['a', 'b']

But if I then switch back to the account with access to all data, there is an unexpected result:

Cloud function log: ['a', 'b', 'c']

Front-end log: ['a', 'b']

The front-end is not receiving the data that the cloud function is logging. This is intermittent, if I make repeat calls, around half get the correct ['a', 'b', 'c'] in the front-end, the other half always show the incorrect ['a', 'b']. All logs in the cloud function show the correct ['a', 'b', 'c'] regardless of the result in the front-end.

It appears the cloud function is caching the result, and just sending an old result.

What I've tried

A similar question states that cloud functions re-use server instances and there's not any remedy.

Here are the steps I've taken:

Redeploying the cloud function: this works, the issue disappears, but returns once I switch tokens again. I can't redeploy my cloud function every time a user needs to change account.

Redeploying the front-end to Firebase: this does not fix the issue.

Disabling cache in the browser: this does not fix the issue.

Disabling cache in firebase hosting (as in this question): this does not fix the issue, similarly I have tried setting this in my firebase.json, which also did not fix the issue:

```<code>"headers": [{
    "source": "**",
        "headers": [{
            "key": "Cache-Control",
            "value": "max-age=0"
        }]
    }]
</code>```

Disabling caching on the axios.get: this does not fix the issue. I tried 3 different methods as in this question: by adding an ever-changing parameter to the URL so it is always different, setting such a parameter in the call params and setting the caching headers directly. None of these fix the issue:

```<code>axios.get(`/cloud/function/url?timestamp=${new Date().getTime()}`, {
  headers: {
    Accept: "application/json, text/plain, */*",
    Authorization: `Bearer ${token}`,
    'Cache-Control': 'no-cache',
    Pragma: 'no-cache',
    Expires: '0',
  },
  params: {
    t: new Date().getTime()
  }
})
</code>```

From my disabling front-end cache, redeploying front-end and the console.log I am confident the issue is not client-side. I curl the API directly to verify this:

```<code>curl '/my/function/url' -H 'Authorization: Bearer '"$token"'
</code>```

Response for token 1: {data: ["a", "b", "c"]}

Response for token 2: {data: ["a", "b"]}

Response going back to token 1: {data: ["a", "b"]}

It seems clear the cloud function really is returning some type of cached response. This is further reinforced by the fact that redeploying the cloud function does fix the issue. How do I stop a Google Cloud Function from caching responses?

Edit: further details on how the backend retrieves the data for each token

Data is stored in a Firestore NoSQL document database. Each entry has the user account as the document name and the allowed data as fields in the document.

```<code>user1: {a: null, b: null, c: null}
user2: {a: null, b: null}
</code>```

The get_authorized_data function gets the user account from the token and retrieves the allowed data items from the Firestore:

from firebase_admin import auth, firestore

db = firestore.client()

def get_authorized_data(token):
    # This returns {'uid': '123', 'email': 'example@example.com'}
    decoded_token = auth.verify_id_token(id_token)
    document = db.collection(u'allowed-data-per-user')\
               .document(decoded_token['email']).get()
    allowed_data = list(document.to_dict().keys())
    return allowed_data
```

If you notice my comments about the print statement in the first block of python at the top of the question, this retrieves the correct data: always ['a', 'b', 'c'] for token 1 and always ['a', 'b'] for token 2. I do not believe that this is the part at fault.

Body:
I have a simple flask app in a Google Cloud Function that returns different data based on the user's authorization, specified by a token in the header:

@functions_framework.http
def main(request):
    token = request.headers['Authorization']
    data: List[str] = my_store.get_authorized_data(token)
    print(data)
    return data

This is deployed using:

gcloud functions deploy myfunc \
--entry-point main \
--project=myproj \
--trigger-http \
--runtime=python39 \
--allow-unauthenticated \
--timeout=540 \
--memory=1024MB \
--min-instances 1

I then have a React/TypeScript front-end deployed to Firebase hosting that calls the function:

axios.get(`cloud/function/url`, {
  headers: {
    Accept: "application/json, text/plain, */*",
    Authorization: `Bearer ${token}`,
  },
})
.then((result) => {
  console.log(result.data);
  return result.data;
});

The cloud functions are regular Google Cloud Functions, not Cloud Functions for Firebase.

The problem

If I send a request with a token authorized for all data ['a', 'b', 'c'], everything works fine:

Cloud function log: ['a', 'b', 'c']

Front-end log: ['a', 'b', 'c']

If I then switch to a user with less data access, just ['a', 'b'], it also works:

Cloud function log: ['a', 'b']

Front-end log: ['a', 'b']

But if I then switch back to the account with access to all data, there is an unexpected result:

Cloud function log: ['a', 'b', 'c']

Front-end log: ['a', 'b']

The front-end is not receiving the data that the cloud function is logging. This is intermittent, if I make repeat calls, around half get the correct ['a', 'b', 'c'] in the front-end, the other half always show the incorrect ['a', 'b']. All logs in the cloud function show the correct ['a', 'b', 'c'] regardless of the result in the front-end.

It appears the cloud function is caching the result, and just sending an old result.

What I've tried

A similar question states that cloud functions re-use server instances and there's not any remedy.

Here are the steps I've taken:

Redeploying the cloud function: this works, the issue disappears, but returns once I switch tokens again. I can't redeploy my cloud function every time a user needs to change account.

Redeploying the front-end to Firebase: this does not fix the issue.

Disabling cache in the browser: this does not fix the issue.

Disabling cache in firebase hosting (as in this question): this does not fix the issue, similarly I have tried setting this in my firebase.json, which also did not fix the issue:

"headers": [{
    "source": "**",
        "headers": [{
            "key": "Cache-Control",
            "value": "max-age=0"
        }]
    }]

Disabling caching on the axios.get: this does not fix the issue. I tried 3 different methods as in this question: by adding an ever-changing parameter to the URL so it is always different, setting such a parameter in the call params and setting the caching headers directly. None of these fix the issue:

axios.get(`/cloud/function/url?timestamp=${new Date().getTime()}`, {
  headers: {
    Accept: "application/json, text/plain, */*",
    Authorization: `Bearer ${token}`,
    'Cache-Control': 'no-cache',
    Pragma: 'no-cache',
    Expires: '0',
  },
  params: {
    t: new Date().getTime()
  }
})

From my disabling front-end cache, redeploying front-end and the console.log I am confident the issue is not client-side. I curl the API directly to verify this:

curl '/my/function/url' -H 'Authorization: Bearer '"$token"'

Response for token 1: {data: ["a", "b", "c"]}

Response for token 2: {data: ["a", "b"]}

Response going back to token 1: {data: ["a", "b"]}

It seems clear the cloud function really is returning some type of cached response. This is further reinforced by the fact that redeploying the cloud function does fix the issue. How do I stop a Google Cloud Function from caching responses?

Edit: further details on how the backend retrieves the data for each token

Data is stored in a Firestore NoSQL document database. Each entry has the user account as the document name and the allowed data as fields in the document.

user1: {a: null, b: null, c: null}
user2: {a: null, b: null}

The get_authorized_data function gets the user account from the token and retrieves the allowed data items from the Firestore:

from firebase_admin import auth, firestore

db = firestore.client()

def get_authorized_data(token):
    # This returns {'uid': '123', 'email': 'example@example.com'}
    decoded_token = auth.verify_id_token(id_token)
    document = db.collection(u'allowed-data-per-user')\
               .document(decoded_token['email']).get()
    allowed_data = list(document.to_dict().keys())
    return allowed_data

If you notice my comments about the print statement in the first block of python at the top of the question, this retrieves the correct data: always ['a', 'b', 'c'] for token 1 and always ['a', 'b'] for token 2. I do not believe that this is the part at fault.


问:
Python pymongo using Aggregate with matching the Date from the DB
I need to Sum all values from different time series.

```<code>yesterday = datetime.datetime.combine(datetime.datetime.now(), datetime.time.min) - datetime.timedelta(days=1)

test = db.aggregate([
                        { "$match": { "date": yesterday, "location": location } },
                        { '$group': { '_id': "$location", 'cost': { '$sum': '$cost' } } }
                    ])
</code>```

This works for me to get the sum for yesterday, but for flexibility i want to change it.

```<code>test = db.aggregate([
                    { "$project": { "year": { "$year": "$date" }, "month": { "$month": "$date" } } },
                    { "$match": { "month": 1, "year": 2023, "location": location } },
                    { '$group': { '_id': "$location", 'cost': { '$sum': '$cost' } } }
                ])
</code>```

When I change it like that, i don't get a result.

I notices, when i run this Code

```<code>test = db.aggregate([{ "$project": { "year" : { "$year": "$posting_date" } } }])
</code>```

I get the output like {'_id': ObjectId('63b6e6c215161672a159417f'), 'year': 2023} so the field year should be created correctly, shouldn't it? So why it is not working with the $match?

Body:
I need to Sum all values from different time series.

yesterday = datetime.datetime.combine(datetime.datetime.now(), datetime.time.min) - datetime.timedelta(days=1)

test = db.aggregate([
                        { "$match": { "date": yesterday, "location": location } },
                        { '$group': { '_id': "$location", 'cost': { '$sum': '$cost' } } }
                    ])

This works for me to get the sum for yesterday, but for flexibility i want to change it.

test = db.aggregate([
                    { "$project": { "year": { "$year": "$date" }, "month": { "$month": "$date" } } },
                    { "$match": { "month": 1, "year": 2023, "location": location } },
                    { '$group': { '_id': "$location", 'cost': { '$sum': '$cost' } } }
                ])

When I change it like that, i don't get a result.

I notices, when i run this Code

test = db.aggregate([{ "$project": { "year" : { "$year": "$posting_date" } } }])

I get the output like {'_id': ObjectId('63b6e6c215161672a159417f'), 'year': 2023} so the field year should be created correctly, shouldn't it? So why it is not working with the $match?


问:
Ag Grid getModel
I have a React project with rowModelType = 'serverSide'.
I also have a custom component for filtering.
And I have an external button that should clear this filter
When I click on the button the function is triggered - gridApi.setFilterModel(null);
Next, the setModel function is called in the component
Where
assigned to this.setState({checkedFilters: []})
Next, the gridApi.getFilterModel() method is called;
Next, the getModel() method is called where this.state.checkedFilters is equal to the old value i.e. [1,2]
Maybe somebody will prompt in what a problem of obtaining of old value?

```<code>**Component state =
this.state = {
checkedFilters: [1,2]
};**
</code>```

Title: Ag Grid getModel

Body:
I have a React project with rowModelType = 'serverSide'.
I also have a custom component for filtering.
And I have an external button that should clear this filter
When I click on the button the function is triggered - gridApi.setFilterModel(null);
Next, the setModel function is called in the component
Where
assigned to this.setState({checkedFilters: []})
Next, the gridApi.getFilterModel() method is called;
Next, the getModel() method is called where this.state.checkedFilters is equal to the old value i.e. [1,2]
Maybe somebody will prompt in what a problem of obtaining of old value?

**Component state =
this.state = {
checkedFilters: [1,2]
};**


问:
typesafe config - prefer empty value over fallback
having config A:

akka {
  cluster {} //empty
}
```
<p>and config B:</p>
<pre class="lang-scala prettyprint-override"><code>akka {
  cluster { some = thing } //non empty
}
</code>```

I would like to get akka.cluster = empty - taken from first object A when merging them, e.g.

val config = A.withFallback(B). // prefers A over B... but
```

but when merging happens, it recursively goes into the contents of A/B
and it then compares null field from A with non-null field of B
and thus returns contents of B.

Long story short: empty object does NOT take priority over non-empty object

Is there a way to make sure that empty A takes over the non-empty B?

thanks

ps: it's a simplified example. I need to merge a more complex A with a more complex B, so I am looking for a general solution

Body:
having config A:

akka {
  cluster {} //empty
}

and config B:

akka {
  cluster { some = thing } //non empty
}

I would like to get akka.cluster = empty - taken from first object A when merging them, e.g.

val config = A.withFallback(B). // prefers A over B... but

but when merging happens, it recursively goes into the contents of A/B
and it then compares null field from A with non-null field of B
and thus returns contents of B.

Long story short: empty object does NOT take priority over non-empty object

Is there a way to make sure that empty A takes over the non-empty B?

thanks

ps: it's a simplified example. I need to merge a more complex A with a more complex B, so I am looking for a general solution


问:
Plotly Hover breaks when adding color attribute
My graph is doing something strange. The hover data works for some of the points, but not all of them.
When I comment out the color piece, it works just fine. But I really would like the colors to stay.

Here is my code for the graph:

```<code>    df = pd.DataFrame(data['df'])
    df['MeasureDate'] = pd.to_datetime(df['MeasureDate'], infer_datetime_format=True)
    df['Sign'] = np.where(df['DeviationValue'] > 0, 'Positive', 'Negative')
    fig = px.area(df,
                  y='DeviationValue',
                  title=f"Graph of {data['engine']} going back one year from {data['date']}",
                  color='Sign',
                  color_discrete_map={
                    'Positive': 'green',
                    'Negative': 'red'
                  },
                  labels={
                    "DeviationValue": 'Deviation',
                    'index': ''
                  },
                  custom_data=['MeasureDate', 'DeviationValue']
                )
    fig.update_traces(showlegend=False, hovertemplate='Date: %{customdata[0]} <br>Deviation: %{customdata[1]}')
</code>```

Please let me know if you have any solutions or thoughts! Thanks!

Body:
My graph is doing something strange. The hover data works for some of the points, but not all of them.
When I comment out the color piece, it works just fine. But I really would like the colors to stay.

Here is my code for the graph:

    df = pd.DataFrame(data['df'])
    df['MeasureDate'] = pd.to_datetime(df['MeasureDate'], infer_datetime_format=True)
    df['Sign'] = np.where(df['DeviationValue'] > 0, 'Positive', 'Negative')
    fig = px.area(df,
                  y='DeviationValue',
                  title=f"Graph of {data['engine']} going back one year from {data['date']}",
                  color='Sign',
                  color_discrete_map={
                    'Positive': 'green',
                    'Negative': 'red'
                  },
                  labels={
                    "DeviationValue": 'Deviation',
                    'index': ''
                  },
                  custom_data=['MeasureDate', 'DeviationValue']
                )
    fig.update_traces(showlegend=False, hovertemplate='Date: %{customdata[0]}
Deviation: %{customdata[1]}')

Please let me know if you have any solutions or thoughts! Thanks!