static char help[] = "Solves the trivial ODE du/dt = 1, u(0) = 0. \n\n"; /* This example tests TSEvent's capability to handle complicated cases. Test 1: an event close to endpoint of a time step should not be detected twice. Test 2: two events in the same time step should be detected in the correct order. Test 3: three events in the same time step should be detected in the correct order. */ #include static PetscErrorCode RHSFunction(TS, PetscReal, Vec, Vec, void *); static PetscErrorCode RHSJacobian(TS, PetscReal, Vec, Mat, Mat, void *); static PetscErrorCode Event(TS, PetscReal, Vec, PetscReal *, void *); static PetscErrorCode PostEvent(TS, PetscInt, PetscInt[], PetscReal, Vec, PetscBool, void *); int main(int argc, char **argv) { TS ts; const PetscReal t_end = 2.0; Vec x; Vec f; Mat A; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &argv, NULL, help)); PetscCall(TSCreate(PETSC_COMM_WORLD, &ts)); PetscCall(VecCreate(PETSC_COMM_WORLD, &f)); PetscCall(VecSetSizes(f, 1, PETSC_DECIDE)); PetscCall(VecSetFromOptions(f)); PetscCall(VecSetUp(f)); PetscCall(TSSetRHSFunction(ts, f, RHSFunction, NULL)); PetscCall(VecDestroy(&f)); PetscCall(MatCreate(PETSC_COMM_WORLD, &A)); PetscCall(MatSetSizes(A, 1, 1, PETSC_DECIDE, PETSC_DECIDE)); PetscCall(MatSetFromOptions(A)); PetscCall(MatSetUp(A)); PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); /* ensure that the Jacobian matrix has diagonal entries since that is required by TS */ PetscCall(MatShift(A, (PetscReal)1)); PetscCall(MatShift(A, (PetscReal)-1)); PetscCall(TSSetRHSJacobian(ts, A, A, RHSJacobian, NULL)); PetscCall(MatDestroy(&A)); PetscCall(VecCreate(PETSC_COMM_WORLD, &x)); PetscCall(VecSetSizes(x, 1, PETSC_DECIDE)); PetscCall(VecSetFromOptions(x)); PetscCall(VecSetUp(x)); PetscCall(TSSetSolution(ts, x)); PetscCall(VecDestroy(&x)); { PetscInt direction[3]; PetscBool terminate[3]; direction[0] = +1; terminate[0] = PETSC_FALSE; direction[1] = -1; terminate[1] = PETSC_FALSE; direction[2] = 0; terminate[2] = PETSC_FALSE; PetscCall(TSSetEventHandler(ts, 3, direction, terminate, Event, PostEvent, NULL)); } PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER)); PetscCall(TSSetMaxTime(ts, t_end)); PetscCall(TSSetFromOptions(ts)); PetscCall(TSSolve(ts, NULL)); PetscCall(TSDestroy(&ts)); PetscCall(PetscFinalize()); return 0; } PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec x, Vec f, PetscCtx ctx) { PetscFunctionBeginUser; PetscCall(VecSet(f, (PetscReal)1)); PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec x, Mat A, Mat B, PetscCtx ctx) { PetscFunctionBeginUser; PetscCall(MatZeroEntries(B)); if (B != A) PetscCall(MatZeroEntries(A)); PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode Event(TS ts, PetscReal t, Vec x, PetscReal *fvalue, PetscCtx ctx) { PetscFunctionBeginUser; fvalue[0] = t - 1.1; fvalue[1] = 1.2 - t; fvalue[2] = t - 1.3; PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode PostEvent(TS ts, PetscInt nevents, PetscInt event_list[], PetscReal t, Vec x, PetscBool forwardsolve, PetscCtx ctx) { PetscInt i; const PetscScalar *a; PetscFunctionBeginUser; PetscCall(TSGetStepNumber(ts, &i)); PetscCall(VecGetArrayRead(x, &a)); PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "%-10s-> step %" PetscInt_FMT " time %g value %g\n", PETSC_FUNCTION_NAME, i, (double)t, (double)PetscRealPart(a[0]))); PetscCall(VecRestoreArrayRead(x, &a)); PetscFunctionReturn(PETSC_SUCCESS); } /*TEST test: args: -ts_type beuler -ts_time_step 0.1 -ts_event_monitor test: suffix: 2 args: -ts_type beuler -ts_time_step 0.2 -ts_event_monitor test: suffix: 3 args: -ts_type beuler -ts_time_step 0.5 -ts_event_monitor TEST*/