231 const PetscInt ti = simCtx->
step;
232 const PetscReal dt = simCtx->
dt;
234 const PetscReal alfa[] = {0.25, 1.0/3.0, 0.5, 1.0};
238 PetscBool force_restart = PETSC_FALSE;
242 const PetscReal tol_abs_delta = simCtx->
mom_atol;
243 const PetscReal tol_rtol_delta = simCtx->
mom_rtol;
248 PetscInt istage, pseudo_iter, ibi;
249 PetscReal ts, te, cput;
252 PetscReal global_norm_delta = 10.0;
253 PetscReal global_rel_delta = 1.0;
254 PetscReal global_rel_resid = 1.0;
257 PetscReal *delta_sol_norm_init, *delta_sol_norm_prev, *delta_sol_norm_curr, *delta_sol_rel_curr;
258 PetscReal *resid_norm_init, *resid_norm_prev, *resid_norm_curr, *resid_rel_curr;
259 PetscReal *pseudo_dt_scaling;
261 PetscFunctionBeginUser;
263 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
267 ierr = PetscMalloc2(block_number, &delta_sol_norm_init, block_number, &delta_sol_norm_prev); CHKERRQ(ierr);
268 ierr = PetscMalloc2(block_number, &delta_sol_norm_curr, block_number, &delta_sol_rel_curr); CHKERRQ(ierr);
269 ierr = PetscMalloc2(block_number, &resid_norm_init, block_number, &resid_norm_prev); CHKERRQ(ierr);
270 ierr = PetscMalloc2(block_number, &resid_norm_curr, block_number, &pseudo_dt_scaling); CHKERRQ(ierr);
271 ierr = PetscMalloc1(block_number, &resid_rel_curr); CHKERRQ(ierr);
272 ierr = PetscMalloc1(block_number, &pRhs); CHKERRQ(ierr);
274 ierr = PetscTime(&ts); CHKERRQ(ierr);
278 if (block_number > 1) {
282 for (PetscInt bi = 0; bi < block_number; bi++) {
288 ierr = VecDuplicate(user[bi].Ucont, &user[bi].Rhs); CHKERRQ(ierr);
289 ierr = VecDuplicate(user[bi].Rhs, &pRhs[bi]); CHKERRQ(ierr);
290 ierr = VecDuplicate(user[bi].Ucont, &user[bi].dUcont); CHKERRQ(ierr);
291 ierr = VecDuplicate(user[bi].Ucont, &user[bi].pUcont); CHKERRQ(ierr);
294 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
300 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
303 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_init[bi]); CHKERRQ(ierr);
306 resid_norm_prev[bi] = resid_norm_init[bi];
307 delta_sol_norm_prev[bi] = 1000.0;
308 pseudo_dt_scaling[bi] = cfl;
315 while ((force_restart || (global_norm_delta > tol_abs_delta || global_rel_delta > tol_rtol_delta) || pseudo_iter < 1)
316 && pseudo_iter < max_pseudo_steps)
319 force_restart = PETSC_FALSE;
321 for (PetscInt bi = 0; bi < block_number; bi++) {
324 for (istage = 0; istage < 4; istage++) {
329 ierr = VecWAXPY(user[bi].Ucont,
330 pseudo_dt_scaling[bi] * alfa[istage] * dt,
332 user[bi].pUcont); CHKERRQ(ierr);
352 ierr = VecWAXPY(user[bi].dUcont, -1.0, user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
355 ierr = VecNorm(user[bi].dUcont, NORM_INFINITY, &delta_sol_norm_curr[bi]); CHKERRQ(ierr);
356 ierr = VecNorm(user[bi].Rhs, NORM_INFINITY, &resid_norm_curr[bi]); CHKERRQ(ierr);
359 if (pseudo_iter == 1) {
360 delta_sol_norm_init[bi] = delta_sol_norm_curr[bi];
361 delta_sol_rel_curr[bi] = 1.0;
362 resid_rel_curr[bi] = 1.0;
365 if (delta_sol_norm_init[bi] > 1.0e-10)
366 delta_sol_rel_curr[bi] = delta_sol_norm_curr[bi] / delta_sol_norm_init[bi];
368 delta_sol_rel_curr[bi] = 0.0;
370 if(resid_norm_init[bi] > 1.0e-10)
371 resid_rel_curr[bi] = resid_norm_curr[bi] / resid_norm_init[bi];
373 resid_rel_curr[bi] = 0.0;
380 sprintf(filen,
"%s/Momentum_Solver_Convergence_History_Block_%1d.log", simCtx->
log_dir, bi);
381 if(simCtx->
step == simCtx->
StartStep + 1 && pseudo_iter == 1) f = fopen(filen,
"w");
382 else f = fopen(filen,
"a");
384 PetscFPrintf(PETSC_COMM_WORLD, f,
"Step: %d | PseudoIter(k): %d| | Pseudo-cfl: %.4f |dUk|: %le | |dUk|/|dUprev|: %le | |Rk|: %le | |Rk|/|Rprev|: %le \n",
385 (
int)ti, (
int)pseudo_iter, pseudo_dt_scaling[bi], delta_sol_norm_curr[bi], delta_sol_rel_curr[bi], resid_norm_curr[bi],resid_rel_curr[bi]);
391 global_norm_delta = -1.0e20;
392 global_rel_delta = -1.0e20;
393 global_rel_resid = -1.0e20;
395 for (PetscInt bi = 0; bi < block_number; bi++) {
396 global_norm_delta = PetscMax(delta_sol_norm_curr[bi], global_norm_delta);
397 global_rel_delta = PetscMax(delta_sol_rel_curr[bi], global_rel_delta);
398 global_rel_resid = PetscMax(resid_rel_curr[bi], global_rel_resid);
400 ierr = PetscTime(&te); CHKERRQ(ierr);
403 pseudo_iter, global_norm_delta, global_rel_delta, global_rel_resid, cput);
406 for (PetscInt bi = 0; bi < block_number; bi++) {
408 PetscReal resid_ratio = resid_norm_curr[bi] / resid_norm_prev[bi];
410 PetscBool is_sol_nan, is_resid_nan, is_diverging;
412 is_sol_nan = (PetscBool)PetscIsNanReal(delta_sol_norm_curr[bi]);
413 is_resid_nan = (PetscBool)PetscIsNanReal(resid_norm_curr[bi]);
416 is_diverging = (PetscBool)(pseudo_iter > 1 &&
418 delta_sol_norm_curr[bi] > delta_sol_norm_prev[bi]
421 if(is_diverging || is_sol_nan || is_resid_nan) {
434 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED,
435 "Block %d: Solver diverged (NaN or explosion) and min time-step reached. Simulation aborted.", bi);
439 force_restart = PETSC_TRUE;
445 LOG_ALLOW(
LOCAL,
LOG_DEBUG,
" Block %d: Backtracking triggered. Reducing scaling to %f.\n", bi, pseudo_dt_scaling[bi]);
448 ierr = VecCopy(user[bi].pUcont, user[bi].Ucont); CHKERRQ(ierr);
450 ierr = VecCopy(pRhs[bi], user[bi].Rhs); CHKERRQ(ierr);
458 delta_sol_norm_curr[bi] = 1000.0;
459 resid_norm_curr[bi] = 1000.0;
464 ierr = VecCopy(user[bi].Ucont, user[bi].pUcont); CHKERRQ(ierr);
465 ierr = VecCopy(user[bi].Rhs, pRhs[bi]); CHKERRQ(ierr);
466 resid_norm_prev[bi] = resid_norm_curr[bi];
467 delta_sol_norm_prev[bi] = delta_sol_norm_curr[bi];
471 PetscBool is_converging_fast;
472 is_converging_fast = (PetscBool)(resid_ratio < 0.9);
473 PetscBool is_stagnating;
474 is_stagnating = (PetscBool)(resid_ratio >= 0.98 && resid_ratio < 1.0);
476 is_noisy = (PetscBool)(resid_ratio >= 1.0 && resid_ratio < simCtx->mom_dt_rk4_residual_norm_noise_allowance_factor);
478 PetscReal current_cfl = pseudo_dt_scaling[bi];
482 if(is_converging_fast){
485 }
else if(is_stagnating && current_cfl < cfl_floor){
488 }
else if(is_stagnating && current_cfl >= cfl_floor && current_cfl < cfl_ceiling && !is_noisy){
491 }
else if(is_stagnating && current_cfl >= cfl_ceiling && !is_noisy){
496 if(current_cfl > cfl_ceiling){
499 }
else if(current_cfl > cfl_floor && current_cfl <= cfl_ceiling){
502 }
else if(current_cfl <= cfl_floor){
509 pseudo_dt_scaling[bi] = PetscMin(pseudo_dt_scaling[bi], simCtx->
max_pseudo_cfl);
510 pseudo_dt_scaling[bi] = PetscMax(pseudo_dt_scaling[bi], simCtx->
min_pseudo_cfl);
515 if (force_restart) pseudo_iter--;
517 if (block_number > 1) {
525 PetscReal local_min_cfl = 1.0e20;
526 PetscReal global_min_cfl;
531 for (PetscInt bi = 0; bi < block_number; bi++) {
532 if (pseudo_dt_scaling[bi] < local_min_cfl) {
533 local_min_cfl = pseudo_dt_scaling[bi];
539 ierr = MPI_Allreduce(&local_min_cfl, &global_min_cfl, 1, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
545 PetscReal cfl_carry_over_relaxation_factor = 1.0;
547 PetscReal next_start_cfl;
549 if(global_min_cfl < cfl_floor){
551 next_start_cfl = cfl_floor * 1.5;
553 next_start_cfl = global_min_cfl * cfl_carry_over_relaxation_factor;
556 next_start_cfl = PetscMin(next_start_cfl, simCtx->
max_pseudo_cfl);
557 next_start_cfl = PetscMax(next_start_cfl, simCtx->
min_pseudo_cfl);
561 LOG_ALLOW(
GLOBAL,
LOG_INFO,
" CFL Adaptation: Step %d finished at CFL %.3f. Next step will start at CFL %.3f.\n",
562 simCtx->
step, global_min_cfl, next_start_cfl);
569 for (PetscInt bi = 0; bi < block_number; bi++) {
570 ierr = VecDestroy(&user[bi].Rhs); CHKERRQ(ierr);
571 ierr = VecDestroy(&user[bi].dUcont); CHKERRQ(ierr);
572 ierr = VecDestroy(&user[bi].pUcont); CHKERRQ(ierr);
573 ierr = VecDestroy(&pRhs[bi]); CHKERRQ(ierr);
575 ierr = PetscFree(pRhs); CHKERRQ(ierr);
577 ierr = PetscFree2(delta_sol_norm_init, delta_sol_norm_prev);CHKERRQ(ierr);
578 ierr = PetscFree2(delta_sol_norm_curr, delta_sol_rel_curr);CHKERRQ(ierr);
579 ierr = PetscFree2(resid_norm_init, resid_norm_prev);CHKERRQ(ierr);
580 ierr = PetscFree2(resid_norm_curr, pseudo_dt_scaling); CHKERRQ(ierr);
581 ierr = PetscFree(resid_rel_curr); CHKERRQ(ierr);
585 PetscFunctionReturn(0);