@@ -37,6 +37,7 @@ int feenox_problem_solve_petsc_transient(void) {
3737 feenox_call (feenox_problem_solve_petsc_nonlinear ());
3838 petsc_call (SNESDestroy (& feenox .pde .snes ));
3939 feenox .pde .snes = NULL ;
40+
4041 }
4142 } else {
4243 feenox_function_to_phi (feenox .pde .initial_condition , feenox .pde .phi );
@@ -50,8 +51,10 @@ int feenox_problem_solve_petsc_transient(void) {
5051 if (feenox .pde .initial_condition != NULL ) {
5152 feenox_call (feenox_problem_build ());
5253 }
53- petsc_call (MatDuplicate (feenox .pde .has_jacobian_K ? feenox .pde .JK : feenox .pde .K , MAT_COPY_VALUES , & feenox .pde .J_tran ));
54- petsc_call (TSSetIJacobian (feenox .pde .ts , feenox .pde .J_tran , feenox .pde .J_tran , feenox_ts_jacobian , NULL ));
54+
55+ feenox_check_alloc (feenox .pde .J_ts = feenox_problem_create_matrix ("J_ts" ));
56+ // petsc_call(MatDuplicate(feenox.pde.has_jacobian_K ? feenox.pde.JK : feenox.pde.K, MAT_COPY_VALUES, &feenox.pde.J_ts));
57+ petsc_call (TSSetIJacobian (feenox .pde .ts , feenox .pde .J_ts , feenox .pde .J_ts , feenox_ts_jacobian , NULL ));
5558
5659 petsc_call (TSSetProblemType (feenox .pde .ts , (feenox .pde .math_type == math_type_linear ) ? TS_LINEAR : TS_NONLINEAR ));
5760
@@ -118,11 +121,6 @@ int feenox_problem_setup_ts(TS ts) {
118121// petsc_call(TSSetMaxStepRejections(feenox.pde.ts, 10000));
119122// petsc_call(TSSetMaxSNESFailures(feenox.pde.ts, 1000));
120123
121- // options overwrite
122- petsc_call (TSSetFromOptions (ts ));
123- // TODO: this guy complains about DM (?)
124- // petsc_call(TSSetUp(ts));
125-
126124 SNES snes ;
127125 petsc_call (TSGetSNES (ts , & snes ));
128126 if (snes != NULL ) {
@@ -135,65 +133,88 @@ int feenox_problem_setup_ts(TS ts) {
135133 }
136134 }
137135
136+ // options overwrite
137+ petsc_call (TSSetFromOptions (ts ));
138138
139139
140140 return FEENOX_OK ;
141141}
142142
143143PetscErrorCode feenox_ts_residual (TS ts , PetscReal t , Vec phi , Vec phi_dot , Vec r , void * ctx ) {
144144
145- // static int count = 0;
146- feenox_var_value (feenox_special_var (t )) = t ;
147-
145+ feenox_special_var_value (t ) = t ;
146+
147+ // TODO: store in a global temporary vector
148+ Vec phi_bc ;
149+ petsc_call (VecDuplicate (phi , & phi_bc ));
150+ petsc_call (VecCopy (phi , phi_bc ));
151+
152+ feenox_call (feenox_problem_dirichlet_eval ());
148153 if (feenox .pde .math_type == math_type_nonlinear ) {
149- feenox_call (feenox_problem_phi_to_solution (phi , 0 ));
154+ feenox_call (feenox_problem_dirichlet_set_phi (phi_bc ));
155+ feenox_call (feenox_problem_phi_to_solution (phi_bc , 0 ));
156+ if (feenox .pde .phi_bc != NULL ) {
157+ petsc_call (VecCopy (phi_bc , feenox .pde .phi_bc ));
158+ }
150159 }
151160
152161 // TODO: for time-dependent neumann BCs it should not be needed to re-build the whole matrix, just the RHS
153162 feenox_call (feenox_problem_build ());
154163
155- // TODO: be smart about this too
156- feenox_call (feenox_problem_dirichlet_eval ());
157-
158- // compute the residual R(t,phi,phi_dot) = M*(phi_dot)_dirichlet + K*(phi)_dirichlet - b
164+ // compute the residual R(t,phi,phi_dot) = M*(phi_dot)_dirichlet + K*(phi)_dirichlet - b (linear)
165+ // = M*(phi_dot)_dirichlet + f(phi)_dirichlet - b (non-linear)
159166
160- // TODO: store in a global temporary vector
161- Vec tmp ;
162- petsc_call (VecDuplicate (phi , & tmp ));
163-
167+ // TODO: start with the K/f term and add the mass later
164168 // set dirichlet BCs on the time derivative and multiply by M
165169 if (feenox .pde .M != NULL ) {
166- petsc_call (VecCopy (phi_dot , tmp ));
167- feenox_call (feenox_problem_dirichlet_set_phi_dot (tmp ));
168- petsc_call (MatMult (feenox .pde .M , tmp , r ));
170+ Vec phi_dot_bc ;
171+ petsc_call (VecDuplicate (phi , & phi_dot_bc ));
172+ petsc_call (VecCopy (phi_dot , phi_dot_bc ));
173+ feenox_call (feenox_problem_dirichlet_set_phi_dot (phi_dot_bc ));
174+ petsc_call (MatMult (feenox .pde .M , phi_dot_bc , r ));
175+ petsc_call (VecDestroy (& phi_dot_bc ));
169176 } else {
170177 petsc_call (VecZeroEntries (r ));
171178 }
172179
173- // set dirichlet BCs on the solution and multiply by K
174- // TODO: only if the problem does not compute an actual residual!
175- petsc_call (VecCopy (phi , tmp ));
176- feenox_call (feenox_problem_dirichlet_set_phi (tmp ));
177-
178- petsc_call (MatMultAdd (feenox .pde .K , tmp , r , r ));
179- petsc_call (VecDestroy (& tmp ));
180+ // set dirichlet BCs on the solution compute the residual
181+ if (feenox .pde .has_internal_fluxes ) {
182+ // if the problem provides an internal flux, use it
183+ petsc_call (VecCopy (feenox .pde .f , r ));
184+ } else {
185+ // otherwise make it up from the stiffness and the solution
186+ petsc_call (MatMultAdd (feenox .pde .K , phi_bc , r , r ));
187+ }
188+ petsc_call (VecDestroy (& phi_bc ));
180189
181190 petsc_call (VecAXPY (r , -1.0 , feenox .pde .b ));
182191
183192 // set dirichlet bcs on the residual
184193 feenox_call (feenox_problem_dirichlet_set_r (r , phi ));
185-
194+
186195 return FEENOX_OK ;
187196}
188197
189- PetscErrorCode feenox_ts_jacobian (TS ts , PetscReal t , Vec phi , Vec phi_dot , PetscReal s , Mat J , Mat P , void * ctx ) {
198+ PetscErrorCode feenox_ts_jacobian (TS ts , PetscReal t , Vec phi , Vec phi_dot , PetscReal s , Mat J_ts , Mat P , void * ctx ) {
190199
191- // return (K + s*M)_dirichlet
192- petsc_call (MatCopy (feenox .pde .K , J , SAME_NONZERO_PATTERN ));
193- if (feenox .pde .M != NULL ) {
194- petsc_call (MatAXPY (J , s , feenox .pde .M , SAME_NONZERO_PATTERN ));
200+ petsc_call (MatAssemblyBegin (feenox .pde .K , MAT_FINAL_ASSEMBLY ));
201+ petsc_call (MatAssemblyEnd (feenox .pde .K , MAT_FINAL_ASSEMBLY ));
202+ petsc_call (MatAssemblyBegin (J_ts , MAT_FINAL_ASSEMBLY ));
203+ petsc_call (MatAssemblyEnd (J_ts , MAT_FINAL_ASSEMBLY ));
204+
205+ // return (K + JK - Jb + s*M)_bc
206+ petsc_call (MatCopy (feenox .pde .K , J_ts , DIFFERENT_NONZERO_PATTERN ));
207+ if (feenox .pde .has_jacobian_K ) {
208+ petsc_call (MatAXPY (J_ts , +1.0 , feenox .pde .JK , DIFFERENT_NONZERO_PATTERN ));
209+ }
210+ if (feenox .pde .has_jacobian_b ) {
211+ petsc_call (MatAXPY (J_ts , -1.0 , feenox .pde .Jb , DIFFERENT_NONZERO_PATTERN ));
212+ }
213+
214+ if (feenox .pde .has_mass ) {
215+ petsc_call (MatAXPY (J_ts , s , feenox .pde .M , DIFFERENT_NONZERO_PATTERN ));
195216 }
196- feenox_call (feenox_problem_dirichlet_set_J (J ));
217+ feenox_call (feenox_problem_dirichlet_set_J (J_ts ));
197218
198219 return FEENOX_OK ;
199220}
0 commit comments