1 /* Siconos is a program dedicated to modeling, simulation and control
2 * of non smooth dynamical systems.
3 *
4 * Copyright 2021 INRIA.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 #include <assert.h> // for assert
19 #include <float.h> // for DBL_EPSILON
20 #include <math.h> // for fabs, sqrt
21 #include <stdio.h> // for fclose, fopen
22 #include <stdlib.h> // for calloc, malloc
23 #include <string.h> // for NULL, memcpy
24 #include "FrictionContactProblem.h" // for FrictionContac...
25 #include "Friction_cst.h" // for SICONOS_FRICTI...
26 #include "NumericsArrays.h" // for uint_shuffle
27 #include "NumericsFwd.h" // for SolverOptions
28 #include "SolverOptions.h" // for SolverOptions
29 #include "fc3d_2NCP_Glocker.h" // for NCPGlocker_update
30 #include "fc3d_NCPGlockerFixedPoint.h" // for fc3d_FixedP_in...
31 #include "fc3d_Path.h" // for fc3d_Path_init...
32 #include "fc3d_Solvers.h" // for ComputeErrorPtr
33 #include "fc3d_compute_error.h" // for fc3d_compute_e...
34 #include "fc3d_local_problem_tools.h" // for fc3d_local_pro...
35 #include "fc3d_onecontact_nonsmooth_Newton_solvers.h" // for fc3d_onecontac...
36 #include "fc3d_projection.h" // for fc3d_projectio...
37 #include "fc3d_unitary_enumerative.h" // for fc3d_unitary_e...
38 #include "numerics_verbose.h" // for numerics_printf
39 #include "SiconosBlas.h" // for cblas_dnrm2
40 /* #define DEBUG_STDOUT */
41 /* #define DEBUG_MESSAGES */
42 #include "siconos_debug.h" // for DEBUG_EXPR
43
44
45 //#define FCLIB_OUTPUT
46
47 #ifdef FCLIB_OUTPUT
48 static int fccounter = -1;
49 #include "fclib_interface.h"
50 #endif
51
52
53
54 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
55
56 /* static void fake_compute_error_nsgs(FrictionContactProblem* problem, double *reaction, double *velocity, double tolerance, SolverOptions *options, double* error) */
57 /* { */
58 /* int n = 3 * problem->numberOfContacts; */
59 /* *error = 0.; */
60 /* int i, m; */
61 /* m = 5 * n / 3; */
62 /* double err = INFINITY; */
63 /* for (i = 0 ; i < m ; ++i) */
64 /* { */
65 /* *error += Compute_NCP_error1(i, err); */
66 /* } */
67 /* } */
68
fc3d_nsgs_update(int contact,FrictionContactProblem * problem,FrictionContactProblem * localproblem,double * reaction,SolverOptions * options)69 void fc3d_nsgs_update(int contact, FrictionContactProblem* problem, FrictionContactProblem* localproblem, double * reaction, SolverOptions* options)
70 {
71 /* Build a local problem for a specific contact
72 reaction corresponds to the global vector (size n) of the global problem.
73 */
74 /* Call the update function which depends on the storage for MGlobal/MBGlobal */
75 /* Build a local problem for a specific contact
76 reaction corresponds to the global vector (size n) of the global problem.
77 */
78
79 /* The part of MGlobal which corresponds to the current block is copied into MLocal */
80 fc3d_local_problem_fill_M(problem, localproblem, contact);
81
82 /**** Computation of qLocal = qBlock + sum over a row of blocks in MGlobal of the products MLocal.reactionBlock,
83 excluding the block corresponding to the current contact. ****/
84 fc3d_local_problem_compute_q(problem, localproblem, reaction, contact);
85
86 /* Friction coefficient for current block*/
87 localproblem->mu[0] = problem->mu[contact];
88 }
89
fc3d_nsgs_initialize_local_solver(SolverPtr * solve,UpdatePtr * update,FreeSolverNSGSPtr * freeSolver,ComputeErrorPtr * computeError,FrictionContactProblem * problem,FrictionContactProblem * localproblem,SolverOptions * options)90 void fc3d_nsgs_initialize_local_solver(SolverPtr* solve, UpdatePtr* update,
91 FreeSolverNSGSPtr* freeSolver,
92 ComputeErrorPtr* computeError,
93 FrictionContactProblem* problem,
94 FrictionContactProblem* localproblem,
95 SolverOptions * options)
96 {
97 SolverOptions * localsolver_options = options->internalSolvers[0];
98 /** Connect to local solver */
99 switch(localsolver_options->solverId)
100 {
101 /* Projection */
102 case SICONOS_FRICTION_3D_ONECONTACT_ProjectionOnConeWithDiagonalization:
103 {
104 *solve = &fc3d_projectionWithDiagonalization_solve;
105 *update = &fc3d_projectionWithDiagonalization_update;
106 *freeSolver = (FreeSolverNSGSPtr)&fc3d_projection_free;
107 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
108 fc3d_projection_initialize(problem, localproblem);
109 break;
110 }
111 case SICONOS_FRICTION_3D_ONECONTACT_ProjectionOnCone:
112 {
113 *solve = &fc3d_projectionOnCone_solve;
114 *update = &fc3d_projection_update;
115 *freeSolver = (FreeSolverNSGSPtr)&fc3d_projection_free;
116 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
117 fc3d_projection_initialize(problem, localproblem);
118 break;
119 }
120 case SICONOS_FRICTION_3D_ONECONTACT_ProjectionOnConeWithLocalIteration:
121 {
122 *solve = &fc3d_projectionOnConeWithLocalIteration_solve;
123 *update = &fc3d_projection_update;
124 *freeSolver = (FreeSolverNSGSPtr)&fc3d_projectionOnConeWithLocalIteration_free;
125 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
126 fc3d_projectionOnConeWithLocalIteration_initialize(problem, localproblem,localsolver_options);
127 break;
128 }
129 case SICONOS_FRICTION_3D_ONECONTACT_ProjectionOnConeWithRegularization:
130 {
131 *solve = &fc3d_projectionOnCone_solve;
132 *update = &fc3d_projection_update_with_regularization;
133 *freeSolver = (FreeSolverNSGSPtr)&fc3d_projection_with_regularization_free;
134 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
135 fc3d_projection_initialize_with_regularization(problem, localproblem);
136 break;
137 }
138 /* Newton solver (Alart-Curnier) */
139 case SICONOS_FRICTION_3D_ONECONTACT_NSN:
140 {
141 *solve = &fc3d_onecontact_nonsmooth_Newton_solvers_solve;
142 *update = &fc3d_onecontact_nonsmooth_Newton_AC_update;
143 *freeSolver = (FreeSolverNSGSPtr)&fc3d_onecontact_nonsmooth_Newton_solvers_free;
144 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
145 fc3d_onecontact_nonsmooth_Newton_solvers_initialize(problem, localproblem, localsolver_options);
146 break;
147 }
148 case SICONOS_FRICTION_3D_ONECONTACT_NSN_GP:
149 {
150 *solve = &fc3d_onecontact_nonsmooth_Newton_solvers_solve;
151 *update = &fc3d_onecontact_nonsmooth_Newton_AC_update;
152 *freeSolver = (FreeSolverNSGSPtr)&fc3d_onecontact_nonsmooth_Newton_solvers_free;
153 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
154 fc3d_onecontact_nonsmooth_Newton_solvers_initialize(problem, localproblem, localsolver_options);
155 break;
156 }
157 case SICONOS_FRICTION_3D_ONECONTACT_NSN_GP_HYBRID:
158 {
159 *solve = &fc3d_onecontact_nonsmooth_Newton_solvers_solve;
160 *update = &fc3d_onecontact_nonsmooth_Newton_AC_update;
161 *freeSolver = (FreeSolverNSGSPtr)&fc3d_onecontact_nonsmooth_Newton_solvers_free;
162 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
163 fc3d_onecontact_nonsmooth_Newton_solvers_initialize(problem, localproblem, localsolver_options);
164 break;
165 } /* Newton solver (Glocker-Fischer-Burmeister)*/
166 case SICONOS_FRICTION_3D_NCPGlockerFBNewton:
167 {
168 *solve = &fc3d_onecontact_nonsmooth_Newton_solvers_solve;
169 *update = &NCPGlocker_update;
170 *freeSolver = (FreeSolverNSGSPtr)&fc3d_onecontact_nonsmooth_Newton_solvers_free;
171 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
172 // *computeError = &fake_compute_error;
173 fc3d_onecontact_nonsmooth_Newton_solvers_initialize(problem, localproblem, localsolver_options);
174 break;
175 }
176 /* Path solver (Glocker Formulation) */
177 case SICONOS_FRICTION_3D_NCPGlockerFBPATH:
178 {
179 *solve = &fc3d_Path_solve;
180 *freeSolver = (FreeSolverNSGSPtr)&fc3d_Path_free;
181 *update = &NCPGlocker_update;
182 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
183 // *computeError = &fake_compute_error;
184 fc3d_Path_initialize(problem, localproblem, localsolver_options);
185 break;
186 }
187
188 /* Fixed Point solver (Glocker Formulation) */
189 case SICONOS_FRICTION_3D_NCPGlockerFBFixedPoint:
190 {
191 *solve = &fc3d_FixedP_solve;
192 *update = &NCPGlocker_update;
193 *freeSolver = (FreeSolverNSGSPtr)&fc3d_FixedP_free;
194 /* *computeError = &fake_compute_error_nsgs; */
195 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
196 fc3d_FixedP_initialize(problem, localproblem, localsolver_options);
197 break;
198 }
199 case SICONOS_FRICTION_3D_ONECONTACT_ProjectionOnCylinder:
200 {
201 *solve = &fc3d_projectionOnCylinder_solve;
202 *update = &fc3d_projectionOnCylinder_update;
203 *freeSolver = (FreeSolverNSGSPtr)&fc3d_projectionOnCylinder_free;
204 *computeError = (ComputeErrorPtr)&fc3d_Tresca_compute_error;
205 fc3d_projectionOnCylinder_initialize(problem, localproblem, options);
206 break;
207 }
208 case SICONOS_FRICTION_3D_ONECONTACT_ProjectionOnCylinderWithLocalIteration:
209 {
210 *solve = &fc3d_projectionOnCylinderWithLocalIteration_solve;
211 *update = &fc3d_projectionOnCylinder_update;
212 *freeSolver = (FreeSolverNSGSPtr)&fc3d_projectionOnCylinderWithLocalIteration_free;
213 *computeError = (ComputeErrorPtr)&fc3d_Tresca_compute_error;
214 fc3d_projectionOnCylinderWithLocalIteration_initialize(problem, localproblem, options, localsolver_options);
215 break;
216 }
217 case SICONOS_FRICTION_3D_ONECONTACT_QUARTIC:
218 {
219 *solve = &fc3d_unitary_enumerative_solve;
220 *update = &fc3d_nsgs_update;
221 *freeSolver = (FreeSolverNSGSPtr)&fc3d_unitary_enumerative_free;
222 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
223 fc3d_unitary_enumerative_initialize(localproblem);
224 break;
225 }
226 case SICONOS_FRICTION_3D_ONECONTACT_QUARTIC_NU:
227 {
228 *solve = &fc3d_unitary_enumerative_solve;
229 *update = &fc3d_nsgs_update;
230 *freeSolver = (FreeSolverNSGSPtr)&fc3d_unitary_enumerative_free;
231 *computeError = (ComputeErrorPtr)&fc3d_compute_error;
232 fc3d_unitary_enumerative_initialize(localproblem);
233 break;
234 }
235 default:
236 {
237 numerics_error("fc3d_nsgs_initialize_local_solver", "Numerics, fc3d_nsgs failed. Unknown internal solver : %s.\n", solver_options_id_to_name(localsolver_options->solverId));
238 }
239 }
240 }
241
242
243
244
245 static
allocShuffledContacts(FrictionContactProblem * problem,SolverOptions * options)246 unsigned int* allocShuffledContacts(FrictionContactProblem *problem,
247 SolverOptions *options)
248 {
249 unsigned int *scontacts = 0;
250 unsigned int nc = problem->numberOfContacts;
251 if(options->iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE||
252 options->iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE_EACH_LOOP)
253 {
254 if(options->iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE_SEED] >0)
255 {
256 srand((unsigned int)options->iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE_SEED]);
257 }
258 else
259 srand(1);
260 scontacts = (unsigned int *) malloc(nc * sizeof(unsigned int));
261 for(unsigned int i = 0; i < nc ; ++i)
262 {
263 scontacts[i] = i;
264 }
265 uint_shuffle(scontacts, nc);
266 }
267 return scontacts;
268 }
269 static
allocfreezingContacts(FrictionContactProblem * problem,SolverOptions * options)270 unsigned int* allocfreezingContacts(FrictionContactProblem *problem,
271 SolverOptions *options)
272 {
273 unsigned int *fcontacts = 0;
274 unsigned int nc = problem->numberOfContacts;
275 if(options->iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT] > 0)
276 {
277 fcontacts = (unsigned int *) malloc(nc * sizeof(unsigned int));
278 for(unsigned int i = 0; i < nc ; ++i)
279 {
280 fcontacts[i] = 0;
281 }
282 }
283 return fcontacts;
284 }
285
286
287 static
solveLocalReaction(UpdatePtr update_localproblem,SolverPtr local_solver,unsigned int contact,FrictionContactProblem * problem,FrictionContactProblem * localproblem,double * reaction,SolverOptions * localsolver_options,double localreaction[3])288 int solveLocalReaction(UpdatePtr update_localproblem, SolverPtr local_solver,
289 unsigned int contact, FrictionContactProblem *problem,
290 FrictionContactProblem *localproblem, double *reaction,
291 SolverOptions *localsolver_options, double localreaction[3])
292 {
293 (*update_localproblem)(contact, problem, localproblem,
294 reaction, localsolver_options);
295
296 localsolver_options->iparam[SICONOS_FRICTION_3D_CURRENT_CONTACT_NUMBER] = contact;
297
298 localreaction[0] = reaction[contact*3 + 0];
299 localreaction[1] = reaction[contact*3 + 1];
300 localreaction[2] = reaction[contact*3 + 2];
301
302 return (*local_solver)(localproblem, localreaction, localsolver_options);
303 }
304
305 static
performRelaxation(double localreaction[3],double * oldreaction,double omega)306 void performRelaxation(double localreaction[3], double *oldreaction, double omega)
307 {
308 localreaction[0] = omega*localreaction[0]+(1.0-omega)*oldreaction[0];
309 localreaction[1] = omega*localreaction[1]+(1.0-omega)*oldreaction[1];
310 localreaction[2] = omega*localreaction[2]+(1.0-omega)*oldreaction[2];
311 }
312
313
314 static
light_error_squared(double localreaction[3],double * oldreaction)315 double light_error_squared( double localreaction[3],
316 double *oldreaction)
317 {
318 return (pow(oldreaction[0] - localreaction[0], 2) +
319 pow(oldreaction[1] - localreaction[1], 2) +
320 pow(oldreaction[2] - localreaction[2], 2) );
321 }
322
323 static
squared_norm(double localreaction[3])324 double squared_norm(double localreaction[3])
325 {
326 return (pow(localreaction[0], 2) +
327 pow(localreaction[1], 2) +
328 pow(localreaction[2], 2));
329 }
330
file_exists(const char * fname)331 int file_exists(const char *fname)
332 {
333 FILE *file;
334 if((file = fopen(fname, "r")))
335 {
336 fclose(file);
337 return 1;
338 }
339 return 0;
340 }
341
342 static
acceptLocalReactionFiltered(FrictionContactProblem * localproblem,SolverOptions * localsolver_options,unsigned int contact,unsigned int iter,double * reaction,double localreaction[3])343 void acceptLocalReactionFiltered(FrictionContactProblem *localproblem,
344 SolverOptions *localsolver_options,
345 unsigned int contact, unsigned int iter,
346 double *reaction, double localreaction[3])
347 {
348 if(isnan(localsolver_options->dparam[SICONOS_DPARAM_RESIDU])
349 || isinf(localsolver_options->dparam[SICONOS_DPARAM_RESIDU])
350 || localsolver_options->dparam[SICONOS_DPARAM_RESIDU] > 1.0)
351 {
352 DEBUG_EXPR(frictionContact_display(localproblem));
353 DEBUG_PRINTF("Discard local reaction for contact %i at iteration %i "
354 "with local_error = %e\n",
355 contact, iter, localsolver_options->dparam[SICONOS_DPARAM_RESIDU]);
356
357 #ifdef FCLIB_OUTPUT
358
359 /* printf("step counter value = %i\n", localsolver_options->iparam[19]); */
360 char fname[256];
361 fccounter ++;
362 sprintf(fname, "./local_problem/localproblem_%i_%i.hdf5", contact, localsolver_options->iparam[19]);
363
364 if(file_exists(fname))
365 {
366 /* printf(" %s already dumped\n", fname); */
367 }
368 else
369 {
370 printf("Dump %s\n", fname);
371 int n = 100;
372 char * title = (char *)malloc(n * sizeof(char));
373 strcpy(title, "Bad local problem dump in hdf5");
374 char * description = (char *)malloc(n * sizeof(char));
375 strcpy(description, "Rewriting in hdf5 from siconos ");
376 strcat(description, fname);
377 strcat(description, " in FCLIB format");
378 char * mathInfo = (char *)malloc(n * sizeof(char));
379 strcpy(mathInfo, "unknown");
380
381 frictionContact_fclib_write(localproblem,
382 title,
383 description,
384 mathInfo,
385 fname,3);
386
387 printf("end of dump %s\n", fname);
388 free(title);
389 free(description);
390 free(mathInfo);
391 }
392
393 #endif
394
395 numerics_printf("Discard local reaction for contact %i at iteration %i "
396 "with local_error = %e",
397 contact, iter, localsolver_options->dparam[SICONOS_DPARAM_RESIDU]);
398 }
399 else
400 memcpy(&reaction[contact*3], localreaction, sizeof(double)*3);
401 }
402
403 static
acceptLocalReactionUnconditionally(unsigned int contact,double * reaction,double localreaction[3])404 void acceptLocalReactionUnconditionally(unsigned int contact,
405 double *reaction, double localreaction[3])
406 {
407 memcpy(&reaction[contact*3], localreaction, sizeof(double)*3);
408 }
409
410 static
calculateLightError(double light_error_sum,unsigned int nc,double * reaction,double * norm_r)411 double calculateLightError(double light_error_sum, unsigned int nc, double *reaction, double * norm_r)
412 {
413 double error = sqrt(light_error_sum);
414 *norm_r = cblas_dnrm2(nc*3, reaction, 1);
415 if(fabs(*norm_r) > DBL_EPSILON)
416 error /= (*norm_r);
417 return error;
418 }
419
420 static
calculateFullErrorAdaptiveInterval(FrictionContactProblem * problem,ComputeErrorPtr computeError,SolverOptions * options,int iter,double * reaction,double * velocity,double tolerance,double norm_q)421 double calculateFullErrorAdaptiveInterval(FrictionContactProblem *problem,
422 ComputeErrorPtr computeError,
423 SolverOptions *options, int iter,
424 double *reaction, double *velocity,
425 double tolerance, double norm_q)
426 {
427 double error=1e+24;
428 if(options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION_FREQUENCY] >0)
429 {
430 if(iter % options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION_FREQUENCY] == 0)
431 {
432 (*computeError)(problem, reaction, velocity, tolerance, options, norm_q, &error);
433 if(error > tolerance
434 && options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_ADAPTIVE)
435 options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION_FREQUENCY] *= 2;
436 }
437 numerics_printf("--------------- FC3D - NSGS - Iteration %i "
438 "options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION_FREQUENCY] = %i, options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] = % i",
439 iter, options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION_FREQUENCY], options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION]);
440 }
441 else
442 (*computeError)(problem, reaction, velocity, tolerance, options, norm_q, &error);
443
444 return error;
445 }
446
447
448
449 static
calculateFullErrorFinal(FrictionContactProblem * problem,SolverOptions * options,ComputeErrorPtr computeError,double * reaction,double * velocity,double tolerance,double norm_q)450 double calculateFullErrorFinal(FrictionContactProblem *problem, SolverOptions *options,
451 ComputeErrorPtr computeError,
452 double *reaction, double *velocity, double tolerance,
453 double norm_q)
454 {
455 double absolute_error;
456 (*computeError)(problem, reaction, velocity, tolerance,
457 options, norm_q, &absolute_error);
458
459
460
461 if(verbose > 0)
462 {
463 if(absolute_error > options->dparam[SICONOS_DPARAM_TOL])
464 {
465 numerics_printf("------- FC3D - NSGS - Warning absolute "
466 "Residual = %14.7e is larger than required precision = %14.7e",
467 absolute_error, options->dparam[SICONOS_DPARAM_TOL]);
468 }
469 else
470 {
471 numerics_printf("------- FC3D - NSGS - absolute "
472 "Residual = %14.7e is smaller than required precision = %14.7e",
473 absolute_error, options->dparam[SICONOS_DPARAM_TOL]);
474 }
475 }
476 return absolute_error;
477 }
478
479
480 static
determine_convergence(double error,double tolerance,int iter,SolverOptions * options)481 int determine_convergence(double error, double tolerance, int iter,
482 SolverOptions *options)
483 {
484 int hasNotConverged = 1;
485 if(error < tolerance)
486 {
487 hasNotConverged = 0;
488 numerics_printf("--------------- FC3D - NSGS - Iteration %i "
489 "Residual = %14.7e < %7.3e\n", iter, error, tolerance);
490 }
491 else
492 {
493 numerics_printf("--------------- FC3D - NSGS - Iteration %i "
494 "Residual = %14.7e > %7.3e\n", iter, error, tolerance);
495 }
496 return hasNotConverged;
497 }
498
499 static
determine_convergence_with_full_final(FrictionContactProblem * problem,SolverOptions * options,ComputeErrorPtr computeError,double * reaction,double * velocity,double * tolerance,double norm_q,double error,int iter)500 int determine_convergence_with_full_final(FrictionContactProblem *problem, SolverOptions *options,
501 ComputeErrorPtr computeError,
502 double *reaction, double *velocity,
503 double *tolerance, double norm_q, double error,
504 int iter)
505 {
506 int hasNotConverged = 1;
507 if(error < *tolerance)
508 {
509 hasNotConverged = 0;
510 numerics_printf("--------------- FC3D - NSGS - Iteration %i "
511 "Residual = %14.7e < %7.3e", iter, error, *tolerance);
512
513 double absolute_error = calculateFullErrorFinal(problem, options,
514 computeError,
515 reaction, velocity, options->dparam[SICONOS_DPARAM_TOL],
516 norm_q);
517 if(absolute_error > options->dparam[SICONOS_DPARAM_TOL])
518 {
519 *tolerance = error/absolute_error*options->dparam[SICONOS_DPARAM_TOL];
520 /* assert(*tolerance > 0.0 && "tolerance has to be positive"); */
521
522 /* if (*tolerance < DBL_EPSILON) */
523 /* { */
524 /* numerics_warning("determine_convergence_with_full_fina", "We try to set a very smal tolerance"); */
525 /* *tolerance = DBL_EPSILON; */
526 /* } */
527 numerics_printf("------- FC3D - NSGS - We modify the required incremental precision to reach accuracy to %e", *tolerance);
528 hasNotConverged = 1;
529 }
530 else
531 {
532 numerics_printf("------- FC3D - NSGS - The incremental precision is sufficient to reach accuracy to %e", *tolerance);
533 }
534
535
536
537
538 }
539 else
540 {
541 numerics_printf("--------------- FC3D - NSGS - Iteration %i "
542 "Residual = %14.7e > %7.3e", iter, error, *tolerance);
543 }
544 return hasNotConverged;
545 }
546
547
548 static
statsIterationCallback(FrictionContactProblem * problem,SolverOptions * options,double * reaction,double * velocity,double error)549 void statsIterationCallback(FrictionContactProblem *problem,
550 SolverOptions *options,
551 double *reaction, double *velocity, double error)
552 {
553 if(options->callback)
554 {
555 options->callback->collectStatsIteration(options->callback->env,
556 problem->numberOfContacts * 3,
557 reaction, velocity,
558 error, NULL);
559 }
560 }
561
562
563
564
fc3d_nsgs(FrictionContactProblem * problem,double * reaction,double * velocity,int * info,SolverOptions * options)565 void fc3d_nsgs(FrictionContactProblem* problem, double *reaction,
566 double *velocity, int* info, SolverOptions* options)
567 {
568 /* verbose=1; */
569 /* int and double parameters */
570 int* iparam = options->iparam;
571 double* dparam = options->dparam;
572
573 /* Number of contacts */
574 unsigned int nc = problem->numberOfContacts;
575
576 /* Maximum number of iterations */
577 int itermax = iparam[SICONOS_IPARAM_MAX_ITER];
578
579 /* Tolerance */
580 double tolerance = dparam[SICONOS_DPARAM_TOL];
581 double norm_q = cblas_dnrm2(nc*3, problem->q, 1);
582 double omega = dparam[SICONOS_FRICTION_3D_NSGS_RELAXATION_VALUE];
583
584 double norm_r[] = {1e24};
585 if(options->numberOfInternalSolvers < 1)
586 {
587 numerics_error("fc3d_nsgs",
588 "The NSGS method needs options for the internal solvers, "
589 "options[0].numberOfInternalSolvers should be >= 1");
590 }
591 SolverOptions * localsolver_options = options->internalSolvers[0];
592 SolverPtr local_solver = NULL;
593 UpdatePtr update_localproblem = NULL;
594 FreeSolverNSGSPtr freeSolver = NULL;
595 ComputeErrorPtr computeError = NULL;
596
597 FrictionContactProblem* localproblem;
598 double localreaction[3];
599
600 /***** NSGS Iterations *****/
601 int iter = 0; /* Current iteration number */
602 double error = 1.; /* Current error */
603 int hasNotConverged = 1;
604 unsigned int contact; /* Number of the current row of blocks in M */
605 unsigned int *scontacts = NULL;
606 unsigned int *freeze_contacts = NULL;
607
608 if(*info == 0)
609 return;
610
611 /***** Initialize various solver options *****/
612 localproblem = fc3d_local_problem_allocate(problem);
613
614 fc3d_nsgs_initialize_local_solver(&local_solver, &update_localproblem,
615 (FreeSolverNSGSPtr *)&freeSolver, &computeError,
616 problem, localproblem, options);
617
618 scontacts = allocShuffledContacts(problem, options);
619 freeze_contacts = allocfreezingContacts(problem, options);
620 /***** Check solver options *****/
621 if(!(iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_FALSE
622 || iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE
623 || iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE_EACH_LOOP))
624 {
625 numerics_error(
626 "fc3d_nsgs", "iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] must be equal to "
627 "SICONOS_FRICTION_3D_NSGS_SHUFFLE_FALSE (0), "
628 "SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE (1) or "
629 "SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE_EACH_LOOP (2)");
630 return;
631 }
632
633 if(!(iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_FULL
634 || iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT_WITH_FULL_FINAL
635 || iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT
636 || iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_ADAPTIVE))
637 {
638 numerics_error(
639 "fc3d_nsgs", "iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] must be equal to "
640 "SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_FULL (0), "
641 "SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT_WITH_FULL_FINAL (1), "
642 "SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT (2) or "
643 "SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_ADAPTIVE (3)");
644 return;
645 }
646
647 /***** NSGS Iterations *****/
648
649 /* A special case for the most common options (should correspond
650 * with mechanics_run.py **/
651 if(iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_FALSE
652 && iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT] == 0
653 && iparam[SICONOS_FRICTION_3D_NSGS_RELAXATION] == SICONOS_FRICTION_3D_NSGS_RELAXATION_FALSE
654 && iparam[SICONOS_FRICTION_3D_NSGS_FILTER_LOCAL_SOLUTION] == SICONOS_FRICTION_3D_NSGS_FILTER_LOCAL_SOLUTION_TRUE
655 && iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT)
656 {
657 while((iter < itermax) && (hasNotConverged > 0))
658 {
659 ++iter;
660 double light_error_sum = 0.0;
661
662 fc3d_set_internalsolver_tolerance(problem, options, localsolver_options, error);
663
664 for(unsigned int i = 0 ; i < nc ; ++i)
665 {
666 contact = i;
667
668
669 solveLocalReaction(update_localproblem, local_solver, contact,
670 problem, localproblem, reaction, localsolver_options,
671 localreaction);
672
673 light_error_sum += light_error_squared(localreaction, &reaction[contact*3]);
674
675 /* #if 0 */
676 acceptLocalReactionFiltered(localproblem, localsolver_options,
677 contact, iter, reaction, localreaction);
678
679 }
680
681 error = calculateLightError(light_error_sum, nc, reaction, norm_r);
682
683 hasNotConverged = determine_convergence(error, tolerance, iter, options);
684
685 statsIterationCallback(problem, options, reaction, velocity, error);
686 }
687 }
688
689 /* All other cases, we put all the ifs inline.. otherwise, too many
690 * variations to have dedicated loops, but add more if there are
691 * common cases to avoid checking booleans on every iteration. **/
692 else
693 {
694 while((iter < itermax) && (hasNotConverged > 0))
695 {
696 ++iter;
697 double light_error_sum = 0.0;
698 double light_error_2 = 0.0;
699 fc3d_set_internalsolver_tolerance(problem, options, localsolver_options, error);
700
701 for(unsigned int i = 0 ; i < nc ; ++i)
702 {
703 if(iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE
704 || iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE_EACH_LOOP)
705 {
706 if(iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] == SICONOS_FRICTION_3D_NSGS_SHUFFLE_TRUE_EACH_LOOP)
707 uint_shuffle(scontacts, nc);
708 contact = scontacts[i];
709 }
710 else
711 contact = i;
712
713 if(iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT] >0)
714 {
715 if (freeze_contacts[contact] >0)
716 {
717 /* we skip freeze contacts */
718 freeze_contacts[contact] -= 1;
719 continue;
720 }
721 }
722
723
724 solveLocalReaction(update_localproblem, local_solver, contact,
725 problem, localproblem, reaction, localsolver_options,
726 localreaction);
727
728 if(iparam[SICONOS_FRICTION_3D_NSGS_RELAXATION] == SICONOS_FRICTION_3D_NSGS_RELAXATION_TRUE)
729 performRelaxation(localreaction, &reaction[contact*3], omega);
730
731 light_error_2= light_error_squared(localreaction, &reaction[contact*3]);
732 light_error_sum += light_error_2;
733
734 /* int test =100; */
735 /* if (contact == test) */
736 /* { */
737 /* printf("reaction[%i] = %16.8e\t",3*contact-1,reaction[3*contact]); */
738 /* printf("localreaction[%i] = %16.8e\n",2,localreaction[0]); */
739 /* } */
740
741 if(iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT] >0)
742 {
743 if ((light_error_2*squared_norm(localreaction) <= tolerance*tolerance/(nc*nc*10)
744 || squared_norm(localreaction) <= (*norm_r* *norm_r/(nc*nc*1000)))
745 && iter >=10)
746 {
747 /* we freeze the contact for n iterations*/
748 freeze_contacts[contact] = iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT];
749
750 DEBUG_EXPR
751 (printf("first criteria : light_error_2*squared_norm(localreaction) <= tolerance*tolerance/(nc*nc*10) ==> %e <= %e\n",
752 light_error_2*squared_norm(localreaction), tolerance*tolerance/(nc*nc*10));
753 printf("second criteria : squared_norm(localreaction) <= (*norm_r* *norm_r/(nc*nc))/1000. ==> %e <= %e\n",
754 squared_norm(localreaction) , (*norm_r* *norm_r/(nc*nc))/1000.);
755 printf("Contact % i is freezed for %i steps\n", contact, iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT]);
756 );
757 }
758 }
759
760
761 if(iparam[SICONOS_FRICTION_3D_NSGS_FILTER_LOCAL_SOLUTION] == SICONOS_FRICTION_3D_NSGS_FILTER_LOCAL_SOLUTION_TRUE)
762 acceptLocalReactionFiltered(localproblem, localsolver_options,
763 contact, iter, reaction, localreaction);
764 else
765 acceptLocalReactionUnconditionally(contact, reaction, localreaction);
766
767
768
769 }
770
771 if(iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT)
772 {
773 error = calculateLightError(light_error_sum, nc, reaction, norm_r);
774 hasNotConverged = determine_convergence(error, tolerance, iter, options);
775 }
776 else if(iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT_WITH_FULL_FINAL)
777 {
778 error = calculateLightError(light_error_sum, nc, reaction, norm_r);
779 hasNotConverged = determine_convergence_with_full_final(problem, options, computeError,
780 reaction, velocity,
781 &tolerance, norm_q, error,
782 iter);
783
784 if(!(tolerance > 0.0))
785 {
786 numerics_warning("fc3d_nsgs", "tolerance has to be positive!!");
787 numerics_warning("fc3d_nsgs", "we stop the iterations");
788 break;
789 }
790
791 }
792 else if(iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_FULL)
793 {
794 error = calculateFullErrorAdaptiveInterval(problem, computeError, options,
795 iter, reaction, velocity,
796 tolerance, norm_q);
797 hasNotConverged = determine_convergence(error, tolerance, iter, options);
798 }
799
800 statsIterationCallback(problem, options, reaction, velocity, error);
801
802 /* if(iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT] >0) */
803 /* { */
804 /* int frozen_contact=0; */
805 /* for(unsigned int i = 0 ; i < nc ; ++i) */
806 /* { */
807 /* if (freeze_contacts[contact] >0) */
808 /* { */
809 /* frozen_contact++; */
810 /* } */
811 /* } */
812 /* printf("number of frozen contacts %i at iter : %i\n", frozen_contact, iter ); */
813 /* } */
814 }
815 }
816
817
818 /* Full criterium */
819 if(iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] == SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT_WITH_FULL_FINAL)
820 {
821 error = calculateFullErrorFinal(problem, options, computeError, reaction, velocity,
822 tolerance, norm_q);
823
824 hasNotConverged = determine_convergence(error, dparam[SICONOS_DPARAM_TOL], iter, options);
825
826
827 }
828
829 *info = hasNotConverged;
830
831
832
833 /** return parameter values */
834 /* dparam[SICONOS_DPARAM_TOL] = tolerance; */
835 dparam[SICONOS_DPARAM_RESIDU] = error;
836 iparam[SICONOS_IPARAM_ITER_DONE] = iter;
837
838 /** Free memory **/
839 (*freeSolver)(problem,localproblem,localsolver_options);
840 fc3d_local_problem_free(localproblem, problem);
841 if(scontacts) free(scontacts);
842 }
843
fc3d_nsgs_set_default(SolverOptions * options)844 void fc3d_nsgs_set_default(SolverOptions* options)
845 {
846 options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION] = SICONOS_FRICTION_3D_NSGS_ERROR_EVALUATION_LIGHT_WITH_FULL_FINAL;
847 options->iparam[SICONOS_FRICTION_3D_IPARAM_INTERNAL_ERROR_STRATEGY] = SICONOS_FRICTION_3D_INTERNAL_ERROR_STRATEGY_GIVEN_VALUE;
848 /* options->iparam[SICONOS_FRICTION_3D_IPARAM_INTERNAL_ERROR_STRATEGY] = SICONOS_FRICTION_3D_INTERNAL_ERROR_STRATEGY_ADAPTIVE; */
849 /* options->iparam[SICONOS_FRICTION_3D_IPARAM_INTERNAL_ERROR_STRATEGY] = SICONOS_FRICTION_3D_INTERNAL_ERROR_STRATEGY_ADAPTIVE_N_CONTACT; */
850 options->iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE] = SICONOS_FRICTION_3D_NSGS_SHUFFLE_FALSE;
851 options->iparam[SICONOS_FRICTION_3D_NSGS_SHUFFLE_SEED] = 0;
852 options->iparam[SICONOS_FRICTION_3D_NSGS_FREEZING_CONTACT] = 0;
853 options->iparam[SICONOS_FRICTION_3D_NSGS_FILTER_LOCAL_SOLUTION] = SICONOS_FRICTION_3D_NSGS_FILTER_LOCAL_SOLUTION_FALSE;
854 options->iparam[SICONOS_FRICTION_3D_NSGS_RELAXATION] = SICONOS_FRICTION_3D_NSGS_RELAXATION_FALSE;
855 options->iparam[SICONOS_FRICTION_3D_IPARAM_ERROR_EVALUATION_FREQUENCY] = 0;
856 options->dparam[SICONOS_DPARAM_TOL] = 1e-4;
857 options->dparam[SICONOS_FRICTION_3D_DPARAM_INTERNAL_ERROR_RATIO] = 10.0;
858 // Internal solver
859 assert(options->numberOfInternalSolvers == 1);
860 options->internalSolvers[0] = solver_options_create(SICONOS_FRICTION_3D_ONECONTACT_NSN_GP_HYBRID);
861 }
862