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