Project: s41467-024-51319-4 | Function: minConstBoxShapeFIRE (cpp)

system: You are an expert C++ programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow C++ best practices and maintain consistent code style.
Return **only** the complete C++ function code.

user: Complete this C++ function:

**DESCRIPTION:** Implements FIRE (Fast Inertial Relaxation Engine) algorithm for energy minimization of granular systems under constant box shape constraint

**KEY TERMS:** {
  "npPos": "negative power position counter",
  "alf": "damping parameter alpha",
  "dtval": "timestep value",
  "fconv": "force convergence threshold",
  "forceMax": "maximum force magnitude",
  "veloc": "particle velocities"
}

**CONTEXT CODE:**
    fire->vdotf = vdotf;
    fire->vdotv = vdotv;
    fire->fdotf = fdotf;
    fire->aveForce = sumForce / particle->nAtom;
}

ConstBoxShapeFIRE *addConstBoxShapeFIRE(Box *box, Particle *particle, Update *update) {
    if (getConstBoxShapeFIRE(update) != NULL) {
        return getConstBoxShapeFIRE(update);
    }
    ConstBoxShapeFIRE *fire = (ConstBoxShapeFIRE *)calloc(sizeof(ConstBoxShapeFIRE), 1);
    addToolkit(&update->toolkit, (void *)fire, NULL, "__ConstBoxShapeFireRelax__");
    
    fire->dtSet = 5E-3;
    fire->isInit = true;
    return fire;
}
int reInitConstBoxShapeFIRE(ConstBoxShapeFIRE *fire){
    memset(fire, '\0', sizeof(ConstBoxShapeFIRE));
    
    fire->dtSet = 5E-3;
    fire->isInit = true;
    return 1;
}
ConstBoxShapeFIRE *getConstBoxShapeFIRE(Update *update) {
    int whichTool = findToolkit(&update->toolkit, "__ConstBoxShapeFireRelax__");
    if (whichTool < 0)
        return NULL;
    return (ConstBoxShapeFIRE *)update->toolkit.toolkit[whichTool];
}
int minConstBoxShapeFIRE(Box *box, Particle *particle, Update *update) {
    ConstBoxShapeFIRE *fire = getConstBoxShapeFIRE(update);
    if (!fire || !fire->isInit) Abort("Call addConstBoxShapeFireRelax(...) or reInitConstBoxShapeFireRelax(...)!");
    
    box->isShapeFixed = true;
    particle->isSizeFixed = true;
    update->nebrList.nDelay = 0;
    update->nebrList.skinSet = 0.1;

    update->Edone = update->Pdone = update->Wdone = update->Tdone = false;
    update->isThermalRun = false;
    update->nebrList.nDelay = 0;
    update->nebrList.nRebuildMax = 0;
    
    double dtmax = 0.5 * update->timeUnits;
    int currStep = 0, last_negative = 0;
    double alpha = ALPHA0;
    fire->dt = fire->dtSet * update->timeUnits;
    double dt0 = fire->dt;
    double ePairLastNeg = 0;
    int rVal = 0;
    
    calcForce(box, particle, update);
    cbsFire_DotProduct(box, particle, fire);
    fire->aveForce /= update->forceUnits;
    // remove the side effects of _dotProduct()
    memset(particle->veloc, '\0', particle->nAtom * sizeof(doubleVector));
    ePairLastNeg = update->ePair;
    while (!(fire->aveForce <= __ZeroForce__)) {
        // update x
        cbsFire_Integrate(box, particle, fire);
        
        // update v
        calcForce(box, particle, update);
        cbsFire_DotProduct(box, particle, fire);
        fire->aveForce /= update->forceUnits;
        currStep++;
        
        // mixing v and update timestep
        if (fire->vdotf > 0) {
            if (currStep - last_negative > DELAYSTEP) {
                fire->dt *= DT_GROW;
                fire->dt = fmin(fire->dt, dtmax);
                alpha *= ALPHA_SHRINK;
            }
            
            double scale1 = 1.0 - alpha;
            double scale2 = alpha * sqrt(fire->vdotv / fire->fdotf);
            for (int iatom = 0; iatom < particle->nAtom; iatom++) {
                doubleVecPtr veloc = particle->veloc[iatom];
                doubleVecPtr force = particle->force[iatom];
                vScale(veloc, scale1, veloc);
                vScaleAdd(veloc, veloc, scale2, force);
            }
        } else {
            int deltaStep = currStep - last_negative;
            if (deltaStep < log(dtmax / dt0) * 10.5 + DELAYSTEP) {
                dtmax = dtmax * 0.9;
                dtmax = fmax(dtmax, 5.0 * fire->dtSet * update->timeUnits);
            } else if (deltaStep > 3.0 * log(dtmax / dt0) * 10.5 + DELAYSTEP) {
                dtmax = dtmax * 1.1;
                dtmax = fmin(dtmax, 0.5 * update->timeUnits);
            }
            
            fire->dt *= DT_SHRINK;
            fire->dt = fmax(fire->dt, 0.1 * fire->dtSet * update->timeUnits);
            
            #ifdef Hertzian
            if (ePairLastNeg - update->ePair < __MinDeltaE__) {
                rVal = 2;
                break;
            }
            #endif
            
            dt0 = fire->dt;
            last_negative = currStep;
            ePairLastNeg = update->ePair;
            alpha = ALPHA0;
            memset(particle->veloc, '\0', particle->nAtom * sizeof(doubleVector));
        }
        
        if (update->ePair / update->energyUnits < __ZeroEnergy__) {
            rVal = 1;
            break;
        }
        
//        if (currStep % 1000==0) {
//            printf("%d %g %g\n",currStep,update->ePair,fire->aveForce);
//        }
        if (currStep >= 1E7) {
            rVal = -1;
            break;
        }
    }
    
    fire->isInit = false;
    return rVal;
    //0: force converge;
    //1: unjamming due to energy criteria；
    //2: deltaE between two successive over runing step is less than 1E-16;
    //-1: not converge and return due to runing step limits 1E7;
}
int delConstBoxShapeFIRE(Update *update) {
    ConstBoxShapeFIRE *fire = getConstBoxShapeFIRE(update);
    if (!fire)
        return -1;
    delToolkit(&update->toolkit, "__ConstBoxShapeFireRelax__");
    return 0;
}

//===============================
void eliminate_fire(Box *box, Particle *particle, Update *update) {
    ConstBoxShapeFIRE *fire = getConstBoxShapeFIRE(update);
    reInitConstBoxShapeFIRE(fire);
    
    update->Edone = update->Pdone = update->Wdone = update->Tdone = false;
    update->isThermalRun = false;
    update->nebrList.nDelay = 0;
    update->nebrList.nRebuildMax = 0;