1 // GetDP - Copyright (C) 1997-2021 P. Dular and C. Geuzaine, University of Liege
2 //
3 // See the LICENSE.txt file for license information. Please report all
4 // issues on https://gitlab.onelab.info/getdp/getdp/issues.
5 //
6 // Contributor(s):
7 //   Johan Gyselinck
8 //   Kevin Jacques
9 //
10 
11 #include <math.h>
12 #include <string.h>
13 #include "ProData.h"
14 #include "F.h"
15 #include "Message.h"
16 #include <iostream>
17 
18 #define SQU(a) ((a)*(a))
19 #define CUB(a) ((a)*(a)*(a))
20 #define MU0 1.25663706144e-6
21 
22 #define FLAG_WARNING_INFO_INV         1
23 #define FLAG_WARNING_INFO_APPROACH    2
24 #define FLAG_WARNING_STOP_INV         10
25 
26 #define FLAG_WARNING_DISPABOVEITER    1
27 
28 #define MIN(a,b) (((a)<(b))?(a):(b))
29 #define MAX(a,b) (((a)>(b))?(a):(b))
30 
31 extern struct CurrentData Current ;
32 
33 /* ------------------------------------------------------------------------ */
34 /*
35   Vectorized Jiles-Atherton hysteresis model
36   J. Gyselinck, P. Dular, N. Sadowski, J. Leite and J.P.A. Bastos,
37   "Incorporation of a Jiles-Atherton vector hysteresis model in
38   2D FE magnetic field computations. Application of the Newton-Raphson method",
39   Vol. 23, No. 3, pp. 685-693, 2004.
40  */
41 
F_Man(double He,double Ms,double a)42 double F_Man(double He, double Ms, double a)
43 {
44   // Anhysteretic magnetisation
45   if(fabs(He) < 0.01*a)
46     //return Ms*He/(3.*a) ; // Aprox. up to 1st order
47     return Ms*(He/(3.*a)-1/45*CUB(He/a)) ; // Approx. up to 3rd order
48   else return Ms*(cosh(He/a)/sinh(He/a)-a/He) ;
49 }
50 
F_dMandHe(double He,double Ms,double a)51 double F_dMandHe(double He, double Ms, double a)
52 {
53   // Derivative of the magnetisation Man with respect to the effective field He
54   if(fabs(He) < 0.01*a)
55     //return Ms/(3.*a) ; // Aprox. up to 1st order
56     return Ms/(3.*a)-Ms/(15*a)*SQU(He/a) ; // Approx. up to 3rd order
57   else return Ms/a*(1-SQU(cosh(He/a)/sinh(He/a))+SQU(a/He)) ;
58 }
59 
FV_Man(double He[3],double Ms,double a,double Man[3])60 void FV_Man(double He[3], double Ms, double a, double Man[3])
61 {
62   double nHe = sqrt(He[0]*He[0]+He[1]*He[1]+He[2]*He[2]) ;
63   if( !nHe ) {
64     Man[0] = Man[1] = Man[2]= 0. ;
65   }
66   else {
67     double auxMan = F_Man(nHe, Ms, a) ;
68     Man[0] = auxMan * He[0]/nHe ;
69     Man[1] = auxMan * He[1]/nHe ;
70     Man[2] = auxMan * He[2]/nHe ;
71   }
72 }
73 
FV_dMandHe(double He[3],double Ms,double a,double dMandHe[6])74 void FV_dMandHe(double He[3], double Ms, double a, double dMandHe[6])
75 {
76   double nHe = sqrt(He[0]*He[0]+He[1]*He[1]+He[2]*He[2]) ;
77   double Man = F_Man(nHe, Ms, a) ;
78   double ndMandHe = F_dMandHe(nHe,Ms,a) ;
79 
80   if( !nHe ) {
81     dMandHe[0] = dMandHe[3] = dMandHe[5] = ndMandHe ;
82     dMandHe[1] = dMandHe[2] = dMandHe[4] = 0. ;
83   }
84   else {
85     dMandHe[0] = Man/nHe + (ndMandHe - Man/nHe)*He[0]*He[0]/(nHe*nHe) ;
86     dMandHe[3] = Man/nHe + (ndMandHe - Man/nHe)*He[1]*He[1]/(nHe*nHe) ;
87     dMandHe[5] = Man/nHe + (ndMandHe - Man/nHe)*He[2]*He[2]/(nHe*nHe) ;
88     dMandHe[1] =           (ndMandHe - Man/nHe)*He[0]*He[1]/(nHe*nHe) ;
89     dMandHe[2] =           (ndMandHe - Man/nHe)*He[0]*He[2]/(nHe*nHe) ;
90     dMandHe[4] =           (ndMandHe - Man/nHe)*He[1]*He[2]/(nHe*nHe) ;
91   }
92 }
93 
FV_dMidHe(double He[3],double Man[3],double Mi[3],double dH[3],double k,double dMidHe[6])94 void FV_dMidHe(double He[3], double Man[3],
95          double Mi[3], double dH[3], double k,
96          double dMidHe[6])
97 {
98   double dM = sqrt( (Man[0]-Mi[0])*(Man[0]-Mi[0]) + (Man[1]-Mi[1])*(Man[1]-Mi[1]) + (Man[2]-Mi[2])*(Man[2]-Mi[2]) ) ;
99 
100   if ( !dM || (Man[0]-Mi[0])*dH[0] + (Man[1]-Mi[1])*dH[1] + (Man[2]-Mi[2])*dH[2] <= 0 ) {
101     dMidHe[0] = dMidHe[3] = dMidHe[5] = dMidHe[1] = dMidHe[2] =  dMidHe[4] = 0. ;
102   } else {
103     double kdM = k * dM;
104     dMidHe[0] = (Man[0]-Mi[0])*(Man[0]-Mi[0]) / kdM ;
105     dMidHe[3] = (Man[1]-Mi[1])*(Man[1]-Mi[1]) / kdM ;
106     dMidHe[5] = (Man[2]-Mi[2])*(Man[2]-Mi[2]) / kdM ;
107     dMidHe[1] = (Man[0]-Mi[0])*(Man[1]-Mi[1]) / kdM ;
108     dMidHe[2] = (Man[0]-Mi[0])*(Man[2]-Mi[2]) / kdM ;
109     dMidHe[4] = (Man[1]-Mi[1])*(Man[2]-Mi[2]) / kdM ;
110   }
111 }
112 
Vector_dBdH(double H[3],double B[3],double dH[3],struct FunctionActive * D,double dBdH[6])113 void Vector_dBdH(double H[3], double B[3], double dH[3],
114                  struct FunctionActive *D, double dBdH[6])
115 {
116   double M[3], He[3], Man[3], Mi[3] ;
117   double dMandHe[6], dMidHe[6], dMdH[6] ;
118   double d[6], e[6], f[6] ;
119 
120   if(D->Case.Interpolation.NbrPoint != 5)
121     Message::Error("Jiles-Atherton parameters missing: {List[{Ms, a, k, c, alpha}]}");
122   double Ms    = D->Case.Interpolation.x[0] ;
123   double a     = D->Case.Interpolation.x[1] ;
124   double kk    = D->Case.Interpolation.x[2] ;
125   double c     = D->Case.Interpolation.x[3] ;
126   double alpha = D->Case.Interpolation.x[4] ;
127 
128   for(int i=0 ; i<3 ; i++){
129     M[i]  = B[i]/MU0 - H[i] ; // Magnetisation
130     He[i] = H[i] + alpha * M[i] ; // Effective field
131   }
132 
133   FV_Man(He, Ms, a, Man) ;
134 
135   for(int i=0 ; i<3 ; i++)
136     Mi[i] = (M[i]-c*Man[i]) / (1-c) ; // Irreversible magnetisation
137 
138   FV_dMandHe(He, Ms, a, dMandHe) ;
139   FV_dMidHe(He, Man, Mi, dH, kk, dMidHe) ;
140 
141   d[0] = 1 - alpha*c*dMandHe[0] - alpha*(1-c)*dMidHe[0] ; // xx
142   d[3] = 1 - alpha*c*dMandHe[3] - alpha*(1-c)*dMidHe[3] ; // yy
143   d[5] = 1 - alpha*c*dMandHe[5] - alpha*(1-c)*dMidHe[5] ; // zz
144   d[1] =   - alpha*c*dMandHe[1] - alpha*(1-c)*dMidHe[1] ; // xy
145   d[2] =   - alpha*c*dMandHe[2] - alpha*(1-c)*dMidHe[2] ; // xz
146   d[4] =   - alpha*c*dMandHe[4] - alpha*(1-c)*dMidHe[4] ; // yz
147 
148   double dd = d[0] * (d[3] *d[5] - d[4] *d[4])
149             - d[1] * (d[1] *d[5] - d[4] *d[2])
150             + d[2] * (d[1] *d[4] - d[3] *d[2]);
151 
152   if(!dd)
153     Message::Error("Null determinant of denominator of dm/dh!");
154 
155   e[0] =  (d[3]*d[5]-d[4]*d[4])/dd ;
156   e[1] = -(d[1]*d[5]-d[2]*d[4])/dd ;
157   e[2] =  (d[1]*d[4]-d[2]*d[3])/dd ;
158   e[3] =  (d[0]*d[5]-d[2]*d[2])/dd ;
159   e[4] = -(d[0]*d[4]-d[1]*d[2])/dd ;
160   e[5] =  (d[0]*d[3]-d[1]*d[1])/dd ;
161 
162   for(int i=0 ; i<6 ; i++)
163     f[i] = c*dMandHe[i] + (1-c)*dMidHe[i] ;
164 
165   dMdH[0] = e[0]*f[0]+e[1]*f[1]+e[2]*f[2] ;
166   dMdH[1] = e[0]*f[1]+e[1]*f[3]+e[2]*f[4] ;
167   dMdH[2] = e[0]*f[2]+e[1]*f[4]+e[2]*f[5] ;
168   dMdH[3] = e[1]*f[1]+e[3]*f[3]+e[4]*f[4] ;
169   dMdH[4] = e[1]*f[2]+e[3]*f[4]+e[4]*f[5] ;
170   dMdH[5] = e[2]*f[2]+e[4]*f[4]+e[5]*f[5] ;
171 
172   double slope_factor = 1; // choose 1e2 for increasing slope, for reducing NR iterations (better convergence)
173 
174   dBdH[0] =  MU0 * (slope_factor + dMdH[0]) ;
175   dBdH[3] =  MU0 * (slope_factor + dMdH[3]) ;
176   dBdH[5] =  MU0 * (slope_factor + dMdH[5]) ;
177   dBdH[1] =  MU0 * dMdH[1] ;
178   dBdH[2] =  MU0 * dMdH[2] ;
179   dBdH[4] =  MU0 * dMdH[4] ;
180 }
181 
Vector_dHdB(double H[3],double B[3],double dH[3],struct FunctionActive * D,double dHdB[6])182 void Vector_dHdB(double H[3], double B[3], double dH[3],
183                  struct FunctionActive *D,
184      double dHdB[6])
185 {
186   double dBdH[6] ;
187 
188   // Inverting the matrix representation of the db/dh we get dh/db
189   Vector_dBdH(H, B, dH, D, dBdH) ;
190 
191   double det =  dBdH[0] * (dBdH[3] *dBdH[5] - dBdH[4] *dBdH[4])
192               - dBdH[1] * (dBdH[1] *dBdH[5] - dBdH[4] *dBdH[2])
193               + dBdH[2] * (dBdH[1] *dBdH[4] - dBdH[3] *dBdH[2]);
194   if(!det)
195     Message::Error("Null determinant of db/dh!");
196 
197   dHdB[0] =  (dBdH[3]*dBdH[5]-dBdH[4]*dBdH[4])/det ;
198   dHdB[1] = -(dBdH[1]*dBdH[5]-dBdH[2]*dBdH[4])/det ;
199   dHdB[2] =  (dBdH[1]*dBdH[4]-dBdH[2]*dBdH[3])/det ;
200   dHdB[3] =  (dBdH[0]*dBdH[5]-dBdH[2]*dBdH[2])/det ;
201   dHdB[4] = -(dBdH[0]*dBdH[4]-dBdH[1]*dBdH[2])/det ;
202   dHdB[5] =  (dBdH[0]*dBdH[3]-dBdH[1]*dBdH[1])/det ;
203 }
204 
F_dhdb_Jiles(F_ARG)205 void F_dhdb_Jiles(F_ARG)
206 {
207   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
208   // input : h, b ,dh
209   // dhdb_Jiles[{h}, {d a}, {h}-{h}[1] ]{List[hyst_FeSi]}
210   // Material parameters: e.g. hyst_FeSi = { Msat, a, k, c, alpha};==> struct FunctionActive *D
211 
212   double H[3], B[3], dH[3], dHdB[6] ;
213   struct FunctionActive  * D ;
214 
215   if( (A+0)->Type != VECTOR || (A+1)->Type != VECTOR || (A+2)->Type != VECTOR )
216     Message::Error("Three vector arguments required");
217 
218   if(!Fct->Active)  Fi_InitListX(Fct, A, V) ;
219   D = Fct->Active ;
220 
221   for(int k=0 ; k<3 ; k++){
222     H[k]  = (A+0)->Val[k] ;
223     B[k]  = (A+1)->Val[k] ;
224     dH[k] = (A+2)->Val[k] ;
225   }
226 
227   Vector_dHdB(H, B, dH, D, dHdB) ;
228 
229   V->Type = TENSOR_SYM ;// xx, xy, xz, yy, yz, zz
230   for(int k=0 ; k<6 ; k++)  V->Val[k] = dHdB[k] ;
231 }
232 
F_dbdh_Jiles(F_ARG)233 void F_dbdh_Jiles(F_ARG)
234 {
235   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
236   // input : h, b, dh
237   // dbdh_Jiles[{h}, {b}, {h}-{h}[1] ]{List[hyst_FeSi]}
238   // Material parameters: e.g. hyst_FeSi = { Msat, a, k, c, alpha};==> struct FunctionActive *D
239 
240   double H[3], B[3], dH[3], dBdH[6] ;
241   struct FunctionActive *D;
242 
243   if( (A+0)->Type != VECTOR || (A+1)->Type != VECTOR || (A+2)->Type != VECTOR )
244     Message::Error("dbdh_Jiles requires three vector: {h} at t_i, {b} at t_i and ({h}-{h}[1]), i.e {h} at t_i - {h} at t_{i-1}");
245 
246   if(!Fct->Active)  Fi_InitListX(Fct, A, V) ;
247   D = Fct->Active ;
248 
249   for(int k=0 ; k<3 ; k++){
250     H[k]  = (A+0)->Val[k] ;
251     B[k]  = (A+1)->Val[k] ;
252     dH[k] = (A+2)->Val[k] ;
253   }
254 
255   Vector_dBdH(H, B, dH, D, dBdH) ;
256 
257   V->Type = TENSOR_SYM ;
258   for(int k=0 ; k<6 ; k++)  V->Val[k] = dBdH[k] ;
259 }
260 
F_h_Jiles(F_ARG)261 void F_h_Jiles(F_ARG)
262 {
263   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
264   // input : h1, b1, b2
265   // h_Jiles[ {h}[1], {b}[1], {b} ]{List[hyst_FeSi]}
266   // Material parameters: e.g. hyst_FeSi = { Msat, a, k, c, alpha};
267 
268   double Hone[3], Bone[3], Btwo[3], Htwo[3] ;
269   struct FunctionActive *D;
270 
271   void Vector_H2(double Hone[3], double Bone[3], double Btwo[3], int n,
272                   struct FunctionActive *D, double Htwo[3]) ;
273 
274   if( (A+0)->Type != VECTOR || (A+1)->Type != VECTOR || (A+2)->Type != VECTOR )
275     Message::Error("h_Jiles requires three vector arguments: {h} at t_{i-1}, {b} at t_{i-1} and {b} at t_i");
276 
277   if(!Fct->Active)  Fi_InitListX(Fct, A, V) ;
278   D = Fct->Active ;
279 
280   for(int k=0 ; k<3 ; k++) {
281     Hone[k] = (A+0)->Val[k] ;
282     Bone[k] = (A+1)->Val[k] ;
283     Btwo[k] = (A+2)->Val[k] ;
284   }
285 
286   Vector_H2(Hone, Bone, Btwo, 10, D, Htwo) ;
287 
288   V->Type = VECTOR ;
289   for(int k=0 ; k<3 ; k++)  V->Val[k] = Htwo[k] ;
290 }
291 
F_b_Jiles(F_ARG)292 void F_b_Jiles(F_ARG)
293 {
294   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
295   // input : b1, h1, h2
296   // b_Jiles[ {b}[1], {h}[1], {h} ]{List[hyst_FeSi]}
297   // Material parameters: e.g. hyst_FeSi = { Msat, a, k, c, alpha};
298 
299   double Bone[3], Hone[3], Btwo[3], Htwo[3] ;
300   struct FunctionActive  * D ;
301 
302   void Vector_B2(double Bone[3], double Hone[3], double Htwo[3], int n,
303                   struct FunctionActive *D, double Btwo[3]) ;
304 
305   if( (A+0)->Type != VECTOR || (A+1)->Type != VECTOR || (A+2)->Type != VECTOR )
306     Message::Error("b_Jiles requires three vector arguments: {b} at t_{i-1}, "
307                    "{h} at t_{i-1} and {h} at t_i");
308 
309   if(!Fct->Active)  Fi_InitListX(Fct, A, V) ;
310   D = Fct->Active ;
311 
312   for(int k = 0; k < 3 ; k++){
313     Bone[k] = (A+0)->Val[k] ;
314     Hone[k] = (A+1)->Val[k] ;
315     Htwo[k] = (A+2)->Val[k] ;
316   }
317   Vector_B2(Bone, Hone, Htwo, 10, D, Btwo) ;
318 
319   V->Type = VECTOR ;
320   for(int k = 0; k < 3 ; k++) V->Val[k] = Btwo[k] ;
321 }
322 
323 
Vector_H2(double Hone[3],double Bone[3],double Btwo[3],int n,struct FunctionActive * D,double Htwo[3])324 void Vector_H2(double Hone[3], double Bone[3], double Btwo[3], int n,
325                   struct FunctionActive *D, double Htwo[3])
326 {
327   double H[3], dH[3], B[3], dB[3] ;
328   double dHdB[6] ;
329 
330   for(int k=0 ; k<3 ; k++) {
331     H[k]  = Hone[k];
332     dB[k] = (Btwo[k] - Bone[k])/(double)n ;
333   }
334 
335   for(int i=0 ; i<n ; i++) {
336     for(int k=0 ; k<3 ; k++)
337       B[k] = (double)(n-i)/(double)n * Bone[k] + (double)i/(double)n * Btwo[k] ;
338     if(!i) {
339       for(int k=0; k<3; k++) dH[k] = dB[k] ;
340 
341       Vector_dHdB(H, B, dH, D, dHdB) ;
342       dH[0] = dHdB[0] * dB[0] + dHdB[1] * dB[1] + dHdB[2] * dB[2] ;
343       dH[1] = dHdB[1] * dB[0] + dHdB[3] * dB[1] + dHdB[4] * dB[2] ;
344       dH[2] = dHdB[2] * dB[0] + dHdB[4] * dB[1] + dHdB[5] * dB[2] ;
345     }
346     Vector_dHdB(H, B, dH, D, dHdB) ;
347     dH[0] = dHdB[0] * dB[0] + dHdB[1] * dB[1] + dHdB[2] * dB[2] ;
348     dH[1] = dHdB[1] * dB[0] + dHdB[3] * dB[1] + dHdB[4] * dB[2] ;
349     dH[2] = dHdB[2] * dB[0] + dHdB[4] * dB[1] + dHdB[5] * dB[2] ;
350 
351     for(int k=0 ; k<3 ; k++)  H[k] += dH[k] ;
352   }
353 
354   for(int k=0 ; k<3 ; k++) Htwo[k] = H[k] ;
355 }
356 
Vector_B2(double Bone[3],double Hone[3],double Htwo[3],int n,struct FunctionActive * D,double Btwo[3])357 void Vector_B2(double Bone[3], double Hone[3], double Htwo[3], int n,
358                struct FunctionActive *D, double Btwo[3])
359 {
360   double H[3], dH[3], B[3] ;
361   double dBdH[6] ;
362 
363   for(int k=0 ; k<3 ; k++) {
364     B[k]  = Bone[k];
365     dH[k] = (Htwo[k] - Hone[k])/(double)n ;
366   }
367 
368   for(int i=0 ; i<n ; i++) {
369     for(int k=0 ; k<3 ; k++)
370       H[k] = (double)(n-i)/(double)n * Hone[k] + (double)i/(double)n * Htwo[k] ;
371 
372     Vector_dBdH(H, B, dH, D, dBdH) ;
373 
374     B[0] += dBdH[0] * dH[0] + dBdH[1] * dH[1] + dBdH[2] * dH[2] ;
375     B[1] += dBdH[1] * dH[0] + dBdH[3] * dH[1] + dBdH[4] * dH[2] ;
376     B[2] += dBdH[2] * dH[0] + dBdH[4] * dH[1] + dBdH[5] * dH[2] ;
377   }
378 
379   for(int k=0 ; k<3 ; k++) Btwo[k] = B[k] ;
380 }
381 
382 /* ------------------------------------------------------------------------ */
383 /*
384    Ducharne's model of static hysteresis
385 
386    Raulet, M.A.; Ducharne, B.; Masson, J.P.; Bayada, G.;
387    "The magnetic field diffusion equation including dynamic hysteresis:
388    a linear formulation of the problem",
389    IEEE Trans. Mag., vol. 40, no. 2, pp. 872-875 (2004).
390 
391    The magnetic field h is computed for the path: (b0,h0)  --->  (b,h)
392    The final flux density b is imposed.
393 
394    In practice, the magnetic field is given by:
395 
396               /b
397        h(b) = |  (dh/db).db
398               /b0
399 
400    where the values of (dh/db) are functions of (b,h) and are interpolated
401    from a provided table {bi, hi, M, NL, NC}, obtained e.g. experimentally.
402 
403    bi  Flux density (T) for the tabulated values
404    hi  Magnetic field (A/m) for the tabulated values
405    M   Matrix with the slopes of reversal paths
406    NL  Number of lines
407    NC  Number of columns
408    b0  Initial flux density (T)
409    h0  Initial magnetic field (A/m)
410    b   Final flux density (T)
411 
412 */
413 /* ------------------------------------------------------------------------ */
414 
Fi_h_Ducharne(double * hi,double * bi,double * M,int NL,int NC,double h0,double b0,double b)415 double Fi_h_Ducharne(double *hi, double *bi, double *M, int NL, int NC,
416                       double h0, double b0, double b)
417 {
418   double db, dh, dHdB, s;
419   int i, N = 200 ; // fixed number of steps for numerical integration
420 
421   db = (b - b0)/N ;
422   s = (b - b0 < 0) ? -1. : 1. ;
423   for(i=0 ; i < N ; ++i) {
424     bool IsInGrid = Fi_InterpolationBilinear(hi, bi, M, NL, NC, s*h0, s*b0, &dHdB);
425     if(!IsInGrid) dHdB = MU0 ;
426     dh = dHdB * db;
427     h0 += dh;
428     b0 += db;
429   }
430   return h0 ;
431 }
432 
F_h_Ducharne(F_ARG)433 void F_h_Ducharne(F_ARG)
434 {
435   int    NL, NC, i;
436   double b0, h0, b, h, *bi, *hi, *M;
437   struct FunctionActive  * D;
438 
439   if(!Fct->Active)  Fi_InitListMatrix(Fct, A, V) ;
440 
441   D = Fct->Active ;
442   NL = D->Case.ListMatrix.NbrLines ;
443   NC = D->Case.ListMatrix.NbrColumns ;
444 
445   hi = D->Case.ListMatrix.x ;
446   bi = D->Case.ListMatrix.y ;
447   M =  D->Case.ListMatrix.data ;
448 
449   for(i=0 ; i<3 ; ++i) {
450     // (h0,b0) = state of the model, and b
451     h0 = (A+0)->Val[i] ;
452     b0 = (A+1)->Val[i] ;
453     b  = (A+2)->Val[i] ;
454 
455     // Compute the magnetic field
456     h = Fi_h_Ducharne(hi, bi, M, NL, NC, h0, b0, b);
457     V->Val[i] = h;
458   }
459 
460   V->Type = VECTOR ;
461 }
462 
F_nu_Ducharne(F_ARG)463 void F_nu_Ducharne(F_ARG)
464 {
465   int    NL, NC, i;
466   double b0, h0, b[3], h[3], *bi, *hi, *M;
467   struct FunctionActive  * D;
468 
469   if(!Fct->Active) Fi_InitListMatrix(Fct, A, V) ;
470 
471   D = Fct->Active ;
472   NL = D->Case.ListMatrix.NbrLines ;
473   NC = D->Case.ListMatrix.NbrColumns ;
474 
475   hi = D->Case.ListMatrix.x ;
476   bi = D->Case.ListMatrix.y ;
477   M  = D->Case.ListMatrix.data ;
478 
479   for(i=0 ; i<3 ; ++i) {
480     // Get (h0,b0) = state of the model, and b
481     h0 = (A+0)->Val[i] ;
482     b0 = (A+1)->Val[i] ;
483     b[i] = (A+2)->Val[i] ;
484 
485     // Compute h
486     h[i] = Fi_h_Ducharne(hi, bi, M, NL, NC, h0, b0, b[i]);
487   }
488 
489   V->Type = TENSOR_SYM ;
490   V->Val[0] = (b[0] == 0) ? 1/(1e4*MU0) : h[0]/b[0]  ;  V->Val[1] = 0.0  ;  V->Val[2] = 0 ;
491   V->Val[3] = (b[1] == 0) ? 1/(1e4*MU0) : h[1]/b[1]  ;  V->Val[4] = 0 ;
492   V->Val[5] = (b[2] == 0) ? 1/(1e4*MU0) : h[2]/b[2]  ;
493 }
494 
F_dhdb_Ducharne(F_ARG)495 void F_dhdb_Ducharne(F_ARG)
496 {
497   int    NL, NC, i;
498   double b0, h0, b[3], *bi, *hi, *M, dHdB[3], s;
499   struct FunctionActive  * D;
500 
501   if(!Fct->Active)  Fi_InitListMatrix(Fct, A, V) ;
502 
503   D = Fct->Active ;
504   NL = D->Case.ListMatrix.NbrLines ;
505   NC = D->Case.ListMatrix.NbrColumns ;
506 
507   hi = D->Case.ListMatrix.x ;
508   bi = D->Case.ListMatrix.y ;
509   M  = D->Case.ListMatrix.data ;
510 
511   for(i=0 ; i<3 ; ++i) {
512     // Get (h0,b0) = state of the model, and b
513     h0 = (A+0)->Val[i] ;
514     b0 = (A+1)->Val[i] ;
515     b[i] = (A+2)->Val[i] ;
516     s = (b[i] - b0 < 0) ? -1 : +1;
517 
518     bool IsInGrid = Fi_InterpolationBilinear(hi, bi, M, NL, NC, s*h0, s*b0, &(dHdB[i]));
519     if(!IsInGrid) dHdB[i] = MU0 ;
520   }
521 
522   V->Type = TENSOR_SYM ;
523   V->Val[0] = dHdB[0]  ;  V->Val[1] = 0.0  ;  V->Val[2] = 0 ;
524   V->Val[3] = dHdB[1]  ;  V->Val[4] = 0 ;
525   V->Val[5] = dHdB[2]  ;
526 }
527 
norm(const double a[3])528 double norm(const double a[3])
529 {
530   return sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
531 }
532 
533 //==============================================================
534 // K. Jacques functions for the Energy-Based Hysteresis Model
535 //==============================================================
536 
537 //---------------------------------------------------------
538 // SENSITIVE PARAMETERS SET AS GLOBAL VALUES
539 //---------------------------------------------------------
540 
541 int    FLAG_DIM;
542 int    FLAG_SYM;
543 int    FLAG_CENTRAL_DIFF;
544 int    FLAG_INVMETHOD;
545 int    FLAG_JACEVAL;
546 int    FLAG_APPROACH;
547 int    FLAG_MINMETHOD;
548 int    FLAG_ANHYLAW;
549 int    FLAG_WARNING;
550 double TOLERANCE_JS;
551 double TOLERANCE_0;
552 double TOLERANCE_NR;
553 int    MAX_ITER_NR;
554 double TOLERANCE_OM;
555 int    MAX_ITER_OM ;
556 int    FLAG_ANA ;
557 double TOLERANCE_NJ ;
558 double DELTA_0;
559 double DELTAJ_0;
560 double SLOPE_FACTOR;
561 int    FLAG_HOMO;
562 int    NCOMP;
563 
set_sensi_param(struct FunctionActive * D)564 void set_sensi_param(struct FunctionActive *D)
565 {
566   ::FLAG_DIM            = D->Case.Interpolation.x[0] ;
567   ::FLAG_SYM            = 0;
568   ::FLAG_CENTRAL_DIFF   = 1;
569   int j = 5+2*D->Case.Interpolation.x[1];
570   //int j = 11 ;
571   ::FLAG_INVMETHOD      = D->Case.Interpolation.x[j+1] ;
572   /*
573   FLAG_INVMETHOD = 1 --> NR_ana (homemade)
574   FLAG_INVMETHOD = 2 --> NR_num (homemade)
575   FLAG_INVMETHOD = 3 --> Good_bfgs (homemade)
576   */
577   ::FLAG_JACEVAL  = D->Case.Interpolation.x[j+2] ;
578   /*
579   FLAG_JACEVAL  = 1 --> JAC_ana
580   FLAG_JACEVAL  = 2 --> JAC_num
581   */
582   ::FLAG_APPROACH      = D->Case.Interpolation.x[j+3] ;
583   /*
584   FLAG_APPROACH = 1 --> variational approach (Jk)
585   FLAG_APPROACH = 2 --> Vector Play Model approach (hrk)
586   FLAG_APPROACH = 3 --> full differential approach (hrk)
587   */
588   ::FLAG_MINMETHOD      = D->Case.Interpolation.x[j+4] ;
589   /*
590   FLAG_MINMETHOD = 1 --> steepest descent (homemade)
591   FLAG_MINMETHOD = 2 --> conjugate fr (gsl)
592   FLAG_MINMETHOD = 3 --> conjugate pr (gsl)
593   FLAG_MINMETHOD = 4 --> bfgs2 (gsl)
594   FLAG_MINMETHOD = 5 --> bfgs (gsl)
595   FLAG_MINMETHOD = 6 --> steepest descent (gsl)
596   FLAG_MINMETHOD = 11   --> steepest descent+ (homemade)\n"
597   FLAG_MINMETHOD = 22   --> conjugate Fletcher-Reeves (homemade)\n"
598   FLAG_MINMETHOD = 33   --> conjugate Polak-Ribiere (homemade)\n"
599   FLAG_MINMETHOD = 333  --> conjugate Polak-Ribiere+ (homemade)\n"
600   FLAG_MINMETHOD = 1999 --> conjugate Dai Yuan 1999 (p.85) (homemade)\n"
601   FLAG_MINMETHOD = 2005 --> conjugate Hager Zhang 2005 (p.161) (homemade)\n"
602   FLAG_MINMETHOD = 77   --> newton (homemade)\n", ::FLAG_MINMETHOD);
603   */
604   ::FLAG_ANHYLAW      = D->Case.Interpolation.x[j+5] ;
605   /*
606   FLAG_ANHYLAW = 1 --> hyperbolic tangent
607   FLAG_ANHYLAW = 2 --> double langevin function
608   */
609   ::FLAG_WARNING        = D->Case.Interpolation.x[j+6] ;
610   /*
611   #define FLAG_WARNING_INFO_INV         1
612   #define FLAG_WARNING_INFO_APPROACH    2
613   #define FLAG_WARNING_STOP_INV         10
614 
615   #define FLAG_WARNING_DISPABOVEITER    1
616   */
617 
618   ::TOLERANCE_JS        = D->Case.Interpolation.x[j+7] ; // SENSITIVE_PARAM (1.e-3) // 1.e-4
619   ::TOLERANCE_0         = D->Case.Interpolation.x[j+8] ; // SENSITIVE_PARAM (1.e-7)
620 
621   ::TOLERANCE_NR        = D->Case.Interpolation.x[j+9] ; // SENSITIVE_PARAM (1.e-7) // 1.e-8 needed for diff with NR,1.e-5
622   ::MAX_ITER_NR         = D->Case.Interpolation.x[j+10] ; // SENSITIVE_PARAM (200)
623 
624   ::TOLERANCE_OM        = D->Case.Interpolation.x[j+11] ; // SENSITIVE_PARAM (1.e-11)// 1.e-15 allows to work for square if TOLERANCE_NJ=1.e-3 & DELTA_0=1.e-5 for numjac)
625   ::MAX_ITER_OM         = D->Case.Interpolation.x[j+12] ; // SENSITIVE_PARAM (700)
626 
627   ::FLAG_ANA            = D->Case.Interpolation.x[j+13] ; // SENSITIVE_PARAM (0='only numerical jacobian')
628   ::TOLERANCE_NJ        = D->Case.Interpolation.x[j+14] ; // SENSITIVE_PARAM (1.e-5 for square;
629                                                           //                  1.e-3 for VinchT.pro & transfo.pro)
630   ::DELTA_0             = D->Case.Interpolation.x[j+15] ; // SENSITIVE_PARAM (1.e-3 for square;
631                                                           //                  1.e0 for VinchT & transfo)
632   ::DELTAJ_0            = 1e-3; //only used with VAR approach when a Numerical approx of the hessian dd_omega is called in Taylor approx
633   ::SLOPE_FACTOR        = 1; // or 1e2 for better convergence
634   ::FLAG_HOMO           = D->Case.Interpolation.x[j+16] ; //
635 
636   /*
637   int LenX= D->Case.ListMatrix.NbrLines-(j+17);
638   printf("oh my: %d\n", LenX   );
639   for (int n=0; n<LenX;n++)
640    printf("h(%d): %g\n", n, D->Case.Interpolation.x[j+17+n]   );
641   getchar();
642   */
643 
644   switch(::FLAG_SYM)
645   {
646     case 1:
647       ::NCOMP=6;
648     break;
649     case 0:
650       ::NCOMP=9;
651     break;
652     default:
653       Message::Error("Invalid parameter (FLAG_SYM = 0 or 1) for function 'set_sensi_param'.\n");
654     break;
655   }
656 }
657 
658 struct params_Cells_EB
659 {
660   int idcell, N;
661   double Ja, ha, Jb, hb;
662   double *kappa, *w, *Xp;
663   double h[3];
664   int compout;
665   double Jp[3];
666 };
667 //----------------------------------------------------------
668 
669 //************************************************
670 // Usefull Mathematical functions :
671 //************************************************
672 
limiter(const double Js,double v[3])673 bool limiter(const double Js, double v[3])
674 {
675   double max = (1-::TOLERANCE_JS)*Js ;
676   double mod = norm(v);
677   if(mod >= max){
678 
679     for (int n=0; n<3; n++)
680       v[n] *= max/mod;
681     return true;
682     //Message::Warning("Js=%g, norm(J)=%g", Js, mod);
683   }
684   return false;
685 }
686 
Mul_VecVec(const double * v1,const double * v2)687 double Mul_VecVec(const double *v1, const double *v2)
688 {
689   return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
690 }
691 
Mul_TensorVec(const double * M,const double * v,double * Mv,const int transpose_M)692 void Mul_TensorVec(const double *M, const double *v, double *Mv, const int transpose_M)
693 {
694   switch(::FLAG_SYM)
695   {
696     case 1:
697       Mv[0]=M[0]*v[0]+M[1]*v[1]+M[2]*v[2];
698       Mv[1]=M[1]*v[0]+M[3]*v[1]+M[4]*v[2];
699       Mv[2]=M[2]*v[0]+M[4]*v[1]+M[5]*v[2];
700     break;
701     case 0:
702       if(transpose_M==1)
703       {
704         Mv[0]=M[0]*v[0]+M[3]*v[1]+M[6]*v[2];
705         Mv[1]=M[1]*v[0]+M[4]*v[1]+M[7]*v[2];
706         Mv[2]=M[2]*v[0]+M[5]*v[1]+M[8]*v[2];
707       }
708       else
709       {
710         Mv[0]=M[0]*v[0]+M[1]*v[1]+M[2]*v[2];
711         Mv[1]=M[3]*v[0]+M[4]*v[1]+M[5]*v[2];
712         Mv[2]=M[6]*v[0]+M[7]*v[1]+M[8]*v[2];
713       }
714     break;
715     default:
716       Message::Error("Invalid parameter for function 'Mul_TensorVec'");
717     break;
718   }
719 }
720 
Mul_TensorSymTensorSym(double * A,double * B,double * C)721 void Mul_TensorSymTensorSym(double *A, double *B, double *C)
722 {
723   //----------------------
724   //What is done actually: C[9] = A[6] . B[6]
725   //----------------------
726   C[0]=A[0]*B[0]+A[1]*B[1]+A[2]*B[2];
727   C[1]=A[0]*B[1]+A[1]*B[3]+A[2]*B[4];
728   C[2]=A[0]*B[2]+A[1]*B[4]+A[2]*B[5];
729   C[3]=A[1]*B[0]+A[3]*B[1]+A[4]*B[2];
730   C[4]=A[1]*B[1]+A[3]*B[3]+A[4]*B[4];
731   C[5]=A[1]*B[2]+A[3]*B[4]+A[4]*B[5];
732   C[6]=A[2]*B[0]+A[4]*B[1]+A[5]*B[2];
733   C[7]=A[2]*B[1]+A[4]*B[3]+A[5]*B[4];
734   C[8]=A[2]*B[2]+A[4]*B[4]+A[5]*B[5];
735 }
736 
Mul_TensorNonSymTensorNonSym(double * A,double * B,double * C)737 void Mul_TensorNonSymTensorNonSym(double *A, double *B, double *C) // NOT USED
738 {
739   //----------------------
740   //What is done actually: C[9] = A[9] . B[9]
741   //----------------------
742   C[0]=A[0]*B[0]+A[1]*B[3]+A[2]*B[6];
743   C[1]=A[0]*B[1]+A[1]*B[4]+A[2]*B[7];
744   C[2]=A[0]*B[2]+A[1]*B[5]+A[2]*B[8];
745   C[3]=A[3]*B[0]+A[4]*B[3]+A[5]*B[6];
746   C[4]=A[3]*B[1]+A[4]*B[4]+A[5]*B[7];
747   C[5]=A[3]*B[2]+A[4]*B[5]+A[5]*B[8];
748   C[6]=A[6]*B[0]+A[7]*B[3]+A[8]*B[6];
749   C[7]=A[6]*B[1]+A[7]*B[4]+A[8]*B[7];
750   C[8]=A[6]*B[2]+A[7]*B[5]+A[8]*B[8];
751 }
752 
Mul_TensorNonSymTensorSym(double * A,double * B,double * C)753 void Mul_TensorNonSymTensorSym(double *A, double *B, double *C) //NOT USED
754 {
755   /*
756   //----------------------
757   //What is done actually: C[9] = A[9] . B[6]
758   //----------------------
759   // Non Sym Output C + 3D case
760   C[0] =  A[0] * B[0]+A[1] * B[1]+A[2] * B[2]; //xx
761   C[1] =  A[0] * B[1]+A[1] * B[3]+A[2] * B[4]; //xy
762   C[2] =  A[0] * B[2]+A[1] * B[4]+A[2] * B[5]; //xz
763   C[3] =  A[3] * B[0]+A[4] * B[1]+A[5] * B[2]; //yx
764   C[4] =  A[3] * B[1]+A[4] * B[3]+A[5] * B[4]; //yy
765   C[5] =  A[3] * B[2]+A[4] * B[4]+A[5] * B[5]; //yz
766   C[6] =  A[6] * B[0]+A[7] * B[1]+A[8] * B[2]; //zx
767   C[7] =  A[6] * B[1]+A[7] * B[3]+A[8] * B[4]; //zy
768   C[8] =  A[6] * B[2]+A[7] * B[4]+A[8] * B[5]; //zz
769 
770   // Non Sym Output C + 2D case
771   C[0] =  A[0] * B[0]+A[1] * B[1]+A[2] * B[2]; //xx
772   C[1] =  A[0] * B[1]+A[1] * B[3]+A[2] * B[4]; //xy
773   C[2] =  0.;                                  //xz
774   C[3] =  A[3] * B[0]+A[4] * B[1]+A[5] * B[2]; //yx
775   C[4] =  A[3] * B[1]+A[4] * B[3]+A[5] * B[4]; //yy
776   C[5] =  0.;                                  //yz
777   C[6] =  0.;                                  //zx
778   C[7] =  0.;                                  //zy
779   C[8] =  1.;                                  //zz
780 
781   // Sym Output C + 3D case
782   C[0] =  A[0] * B[0]+A[1] * B[1]+A[2] * B[2]; //xx
783   C[1] =  A[0] * B[1]+A[1] * B[3]+A[2] * B[4]; //xy
784   C[2] =  A[0] * B[2]+A[1] * B[4]+A[2] * B[5]; //xz
785   C[3] =  A[3] * B[1]+A[4] * B[3]+A[5] * B[4]; //yy
786   C[4] =  A[3] * B[2]+A[4] * B[4]+A[5] * B[5]; //yz
787   C[5] =  A[6] * B[2]+A[7] * B[4]+A[8] * B[5]; //zz
788 
789   // Sym Output C + 2D case
790   C[0] =  A[0] * B[0]+A[1] * B[1]+A[2] * B[2]; //xx
791   C[1] =  A[0] * B[1]+A[1] * B[3]+A[2] * B[4]; //xy
792   C[2] =  0.;                                  //xz
793   C[3] =  A[3] * B[1]+A[4] * B[3]+A[5] * B[4]; //yy
794   C[4] =  0.;                                  //yz
795   C[5] =  1.;                                  //zz
796   //----------------------
797   */
798 
799   C[0] =  A[0] * B[0]+A[1] * B[1]+A[2] * B[2]; //xx
800   C[1] =  A[0] * B[1]+A[1] * B[3]+A[2] * B[4]; //xy
801   switch(::FLAG_SYM)
802   {
803     case 1: // Symmetrical Tensor
804       C[3] =  A[3] * B[1]+A[4] * B[3]+A[5] * B[4]; //yy
805       switch(::FLAG_DIM) {
806         case 2: // 2D case
807           C[5] = 1.; // zz
808           C[2] = C[4] = 0.; //xz //yz
809         break;
810         case 3: // 3D case
811           C[2] =  A[0] * B[2]+A[1] * B[4]+A[2] * B[5]; //xz
812           C[4] =  A[3] * B[2]+A[4] * B[4]+A[5] * B[5]; //yz
813           C[5] =  A[6] * B[2]+A[7] * B[4]+A[8] * B[5]; //zz
814         break;
815         default:
816           Message::Error("Invalid parameter (dimension = 2 or 3) for function 'Mul_TensorSymTensorNonSym'.");
817         break;
818       }
819     break;
820     case 0: // Non Symmetrical Tensor
821       C[3] =  A[3] * B[0]+A[4] * B[1]+A[5] * B[2]; //yx
822       C[4] =  A[3] * B[1]+A[4] * B[3]+A[5] * B[4]; //yy
823       switch(::FLAG_DIM) {
824         case 2: // 2D case
825           C[8] = 1.; // zz
826           C[2] = C[5] = C[6] = C[7] = 0.; //xz //yz //zx //zy
827         break;
828         case 3: // 3D case
829           C[2] =  A[0] * B[2]+A[1] * B[4]+A[2] * B[5]; //xz
830           C[5] =  A[3] * B[2]+A[4] * B[4]+A[5] * B[5]; //yz
831           C[6] =  A[6] * B[0]+A[7] * B[1]+A[8] * B[2]; //zx
832           C[7] =  A[6] * B[1]+A[7] * B[3]+A[8] * B[4]; //zy
833           C[8] =  A[6] * B[2]+A[7] * B[4]+A[8] * B[5]; //zz
834         break;
835         default:
836           Message::Error("Invalid parameter (dimension = 2 or 3) for function 'Mul_TensorSymTensorNonSym'.");
837         break;
838       }
839     break;
840     default:
841       Message::Error("Invalid parameter (FLAG_SYM = 0 or 1) for function 'Mul_TensorSymTensorNonSym'.\n");
842     break;
843   }
844 }
845 
846 
Mul_TensorSymTensorNonSym(double * A,double * B,double * C)847 void Mul_TensorSymTensorNonSym(double *A, double *B, double *C)
848 {
849 
850   /*
851   //----------------------
852   //What is done actually: C[9] = A[6] . B[9]
853   //----------------------
854   // Non Sym Output C + 3D case
855   C[0] =  A[0] * B[0]+A[1] * B[3]+A[2] * B[6]; //xx
856   C[1] =  A[0] * B[1]+A[1] * B[4]+A[2] * B[7]; //xy
857   C[2] =  A[0] * B[2]+A[1] * B[5]+A[2] * B[8]; //xz
858   C[3] =  A[1] * B[0]+A[3] * B[3]+A[4] * B[6]; //yx
859   C[4] =  A[1] * B[1]+A[3] * B[4]+A[4] * B[7]; //yy
860   C[5] =  A[1] * B[2]+A[3] * B[5]+A[4] * B[8]; //yz
861   C[6] =  A[2] * B[0]+A[4] * B[3]+A[5] * B[6]; //zx
862   C[7] =  A[2] * B[1]+A[4] * B[4]+A[5] * B[7]; //zy
863   C[8] =  A[2] * B[2]+A[4] * B[5]+A[5] * B[8]; //zz
864 
865   // Non Sym Output C + 2D case
866   C[0] =  A[0] * B[0]+A[1] * B[3]+A[2] * B[6]; //xx
867   C[1] =  A[0] * B[1]+A[1] * B[4]+A[2] * B[7]; //xy
868   C[2] =  0.;                                  //xz
869   C[3] =  A[1] * B[0]+A[3] * B[3]+A[4] * B[6]; //yx
870   C[4] =  A[1] * B[1]+A[3] * B[4]+A[4] * B[7]; //yy
871   C[5] =  0.;                                  //yz
872   C[6] =  0.;                                  //zx
873   C[7] =  0.;                                  //zy
874   C[8] =  1.;                                  //zz
875 
876   // Sym Output C + 3D case
877   C[0] =  A[0] * B[0]+A[1] * B[3]+A[2] * B[6]; //xx
878   C[1] =  A[0] * B[1]+A[1] * B[4]+A[2] * B[7]; //xy
879   C[2] =  A[0] * B[2]+A[1] * B[5]+A[2] * B[8]; //xz
880   C[3] =  A[1] * B[1]+A[3] * B[4]+A[4] * B[7]; //yy
881   C[4] =  A[1] * B[2]+A[3] * B[5]+A[4] * B[8]; //yz
882   C[5] =  A[2] * B[2]+A[4] * B[5]+A[5] * B[8]; //zz
883 
884   // Sym Output C + 2D case
885   C[0] =  A[0] * B[0]+A[1] * B[3]+A[2] * B[6]; //xx
886   C[1] =  A[0] * B[1]+A[1] * B[4]+A[2] * B[7]; //xy
887   C[2] =  0.;                                  //xz
888   C[3] =  A[1] * B[1]+A[3] * B[4]+A[4] * B[7]; //yy
889   C[4] =  0.;                                  //yz
890   C[5] =  1.;                                  //zz
891   //----------------------
892   */
893 
894   C[0] =  A[0] * B[0]+A[1] * B[3]+A[2] * B[6]; //xx
895   C[1] =  A[0] * B[1]+A[1] * B[4]+A[2] * B[7]; //xy
896   switch(::FLAG_SYM)
897   {
898     case 1: // Symmetrical Tensor
899       C[3] =  A[1] * B[1]+A[3] * B[4]+A[4] * B[7]; //yy
900       switch(::FLAG_DIM) {
901         case 2: // 2D case
902           C[5] = 1.; // zz
903           C[2] = C[4] = 0.; //xz //yz
904         break;
905         case 3: // 3D case
906           C[2] =  A[0] * B[2]+A[1] * B[5]+A[2] * B[8]; //xz
907           C[4] =  A[1] * B[2]+A[3] * B[5]+A[4] * B[8]; //yz
908           C[5] =  A[2] * B[2]+A[4] * B[5]+A[5] * B[8]; //zz
909         break;
910         default:
911           Message::Error("Invalid parameter (dimension = 2 or 3) for function 'Mul_TensorSymTensorNonSym'.");
912         break;
913       }
914     break;
915     case 0: // Non Symmetrical Tensor
916       C[3] =  A[1] * B[0]+A[3] * B[3]+A[4] * B[6]; //yx
917       C[4] =  A[1] * B[1]+A[3] * B[4]+A[4] * B[7]; //yy
918       switch(::FLAG_DIM) {
919         case 2: // 2D case
920           C[8] = 1.; // zz
921           C[2] = C[5] = C[6] = C[7] = 0.; //xz //yz //zx //zy
922         break;
923         case 3: // 3D case
924           C[2] =  A[0] * B[2]+A[1] * B[5]+A[2] * B[8]; //xz
925           C[5] =  A[1] * B[2]+A[3] * B[5]+A[4] * B[8]; //yz
926           C[6] =  A[2] * B[0]+A[4] * B[3]+A[5] * B[6]; //zx
927           C[7] =  A[2] * B[1]+A[4] * B[4]+A[5] * B[7]; //zy
928           C[8] =  A[2] * B[2]+A[4] * B[5]+A[5] * B[8]; //zz
929         break;
930         default:
931           Message::Error("Invalid parameter (dimension = 2 or 3) for function 'Mul_TensorSymTensorNonSym'.");
932         break;
933       }
934     break;
935     default:
936       Message::Error("Invalid parameter (FLAG_SYM = 0 or 1) for function 'Mul_TensorSymTensorNonSym'.\n");
937     break;
938   }
939 }
940 
Inv_Tensor3x3(double * T,double * invT)941 void Inv_Tensor3x3(double *T, double *invT)
942 {
943   double det;
944   switch(::FLAG_DIM)
945   {
946     case 2:
947       det =  T[0] * T[4] - T[1] * T[3];
948       if (!det)
949         Message::Error("Null determinant of invT! Case %d", ::FLAG_DIM);
950       invT[0]= T[4]/det;
951       invT[1]= -T[1]/det;
952       invT[3]= -T[3]/det;
953       invT[4]= T[0]/det;
954       invT[2]=  invT[5] = invT[6] =  invT[7] = 0.;
955       invT[8]= 1.;
956 
957     break;
958     case 3:
959       det= T[0]*T[4]*T[8]+T[1]*T[5]*T[6]+T[2]*T[3]*T[7]
960           -T[2]*T[4]*T[6]-T[0]*T[5]*T[7]-T[1]*T[3]*T[8];
961       if (!det)
962         Message::Error("Null determinant of invT! Case %d", ::FLAG_DIM);
963       invT[0]=(T[4]*T[8]-T[5]*T[7])/det;
964       invT[1]=(T[2]*T[7]-T[1]*T[8])/det;
965       invT[2]=(T[1]*T[5]-T[2]*T[4])/det;
966       invT[3]=(T[5]*T[6]-T[3]*T[8])/det;
967       invT[4]=(T[0]*T[8]-T[2]*T[6])/det;
968       invT[5]=(T[2]*T[3]-T[0]*T[5])/det;
969       invT[6]=(T[3]*T[7]-T[4]*T[6])/det;
970       invT[7]=(T[1]*T[6]-T[0]*T[7])/det;
971       invT[8]=(T[0]*T[4]-T[1]*T[3])/det;
972 
973     break;
974     default:
975       Message::Error("Invalid parameter for function 'Inv_Tensor3x3'");
976     break;
977   }
978 }
979 
Inv_TensorSym3x3(double * T,double * invT)980 void Inv_TensorSym3x3(double *T, double *invT)
981 {
982   double det ;
983   switch(::FLAG_DIM)
984   {
985     case 2:
986       det =  T[0] * T[3] - T[1] * T[1];
987       if (!det)
988         Message::Error("Null determinant of Sym invT! Case %d", ::FLAG_DIM);
989       invT[0] =  T[3]/det ;
990       invT[1] = -T[1]/det ;
991       invT[3] =  T[0]/det ;
992       invT[2] =  invT[4] =  0. ;
993       invT[5] =  1.;
994     break;
995 
996     case 3:
997       det =  T[0] * (T[3] * T[5] - T[4] * T[4])
998            - T[1] * (T[1] * T[5] - T[4] * T[2])
999            + T[2] * (T[1] * T[4] - T[3] * T[2]);
1000       if (!det)
1001         Message::Error("Null determinant of Sym invT! Case %d", ::FLAG_DIM);
1002       invT[0] =  (T[3]*T[5]-T[4]*T[4])/det ;
1003       invT[1] = -(T[1]*T[5]-T[2]*T[4])/det ;
1004       invT[2] =  (T[1]*T[4]-T[2]*T[3])/det ;
1005       invT[3] =  (T[0]*T[5]-T[2]*T[2])/det ;
1006       invT[4] = -(T[0]*T[4]-T[1]*T[2])/det ;
1007       invT[5] =  (T[0]*T[3]-T[1]*T[1])/det ;
1008     break;
1009 
1010     default:
1011       Message::Error("Invalid parameter for function 'Inv_TensorSym3x3'");
1012     break;
1013   }
1014 }
1015 
1016 // pour info
1017 // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
1018 // http://www.gnu.org/software/gsl/manual/html_node/Multimin-Examples.html
1019 
1020 
1021 #if defined(HAVE_GSL)
1022 #include <gsl/gsl_vector.h>
1023 #include <gsl/gsl_multiroots.h>
1024 #include <gsl/gsl_multimin.h>
1025 #include <gsl/gsl_errno.h>
1026 #include <gsl/gsl_math.h>
1027 #include <gsl/gsl_min.h>
1028 #include <gsl/gsl_roots.h>
1029 #endif
1030 
1031 //************************************************
1032 // Anhysteretic curve Characteristics :
1033 //************************************************
1034 
1035 // 1. Hyperbolic tangent ( used parameters : Js, alpha)
Janhy(double nhr,double Js,double alpha)1036 double Janhy(double nhr, double Js, double alpha)
1037 {
1038     double y=nhr/alpha;
1039    if (fabs(y)<(::TOLERANCE_0))
1040       return Js*y;
1041    else
1042       return Js*tanh(y);
1043 
1044 }
dJanhy(double nhr,double Js,double alpha)1045 double dJanhy(double nhr, double Js, double alpha)
1046 {
1047   double y=nhr/alpha;
1048    if (fabs(y)<(::TOLERANCE_0))
1049        return Js/alpha;
1050    else if (fabs(y)>350) // otherwise overflow
1051        return 0;
1052    else
1053        return Js/alpha*(1.-SQU(tanh(y)));
1054 }
Xanhy(double nhr,double Js,double alpha)1055 double Xanhy(double nhr,double Js, double alpha)
1056 {
1057    double y=nhr/alpha;
1058    if (fabs(y)<(::TOLERANCE_0))
1059        return Js/alpha;
1060    else
1061        return Js*tanh(y)/nhr;
1062 }
1063 
dXanhy(double nhr,double Js,double alpha)1064 double dXanhy(double nhr,double Js, double alpha)
1065 {
1066    double y=nhr/alpha;
1067    if (fabs(y)<(::TOLERANCE_0))
1068        return 2./3.*Js*y/alpha;  // DOUBT : need to add .../ fxc ??
1069    else
1070        return (dJanhy(nhr,Js,alpha)-Xanhy(nhr,Js,alpha))/nhr;
1071 }
1072 
IJanhy(double nhr,double Js,double alpha)1073 double IJanhy(double nhr, double Js, double alpha)  // = Co-energy
1074 {
1075     double y=nhr/alpha;
1076    if (fabs(y)<(::TOLERANCE_0))
1077        return Js*alpha*SQU(y)/2.;
1078    else
1079        return Js*alpha*log(cosh(y));
1080 }
1081 
InvJanhy(double nJ,double Js,double alpha)1082 double InvJanhy(double nJ, double Js, double alpha) // = y + y^3/3 + y^5/5 + y^7/7
1083 {
1084    double x=nJ/Js;
1085    if (fabs(x)<(::TOLERANCE_0))
1086        return alpha*x;
1087    else
1088        return alpha*atanh(x);
1089 }
1090 
dInvJanhy(double nJ,double Js,double alpha)1091 double dInvJanhy(double nJ, double Js, double alpha)
1092 {
1093     double x=nJ/Js;
1094     return (alpha/Js)*(1/(1-SQU(x))); // Warning : case x -> 1 <=> J -> Js
1095 }
1096 
1097 
1098 // 2. Double Langevin function ( used parameters : Ja, ha, Jb, hb)
Lang(double nhr,double Ja,double ha)1099 double Lang(double nhr, double Ja, double ha) //Langevin function = x/3-x^3/45+2*x^5/945-x^7/4725+...
1100 {
1101    double y=nhr/ha;
1102    if (fabs(y)<(::TOLERANCE_0))
1103        return Ja*y/3.;
1104    else
1105        return Ja*(1./tanh(y)-1./y);
1106 
1107 }
1108 
dLang(double nhr,double Ja,double ha)1109 double dLang(double nhr, double Ja, double ha)
1110 {
1111    double y=nhr/ha;
1112    if (fabs(y)<(::TOLERANCE_0))
1113        return Ja/ha/3. ;
1114    else if (fabs(y)>350) // otherwise overflow
1115        return 0 ;
1116    else
1117        return Ja/ha*(1./SQU(y)-1./SQU(sinh(y))) ;
1118 }
1119 
LangOverx(double nhr,double Ja,double ha)1120 double LangOverx(double nhr, double Ja, double ha)
1121 {   double y=nhr/ha;
1122    if (fabs(y)<(::TOLERANCE_0))
1123        return Ja/ha/3.;
1124    else
1125        return Ja*(1./tanh(y)-1./y)/nhr;
1126 }
1127 
dLangOverx(double nhr,double Ja,double ha)1128 double dLangOverx(double nhr, double Ja, double ha)
1129 {
1130    double y=nhr/ha;
1131    if (fabs(y)<(::TOLERANCE_0))
1132        return 2./45.*Ja*y/ha; // DOUBT : need to add .../ fxc ??
1133    else
1134        return (dLang(nhr,Ja,ha)-LangOverx(nhr,Ja,ha))/nhr;
1135 }
1136 
ILang(double nhr,double Ja,double ha)1137 double ILang(double nhr, double Ja, double ha)
1138 {
1139    double y=nhr/ha;
1140    if (fabs(y)<(::TOLERANCE_0))
1141        return Ja*ha*SQU(y)/6.;
1142    else     // ILdx(x)=log(sinh(x)/x) gives infinity for x>~300
1143        return Ja*ha*( y + log(1.-exp(-2.*y)) - log(2.*y) );
1144 }
1145 
Janhy(double nhr,double Ja,double ha,double Jb,double hb)1146 double Janhy(double nhr, double Ja, double ha, double Jb, double hb)
1147 {
1148   return Lang(nhr,Ja,ha)+Lang(nhr,Jb,hb);
1149 }
1150 
dJanhy(double nhr,double Ja,double ha,double Jb,double hb)1151 double dJanhy(double nhr, double Ja, double ha, double Jb, double hb)
1152 {
1153   return dLang(nhr,Ja,ha)+dLang(nhr,Jb,hb);
1154 }
1155 
Xanhy(double nhr,double Ja,double ha,double Jb,double hb)1156 double Xanhy(double nhr, double Ja, double ha, double Jb, double hb)
1157 {
1158   return LangOverx(nhr,Ja,ha)+LangOverx(nhr,Jb,hb);
1159 }
1160 
dXanhy(double nhr,double Ja,double ha,double Jb,double hb)1161 double dXanhy(double nhr, double Ja, double ha, double Jb, double hb)
1162 {
1163   return dLangOverx(nhr,Ja,ha)+dLangOverx(nhr,Jb,hb);
1164 }
1165 
IJanhy(double nhr,double Ja,double ha,double Jb,double hb)1166 double IJanhy(double nhr, double Ja, double ha, double Jb, double hb)  // = Co-energy
1167 {
1168   return ILang(nhr,Ja,ha)+ILang(nhr,Jb,hb);
1169 }
1170 
InvJanhy(double nJ,double Ja,double ha,double Jb,double hb)1171 double InvJanhy(double nJ, double Ja, double ha, double Jb, double hb)
1172 {
1173     double y=nJ;
1174     if (fabs(y)<(::TOLERANCE_0))
1175         return y/dJanhy(0.,Ja,ha,Jb,hb);
1176     ///* Fictitious slope above 1e6 (09/06/2016)-------------
1177     double tmp = y - Janhy(1100,Ja,ha,Jb,hb);
1178     if (tmp>0)
1179       return 1100+1e16*tmp;
1180      //*///---------------------------------------------------------------------------
1181     int i=0;
1182     double x=0.0;
1183     double dJan=dJanhy(x,Ja,ha,Jb,hb);
1184     dJan=(dJan>1e-10)?dJan:1e-10; // Limitation
1185     double dx = (y-Janhy(x,Ja,ha,Jb,hb))/dJan;
1186     int imax=100;
1187       while ( ((fabs(dx)/((1>fabs(x))?1:fabs(x))) > ::TOLERANCE_NR) && (i<imax) )
1188       {
1189           dJan = dJanhy(x,Ja,ha,Jb,hb);
1190           dJan = (dJan>1e-10)?dJan:1e-10; // Limitation
1191           dx = (y-Janhy(x,Ja,ha,Jb,hb))/dJan;
1192           x +=  dx;
1193           i++;
1194       }
1195       return x;
1196 }
1197 
dInvJanhy_hr(double nhr,double Ja,double ha,double Jb,double hb)1198 double dInvJanhy_hr(double nhr, double Ja, double ha, double Jb, double hb)
1199 {
1200   double dJdhr=dJanhy(nhr, Ja, ha, Jb, hb);
1201   if (dJdhr==0.)
1202   {
1203     Message::Warning("dJdhr is too small to be inverted in function 'dInvJanhy_hr'.");
1204     return 1.;
1205   }
1206   else
1207     return 1/dJdhr;
1208 }
1209 
1210 
u_hr(double nhr,double Ja,double ha,double Jb,double hb)1211 double u_hr(double nhr, double Ja, double ha, double Jb, double hb)  // = Energy with hr as input
1212 {
1213   return Janhy(nhr,Ja,ha,Jb,hb)*nhr - IJanhy(nhr,Ja,ha,Jb,hb);
1214 }
1215 
u_J(double nJ,double Js,double alpha)1216 double u_J(double nJ, double Js, double alpha) // = Energy with J as input = IInvJanhy // only valid for TANH version
1217 {
1218   return alpha*Js *( nJ/Js*atanh(nJ/Js) + 0.5*log(fabs(SQU(nJ/Js)-1)) );
1219 }
1220 
Vector_Jk_From_hrk(const double hrk[3],void * params,double Jk[3])1221 void Vector_Jk_From_hrk(const double hrk[3],
1222                        void * params,
1223                        double Jk[3])
1224 {
1225   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1226   double wk=1;
1227   if (p->idcell>=0 && p->idcell<p->N)
1228     wk  = p->w[p->idcell];
1229   double Ja  = wk*p->Ja;
1230   double Jb  = wk*p->Jb;
1231   double ha = p->ha ;
1232   double hb = p->hb ;
1233 
1234   double nhrk = norm(hrk);
1235   double Xan = 0;
1236 
1237   switch(::FLAG_ANHYLAW) {
1238     case 1: // Hyperbolic Tangent Case
1239         Xan = Xanhy(nhrk, Ja, ha);
1240     break;
1241     case 2: // Double Langevin Function Case
1242         Xan = Xanhy(nhrk, Ja, ha, Jb, hb);
1243     break;
1244     default:
1245       Message::Error("Invalid parameter (AnhyLaw = 1 (Tanh) or 2 (DLan) )"
1246                      "for function 'Vector_Jk_From_hrk'.");
1247     break;
1248   }
1249   for (int n = 0; n < 3 ; n++)
1250     Jk[n] = Xan * hrk[n];
1251 }
1252 
Vector_hrk_From_Jk(const double Jk[3],void * params,double hrk[3])1253 void Vector_hrk_From_Jk(const double Jk[3],
1254                         void * params,
1255                         double hrk[3])
1256 {
1257 
1258   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1259   double wk=1;
1260   if (p->idcell >= 0 && p->idcell < p->N)
1261     wk  = p->w[p->idcell];
1262   double Ja  = wk*p->Ja;
1263   double Jb  = wk*p->Jb;
1264   double ha  = p->ha;
1265   double hb  = p->hb;
1266 
1267   double nhrk = 0;
1268   double nJk  = norm(Jk);
1269   switch(::FLAG_ANHYLAW) {
1270     case 1: // Hyperbolic Tangent Case
1271         nhrk = InvJanhy(nJk, Ja, ha) ;
1272     break;
1273     case 2: // Double Langevin Function Case
1274         nhrk = InvJanhy(nJk, Ja, ha, Jb, hb) ;
1275     break;
1276     default:
1277       Message::Error("Invalid parameter (AnhyLaw = 1 (Tanh) or 2 (DLan) )"
1278                      "for function 'Vector_hrk_From_Jk'.");
1279     break;
1280   }
1281 
1282   for (int n=0; n<3; n++)
1283     hrk[n] = (nJk) ?  (nhrk/nJk)*Jk[n] : 0. ;
1284     //hrk[n] = (nJk>(::TOLERANCE_0)) ?  (nhrk/nJk)*Jk[n] : 0. ;
1285 }
1286 
1287 
Tensor_dJkdhrk(const double hr[3],void * params,double mutg[6])1288 void Tensor_dJkdhrk(const double hr[3],
1289                       void * params,
1290                       double mutg[6])
1291 {
1292 
1293   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1294   double wk=1.;
1295   if (p->idcell>=0 && p->idcell<p->N)
1296     wk  = p->w[p->idcell];
1297   double Ja  = wk*p->Ja;
1298   double Jb  = wk*p->Jb;
1299   double ha = p->ha ;
1300   double hb = p->hb ;
1301 
1302   double nhr  = norm(hr);
1303   double Xan=0., dXandH2=0.;
1304 
1305   switch(::FLAG_ANHYLAW) {
1306     case 1: // Hyperbolic Tangent Case
1307       Xan      = Xanhy(nhr, Ja, ha);
1308       dXandH2  = (nhr>(::TOLERANCE_0)) ? (dXanhy(nhr, Ja, ha)/(2*nhr)) : 0. ;
1309     break;
1310     case 2: // Double Langevin Function Case
1311       Xan      = Xanhy(nhr, Ja, ha, Jb, hb);
1312       dXandH2  = (nhr>(::TOLERANCE_0)) ? (dXanhy(nhr, Ja, ha, Jb, hb)/(2*nhr)) : 0. ;
1313     break;
1314     default:
1315       Message::Error("Invalid parameter (AnhyLaw = 1 (Tanh) or 2 (DLan) )"
1316         "for function 'Tensor_dJkdhrk'.");
1317     break;
1318   }
1319 
1320   mutg[0] = Xan  + 2 * dXandH2 * ( hr[0]* hr[0] ) ;//xx
1321   mutg[3] = Xan  + 2 * dXandH2 * ( hr[1]* hr[1] ); //yy
1322   mutg[1] =        2 * dXandH2 * ( hr[1]* hr[0] ); //xy
1323   switch(::FLAG_DIM) {
1324     case 2: // 2D case
1325       mutg[5] = 1.;
1326       mutg[2] = mutg[4] = 0.;
1327     break;
1328     case 3: // 3D case
1329       mutg[5]= Xan  + 2 * dXandH2 * ( hr[2]* hr[2] ) ; //zz
1330       mutg[2]=        2 * dXandH2 * ( hr[2]* hr[0] ) ; //xz
1331       mutg[4]=        2 * dXandH2 * ( hr[2]* hr[1] ) ; //yz
1332     break;
1333     default:
1334       Message::Error("Invalid parameter (dimension = 2 or 3)"
1335         "for function 'Tensor_dJkdhrk'. Analytic Jacobian computation.");
1336     break;
1337   }
1338 
1339 }
1340 
1341 
1342 //************************************************
1343 // Pseudo-Potential Functional Characteristics :
1344 //************************************************
1345 
1346 #if defined(HAVE_GSL) // due to the use of gsl_vector
omega_f(const gsl_vector * v,void * params)1347 double omega_f(const gsl_vector *v, void *params)  // not in F.h
1348 {
1349   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1350   double wk  = p->w[p->idcell];
1351   double Ja  = wk*p->Ja;
1352   double Jb  = wk*p->Jb;
1353 
1354   double h[3];
1355   for (int n=0; n<3; n++)
1356     h[n]  = p->h[n];
1357 
1358   double J[3];
1359   for (int i=0; i<3; i++) J[i] = gsl_vector_get(v, i);
1360   limiter(Ja+Jb, J) ;
1361 
1362   double omega = fct_omega_VAR(h, J, params) ;
1363   return omega;
1364 }
1365 
omega_df(const gsl_vector * v,void * params,gsl_vector * df)1366 void omega_df (const gsl_vector *v, void *params, gsl_vector *df)  // not in F.h
1367 {
1368 
1369   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1370   double wk  = p->w[p->idcell];
1371   double Ja  = wk*p->Ja;
1372   double Jb  = wk*p->Jb;
1373 
1374   double h[3];
1375   for (int n=0; n<3; n++)
1376     h[n]  = p->h[n];
1377 
1378   double J[3];
1379   for (int i=0; i<3; i++) J[i] = gsl_vector_get(v, i);
1380   limiter(Ja+Jb, J);
1381 
1382   double d_omega[3];
1383   fct_d_omega_VAR (J,d_omega,h, params ) ;
1384   for (int i=0; i<3; i++) gsl_vector_set(df, i, d_omega[i]);
1385 }
1386 
omega_fdf(const gsl_vector * x,void * params,double * f,gsl_vector * df)1387 void omega_fdf (const gsl_vector *x, void *params, double *f, gsl_vector *df)  // not in F.h
1388 {
1389   *f = omega_f(x, params);
1390   omega_df(x, params, df);
1391 }
1392 #endif
1393 
fct_omega_VAR(const double h[3],const double Jk[3],void * params)1394 double fct_omega_VAR(const double h[3],
1395                      const double Jk[3],
1396                      void * params )
1397 {
1398   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1399 
1400   double kappa  = p->kappa[p->idcell];
1401   double wk     = p->w[p->idcell];
1402   double Ja     = wk*p->Ja;
1403   double ha     = p->ha ;
1404   double Jb     = wk*p->Jb;
1405   double hb     = p->hb ;
1406 
1407   double Jkp[3];
1408   for (int n=0; n<3; n++)
1409     Jkp[n] = p->Xp[n+3*p->idcell];
1410 
1411   double diff[3];
1412   for (int n=0; n<3; n++)
1413     diff[n] = Jk[n]-Jkp[n]; // J-Jp
1414 
1415   // magnetisation Jk assumed to be < the saturation magnetisation Js
1416   double nJk = norm(Jk), u=0., nhr=0.;
1417 
1418   // TODO: build a generic u function
1419   switch(::FLAG_ANHYLAW) {
1420     case 1: // Hyperbolic Tangent Case
1421       u     = u_J(nJk,Ja,ha); // magnetic energy u(J)
1422     break;
1423     case 2: // Double Langevin Function Case
1424       nhr   = InvJanhy(nJk, Ja, ha, Jb, hb);
1425       u     = u_hr(nhr,Ja,ha,Jb,hb); // magnetic energy u(J)
1426     break;
1427     default:
1428       Message::Error("Invalid parameter (AnhyLaw = 1 (Tanh) or 2 (DLan) )"
1429         "for function 'fct_omega_VAR'.");
1430     break;
1431   }
1432 
1433   double Jh     = Jk[0] * h[0] + Jk[1] * h[1] + Jk[2] * h[2]; // -J.h
1434   double Dissip = kappa * norm(diff) ; // kappa | J-Jp |
1435 
1436   return (u-Jh+Dissip);
1437 }
1438 
1439 
fct_d_omega_VAR(const double Jk[3],double * d_omega,double h[3],void * params)1440 void fct_d_omega_VAR(const double Jk[3],
1441                      double *d_omega,
1442                      double h[3],
1443                      void * params )
1444 {
1445   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1446 
1447   double kappa  = p->kappa[p->idcell];
1448 
1449   double Jkp[3], dJk[3], hrk[3];
1450 
1451   for (int n=0; n<3; n++)
1452     Jkp[n] = p->Xp[n+3*p->idcell];
1453 
1454   for (int n=0; n<3; n++)
1455     dJk[n] = Jk[n]-Jkp[n];
1456   double ndJk = norm(dJk);
1457 
1458   Vector_hrk_From_Jk(Jk, params, hrk);
1459 
1460   d_omega[0] = d_omega[1] = d_omega[2] = 0.;
1461   for (int n = 0; n < 3; n++) {
1462     d_omega[n] += hrk[n] - h[n];
1463     if(ndJk) d_omega[n] += kappa * dJk[n]/ndJk ;
1464   }
1465 }
1466 
1467 
fct_dd_omega_VAR(const double h[3],const double Jk[3],void * params,double * ddfdJ2)1468 void fct_dd_omega_VAR(const double h[3],
1469                       const double Jk[3],
1470                       void * params,
1471                       double *ddfdJ2)
1472 {
1473   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1474 
1475   double Jkp[3];
1476   for (int n=0; n<3; n++)
1477     Jkp[n] = p->Xp[n+3*p->idcell];
1478 
1479   double kappa  = p->kappa[p->idcell];
1480   double wk     = p->w[p->idcell];
1481   double Ja     = wk*p->Ja;
1482   double ha     = p->ha ;
1483   double Jb     = wk*p->Jb;
1484   double hb     = p->hb ;
1485 
1486   double dJk[3];
1487   for (int n=0; n<3; n++)
1488     dJk[n] = Jk[n]-Jkp[n];
1489 
1490   double nJk  = norm(Jk);
1491   double ndJk = norm(dJk);
1492 
1493   if ( (::FLAG_ANA) && (nJk>(::TOLERANCE_NJ) && ndJk>(::TOLERANCE_NJ))){
1494     Message::Debug("--- fct_dd_omega_VAR: Analytical Jacobian ---");
1495 
1496     double kappaOverndJk = kappa/ndJk;
1497     double nhr=0.; double dhrdJkOvernJk2=0.; double nhrOvernJk=0.;
1498 
1499     switch(::FLAG_ANHYLAW) {
1500       case 1: // Hyperbolic Tangent Case
1501           nhr = InvJanhy(nJk, Ja, ha) ;
1502           nhrOvernJk = nhr/nJk;
1503           dhrdJkOvernJk2 = dInvJanhy(nJk, Ja, ha) /SQU(nJk);
1504       break;
1505       case 2: // Double Langevin Function Case
1506           nhr = InvJanhy(nJk, Ja, ha, Jb, hb) ;
1507           nhrOvernJk = nhr/nJk;
1508           dhrdJkOvernJk2 = dInvJanhy_hr(nhr, Ja, ha, Jb, hb) /SQU(nJk);
1509       break;
1510       default:
1511         Message::Error("Invalid parameter (AnhyLaw = 1 (Tanh) or 2 (DLan) )"
1512           "for function 'fct_dd_omega_VAR'.");
1513       break;
1514     }
1515 
1516     ddfdJ2[0] = dhrdJkOvernJk2  * (Jk[0]*Jk[0])
1517               + nhrOvernJk      * (1. - (1/SQU(nJk))*(Jk[0]*Jk[0]))
1518               + kappaOverndJk   * (1. - (1/SQU(ndJk))*(dJk[0]*dJk[0])) ; //xx
1519     ddfdJ2[1] = dhrdJkOvernJk2  * (Jk[1]*Jk[0])
1520               + nhrOvernJk      * (   - (1/SQU(nJk))*(Jk[1]*Jk[0]))
1521               + kappaOverndJk   * (   - (1/SQU(ndJk))*(dJk[1]*dJk[0])) ; //xy
1522     switch(::FLAG_SYM)
1523     {
1524       case 1: // Symmetric tensor
1525         ddfdJ2[3] = dhrdJkOvernJk2 * (Jk[1]*Jk[1])
1526                   + nhrOvernJk     * (1. - (1/SQU(nJk))*(Jk[1]*Jk[1]))
1527                   + kappaOverndJk  * (1. - (1/SQU(ndJk))*(dJk[1]*dJk[1])) ; //yy
1528         switch(::FLAG_DIM) {
1529           case 2: // 2D case
1530             ddfdJ2[5] = 1.;
1531             ddfdJ2[2] = ddfdJ2[4] = 0.;
1532           break;
1533           case 3: // 3D case
1534             ddfdJ2[5] = dhrdJkOvernJk2  * (Jk[2]*Jk[2])
1535                       + nhrOvernJk      * (1. - (1/SQU(nJk))*(Jk[2]*Jk[2]))
1536                       + kappaOverndJk   * (1. - (1/SQU(ndJk))*(dJk[2]*dJk[2])) ; //zz
1537             ddfdJ2[2] = dhrdJkOvernJk2  * (Jk[2]*Jk[0])
1538                       + nhrOvernJk      * (   - (1/SQU(nJk))*(Jk[2]*Jk[0]))
1539                       + kappaOverndJk   * (   - (1/SQU(ndJk))*(dJk[2]*dJk[0])) ; //xz
1540             ddfdJ2[4] = dhrdJkOvernJk2  * (Jk[2]*Jk[1])
1541                       + nhrOvernJk      * (   - (1/SQU(nJk))*(Jk[2]*Jk[1]))
1542                       + kappaOverndJk   * (   - (1/SQU(ndJk))*(dJk[2]*dJk[1])) ; //yz
1543           break;
1544           default:
1545             Message::Error("Invalid parameter (dimension = 2 or 3)"
1546               "for function 'fct_dd_omega_VAR'. Analytic Jacobian computation.");
1547           break;
1548         }
1549       break;
1550       case 0: // Non Symmetric Tensor
1551         ddfdJ2[3] = ddfdJ2[1]; //yx
1552         ddfdJ2[4] = dhrdJkOvernJk2  * (Jk[1]*Jk[1])
1553                   + nhrOvernJk      * (1. - (1/SQU(nJk))*(Jk[1]*Jk[1]))
1554                   + kappaOverndJk   * (1. - (1/SQU(ndJk))*(dJk[1]*dJk[1])) ; //yy
1555         switch(::FLAG_DIM) {
1556           case 2: // 2D case
1557             ddfdJ2[8] = 1.; // zz
1558             ddfdJ2[2] = ddfdJ2[5] = ddfdJ2[6] =ddfdJ2[7] =0.; //xz //xy //zx //zy
1559           break;
1560           case 3: // 3D case
1561             ddfdJ2[8] = dhrdJkOvernJk2  * (Jk[2]*Jk[2])
1562                       + nhrOvernJk      * (1. - (1/SQU(nJk))*(Jk[2]*Jk[2]))
1563                       + kappaOverndJk   * (1. - (1/SQU(ndJk))*(dJk[2]*dJk[2])) ; //zz
1564             ddfdJ2[2] = dhrdJkOvernJk2  * (Jk[2]*Jk[0])
1565                       + nhrOvernJk      * (   - (1/SQU(nJk))*(Jk[2]*Jk[0]))
1566                       + kappaOverndJk   * (   - (1/SQU(ndJk))*(dJk[2]*dJk[0])) ; //xz
1567             ddfdJ2[5] = dhrdJkOvernJk2  * (Jk[2]*Jk[1])
1568                       + nhrOvernJk      * (   - (1/SQU(nJk))*(Jk[2]*Jk[1]))
1569                       + kappaOverndJk   * (   - (1/SQU(ndJk))*(dJk[2]*dJk[1])) ; //yz
1570             ddfdJ2[6] = ddfdJ2[2]; //zx
1571             ddfdJ2[7] = ddfdJ2[5]; //zy
1572           break;
1573           default:
1574             Message::Error("Invalid parameter (dimension = 2 or 3)"
1575               "for function 'fct_dd_omega_VAR'. Analytic Jacobian computation.");
1576           break;
1577         }
1578       break;
1579       default:
1580         Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
1581           "for function 'fct_dd_omega_VAR'.\n");
1582       break;
1583     }
1584   }
1585   else
1586   {
1587     Message::Debug("--- fct_dd_omega_VAR: Numerical Jacobian ---");
1588     double hcopy[3]={h[0],h[1],h[2]}; // because h is constant double
1589     Tensor_num(fct_d_omega_VAR, Jk, ::DELTAJ_0, hcopy, params, ddfdJ2);
1590   }
1591 }
1592 
1593 //************************************************
1594 // Usefull Functions for the Full Differential Approach
1595 //************************************************
1596 
fct_ehirr_DIFF_3d(const double x[2],double ehi[3])1597 void fct_ehirr_DIFF_3d(const double x[2],
1598                        double ehi[3])
1599 {
1600   const double theta = x[0];
1601   const double phi   = x[1];
1602 
1603   ehi[0]=sin(phi)*cos(theta);
1604   ehi[1]=sin(phi)*sin(theta);
1605   ehi[2]=cos(phi)  ;
1606 }
1607 
1608 
fct_hr_DIFF_3d(const double x[2],const double kappa,const double ehi[3],const double h[3],double xup[3])1609 void fct_hr_DIFF_3d(const double x[2],
1610                     const double kappa,
1611                     const double ehi[3],
1612                     const double h[3],
1613                     double xup[3])
1614 {
1615   for (int n=0 ; n<3 ; n++)
1616     xup[n]=h[n] + kappa*ehi[n];
1617 }
1618 
fct_fall_DIFF_3d(const double ang[2],void * params,double fall[3])1619 void fct_fall_DIFF_3d (const double ang[2],
1620                        void *params,
1621                        double fall[3])
1622 {
1623 
1624   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1625   double kappa  = p->kappa[p->idcell];
1626   double h[3]   = { p->h[0] , p->h[1] , p->h[2]  };
1627   double Jp[3]  = { p->Jp[0], p->Jp[1], p->Jp[2] };
1628 
1629   double xup[3];
1630   double dJ[3];
1631   double ehi[3];
1632   fct_ehirr_DIFF_3d(ang,ehi);
1633   fct_hr_DIFF_3d(ang, kappa, ehi,h, xup);
1634 
1635   Vector_Jk_From_hrk (xup, params, dJ); // dJ contains Jup here
1636   for (int n=0; n<3; n++)
1637     dJ[n] -= Jp[n]; // dJ = Jup - Jp as it should be here
1638 
1639   fall[0] =  dJ[1]*ehi[2] -  dJ[2]*ehi[1];
1640   fall[1] =  dJ[2]*ehi[0] -  dJ[0]*ehi[2];
1641   fall[2] =  dJ[0]*ehi[1] -  dJ[1]*ehi[0];
1642 }
1643 
1644 
1645 // due to the use of gsl_vector, GSL_SUCCESS, gsl_multiroot_fsolver, ...
1646 #if defined(HAVE_GSL)
fct_f_DIFF_3d(const gsl_vector * gsl_ang,void * params,gsl_vector * f)1647 int fct_f_DIFF_3d ( const gsl_vector * gsl_ang,
1648                     void *params,
1649                     gsl_vector * f) // not in F.h
1650 {
1651 
1652   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1653 
1654   double ang[2];
1655   for (int n=0; n<2; n++)
1656     ang[n]=gsl_vector_get (gsl_ang, n);
1657 
1658   double fall[3];
1659   fct_fall_DIFF_3d(ang,params,fall);
1660 
1661   // remove compout from fall:
1662   int i=0;
1663   for (int n=0; n<3; n++)
1664   {
1665     if(p->compout!=n)
1666     {
1667       gsl_vector_set (f, i, fall[n]);
1668       i++;
1669     }
1670   }
1671   /* Actually do this:
1672     if (p->compout==0)
1673     {
1674       gsl_vector_set (f, 0, fall[1]);
1675       gsl_vector_set (f, 1, fall[2]);
1676     }
1677     else if (p->compout==1)
1678     {
1679       gsl_vector_set (f, 0, fall[0]);
1680       gsl_vector_set (f, 1, fall[2]);
1681     }
1682     else //if (p-> compout==2)
1683     {
1684       gsl_vector_set (f, 0, fall[0]);
1685       gsl_vector_set (f, 1, fall[1]);
1686     }
1687   */
1688   return GSL_SUCCESS;
1689 }
1690 
print_state_3d(int iterb,const char * s_name,int status,gsl_multiroot_fsolver * s)1691 void print_state_3d (int iterb,
1692                      const char *s_name,
1693                      int status,
1694                      gsl_multiroot_fsolver * s)  // not in F.h
1695 {
1696   if(::FLAG_WARNING>=FLAG_WARNING_INFO_APPROACH
1697     && iterb>=FLAG_WARNING_DISPABOVEITER)
1698   {
1699     if (iterb == FLAG_WARNING_DISPABOVEITER)
1700       printf ("using %s method",
1701               s_name);
1702 
1703       printf ("\niter = %3u x = % .3f % .3f "
1704               "f(x) = % .3e % .3e",
1705               iterb,
1706               gsl_vector_get (s->x, 0),
1707               gsl_vector_get (s->x, 1),
1708               gsl_vector_get (s->f, 0),
1709               gsl_vector_get (s->f, 1));
1710 
1711     if (status == GSL_SUCCESS)
1712       printf (" (Converged)\n");
1713   }
1714 }
1715 #endif
1716 
1717 
Vector_hirr_DIFF_2d(double x,double kappa,double ex[3])1718 void Vector_hirr_DIFF_2d(double x,
1719                          double kappa,
1720                          double ex[3])
1721 {
1722   ex[0]=kappa*cos(x);
1723   ex[1]=kappa*sin(x);
1724   ex[2]=0;
1725 }
1726 
fct_hr_DIFF_2d(double x,double kappa,double h[3],double xup[3])1727 void fct_hr_DIFF_2d(double x,
1728                     double kappa,
1729                     double h[3],
1730                     double xup[3])
1731 {
1732   double hi[3];
1733   Vector_hirr_DIFF_2d(x, kappa, hi);
1734   for (int n=0 ; n<3 ; n++)
1735     xup[n]=h[n]-hi[n];
1736 }
1737 
fct_f_DIFF_2d(double y,void * params)1738 double fct_f_DIFF_2d (double y,
1739                       void *params)
1740 {
1741   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1742 
1743   double kappa  = p->kappa[p->idcell];
1744 
1745   double h[3]  ,Jp[3] ;
1746   for (int n=0; n<3; n++){
1747     Jp[n]   = p->Jp[n];
1748     h[n]    = p->h[n] ;
1749   }
1750 
1751   double xup[3], dJ[3];
1752   fct_hr_DIFF_2d(y, kappa, h, xup);
1753   Vector_Jk_From_hrk (xup, params, dJ); // dJ contains Jup here
1754   for (int n=0; n<3; n++)
1755     dJ[n] -= Jp[n]; // dJ = Jup - Jp as it should be here
1756 
1757   return dJ[0]*sin(y)-dJ[1]*cos(y);
1758 }
1759 
1760 #if defined(HAVE_GSL) // due to the use of GSL_SUCCESS
print_state_2d(int iterb,const char * s_name,int status,double al,double br,double alpha,double err)1761 void print_state_2d ( int iterb,
1762                       const char *s_name,
1763                       int status,
1764                       double al,
1765                       double br,
1766                       double alpha,
1767                       double err)  // not in F.h
1768 {
1769   if(::FLAG_WARNING>=FLAG_WARNING_INFO_APPROACH
1770     && iterb>=FLAG_WARNING_DISPABOVEITER )
1771   {
1772     if( iterb==FLAG_WARNING_DISPABOVEITER)
1773     {
1774       printf ("using %s method\n",
1775               s_name);
1776       printf ("%5s [%9s, %9s] %9s %9s\n",
1777               "iter", "lower", "upper", "alpha", "err(est)");
1778     }
1779 
1780     if (status == GSL_SUCCESS)
1781       printf ("Converged:\n");
1782 
1783     printf ("%5d [%.7f, %.7f] "
1784             "%.7f %.7f\n",
1785             iterb, al, br,
1786             alpha, err);
1787   }
1788 }
1789 #endif
1790 
1791 //************************************************
1792 // Energy-Based Model - Vector Update
1793 //************************************************
1794 
Vector_Update_Jk_VAR(const double h[3],double Jk[3],double Jk0[3],void * params)1795 void Vector_Update_Jk_VAR(const double h[3],
1796                           double Jk[3],
1797                           double Jk0[3],
1798                           void * params)
1799 {
1800   double Jkp[3];
1801   double hcopy[3]={h[0],h[1],h[2]}; // because h is constant double
1802 
1803   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
1804 
1805   for (int n=0; n<3; n++){
1806     Jkp[n]  = p->Xp[n+3*p->idcell];
1807     p->h[n] = h[n];
1808   }
1809 
1810   double kappa  = p->kappa[p->idcell];
1811   double wk     = p->w[p->idcell];
1812   double Ja     = wk*p->Ja;
1813   double Jb     = wk*p->Jb;
1814 
1815   //No minimization needed when |h-hrp|<kappa! ==> |nhirrp|<kappa ==> Jk = Jkp
1816   double hrp[3];
1817 
1818   Vector_hrk_From_Jk(Jkp,params, hrp);
1819   double hirrp[3];
1820   for (int n = 0; n < 3; n++)
1821     hirrp[n]=h[n] - hrp[n];
1822 
1823   double nhirrp=norm(hirrp);
1824 
1825   if (nhirrp<=kappa)
1826   {
1827     for (int n = 0; n < 3; n++)
1828       Jk[n]=Jkp[n];
1829     return;
1830   }
1831 
1832   // If one wants to start from Jk = Jk from VPM Approach------------------
1833   double hr[3], Jk_VPM[3];
1834   Vector_Update_hrk_VPM_ (h, hr, hrp, kappa);
1835   Vector_Jk_From_hrk (hr, params, Jk_VPM); // dJ contains Jup here
1836   double nJ0[3];
1837   for (int n=0; n<3; n++) nJ0[n] = Jk_VPM[n]-Jkp[n];
1838 
1839   // diff hr induced an imperceptible diff Jk in that case => kill early
1840   if (norm(nJ0)<1e-16*norm(Jk_VPM) )
1841   {
1842     for (int n = 0; n < 3; n++)
1843       Jk[n]=Jkp[n];
1844     return;
1845   }
1846   double J0[3];
1847   for (int n=0; n<3; n++) J0[n] = Jk_VPM[n];
1848   switch(::FLAG_MINMETHOD) {
1849     case 1:
1850     {
1851       //-------------------------------------------------------------------
1852       // Updating Jk with a steepest descent algorithm
1853       //-------------------------------------------------------------------
1854 
1855       double min_Jk[3] ;
1856       for (int n=0 ; n<3 ; n++) min_Jk[n] = J0[n];
1857       double d_omega[3] ;
1858       double sdfactor  = 0.1; //suitable value of tol for most applications
1859       double TOL = ::TOLERANCE_OM;
1860       double Js=(Ja+Jb);
1861       for (int n=0; n<3; n++) Jk[n] = J0[n];
1862 
1863       limiter(Js, Jk ); // avoiding possible NaN with atanh
1864 
1865       fct_d_omega_VAR(Jk, d_omega, hcopy, params) ; // updating the derivative of omega
1866       double omega = fct_omega_VAR(h,Jk, params); // updating omega
1867 
1868       double min_omega = 1e+22 ;
1869 
1870       int iter = 0 ;
1871       const int MAX_ITER = ::MAX_ITER_OM;
1872       while( iter < MAX_ITER &&
1873              (fabs(d_omega[0])/(1+fabs(omega))*sdfactor > TOL ||
1874               fabs(d_omega[1])/(1+fabs(omega))*sdfactor > TOL ||
1875               fabs(d_omega[2])/(1+fabs(omega))*sdfactor > TOL ))
1876       {
1877         for (int n = 0; n < 3; n++)
1878           min_Jk[n] = Jk[n] - sdfactor * d_omega[n] ; // gradient descent algorithm
1879 
1880         limiter(Js, min_Jk);
1881         min_omega = fct_omega_VAR(h,min_Jk, params);  //updating omega
1882 
1883         if( min_omega < omega-TOL/10 && norm(min_Jk) < Js ){
1884           fct_d_omega_VAR(min_Jk,  d_omega,hcopy, params) ;  //update the derivative d_omega
1885           omega = min_omega;
1886           //if(Jk[0]==Jkp[0] && Jk[1]==Jkp[1] && Jk[2]==Jkp[2])
1887           if( fabs(Jk[0]-Jkp[0])<= TOL &&
1888               fabs(Jk[1]-Jkp[1])<= TOL &&
1889               fabs(Jk[2]-Jkp[2])<= TOL    ) //(diff zero)
1890             sdfactor=0.1; // re-initialize rfactor which may have become very small due to an angulous starting point
1891 
1892           for (int n=0; n<3; n++) Jk[n] = min_Jk[n];
1893         }
1894         else sdfactor = sdfactor/2 ;
1895 
1896         iter++ ;
1897       }
1898       if (::FLAG_WARNING>=FLAG_WARNING_INFO_APPROACH && iter==MAX_ITER)
1899         Message::Warning("\t\tMinimization status : the minimization has not converged yet,"
1900           "after %d iteration(s)", MAX_ITER);
1901 
1902       for (int n=0 ; n<3 ; n++)
1903         Jk[n] = min_Jk[n];
1904     }
1905     break;
1906     case 11:   //steepest descent
1907     case 22:   //Fletcher-Reeves
1908     case 33:   //Polak-Ribiere
1909     case 333:  //Polak-Ribiere+
1910     case 1999: //85 Dai Yuan 1999
1911     case 2005: //161 Hager Zhang 2005
1912     case 77:   //newton
1913     {
1914       //-------------------------------------------------------------------
1915       // NEW Updating Jk with a steepest descent algorithm
1916       //-------------------------------------------------------------------
1917 
1918       int    FLAG_TAYLORCRIT = 1;
1919       double GTOL            = 1e-7;//::TOLERANCE_OM;
1920       double TOL_DX          = ::TOLERANCE_OM;
1921       double TOL_TAYLOR      = 1e-8;
1922       double TOL_LOOSECRIT   = 1e-14;
1923       /*
1924       double GTOL            = 1e-5*norm(J0);//::TOLERANCE_OM;
1925       double TOL_DX          = ::TOLERANCE_OM*norm(J0);
1926       double TOL_TAYLOR      = 1e-12*norm(J0);
1927       double TOL_LOOSECRIT   = 1e-14*norm(J0);
1928       */
1929 
1930       //for cg
1931       double deltak, beta = 0, ykpk, yk2;
1932       double gfkp1[3], yk[3];
1933 
1934       //for sd & cg
1935       double gnorm, pknorm, pk2, min_fval, gfkpk, xkpk;
1936       double xknorm, a1,a2,alpha_max,sqrdelta, sum_ddfdJ2_pkpkT = 0;
1937       double xk[3], min_xk[3] ,gfk[3], pk[3], pkpkT[6] ;
1938       double alpha  = 0.1; //suitable value of tol for most applications
1939       double Js=(Ja+Jb);
1940 
1941       for (int n=0; n<3; n++)
1942         xk[n] = J0[n];
1943 
1944       double old_fval = fct_omega_VAR(h,xk, params); // updating omega
1945       fct_d_omega_VAR(xk,  gfk,hcopy, params) ; // updating the derivative of omega = gfk
1946       for (int n = 0; n < 3; n++)
1947         pk[n]=-gfk[n];
1948       gnorm=norm(gfk);
1949       pknorm=norm(pk);
1950 
1951       int ncomp=::NCOMP;
1952       double *ddfdJ2; ddfdJ2 = new double[ncomp];
1953 
1954       int k = 1 ;
1955       const int MAX_ITER = ::MAX_ITER_OM;
1956 
1957       //while( k <= MAX_ITER && gnorm > GTOL )
1958       //while( k <= MAX_ITER && alpha*pknorm>TOL_DX )
1959       while( k <= MAX_ITER && alpha*pknorm>TOL_DX && gnorm > GTOL )
1960       {
1961         xkpk=xk[0]*pk[0]+xk[1]*pk[1]+xk[2]*pk[2];
1962         xknorm=norm(xk);
1963         pk2 = SQU(pknorm);
1964         sqrdelta=sqrt(SQU(xkpk)-pk2*(SQU(xknorm)-SQU(Js)));
1965         a1=(pk2!=0)? (- xkpk- sqrdelta )/pk2: 0.;
1966         a2=(pk2!=0)? (- xkpk+ sqrdelta )/pk2: 0.;
1967         alpha_max=(a1>a2)?a1:a2;
1968         gfkpk=gfk[0]*pk[0]+gfk[1]*pk[1]+gfk[2]*pk[2];
1969         int k_ls=1;
1970         //while( gnorm > GTOL )
1971         //while(alpha*pknorm>TOL_DX)
1972         while(alpha*pknorm>TOL_DX && gnorm > GTOL)
1973         {
1974           if (gfkpk>0)
1975             break;
1976 
1977           alpha=(alpha<alpha_max)? alpha: alpha_max;
1978 
1979           if (FLAG_TAYLORCRIT && alpha*pknorm<=TOL_TAYLOR) //taylorcrit
1980           {
1981             fct_dd_omega_VAR(h,xk,params,ddfdJ2);
1982             // compute pkpkT
1983             pkpkT[0]=pk[0]*pk[0]; //xx
1984             pkpkT[1]=pk[0]*pk[1]; //xy
1985             pkpkT[2]=pk[0]*pk[2]; //xz
1986             pkpkT[3]=pk[1]*pk[1]; //yy
1987             pkpkT[4]=pk[1]*pk[2]; //yz
1988             pkpkT[5]=pk[2]*pk[2]; //zz
1989             // compute new alpha
1990             switch(::FLAG_SYM)
1991             {
1992               case 1: // ddfdJ2 Symmetric tensor
1993                 sum_ddfdJ2_pkpkT= ddfdJ2[0]*pkpkT[0]+
1994                                   ddfdJ2[3]*pkpkT[3]+
1995                                   ddfdJ2[5]*pkpkT[5]+
1996                                   2*ddfdJ2[1]*pkpkT[1]+
1997                                   2*ddfdJ2[2]*pkpkT[2]+
1998                                   2*ddfdJ2[4]*pkpkT[4];
1999               break;
2000               case  0: // ddfdJ2 Non Symmetric tensor
2001                 sum_ddfdJ2_pkpkT= ddfdJ2[0]*pkpkT[0]+
2002                                   ddfdJ2[1]*pkpkT[1]+
2003                                   ddfdJ2[2]*pkpkT[2]+
2004                                   ddfdJ2[3]*pkpkT[1]+
2005                                   ddfdJ2[4]*pkpkT[3]+
2006                                   ddfdJ2[5]*pkpkT[4]+
2007                                   ddfdJ2[6]*pkpkT[2]+
2008                                   ddfdJ2[7]*pkpkT[4]+
2009                                   ddfdJ2[8]*pkpkT[5];
2010               break;
2011               default:
2012                 Message::Error("Invalid parameter (sym = 0 or 1)"
2013                   "for function 'Vector_Update_Jk_VAR'.");
2014               break;
2015             }
2016             alpha=((sum_ddfdJ2_pkpkT)!=0)? -gfkpk/sum_ddfdJ2_pkpkT:0.;
2017 
2018             if (alpha> alpha_max)
2019             {
2020               Message::Warning("alpha from taylor %g >= alpha_max %g",alpha,alpha_max);
2021               alpha=alpha_max/(k+1);
2022             }
2023             for (int n = 0; n < 3; n++)
2024               min_xk[n] = xk[n] + alpha * pk[n] ;
2025             min_fval = fct_omega_VAR(h,min_xk, params);//updating omega
2026 
2027             for (int n=0; n<3; n++)
2028               xk[n] = min_xk[n];
2029             old_fval=min_fval;
2030 
2031             break;
2032           } // end taylorcrit
2033 
2034           if (!FLAG_TAYLORCRIT && alpha*pknorm<TOL_LOOSECRIT)
2035             break;
2036 
2037           for (int n = 0; n < 3; n++)
2038             min_xk[n] = xk[n] + alpha * pk[n] ;
2039           min_fval = fct_omega_VAR(h,min_xk, params);//updating omega
2040 
2041           if( min_fval < old_fval && norm(min_xk) < Js )
2042           {
2043             alpha=((k+1)/k)*alpha; //sure that alpha > alphap with this
2044             // Is this useful ? .............
2045             if(xk[0]==J0[0] && xk[1]==J0[1] && xk[2]==J0[2])
2046             //if( fabs(xk[0]-J0[0])<TOL &&
2047             //    fabs(xk[1]-J0[1])<TOL &&
2048             //    fabs(xk[2]-J0[2])<TOL    ) //(diff zero)
2049               alpha=0.1; // re-initialize alpha which may have become
2050                          // very small due to an angulous starting point
2051             //...............................
2052 
2053             for (int n=0; n<3; n++)
2054               xk[n] = min_xk[n];
2055             old_fval=min_fval;
2056             break;
2057           }
2058           else
2059           {
2060             alpha = alpha/2 ;
2061           }
2062           k_ls+=1;
2063         } //end first while
2064 
2065 
2066         if ( (gfkpk<0) &&
2067              ( (alpha*pknorm<TOL_LOOSECRIT) || (gnorm <= GTOL ) )
2068            )
2069           break;
2070 
2071         switch(::FLAG_MINMETHOD) {
2072           case 11: //steepest descent
2073           {
2074             fct_d_omega_VAR(xk, gfk, hcopy,  params) ; //update the derivative d_omega
2075             for (int n = 0; n < 3; n++)
2076               pk[n]=-gfk[n];
2077           }
2078           break;
2079           case 22: //conjugate gradient
2080           case 33:
2081           case 333:
2082           case 1999:
2083           case 2005:
2084           {
2085             deltak = gfk[0]*gfk[0]+gfk[1]*gfk[1]+gfk[2]*gfk[2];
2086             fct_d_omega_VAR(xk,  gfkp1, hcopy, params) ; //update the derivative d_omega
2087             for (int n=0; n<3; n++)
2088               yk[n]=gfkp1[n]-gfk[n];
2089 
2090             switch(::FLAG_MINMETHOD) {
2091               case 22: //Fletcher-Reeves
2092                 beta= (gfkp1[0]*gfkp1[0]+gfkp1[1]*gfkp1[1]+gfkp1[2]*gfkp1[2])/deltak;
2093               break;
2094               case 33: //Polak-Ribiere
2095                 beta= (yk[0]*gfkp1[0]+yk[1]*gfkp1[1]+yk[2]*gfkp1[2])/deltak;
2096               break;
2097               case 333: //Polak-Ribiere+ #original
2098                 beta= (yk[0]*gfkp1[0]+yk[1]*gfkp1[1]+yk[2]*gfkp1[2])/deltak;
2099                 beta = (beta>0)? beta : 0;
2100               break;
2101               case 1999: //85 Dai Yuan 1999
2102                 beta= (gfkp1[0]*gfkp1[0]+gfkp1[1]*gfkp1[1]+gfkp1[2]*gfkp1[2])
2103                       /(yk[0]*pk[0]+yk[1]*pk[1]+yk[2]*pk[2]);
2104               break;
2105               case 2005: //161 Hager Zhang 2005
2106                 yk2=(yk[0]*yk[0]+yk[1]*yk[1]+yk[2]*yk[2]);
2107                 ykpk=(yk[0]*pk[0]+yk[1]*pk[1]+yk[2]*pk[2]);
2108                 beta=0;
2109                 for (int n = 0; n < 3; n++)
2110                   beta+= (yk[n]-2*pk[n]*(yk2/ykpk))*(gfkp1[n]/ykpk);
2111               break;
2112               default:
2113               break;
2114             }
2115 
2116             for (int n = 0; n < 3; n++)
2117             {
2118               pk[n] = -gfkp1[n]+ beta*pk[n];
2119               gfk[n]=  gfkp1[n];
2120             }
2121 
2122           }
2123           break;
2124           case 77: //newton
2125           {
2126             fct_d_omega_VAR(xk, gfk, hcopy, params) ; //update the derivative d_omega
2127             fct_dd_omega_VAR(h,xk,params,ddfdJ2);
2128             int ncomp = ::NCOMP;
2129             double *iddfdJ2; iddfdJ2 = new double[ncomp];
2130             switch(::FLAG_SYM)
2131             {
2132               case 1: // Symmetric tensor
2133                 Inv_TensorSym3x3(ddfdJ2, iddfdJ2); // T, invT
2134                 pk[0]= -(iddfdJ2[0]*gfk[0]+iddfdJ2[1]*gfk[1]+iddfdJ2[2]*gfk[2]);
2135                 pk[1]= -(iddfdJ2[1]*gfk[0]+iddfdJ2[3]*gfk[1]+iddfdJ2[4]*gfk[2]);
2136                 pk[2]= -(iddfdJ2[2]*gfk[0]+iddfdJ2[4]*gfk[1]+iddfdJ2[6]*gfk[2]);
2137               break;
2138               case 0: // Non Symmetric Tensor
2139                 Inv_Tensor3x3(ddfdJ2, iddfdJ2); // T, invT
2140                 pk[0]= -(iddfdJ2[0]*gfk[0]+iddfdJ2[1]*gfk[1]+iddfdJ2[2]*gfk[2]);
2141                 pk[1]= -(iddfdJ2[3]*gfk[0]+iddfdJ2[4]*gfk[1]+iddfdJ2[5]*gfk[2]);
2142                 pk[2]= -(iddfdJ2[6]*gfk[0]+iddfdJ2[7]*gfk[1]+iddfdJ2[8]*gfk[2]);
2143               break;
2144               default:
2145                 Message::Error("Invalid parameter (FLAG_SYM = 0 or 1) for newton"
2146                   "in function 'Vector_Update_Jk_VAR'.\n");
2147               break;
2148             }
2149             //alpha=1;
2150 
2151             delete [] iddfdJ2;
2152           }
2153           break;
2154           default:
2155           break;
2156         }
2157         gnorm=norm(gfk);
2158         pknorm=norm(pk);
2159         k++;
2160       } // end second while
2161       delete [] ddfdJ2;
2162       if (::FLAG_WARNING>=FLAG_WARNING_INFO_APPROACH && k>=MAX_ITER)
2163         Message::Warning("\t\tMinimization status : the minimization has not converged yet,"
2164           "after %d iteration(s)", MAX_ITER);
2165       for (int n=0 ; n<3 ; n++)
2166         Jk[n] = xk[n];
2167     }
2168     break;
2169     case 2:
2170     case 3:
2171     case 4:
2172     case 5:
2173     case 6:
2174     {
2175       //-------------------------------------------------------------------
2176       // Updating Jk with gnu gsl
2177       //-------------------------------------------------------------------
2178 
2179 #if !defined(HAVE_GSL)
2180       Message::Error("FLAG_MINMETHOD = %d requires the GSL in function 'Vector_Update_Jk_VAR'.\n"
2181                         "FLAG_MINMETHOD = 1 --> steepest descent (homemade)\n"
2182                         "FLAG_MINMETHOD = 2 --> conjugate fr (gsl)\n"
2183                         "FLAG_MINMETHOD = 3 --> conjugate pr (gsl)\n"
2184                         "FLAG_MINMETHOD = 4 --> bfgs2 (gsl)\n"
2185                         "FLAG_MINMETHOD = 5 --> bfgs (gsl)\n"
2186                         "FLAG_MINMETHOD = 6 --> steepest descent (gsl)\n"
2187                         "FLAG_MINMETHOD = 11   --> steepest descent (homemade)\n"
2188                         "FLAG_MINMETHOD = 22   --> conjugate Fletcher-Reeves (homemade)\n"
2189                         "FLAG_MINMETHOD = 33   --> conjugate Polak-Ribiere (homemade)\n"
2190                         "FLAG_MINMETHOD = 333  --> conjugate Polak-Ribiere+ (homemade)\n"
2191                         "FLAG_MINMETHOD = 1999 --> conjugate Dai Yuan 1999 (p.85) (homemade)\n"
2192                         "FLAG_MINMETHOD = 2005 --> conjugate Hager Zhang 2005 (p.161) (homemade)\n"
2193                         "FLAG_MINMETHOD = 77   --> newton (homemade)\n", ::FLAG_MINMETHOD);
2194 #else
2195 
2196       const int MAX_ITER = ::MAX_ITER_OM;
2197       int iter = 0, status;
2198       double step_size = 0.01;   // 0.01 at basic
2199       double TOL = ::TOLERANCE_OM;
2200       double tol = TOL; //(0.1 recommended for bfgs and steepest descent else tol=TOL)
2201       double omegap;
2202 
2203       double J[3] = { J0[0], J0[1], J0[2] };
2204 
2205       //http://www.gnu.org/software/gsl/manual/html_node/Multimin-Algorithms-with-Derivatives.html
2206       const gsl_multimin_fdfminimizer_type *TYPE = 0;
2207       switch(::FLAG_MINMETHOD) {
2208         case 2:
2209           TYPE = gsl_multimin_fdfminimizer_conjugate_fr;
2210         break;
2211         case 3:
2212           TYPE = gsl_multimin_fdfminimizer_conjugate_pr;
2213         break;
2214         case 4:
2215           //FIXME: test GSL version (requires 1.?)
2216           TYPE = gsl_multimin_fdfminimizer_vector_bfgs2; // not work
2217         break;
2218         case 5:
2219           TYPE = gsl_multimin_fdfminimizer_vector_bfgs;
2220         break;
2221         case 6:
2222           // (The steepest descent method is inefficient and is included only for demonstration purposes)
2223           TYPE = gsl_multimin_fdfminimizer_steepest_descent;
2224         break;
2225         default:
2226         break;
2227       }
2228 
2229       gsl_multimin_function_fdf my_func;
2230 
2231       my_func.n      = 3;
2232       my_func.f      = omega_f  ;
2233       my_func.df     = omega_df ;
2234       my_func.fdf    = omega_fdf;
2235       my_func.params = params;
2236 
2237       gsl_vector* x = gsl_vector_alloc (3);
2238       for (int i=0; i<3; i++) gsl_vector_set(x, i, J[i]) ; // initial value for the minimizer
2239 
2240       gsl_multimin_fdfminimizer *solver = gsl_multimin_fdfminimizer_alloc(TYPE, 3);
2241       gsl_multimin_fdfminimizer_set (solver, &my_func, x, step_size, tol);
2242 
2243       do {
2244         iter++;
2245         omegap = solver->f;
2246         status = gsl_multimin_fdfminimizer_iterate (solver);
2247         if (status) break; // check if solver is stuck
2248       }  while( fabs(solver->f-omegap)>TOL && iter < MAX_ITER);
2249 
2250 
2251       if (::FLAG_WARNING>=FLAG_WARNING_INFO_APPROACH && iter==MAX_ITER)
2252         Message::Warning("Minimization status : the iteration has not converged yet,"
2253           "after %d iteration(s)", iter);
2254 
2255       for (int n=0 ; n<3 ; n++)
2256         Jk[n] = gsl_vector_get (solver->x, n) ;
2257 
2258       gsl_multimin_fdfminimizer_free (solver);
2259       gsl_vector_free (x);
2260 #endif
2261     }
2262     break;
2263     default:
2264       Message::Error("Invalid parameter (FLAG_MINMETHOD = 1,2,..6,11,22,33,333,1999,2005,77) for function 'Vector_Update_Jk_VAR'.\n"
2265                         "FLAG_MINMETHOD = 1 --> steepest descent (homemade)\n"
2266                         "FLAG_MINMETHOD = 2 --> conjugate fr (gsl)\n"
2267                         "FLAG_MINMETHOD = 3 --> conjugate pr (gsl)\n"
2268                         "FLAG_MINMETHOD = 4 --> bfgs2 (gsl)\n"
2269                         "FLAG_MINMETHOD = 5 --> bfgs (gsl)\n"
2270                         "FLAG_MINMETHOD = 6 --> steepest descent (gsl)\n"
2271                         "FLAG_MINMETHOD = 11   --> steepest descent (homemade)\n"
2272                         "FLAG_MINMETHOD = 22   --> conjugate Fletcher-Reeves (homemade)\n"
2273                         "FLAG_MINMETHOD = 33   --> conjugate Polak-Ribiere (homemade)\n"
2274                         "FLAG_MINMETHOD = 333  --> conjugate Polak-Ribiere+ (homemade)\n"
2275                         "FLAG_MINMETHOD = 1999 --> conjugate Dai Yuan 1999 (p.85) (homemade)\n"
2276                         "FLAG_MINMETHOD = 2005 --> conjugate Hager Zhang 2005 (p.161) (homemade)\n"
2277                         "FLAG_MINMETHOD = 77   --> newton (homemade)\n");
2278     break;
2279   }
2280 }
2281 
Vector_Update_hrk_DIFF_3d(const double h[3],double hr[3],void * params)2282 void Vector_Update_hrk_DIFF_3d( const double h[3],
2283                                 double hr[3],
2284                                 void *params)  // not in F.h
2285 {
2286 #if !defined(HAVE_GSL)
2287   Message::Error("FLAG_APPROACH = %d requires the GSL for the moment in Vector_Update_hrk_DIFF\n"
2288                       "FLAG_APPROACH = 1 --> Variational Approach\n"
2289                       "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
2290                       "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)", ::FLAG_APPROACH);
2291 #else
2292 
2293   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
2294 
2295   double hrp[3];
2296   for (int n=0; n<3; n++)
2297     hrp[n] = p->Xp[n+3*p->idcell];
2298 
2299   double kappa  = p->kappa[p->idcell];
2300 
2301   // Full Differential Case
2302   if (kappa==0) // When kappa =0, we automatically know that hr=h !!!
2303   {
2304     for (int n=0; n<3; n++)
2305       hr[n]=h[n];
2306   }
2307   else
2308   {
2309     double tmp[3];
2310     for (int n=0; n<3; n++)
2311       tmp[n] = h[n]-hrp[n];
2312 
2313     if (norm(tmp)>kappa)
2314     {
2315       int status;
2316       int iterb = 0, max_iterb = ::MAX_ITER_NR;
2317       double TOL = ::TOLERANCE_OM;
2318 
2319       for (int n=0 ; n<3 ; n++)
2320         p->h[n]=h[n];
2321       Vector_Jk_From_hrk (hrp, params, p->Jp); // init p->Jp
2322 
2323       const size_t nang = 2;
2324       char solver_type[100]="'Multivariate Angles Root Finding for Update hr' ";
2325 
2326       const gsl_multiroot_fsolver_type *T;
2327       gsl_multiroot_fsolver *s;
2328 
2329       double xinit[2]= {atan2(-tmp[1],-tmp[0]), acos(-tmp[2]/norm(tmp))};
2330 
2331       double finit[3];
2332       fct_fall_DIFF_3d(xinit, params,finit);
2333 
2334       p->compout=0;
2335       double finitmin=abs(finit[0]);
2336       for (int n=1; n<3; n++)
2337       {
2338         if (abs(finit[n])<finitmin)
2339         {
2340           finitmin=abs(finit[n]);
2341           p->compout=n;
2342         }
2343       }
2344 
2345       gsl_multiroot_function f = {&fct_f_DIFF_3d, nang, params};
2346 
2347       gsl_vector *x = gsl_vector_alloc(nang);
2348 
2349       gsl_vector_set (x, 0, xinit[0]);
2350       gsl_vector_set (x, 1, xinit[1]);
2351 
2352       T = gsl_multiroot_fsolver_hybrids; // BEST
2353       //T = gsl_multiroot_fsolver_hybrid;
2354       //T = gsl_multiroot_fsolver_dnewton; // may lead to Error   : GSL: matrix is singular
2355       //T = gsl_multiroot_fsolver_broyden; // may lead to Error   : GSL: matrix is singular
2356 
2357       s = gsl_multiroot_fsolver_alloc (T, 2);
2358       gsl_multiroot_fsolver_set (s, &f, x);
2359 
2360       strcat(solver_type,gsl_multiroot_fsolver_name(s));
2361 
2362       do
2363         {
2364           iterb++;
2365           status = gsl_multiroot_fsolver_iterate (s);
2366 
2367           if (status)   //check if solver is stuck
2368             break;
2369 
2370           status =
2371             gsl_multiroot_test_residual (s->f, TOL);
2372 
2373           print_state_3d (iterb, solver_type, status, s);
2374         }
2375       while (status == GSL_CONTINUE && iterb < max_iterb);
2376 
2377       double x0[2];
2378       x0[0]=gsl_vector_get (s->x, 0);
2379       x0[1]=gsl_vector_get (s->x, 1);
2380 
2381 
2382       double ehi[3];
2383       fct_ehirr_DIFF_3d(x0, ehi);
2384       for (int n=0; n<3; n++)
2385         hr[n]=h[n]+kappa*ehi[n];
2386 
2387       gsl_multiroot_fsolver_free (s);
2388       gsl_vector_free (x);
2389     }
2390     else
2391     {
2392       for (int n=0; n<3; n++)
2393         hr[n]=hrp[n];
2394     }
2395   }
2396 #endif
2397 }
2398 
2399 
Vector_Update_hrk_DIFF_2d(const double h[3],double hr[3],void * params)2400 void Vector_Update_hrk_DIFF_2d (const double h[3],
2401                                 double hr[3],
2402                                 void * params) // not in F.h
2403 {
2404 #if !defined(HAVE_GSL)
2405   Message::Error("FLAG_APPROACH = %d requires the GSL for the moment in Vector_Update_hrk_DIFF\n"
2406                       "FLAG_APPROACH = 1 --> Variational Approach\n"
2407                       "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
2408                       "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)", ::FLAG_APPROACH);
2409 #else
2410 
2411   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
2412 
2413   double hrp[3];
2414   for (int n=0; n<3; n++)
2415     hrp[n] = p->Xp[n+3*p->idcell];
2416 
2417   double kappa  = p->kappa[p->idcell];
2418 
2419   // Full Differential Case
2420   if (kappa==0) // When kappa =0, we automatically know that hr=h !!!
2421   {
2422     for (int n=0; n<3; n++)
2423       hr[n]=h[n];
2424   }
2425   else
2426   {
2427     double tmp[3];
2428     for (int n=0; n<3; n++)
2429       tmp[n] = h[n]-hrp[n];
2430 
2431     if (norm(tmp)>kappa)
2432     {
2433       int status;
2434       int iterb = 0, max_iterb = ::MAX_ITER_NR;
2435       double TOL = ::TOLERANCE_OM;
2436 
2437       for (int n=0 ; n<3 ; n++)
2438         p->h[n]=h[n];
2439       Vector_Jk_From_hrk(hrp, params, p->Jp); // init p->Jp
2440 
2441       char solver_type[100]="'1D Brent for Update hr' ";
2442       const gsl_root_fsolver_type *T;
2443       gsl_root_fsolver *s;
2444       double xinit= atan2(tmp[1],tmp[0]);
2445       double r = xinit;
2446       double al, br;
2447       double phi = acos(kappa/norm(tmp));
2448       al=xinit-phi; br=xinit+phi;
2449       double x0;
2450 
2451       double ffa=fct_f_DIFF_2d(al, params);
2452       double ffb=fct_f_DIFF_2d(br, params);
2453       if (ffa * ffb>0)
2454       {
2455         if (::FLAG_WARNING>=FLAG_WARNING_INFO_APPROACH)
2456           Message::Warning("ff(a)*ff(b) > 0 : ff(a)=%g; ff(b)=%g kappa=%g",ffa,ffb,kappa);
2457         x0=xinit;
2458       }
2459       else
2460       {
2461         gsl_function F;
2462 
2463         F.function = &fct_f_DIFF_2d;
2464         F.params = params;
2465 
2466         //T = gsl_root_fsolver_bisection;
2467         T = gsl_root_fsolver_brent; // BEST
2468         //T = gsl_root_fsolver_falsepos;
2469 
2470         s = gsl_root_fsolver_alloc (T);
2471         gsl_root_fsolver_set (s, &F, al, br);
2472         strcat(solver_type,gsl_root_fsolver_name(s));
2473 
2474         do
2475           {
2476             iterb++;
2477             status = gsl_root_fsolver_iterate (s);
2478 
2479             r = gsl_root_fsolver_root (s);
2480             al = gsl_root_fsolver_x_lower (s);
2481             br = gsl_root_fsolver_x_upper (s);
2482 
2483             status
2484               = gsl_root_test_interval (al, br, TOL, TOL);
2485 
2486             print_state_2d(iterb, solver_type,
2487                            status, al, br, r, br - al);
2488           }
2489         while (status == GSL_CONTINUE && iterb < max_iterb);
2490 
2491         gsl_root_fsolver_free (s);
2492         x0=r;
2493       }
2494       double hi[3];
2495       Vector_hirr_DIFF_2d(x0,  kappa, hi);
2496       for (int n=0; n<3; n++)
2497         hr[n]=h[n]-hi[n];
2498     }
2499     else
2500     {
2501       for (int n=0; n<3; n++)
2502         hr[n]=hrp[n];
2503     }
2504   }
2505 #endif
2506 }
2507 
2508 
Vector_Update_hrk_DIFF(const double h[3],double hr[3],double hr0[3],void * params)2509 void Vector_Update_hrk_DIFF(  const double h[3],
2510                               double hr[3],
2511                               double hr0[3],
2512                               void * params)
2513 {
2514   // Full Differential Case
2515   switch(::FLAG_DIM)
2516   {
2517     case 2: // 2D case
2518       Vector_Update_hrk_DIFF_2d(h,hr,params);
2519     break;
2520     case 3: // 3D case
2521       Vector_Update_hrk_DIFF_3d(h,hr,params);
2522     break;
2523     default:
2524       Message::Error("Invalid parameter (dimension = 2 or 3)"
2525         "for function 'Vector_Update_hrk_DIFF'.");
2526     break;
2527   }
2528 }
2529 
Vector_Update_hrk_VPM(const double h[3],double hr[3],double hr0[3],void * params)2530 void Vector_Update_hrk_VPM( const double h[3],
2531                             double hr[3],
2532                             double hr0[3],
2533                             void * params)
2534 {
2535   // Vector Play Model Approach
2536   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
2537 
2538   double hrp[3];
2539   for (int n=0; n<3; n++)
2540     hrp[n] = p->Xp[n+3*p->idcell];
2541   double kappa  = p->kappa[p->idcell];
2542 
2543   Vector_Update_hrk_VPM_( h, hr, hrp,  kappa);
2544 }
2545 
Vector_Update_hrk_VPM_(const double h[3],double hr[3],const double hrp[3],const double kappa)2546 void Vector_Update_hrk_VPM_ ( const double h[3],
2547                              double hr[3],
2548                              const double hrp[3],
2549                              const double kappa)
2550 {
2551   // Vector Play Model Approach
2552   double dhr[3];
2553   for (int n=0; n<3; n++)
2554     dhr[n] = h[n]-hrp[n];
2555   double ndhr = norm(dhr);
2556   if (ndhr >= kappa) {
2557     for (int n=0; n<3; n++)
2558       hr[n]=(ndhr>0)? h[n]-kappa*(dhr[n]/ndhr) : h[n];
2559   }
2560   else {
2561     for (int n=0; n<3; n++)
2562       hr[n]=hrp[n];
2563   }
2564 }
2565 
Vector_b_EB(const double h[3],double b[3],double * Xk_all,void * params)2566 void Vector_b_EB (const double h[3],
2567                   double b[3],
2568                   double *Xk_all,
2569                   void * params)
2570 {
2571 
2572   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
2573 
2574   double hrtot[3], hrk[3];
2575   for (int n=0; n<3; n++)
2576   {
2577      hrtot[n]=0.;
2578      hrk[n]=0.;
2579      b[n] = ::SLOPE_FACTOR* MU0 * h[n]; // Slope forcing
2580   }
2581 
2582   double wk, Xk[3];
2583   for (int k=0; k<p->N; k++) {
2584     p->idcell = k;
2585     wk   = p->w[k];
2586     for (int n=0; n<3; n++)
2587       Xk[n]  = Xk_all[n+3*k];
2588     switch(::FLAG_APPROACH) {
2589       case 1: // Variationnal Case
2590       {
2591         Vector_Update_Jk_VAR(h,Xk,Xk, params);
2592         for (int n=0; n<3; n++)
2593           Xk_all[n+3*k] = Xk[n]; // up Xk_all
2594         switch (::FLAG_HOMO) {
2595           case 0:
2596           {
2597             for (int n=0; n<3; n++)
2598               b[n] += Xk[n];
2599           }
2600           break;
2601           case 1:
2602           {
2603             // Find hrk
2604             Vector_hrk_From_Jk(Xk,params, hrk);
2605             // hrtot = sum hrk
2606             for (int n=0; n<3; n++)
2607               hrtot[n] +=  wk*hrk[n];
2608           }
2609           break;
2610           default:
2611             Message::Error("Flag_Homo not defined (1 or 0)"
2612               "for function 'Vector_b_EB'.");
2613           break;
2614         }
2615 
2616       }
2617       break;
2618       case 2: // VPM Approach
2619       case 3: // Full Differential Approach
2620       {
2621         switch(::FLAG_APPROACH) {
2622           case 2:
2623             Vector_Update_hrk_VPM(h,Xk,Xk, params);
2624           break;
2625           case 3:
2626             Vector_Update_hrk_DIFF(h,Xk,Xk, params);
2627           break;
2628         }
2629         for (int n=0; n<3; n++)
2630           Xk_all[n+3*k] = Xk[n]; // up Xk_all
2631         switch (::FLAG_HOMO) {
2632           case 0:
2633           {
2634             double Jk[3];
2635             Vector_Jk_From_hrk(Xk,params,Jk);
2636             for (int n=0; n<3; n++)
2637               b[n] += Jk[n];
2638           }
2639           break;
2640           case 1:
2641           {
2642             // hrtot = sum hrk
2643             for (int n=0; n<3; n++)
2644               hrtot[n] +=  wk* Xk[n];
2645           }
2646           break;
2647           default:
2648             Message::Error("Flag_Homo not defined (1 or 0)"
2649               "for function 'Vector_b_EB'.");
2650           break;
2651         }
2652       }
2653       break;
2654       default:
2655         Message::Error("Invalid parameter (FLAG_APPROACH = 1,2 or 3) for function 'Vector_b_EB'.\n"
2656                       "FLAG_APPROACH = 1 --> Variational Approach\n"
2657                       "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
2658                       "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)");
2659       break;
2660     }
2661   }
2662 
2663   if (::FLAG_HOMO==1)
2664   {
2665     double Jtot[3];
2666     p->idcell=-1; // due to the need to take global Ja, Jb (not Jak=wk*Ja, Jbk=wk*Jb) !
2667     Vector_Jk_From_hrk(hrtot,params,Jtot);
2668     for (int n=0; n<3; n++)
2669       b[n] += Jtot[n];
2670   }
2671 }
2672 
Vector_h_EB(const double b[3],double bc[3],double h[3],double * Xk_all,void * params)2673 void Vector_h_EB  ( const double b[3],
2674                     double bc[3],
2675                     double h[3],
2676                     double *Xk_all,
2677                     void * params )
2678 {
2679   // Use an Inversion Method to deduce the h associated to b.
2680 
2681   // First, update bc and Xk_all:
2682   Vector_b_EB(h, bc, Xk_all, params);
2683   // * This recompute the bc (and Jkall) from h - which is a hinit - to start the NR
2684   // (instead of taking the bc (and Jkall) given in argument...
2685   // thus, the bc and Jkall given in argument are not necessary now.)
2686 
2687   // * h can be {h}[1], ie. the h found at the last timestep. (original approach)
2688   // in this case, bc={b}[1] could be used also
2689   // in order to avoid the re-evaluation of Vector_b_EB.
2690   // However, this is not totally correct because
2691   // bc=b_EB({h[1]}) and {b}[1] are not exactly the same
2692   // but are as close as the stopping criterion defined for
2693   // the NR process allows to tolerate.
2694 
2695   // * h can be {h}, ie. the h from the last iteration, (new since 2/3/2018)
2696   // Note: this works because there is a small lag through iterations
2697   // between the dof{h} that depends on {b} and dof{b} that depends on dof{h}
2698   // as can be seen in the formulation in magstadyna.pro (a-v formulation).
2699   // Therefore the arguments b={b} and bc=b_EB({h}) are different,
2700   // otherwise the NR stop criterion would be directly satisfied.
2701 
2702   // * This is even more recommended when ExtrapolatePolynomial
2703   // is activated to init the next generated Timestep, because
2704   // bc=b_EB({h}) has not yet been computed with the new predicted {h}
2705 
2706   double TOL = ::TOLERANCE_NR;
2707   const int MAX_ITER = ::MAX_ITER_NR;
2708 
2709   double dh[3], dx[3], df[3],res[3], b_bc[3] ;
2710   double Ib_bcI;
2711 
2712   int ncomp = ::NCOMP;
2713   double *dbdh; dbdh = new double[ncomp];
2714   double *dhdb; dhdb = new double[ncomp];
2715   for (int n=0; n<ncomp; n++) {dbdh[n]=0.; dhdb[n]=0.;}
2716 
2717   for (int n=0; n<3; n++) dh[n]=10.*::DELTA_0;
2718   double ndh=norm(dh);
2719 
2720   int iter = 0 ;
2721   while( iter < MAX_ITER &&
2722          ((fabs(bc[0]-b[0])/(1+fabs(b[0]))) > TOL ||
2723           (fabs(bc[1]-b[1])/(1+fabs(b[1]))) > TOL ||
2724           (fabs(bc[2]-b[2])/(1+fabs(b[2]))) > TOL ))
2725   {
2726 
2727     ::DELTA_0=norm(dh)/10; //DELTA_00 +++
2728 
2729     switch(::FLAG_INVMETHOD) {
2730     //---------------------------------------------
2731     // CASE 1 : NR
2732     //---------------------------------------------
2733     case 1: // NR
2734       {
2735         Tensor_dbdh_ana(h, Xk_all, params , dbdh); // eval dbdh
2736         switch(::FLAG_SYM)
2737         {
2738           case 1:
2739             Inv_TensorSym3x3(dbdh, dhdb);
2740           break;
2741           case 0:
2742             Inv_Tensor3x3(dbdh, dhdb);
2743           break;
2744           default:
2745             Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
2746               "for function 'Vector_h_EB'.\n");
2747           break;
2748         }
2749       }
2750     break;
2751     //---------------------------------------------
2752     // CASE 2 : NR_num
2753     //---------------------------------------------
2754     case 2: // NR_num
2755       {
2756         Tensor_num(Vector_b_EB, h, ::DELTA_0, Xk_all, params, dbdh);
2757         switch(::FLAG_SYM)
2758         {
2759           case 1:
2760             Inv_TensorSym3x3(dbdh, dhdb);
2761           break;
2762           case 0:
2763             Inv_Tensor3x3(dbdh, dhdb);
2764           break;
2765           default:
2766             Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
2767               "for function 'Vector_h_EB'.\n");
2768           break;
2769         }
2770       }
2771     break;
2772     //---------------------------------------------
2773     // CASE 3 : Good_BFGS
2774     //---------------------------------------------
2775     case 3: // Good_BFGS
2776       {
2777         if (iter>0 )
2778           Tensor_dhdb_GoodBFGS(dx,df,dhdb);
2779         else
2780         {
2781           Tensor_dbdh_ana(h, Xk_all, params, dbdh ); // eval dbdh analytically
2782           //Tensor_num(Vector_b_EB, h, ::DELTA_0, Xk_all, params, dbdh); // eval dbdh numerically
2783           switch(::FLAG_SYM)
2784           {
2785             case 1:
2786               Inv_TensorSym3x3(dbdh, dhdb);
2787             break;
2788             case 0:
2789               Inv_Tensor3x3(dbdh, dhdb);
2790             break;
2791             default:
2792               Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
2793                 "for function 'Vector_h_EB'.\n");
2794             break;
2795           }
2796         }
2797       }
2798     break;
2799     default:
2800       Message::Error("Invalid parameter (FLAG_INVMETHOD = 1,2,3) for function 'Vector_h_EB'.\n"
2801                      "FLAG_INVMETHOD = 1 --> NR_ana (homemade)\n"
2802                      "FLAG_INVMETHOD = 2 --> NR_num (homemade)\n"
2803                      "FLAG_INVMETHOD = 3 --> Good_BFGS (homemade)");
2804       break;
2805     }
2806 
2807     for (int n=0; n<3; n++) b_bc[n]=b[n]-bc[n];
2808     Ib_bcI=norm(b_bc);
2809 
2810     Mul_TensorVec(dhdb, b_bc, dh, 0);
2811 
2812     //............................................... (WHILE LOOP) // dh/2
2813     double b_btest[3], htest[3];
2814     for (int n=0 ; n<3 ; n++)
2815     {
2816       df[n] = -bc[n];
2817       dh[n] = 2*dh[n];
2818     }
2819     int counter=0;
2820     ndh=norm(dh);
2821     do
2822     {
2823       ndh=ndh/2;
2824       for (int n=0 ; n<3 ; n++)
2825       {
2826         dh[n]=dh[n]/2;
2827         htest[n] = h[n]+dh[n];
2828       }
2829       Vector_b_EB(htest, bc, Xk_all, params); // Update bc, Jk_all
2830       for (int n=0 ; n<3 ; n++){
2831         b_btest[n]=b[n]-bc[n];
2832       }
2833       counter++;
2834       if (::FLAG_WARNING>=FLAG_WARNING_INFO_INV && counter>1)
2835         Message::Warning("activated dh/2 in inversion process %d",counter);
2836     }
2837     while ( (norm(b_btest) > Ib_bcI) &&
2838             counter<10 && ndh>::TOLERANCE_NR);
2839 
2840     for (int n=0 ; n<3 ; n++){
2841       dx[n]= dh[n];
2842       h[n] = htest[n];
2843       df[n] += bc[n];
2844     }
2845     //...............................................
2846 
2847     if(::FLAG_WARNING>=FLAG_WARNING_INFO_INV && iter>=FLAG_WARNING_DISPABOVEITER){
2848       //printf("dh(%d)=[%.8g,%.8g,%.8g];\t",iter,dh[0],dh[1],dh[2] );
2849       printf("h(%d)=[%.8g,%.8g,%.8g];\t",iter,h[0],h[1],h[2] );
2850       printf("b(%d)=[%.8g,%.8g,%.8g];\t",iter,bc[0],bc[1],bc[2] );
2851       for (int n=0 ; n<3 ; n++)
2852         res[n]=(fabs(bc[n]-b[n])/(1+fabs(b[n])));
2853       printf("residu(%d) = %.8g ([%.8g,%.8g,%.8g])\n", iter, norm(res), res[0],res[1],res[2]);
2854     }
2855     iter++;
2856   }
2857 
2858   if (::FLAG_WARNING>=FLAG_WARNING_STOP_INV)
2859     Message::Warning("Inversion status = %d iteration(s) needed",iter);
2860 
2861   // Show b et h obtained at the end of the NR loop :
2862   if (::FLAG_WARNING>=FLAG_WARNING_INFO_INV && iter==MAX_ITER){
2863     Message::Warning("Inversion status = the inversion has not converged yet, after %d iteration(s)",iter);
2864     if (::FLAG_WARNING>=FLAG_WARNING_INFO_INV){
2865       Message::Warning("b_desired : [%.10g, %.10g, %.10g]", b[0],b[1],b[2]);
2866       Message::Warning("b_get     : [%.10g, %.10g, %.10g]", bc[0],bc[1],bc[2]);
2867       Message::Warning("h_get     : [%.10g, %.10g, %.10g]", h[0],h[1],h[2]);
2868       if (::FLAG_WARNING >= FLAG_WARNING_STOP_INV){
2869         if(getchar()){
2870         }
2871       }
2872     }
2873   }
2874 
2875   delete [] dbdh;
2876   delete [] dhdb;
2877 }
2878 
2879 //************************************************
2880 // Energy-Based Model - Tensor Construction
2881 //************************************************
2882 
Tensor_dJkdh_VAR(const double h[3],const double Jk[3],void * params,double * dJkdh)2883 void Tensor_dJkdh_VAR ( const double h[3],
2884                         const double Jk[3],
2885                         void * params,
2886                         double *dJkdh)
2887 {
2888 
2889   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
2890 
2891   double Jkp[3];
2892   for (int n=0; n<3; n++)
2893     Jkp[n] = p->Xp[n+3*p->idcell];
2894 
2895   double dJk[3];
2896   for (int n=0; n<3; n++)
2897     dJk[n] = Jk[n]-Jkp[n];
2898 
2899   double nJk  = norm(Jk);
2900   double ndJk = norm(dJk);
2901 
2902   if ((::FLAG_ANA) && (nJk>(::TOLERANCE_NJ) && ndJk>(::TOLERANCE_NJ))){
2903     Message::Debug("--- Tensor_dJkdh_VAR: Analytical Jacobian ---");
2904 
2905     int ncomp = ::NCOMP;
2906     double *idJkdh; idJkdh = new double[ncomp];
2907     fct_dd_omega_VAR(h,Jk,params,idJkdh);
2908     switch(::FLAG_SYM)
2909     {
2910       case 1: // Symmetric tensor
2911         Inv_TensorSym3x3(idJkdh, dJkdh); // T, invT
2912       break;
2913       case 0: // Non Symmetric Tensor
2914         Inv_Tensor3x3(idJkdh, dJkdh); // T, invT
2915       break;
2916       default:
2917         Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
2918           "for function 'Tensor_dJkdh_VAR'.\n");
2919       break;
2920     }
2921     delete [] idJkdh;
2922   }
2923   else{
2924     Message::Debug("--- Tensor_dJkdh_VAR: Numerical Jacobian ---");
2925     double Jkdummy[3]={0,0,0};
2926     Tensor_num(Vector_Update_Jk_VAR, h, ::DELTA_0, Jkdummy, params, dJkdh);
2927   }
2928 }
2929 
Tensor_dJkdh_VPMorDIFF(const double h[3],const double hrk[3],void * params,double * dJkdh)2930 void Tensor_dJkdh_VPMorDIFF ( const double h[3],
2931                               const double hrk[3],
2932                               void * params,
2933                               double *dJkdh)
2934 {
2935   // dJkdhrk -----------------------------------------------------------------------------------
2936   // -> dJkdhrk is always symmetric
2937   double dJkdhrk[6];
2938   Tensor_dJkdhrk(hrk , params, dJkdhrk);
2939 
2940   // dhrkdh -----------------------------------------------------------------------------------
2941   // -> dhrkdh is symmetric in that case but still stored with non-syn (9 comp)
2942   double dhrkdh[9];
2943   switch(::FLAG_APPROACH)
2944   {
2945     case 2: // VPM
2946       Tensor_dhrkdh_VPM_ana(h,hrk,params,dhrkdh);
2947     break;
2948     case 3: //  FULL DIFF
2949       Tensor_dhrkdh_DIFF_ana(h,hrk,dJkdhrk,params,dhrkdh);
2950     break;
2951     default:
2952       Message::Error("Invalid parameter (FLAG_APPROACH = 2 or 3) for function 'Tensor_dJkdh_VPMorDIFF'.\n"
2953                     "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
2954                     "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)");
2955     break;
2956   }
2957 
2958   // Product dJkdh = dJkdhrk * dhrkdh ------------------------------------------------------------
2959   Mul_TensorSymTensorNonSym(dJkdhrk,dhrkdh,dJkdh);
2960 }
2961 
Tensor_dhrkdh_DIFF_ana(const double h[3],const double hrk[3],const double dJkdhrk[6],void * params,double * dhrkdh)2962 void Tensor_dhrkdh_DIFF_ana ( const double h[3],
2963                               const double hrk[3],
2964                               const double dJkdhrk[6],
2965                               void * params,
2966                               double *dhrkdh)
2967 {
2968   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
2969 
2970   double hrkp[3];
2971   for (int n=0; n<3; n++)
2972     hrkp[n] = p->Xp[n+3*p->idcell];
2973 
2974   double kappa  = p->kappa[p->idcell];
2975 
2976   double h_hrkp[3];
2977   for (int n=0; n<3; n++)
2978     h_hrkp[n] = h[n]-hrkp[n];
2979 
2980   double Ih_hrkpI  = norm(h_hrkp);
2981 
2982   if (Ih_hrkpI>kappa)
2983   {
2984     double dJ[3], mutgu[6];
2985 
2986     for (int n=0; n<6; n++)
2987       mutgu[n] = dJkdhrk[n];
2988     double Jkp[3];
2989     Vector_Jk_From_hrk( hrkp,params,Jkp);
2990     Vector_Jk_From_hrk( hrk,params,dJ);
2991     for (int n=0; n<3; n++)
2992       dJ[n] -= Jkp[n];
2993 
2994     double ndJ = norm(dJ);
2995 
2996     if (kappa>0 && ndJ>(::TOLERANCE_0))
2997     {
2998       double temp[6], temp2[9];
2999 
3000       temp[0]=1. - (dJ[0]*dJ[0])/SQU(ndJ);
3001       temp[1]=   - (dJ[0]*dJ[1])/SQU(ndJ);
3002       temp[2]=   - (dJ[0]*dJ[2])/SQU(ndJ);
3003       temp[3]=1. - (dJ[1]*dJ[1])/SQU(ndJ);
3004       temp[4]=   - (dJ[1]*dJ[2])/SQU(ndJ);
3005       temp[5]=1. - (dJ[2]*dJ[2])/SQU(ndJ);
3006 
3007       Mul_TensorSymTensorSym(temp,mutgu,temp2);
3008 
3009       temp2[0]=1. + (kappa/ndJ) * temp2[0];
3010       temp2[1]=     (kappa/ndJ) * temp2[1];
3011       temp2[2]=     (kappa/ndJ) * temp2[2];
3012       temp2[3]=     (kappa/ndJ) * temp2[3];
3013       temp2[4]=1. + (kappa/ndJ) * temp2[4];
3014       temp2[5]=     (kappa/ndJ) * temp2[5];
3015       temp2[6]=     (kappa/ndJ) * temp2[6];
3016       temp2[7]=     (kappa/ndJ) * temp2[7];
3017       temp2[8]=1. + (kappa/ndJ) * temp2[8];
3018       Inv_Tensor3x3(temp2,dhrkdh);
3019 
3020       // OR one can use a numerical approximation for dhrkdh:
3021       // double hrkdummy[3]={0,0,0};
3022       // Tensor_num(Vector_Update_hrk_DIFF, h, ::DELTA_0, hrkdummy, params, dhrkdh);
3023     }
3024     else // IF kappa==0 or ndJ<=(::TOLERANCE_0)
3025     {
3026       dhrkdh[0] = dhrkdh[4] = dhrkdh[8] = 1.; //xx //yy //zz
3027       dhrkdh[1] = dhrkdh[2] = dhrkdh[3] = dhrkdh[5] = dhrkdh[6] = dhrkdh[7] = 0.; //xy //xz //yx //yz //zx //zy
3028     }
3029   }
3030   else // IF Ih_hrkpI<=kappa :
3031   {
3032     // should be zero always in practice but may induce convergence issue.
3033     double hrkdummy[3]={0,0,0};
3034     Tensor_num(Vector_Update_hrk_DIFF, h, ::DELTA_0, hrkdummy, params, dhrkdh);
3035   }
3036 }
3037 
Tensor_dhrkdh_VPM_ana(const double h[3],const double hrk[3],void * params,double * dhrkdh)3038 void Tensor_dhrkdh_VPM_ana ( const double h[3],
3039                              const double hrk[3],
3040                              void * params,
3041                              double *dhrkdh)
3042 {
3043   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
3044 
3045   double hrkp[3];
3046   for (int n=0; n<3; n++)
3047     hrkp[n] = p->Xp[n+3*p->idcell];
3048 
3049   double kappa  = p->kappa[p->idcell];
3050 
3051   double dhrk[3];
3052   for (int n=0; n<3; n++)
3053     dhrk[n] = h[n]-hrkp[n];
3054 
3055   double Ih_hrkpI  = norm(dhrk);
3056 
3057   if (Ih_hrkpI>kappa)
3058   {
3059     if (kappa>0.)
3060     {
3061       dhrkdh[0] = (1-kappa/Ih_hrkpI)
3062                 + (kappa/CUB(Ih_hrkpI)) * (dhrk[0]*dhrk[0]) ; //xx
3063       dhrkdh[4] = (1-kappa/Ih_hrkpI)
3064                 + (kappa/CUB(Ih_hrkpI)) * (dhrk[1]*dhrk[1]) ; //yy
3065       dhrkdh[1] = (kappa/CUB(Ih_hrkpI)) * (dhrk[1]*dhrk[0]) ; //xy
3066       dhrkdh[3] = dhrkdh[1]; //yx
3067       switch(::FLAG_DIM) {
3068         case 2: // 2D case
3069           dhrkdh[8] = 1.;
3070           dhrkdh[2] = dhrkdh[5] = dhrkdh[6] = dhrkdh[7] = 0.;
3071         break;
3072         case 3: // 3D case
3073           dhrkdh[8] = (1-kappa/Ih_hrkpI)
3074                     + (kappa/CUB(Ih_hrkpI))*(dhrk[2]*dhrk[2]) ; //zz
3075           dhrkdh[2] = (kappa/CUB(Ih_hrkpI))*(dhrk[2]*dhrk[0]) ; //xz
3076           dhrkdh[6] = dhrkdh[2]; //zx
3077           dhrkdh[5] = (kappa/CUB(Ih_hrkpI))*(dhrk[2]*dhrk[1]) ; //yz
3078           dhrkdh[7] = dhrkdh[5]; //zy
3079         break;
3080         default:
3081           Message::Error("Invalid parameter (dimension = 2 or 3)"
3082             "for function 'Tensor_dhrkdh_VPM_ana'. Analytic Jacobian computation.");
3083         break;
3084       }
3085     }
3086     else // IF kappa==0
3087     {
3088       dhrkdh[0] = dhrkdh[4] = dhrkdh[8] = 1.; //xx //yy //zz
3089       dhrkdh[1] = dhrkdh[2] = dhrkdh[3] = dhrkdh[5] = dhrkdh[6] = dhrkdh[7] = 0.; //xy //xz //yx //yz //zx //zy
3090     }
3091   }
3092   else // IF Ih_hrkpI<=kappa :
3093   {
3094     // should be zero always in practice but may induce convergence issue.
3095     double hrkdummy[3]={0,0,0};
3096     Tensor_num(Vector_Update_hrk_VPM, h, ::DELTA_0, hrkdummy, params, dhrkdh);
3097   }
3098 }
3099 
3100 
Tensor_dbdh_ana(const double h[3],const double * Xk_all,void * params,double * dbdh)3101 void Tensor_dbdh_ana ( const double h[3],
3102                        const double *Xk_all,
3103                        void * params,
3104                        double *dbdh)
3105 {
3106 
3107   struct params_Cells_EB *p = (struct params_Cells_EB *) params;
3108 
3109   int N         = p->N ;
3110 
3111   double hrtot[3], hrk[3];
3112   for (int n=0; n<3; n++)
3113   {
3114      hrtot[n]=0.;
3115      hrk[n]=0.;
3116   }
3117 
3118   switch(::FLAG_SYM)
3119   {
3120     case 1:
3121       dbdh[0] = dbdh[3] = dbdh[5] = ::SLOPE_FACTOR*MU0 ; //Slope forcing
3122       dbdh[1] = dbdh[2] = dbdh[4] = 0. ;
3123     break;
3124     case 0:
3125       dbdh[0] = dbdh[4] = dbdh[8] = ::SLOPE_FACTOR*MU0 ; //Slope forcing
3126       dbdh[1] = dbdh[2] = dbdh[3] = dbdh[5] = dbdh[6] = dbdh[7] = 0. ;
3127     break;
3128     default:
3129       Message::Error("Invalid parameter (sym = 0 or 1)"
3130         "for function 'Tensor_dbdh_ana'.");
3131     break;
3132   }
3133 
3134   int ncomp=::NCOMP;
3135   double *dJkdh; dJkdh = new double[ncomp];
3136   double *dJtotdh; dJtotdh = new double[ncomp];
3137   for (int n=0; n<ncomp; n++) {
3138     dJkdh[n]=0.;
3139     dJtotdh[n]=0.;
3140   }
3141 
3142   double mutgtot[6], mutg[6], dhrkdJk[6];
3143   double dhrkdh[9], dhrtotdh[9];
3144 
3145   for (int n=0; n<9; n++)
3146     dhrtotdh[n]=0.;
3147 
3148   double wk, Xk[3] ;
3149   for (int k=0; k<N; k++) {
3150     p->idcell = k;
3151     wk    = p->w[k];
3152     for (int n=0; n<3; n++)
3153       Xk[n]  = Xk_all[n+3*k];
3154     switch(::FLAG_HOMO)
3155     {
3156       case 0:
3157       {
3158         switch(::FLAG_APPROACH) {
3159           case 1: // Variationnal Case
3160             Tensor_dJkdh_VAR(h, Xk, params, dJkdh);
3161           break;
3162           case 2: // Differential Case
3163           case 3:
3164             Tensor_dJkdh_VPMorDIFF(h, Xk, params, dJkdh);
3165           break;
3166           default:
3167             Message::Error("Invalid parameter (FLAG_APPROACH = 1,2 or 3) for function 'Tensor_dbdh_ana'.\n"
3168                           "FLAG_APPROACH = 1 --> Variational Approach\n"
3169                           "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
3170                           "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)");
3171           break;
3172         }
3173         for (int n=0; n<ncomp; n++)
3174           dbdh[n] += dJkdh[n] ;
3175       }
3176       break;
3177       case 1:
3178       {
3179         switch(::FLAG_APPROACH) {
3180           case 1: // Variationnal Case
3181             // Find hrk
3182             Vector_hrk_From_Jk(Xk,params, hrk);
3183             // hrtot = sum wk hrk
3184             for (int n=0; n<3; n++)
3185               hrtot[n] +=  wk*hrk[n];
3186 
3187             // Build dhrkdh
3188             Tensor_dJkdh_VAR(h, Xk, params, dJkdh);
3189             Tensor_dJkdhrk(hrk , params, mutg);
3190             Inv_TensorSym3x3(mutg, dhrkdJk);
3191             Mul_TensorSymTensorNonSym(dhrkdJk, dJkdh, dhrkdh);
3192 
3193             //dhrtotdh = sum wk * dhrkdh
3194             for (int n=0; n<9; n++)
3195               dhrtotdh[n] +=  wk*dhrkdh[n];
3196 
3197           break;
3198           case 2: // Differential Case
3199           case 3:
3200           {
3201             // hrtot = sum wk hrk
3202             for (int n=0; n<3; n++)
3203               hrtot[n] +=  wk*Xk[n];
3204 
3205             // Build dhrkdh
3206             // -> dhrkdh is symmetric in that case but still stored with non-syn
3207             switch(::FLAG_APPROACH)
3208             {
3209               case 2: // VPM
3210                 Tensor_dhrkdh_VPM_ana(h, Xk, params, dhrkdh);
3211               break;
3212               case 3: //  FULL DIFF
3213                 Tensor_dJkdhrk(Xk, params, mutg);
3214                 Tensor_dhrkdh_DIFF_ana(h,Xk,mutg,params,dhrkdh);
3215               break;
3216             }
3217 
3218             //dhrtotdh = sum wk * dhrkdh
3219             for (int n=0; n<9; n++)
3220               dhrtotdh[n] +=  wk*dhrkdh[n];
3221           }
3222           break;
3223           default:
3224             Message::Error("Invalid parameter (FLAG_APPROACH = 1,2 or 3) for function 'Tensor_dbdh_ana'.\n"
3225                           "FLAG_APPROACH = 1 --> Variational Approach\n"
3226                           "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
3227                           "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)");
3228           break;
3229         }
3230       }
3231       break;
3232       default:
3233         Message::Error("Flag_Homo not defined (1 or 0)"
3234           "for function 'Tensor_dbdh_ana'.");
3235       break;
3236     }
3237 
3238   }
3239 
3240   if (::FLAG_HOMO==1)
3241   {
3242     //Build mutgtot
3243     p->idcell=-1; // due to the need to take global Ja, Jb (not Jak=wk*Ja, Jbk=wk*Jb) !
3244     Tensor_dJkdhrk(hrtot,params, mutgtot) ;
3245 
3246     //dJtotdh= mutgtot*dhrtotdh
3247     Mul_TensorSymTensorNonSym(mutgtot,dhrtotdh, dJtotdh) ;
3248 
3249     //dbdh= dbdh+dJtotdh
3250     for (int n=0; n<9; n++)
3251       dbdh[n] += dJtotdh[n];
3252   }
3253   delete [] dJkdh;
3254   delete [] dJtotdh;
3255 }
3256 
3257 
Tensor_num(void (* f)(const double *,double *,double *,void *),const double x[3],const double delta0,double * Xk_all,void * params,double * dfdx)3258 void Tensor_num ( void (*f) (const double*, double*, double*, void *),
3259                  const double x[3],
3260                  const double delta0,
3261                  double *Xk_all,
3262                  void * params,
3263                  double *dfdx)
3264 {
3265 
3266   //int dim = D->Case.Interpolation.x[0] ;
3267 
3268   //double delta0  = ::DELTA_0 ;
3269   // Different following the different directions ??? TO CHECK
3270   /*
3271   double EPSILON = 1 ; // PARAM (1) // 1e-8  // Take this again because Test_Basic_SimpleDiff_Num not working otherwise
3272   double delta[3] = { (fabs(h[0])>EPSILON) ? (fabs(h[0])) * delta0 : delta0,
3273                       (fabs(h[1])>EPSILON) ? (fabs(h[1])) * delta0 : delta0,
3274                       (fabs(h[2])>EPSILON) ? (fabs(h[2])) * delta0 : delta0 } ;
3275   //*/
3276 
3277   /*
3278   double delta[3] = {((norm(h)>EPSILON) ? (norm(h)+1) * delta0 : delta0),
3279                      ((norm(h)>EPSILON) ? (norm(h)+1) * delta0 : delta0),
3280                      ((norm(h)>EPSILON) ? (norm(h)+1) * delta0 : delta0) } ;
3281   */
3282   /*
3283   double delta[3] = {((norm(h)>EPSILON) ? norm(h) * delta0 : delta0),
3284                      ((norm(h)>EPSILON) ? norm(h) * delta0 : delta0),
3285                      ((norm(h)>EPSILON) ? norm(h) * delta0 : delta0) } ;
3286   */
3287   double delta[3]={delta0,delta0,delta0};
3288 
3289   double fxr[3]={0.,0.,0.};
3290   double fxl[3]={0.,0.,0.};
3291   double fyr[3]={0.,0.,0.};
3292   double fyl[3]={0.,0.,0.};
3293   double fzr[3]={0.,0.,0.};
3294   double fzl[3]={0.,0.,0.};
3295 
3296   double xxr[3]={x[0]+delta[0], x[1]          ,x[2]};
3297   double xyr[3]={x[0],          x[1]+delta[1] ,x[2]};
3298   double xzr[3]={x[0],          x[1]          ,x[2]+delta[2]};
3299 
3300 
3301   f(xxr, fxr, Xk_all, params );
3302   f(xyr, fyr, Xk_all, params);
3303 
3304   double xxl[3],xyl[3],xzl[3];
3305   for (int n=0; n<3; n++) {xxl[n]=x[n]; xyl[n]=x[n]; xzl[n]=x[n];}
3306   switch(::FLAG_CENTRAL_DIFF)
3307   {
3308     case 1: // Central Differences
3309       xxl[0]=x[0]-delta[0];
3310       xyl[1]=x[1]-delta[1];
3311       xzl[2]=x[2]-delta[2];
3312       f(xxl, fxl, Xk_all, params);
3313       f(xyl, fyl, Xk_all, params);
3314     break;
3315     case 0: // Forward Differences
3316       f(x, fxl, Xk_all, params );
3317       for (int n=0; n<3; n++) fyl[n] = fxl[n] ;
3318     break;
3319     default:
3320       Message::Error("Invalid parameter (central diff = 0 or 1)"
3321         "for function 'Tensor_num'.");
3322     break;
3323   }
3324 
3325   dfdx[0]= (fxr[0]-fxl[0])/(xxr[0]-xxl[0]); //xx
3326 
3327   //dfdx[1]= (fxr[1]-fxl[1])/(xxr[0]-xxl[0]);//yx // This one was used originally
3328   dfdx[1]= (fyr[0]-fyl[0])/(xyr[1]-xyl[1]);  //xy // other possibility (more natural)
3329   // ------
3330   switch(::FLAG_SYM)
3331   {
3332     case 1:// Symmetric tensor
3333       dfdx[3]= (fyr[1]-fyl[1])/(xyr[1]-xyl[1]); //yy
3334       switch(::FLAG_DIM)
3335       {
3336         case 2: // 2D case
3337           dfdx[5] = 1.; //zz
3338           dfdx[2] = dfdx[4]= 0.; //xz // yz
3339         break;
3340         case 3: // 3D case
3341           f(xzr, fzr, Xk_all, params);
3342           switch(::FLAG_CENTRAL_DIFF)
3343           {
3344             case 1: // Central Differences
3345               f(xzl, fzl, Xk_all, params);
3346             break;
3347             case 0: // Forward Differences
3348               for (int n=0; n<3; n++) fzl[n] = fxl[n] ;
3349             break;
3350             default:
3351               Message::Error("Invalid parameter (central diff = 0 or 1)"
3352                 "for function 'Tensor_num'.");
3353             break;
3354           }
3355           dfdx[5]= (fzr[2]-fzl[2])/(xzr[2]-xzl[2]); //zz
3356           //dfdx[2]= (fxr[2]-fxl[2])/(xxr[0]-xxl[0]); //zx // This one was used originally
3357           dfdx[2]= (fzr[0]-fzl[0])/(xzr[2]-xzl[2]); //xz //other possibility (more natural)
3358           //dfdx[4]= (fyr[2]-fyl[2])/(xyr[1]-xyl[1]); //zy // This one was used originally
3359           dfdx[4]= (fzr[1]-fzl[1])/(xzr[2]-xzl[2]); //yz //other possibility (more natural)
3360         break;
3361         default:
3362           Message::Error("Invalid parameter (dimension = 2 or 3)"
3363             "for function 'Tensor_num'.");
3364         break;
3365       }
3366     break;
3367     case  0:// Non Symmetric tensor
3368       dfdx[3]= (fxr[1]-fxl[1])/(xxr[0]-xxl[0]); //yx
3369       dfdx[4]= (fyr[1]-fyl[1])/(xyr[1]-xyl[1]); //yy
3370       switch(::FLAG_DIM)
3371       {
3372         case 2: // 2D case
3373           dfdx[8] = 1.; //zz
3374           dfdx[2] = dfdx[5] = dfdx[6] = dfdx[7] = 0.; //xz //yz //zx //zy
3375         break;
3376         case 3: // 3D case
3377           f(xzr, fzr, Xk_all, params );
3378           switch(::FLAG_CENTRAL_DIFF)
3379           {
3380             case 1: // Central Differences
3381               f(xzl, fzl , Xk_all, params );
3382             break;
3383             case 0: // Forward Differences
3384               for (int n=0; n<3; n++) fzl[n] = fxl[n] ;
3385             break;
3386             default:
3387               Message::Error("Invalid parameter (central diff = 0 or 1)"
3388                 "for function 'Tensor_num'.");
3389             break;
3390           }
3391           dfdx[8] = (fzr[2]-fzl[2])/(xzr[2]-xzl[2]);//zz
3392           dfdx[2] = (fzr[0]-fzl[0])/(xzr[2]-xzl[2]);//xz
3393           dfdx[5] = (fzr[1]-fzl[1])/(xzr[2]-xzl[2]);//yz
3394           dfdx[6] = (fxr[2]-fxl[2])/(xxr[0]-xxl[0]); //zx
3395           dfdx[7] = (fyr[2]-fyl[2])/(xyr[1]-xyl[1]); //zy
3396         break;
3397         default:
3398           Message::Error("Invalid parameter (dimension = 2 or 3)"
3399             "for function 'Tensor_num'.");
3400         break;
3401       }
3402     break;
3403     default:
3404       Message::Error("Invalid parameter (sym = 0 or 1)"
3405         "for function 'Tensor_num'.");
3406     break;
3407   }
3408 }
3409 
Tensor_dhdb_GoodBFGS(const double dx[3],const double df[3],double * dhdb)3410 void Tensor_dhdb_GoodBFGS(const double dx[3],const double df[3], double *dhdb)
3411 {
3412 
3413   double iJn_1df[3], dfiJn_1[3];
3414   double dxdf, dfiJn_1df ;
3415 
3416   ///* New: Deal with Symmetrical or Asymmetrical Tensor consideration (13/06/2016)-------------
3417   Mul_TensorVec(dhdb,df, iJn_1df, 0);
3418   Mul_TensorVec(dhdb,df, dfiJn_1, 1);
3419   dxdf=Mul_VecVec(dx,df);
3420   dfiJn_1df=Mul_VecVec(df,iJn_1df);
3421 
3422   switch(::FLAG_SYM)
3423   {
3424     case 1: // Symmetric tensor
3425       dhdb[0] = dhdb[0]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[0]*dx[0]) -  ( iJn_1df[0]*dx[0] + dx[0]*dfiJn_1[0] )/dxdf ; //xx
3426       dhdb[3] = dhdb[3]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[1]*dx[1]) -  ( iJn_1df[1]*dx[1] + dx[1]*dfiJn_1[1] )/dxdf ; //yy
3427       dhdb[1] = dhdb[1]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[0]*dx[1]) -  ( iJn_1df[0]*dx[1] + dx[0]*dfiJn_1[1] )/dxdf ; //xy
3428       switch(::FLAG_DIM)
3429       {
3430         case 2: // 2D case
3431           dhdb[5] = 1.; //zz
3432           dhdb[2] = dhdb[4] = 0.; //xz //yz
3433         break;
3434         case 3: // 3D case
3435           dhdb[5] = dhdb[5]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[2]*dx[2]) -  ( iJn_1df[2]*dx[2] + dx[2]*dfiJn_1[2] )/dxdf ; //zz
3436           dhdb[2] = dhdb[2]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[0]*dx[2]) -  ( iJn_1df[0]*dx[2] + dx[0]*dfiJn_1[2] )/dxdf ; //xz
3437           dhdb[4] = dhdb[4]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[1]*dx[2]) -  ( iJn_1df[1]*dx[2] + dx[1]*dfiJn_1[2] )/dxdf ; //yz
3438         break;
3439         default:
3440           Message::Error("Invalid parameter (dimension = 2 or 3)"
3441             "for function 'Tensor_dhdb_GoodBFGS'.");
3442         break;
3443       }
3444     break;
3445     case  0: // Non Symmetric tensor
3446       dhdb[0] = dhdb[0]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[0]*dx[0]) -  ( iJn_1df[0]*dx[0] + dx[0]*dfiJn_1[0] )/dxdf ; //xx
3447       dhdb[4] = dhdb[4]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[1]*dx[1]) -  ( iJn_1df[1]*dx[1] + dx[1]*dfiJn_1[1] )/dxdf ; //yy
3448       dhdb[1] = dhdb[1]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[0]*dx[1]) -  ( iJn_1df[0]*dx[1] + dx[0]*dfiJn_1[1] )/dxdf ; //xy
3449       dhdb[3] = dhdb[3]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[1]*dx[0]) -  ( iJn_1df[1]*dx[0] + dx[1]*dfiJn_1[0] )/dxdf ; //yx
3450       switch(::FLAG_DIM)
3451       {
3452         case 2: // 2D case
3453           dhdb[8] = 1.; //zz
3454           dhdb[2] = dhdb[5] = dhdb[6] = dhdb[7] = 0.; //xz //yz //zx //zy
3455         break;
3456         case 3: // 3D case
3457           dhdb[8] = dhdb[8]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[2]*dx[2]) -  ( iJn_1df[2]*dx[2] + dx[2]*dfiJn_1[2] )/dxdf ; //zz
3458           dhdb[2] = dhdb[2]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[0]*dx[2]) -  ( iJn_1df[0]*dx[2] + dx[0]*dfiJn_1[2] )/dxdf ; //xz
3459           dhdb[5] = dhdb[5]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[1]*dx[2]) -  ( iJn_1df[1]*dx[2] + dx[1]*dfiJn_1[2] )/dxdf ; //yz
3460           dhdb[6] = dhdb[6]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[2]*dx[0]) -  ( iJn_1df[2]*dx[0] + dx[2]*dfiJn_1[0] )/dxdf ; //zx
3461           dhdb[7] = dhdb[7]+ ((dxdf + dfiJn_1df)/(SQU(dxdf)))*(dx[2]*dx[1]) -  ( iJn_1df[2]*dx[1] + dx[2]*dfiJn_1[1] )/dxdf ; //zy
3462         break;
3463         default:
3464           Message::Error("Invalid parameter (dimension = 2 or 3)"
3465             "for function 'Tensor_dhdb_GoodBFGS'.");
3466         break;
3467       }
3468     break;
3469     default:
3470       Message::Error("Invalid parameter (sym = 0 or 1)"
3471         "for function 'Tensor_dhdb_GoodBFGS'.");
3472     break;
3473   }
3474   //*///-------------------------------------------------------------------------------------------
3475 }
3476 
3477 //*///-------------------------------------------------------------------------------------------
3478 
3479 //************************************************
3480 // Functions usable in a .pro file
3481 //************************************************
3482 
F_Cell_EB(F_ARG)3483 void F_Cell_EB(F_ARG) {
3484 
3485   // Updating the Cell variable : Jk (for variationnal approach) or hrk (for differential approach)
3486   // ---------------------------------------------
3487   // input:
3488   // (A+0)->Val = number corresponding to the cell studied -- k
3489   // (A+1)->Val = magnetic field -- h
3490   // (A+2)->Val = material magnetization (var) or reversible magnetic field (diff) at previous time step -- xkp
3491   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3492   // ---------------------------------------------
3493   // output: updated Jk
3494 
3495   struct FunctionActive  * D ;
3496   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3497   D = Fct->Active ;
3498   set_sensi_param(D);
3499 
3500   if( (A+0)->Type != SCALAR ||
3501       (A+1)->Type != VECTOR ||
3502       (A+2)->Type != VECTOR )
3503     Message::Error("Function 'Cell_EB' requires one scalar argument (n)"
3504       "and two vector arguments (h, Jkp)");
3505 
3506 ///* //Init Creation of EB parameters structure
3507   struct params_Cells_EB params;
3508   params.idcell = ((A+0)->Val[0])-1;
3509   params.N = D->Case.Interpolation.x[1] ;
3510   params.Ja= D->Case.Interpolation.x[2] ;
3511   params.ha= D->Case.Interpolation.x[3] ;
3512   params.Jb= D->Case.Interpolation.x[4] ;
3513   params.hb= D->Case.Interpolation.x[5] ;
3514 
3515   params.kappa=new double[params.N];
3516   params.w=new double[params.N];
3517 
3518   params.w[params.idcell]     = D->Case.Interpolation.x[6+2*params.idcell];
3519   params.kappa[params.idcell] = D->Case.Interpolation.x[7+2*params.idcell];
3520 
3521   double h[3];
3522   for (int n=0; n<3; n++)
3523     h[n] = (A+1)->Val[n];
3524 
3525   params.Xp=new double[3*params.N];
3526   for (int n=0; n<3; n++)
3527     params.Xp[n+3*params.idcell] = (A+2)->Val[n];
3528 
3529   //End Creation of EB parameters structure
3530   double Xk[3];
3531 
3532   switch(::FLAG_APPROACH)
3533   {
3534     case 1: // Variationnal Case
3535       Vector_Update_Jk_VAR(h,Xk,Xk,&params);
3536     break;
3537     case 2: // Vector Play Model Case
3538       Vector_Update_hrk_VPM(h,Xk,Xk,&params);
3539     break;
3540     case 3: // Full Differential Case
3541       Vector_Update_hrk_DIFF(h,Xk,Xk,&params);
3542     break;
3543     default:
3544       Message::Error("Invalid parameter (FLAG_APPROACH = 1,2 or 3) for function 'Update_Cell'.\n"
3545                     "FLAG_APPROACH = 1 --> Variational Approach\n"
3546                     "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
3547                     "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)");
3548     break;
3549   }
3550   V->Type = VECTOR ;
3551   for (int n=0 ; n<3 ; n++) V->Val[n] = Xk[n];
3552 }
3553 
F_h_EB(F_ARG)3554 void F_h_EB(F_ARG)
3555 {
3556   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
3557   // input :
3558   // (A+0)    ->Val = last computed magnetic field (for example at previous time step -- hp) // usefull for initialization
3559   // (A+1)    ->Val = magnetic induction -- b
3560   // (A+2+1*k)->Val = material magnetization at previous time step -- Jkp
3561   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3562   // ---------------------------------------------
3563   // output: magnetic field -- h
3564 
3565   struct FunctionActive  * D ;
3566   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3567   D = Fct->Active ;
3568   set_sensi_param(D);
3569 
3570   ///* //Init Creation of EB parameters structure
3571   struct params_Cells_EB params;
3572   params.N = D->Case.Interpolation.x[1] ;
3573   params.Ja= D->Case.Interpolation.x[2] ;
3574   params.ha= D->Case.Interpolation.x[3] ;
3575   params.Jb= D->Case.Interpolation.x[4] ;
3576   params.hb= D->Case.Interpolation.x[5] ;
3577 
3578   params.kappa=new double[params.N];
3579   params.w=new double[params.N];
3580   for (int k=0; k<params.N; k++){
3581     params.w[k]     = D->Case.Interpolation.x[6+2*k];
3582     params.kappa[k] = D->Case.Interpolation.x[7+2*k];
3583   }
3584 
3585   params.Xp=new double[3*params.N];
3586   for (int k=0; k<params.N; k++) {
3587     for (int n=0; n<3; n++) {
3588       params.Xp[n+3*k] = (A+2+1*k)->Val[n];
3589     }
3590   }
3591   //End Creation of EB parameters structure
3592 
3593   double Xk_all[3*params.N];
3594   double h[3], b[3], bc[3] ;
3595   for (int n=0; n<3; n++) {
3596      h[n]  = (A+0)->Val[n]; // h is initialized at hp
3597      b[n]  = (A+1)->Val[n];
3598      bc[n] =0.;
3599   }
3600 
3601   Vector_h_EB(b, bc, h, Xk_all, &params); // Update h
3602 
3603   V->Type = VECTOR ;
3604   for (int n=0 ; n<3 ; n++) V->Val[n] = h[n];
3605 
3606   delete [] params.kappa;
3607   delete [] params.w;
3608   delete [] params.Xp;
3609 }
3610 
F_b_EB(F_ARG)3611 void F_b_EB(F_ARG)
3612 {
3613   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
3614   // input :
3615   // (A+0)    ->Val = magnetic field  -- h
3616   // (A+1+1*k)->Val = material magnetization at previous time step -- Jkp
3617   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3618   // ---------------------------------------------
3619   // output: magnetic induction -- b
3620 
3621   struct FunctionActive  * D ;
3622   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3623   D = Fct->Active ;
3624   set_sensi_param(D);
3625 
3626   ///* //Init Creation of EB parameters structure
3627   struct params_Cells_EB params;
3628   params.N = D->Case.Interpolation.x[1] ;
3629   params.Ja= D->Case.Interpolation.x[2] ;
3630   params.ha= D->Case.Interpolation.x[3] ;
3631   params.Jb= D->Case.Interpolation.x[4] ;
3632   params.hb= D->Case.Interpolation.x[5] ;
3633 
3634   params.kappa=new double[params.N];
3635   params.w=new double[params.N];
3636   for (int k=0; k<params.N; k++){
3637     params.w[k]     = D->Case.Interpolation.x[6+2*k];
3638     params.kappa[k] = D->Case.Interpolation.x[7+2*k];
3639   }
3640 
3641   params.Xp=new double[3*params.N];
3642   for (int k=0; k<params.N; k++) {
3643     for (int n=0; n<3; n++) {
3644       params.Xp[n+3*k] = (A+1+1*k)->Val[n];
3645     }
3646   }
3647   //End Creation of EB parameters structure
3648 
3649   double Xk_all[3*params.N];
3650   double h[3], b[3];
3651   for (int n=0; n<3; n++)
3652     h[n] = (A+0)->Val[n];
3653 
3654   Vector_b_EB(h, b, Xk_all, &params);
3655 
3656   V->Type = VECTOR ;
3657   for (int n=0 ; n<3 ; n++) V->Val[n] = b[n];
3658 
3659   delete [] params.kappa;
3660   delete [] params.w;
3661   delete [] params.Xp;
3662 }
3663 
F_hrev_EB(F_ARG)3664 void F_hrev_EB(F_ARG)
3665 {
3666   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
3667   // input :
3668   // (A+0)->Val = number corresponding to the cell studied -- k
3669   // (A+1+1*k)->Val = magnetic material field variable xk (either J if Var approach or hr if Diff approach)
3670   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3671   // ---------------------------------------------
3672   // output: reversible magnetic field -- hr
3673 
3674   struct FunctionActive  * D ;
3675   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3676   D = Fct->Active ;
3677   set_sensi_param(D);
3678 
3679 ///* //Init Creation of EB parameters structure
3680   struct params_Cells_EB params;
3681   params.idcell = ((A+0)->Val[0])-1;
3682   params.N = D->Case.Interpolation.x[1] ;
3683   params.Ja= D->Case.Interpolation.x[2] ;
3684   params.ha= D->Case.Interpolation.x[3] ;
3685   params.Jb= D->Case.Interpolation.x[4] ;
3686   params.hb= D->Case.Interpolation.x[5] ;
3687 
3688   params.w=new double[params.N];
3689   params.w[params.idcell]     = D->Case.Interpolation.x[6+2*params.idcell];
3690   //End Creation of EB parameters structure
3691 
3692   double hrk[3], xk[3];
3693   switch(::FLAG_APPROACH) {
3694     case 1:
3695         for (int n=0; n<3; n++)
3696           xk[n]  = (A+1)->Val[n];
3697         Vector_hrk_From_Jk(xk,&params, hrk);
3698     break;
3699     case 2:
3700     case 3:
3701       for (int n=0; n<3; n++)
3702         hrk[n]  = (A+1)->Val[n];
3703     break;
3704     default:
3705       Message::Error("Invalid parameter (FLAG_APPROACH = 1,2 or 3) for function 'F_hr_EB'.\n"
3706                       "FLAG_APPROACH = 1 --> Variational Approach\n"
3707                       "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
3708                       "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)");
3709     break;
3710   }
3711 
3712   V->Type = VECTOR ;
3713   for (int n=0 ; n<3 ; n++) V->Val[n] = hrk[n];
3714 
3715   delete [] params.w;
3716 
3717 }
3718 
3719 
F_Jrev_EB(F_ARG)3720 void F_Jrev_EB(F_ARG)
3721 {
3722   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
3723   // input :
3724   // (A+0)->Val = number corresponding to the cell studied -- k
3725   // (A+1+1*k)->Val = magnetic material field variable xk (either J if Var approach or hr if Diff approach)
3726   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3727   // ---------------------------------------------
3728   // output: magnetic magnetization -- J
3729 
3730   struct FunctionActive  * D ;
3731   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3732   D = Fct->Active ;
3733   set_sensi_param(D);
3734 
3735   ///* //Init Creation of EB parameters structure
3736   struct params_Cells_EB params;
3737   params.idcell = ((A+0)->Val[0])-1;
3738   params.N = D->Case.Interpolation.x[1] ;
3739   params.Ja= D->Case.Interpolation.x[2] ;
3740   params.ha= D->Case.Interpolation.x[3] ;
3741   params.Jb= D->Case.Interpolation.x[4] ;
3742   params.hb= D->Case.Interpolation.x[5] ;
3743 
3744   params.w=new double[params.N];
3745   params.w[params.idcell]     = D->Case.Interpolation.x[6+2*params.idcell];
3746   //End Creation of EB parameters structure
3747 
3748   double Jk[3], xk[3];
3749   switch(::FLAG_APPROACH) {
3750     case 1:
3751       for (int n=0; n<3; n++)
3752         Jk[n]  = (A+1)->Val[n];
3753     break;
3754     case 2:
3755     case 3:
3756         for (int n=0; n<3; n++)
3757           xk[n]  = (A+1)->Val[n];
3758         Vector_Jk_From_hrk(xk,&params, Jk);
3759     break;
3760     default:
3761       Message::Error("Invalid parameter (FLAG_APPROACH = 1,2 or 3) for function 'F_Jr_EB'.\n"
3762                       "FLAG_APPROACH = 1 --> Variational Approach\n"
3763                       "FLAG_APPROACH = 2 --> Vector Play Model approach\n"
3764                       "FLAG_APPROACH = 3 --> Full Differential Approach (gsl)");
3765     break;
3766   }
3767 
3768   V->Type = VECTOR ;
3769   for (int n=0 ; n<3 ; n++) V->Val[n] = Jk[n];
3770 }
3771 
F_dbdh_EB(F_ARG)3772 void F_dbdh_EB(F_ARG)
3773 {
3774   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
3775   // input :
3776   // (A+0)    ->Val = magnetic field -- h
3777   // (A+1+1*k)->Val = material magnetization at previous time step -- Jkp
3778   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3779   // ---------------------------------------------
3780   // output: differential reluctivity -- dbdh
3781 
3782   struct FunctionActive  * D ;
3783   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3784   D = Fct->Active ;
3785   set_sensi_param(D);
3786 
3787   ///* //Init Creation of EB parameters structure
3788   struct params_Cells_EB params;
3789   params.N = D->Case.Interpolation.x[1] ;
3790   params.Ja= D->Case.Interpolation.x[2] ;
3791   params.ha= D->Case.Interpolation.x[3] ;
3792   params.Jb= D->Case.Interpolation.x[4] ;
3793   params.hb= D->Case.Interpolation.x[5] ;
3794 
3795   params.kappa=new double[params.N];
3796   params.w=new double[params.N];
3797   for (int k=0; k<params.N; k++){
3798     params.w[k]     = D->Case.Interpolation.x[6+2*k];
3799     params.kappa[k] = D->Case.Interpolation.x[7+2*k];
3800   }
3801 
3802   params.Xp=new double[3*params.N];
3803   for (int k=0; k<params.N; k++) {
3804     for (int n=0; n<3; n++) {
3805       params.Xp[n+3*k] = (A+1+1*k)->Val[n];
3806     }
3807   }
3808   //End Creation of EB parameters structure
3809 
3810   double h[3];
3811   for (int n=0; n<3; n++)
3812      h[n]  = (A+0)->Val[n];
3813 
3814   double Xk_all[3*params.N], bdummy[3];
3815   Vector_b_EB(h, bdummy, Xk_all, &params); // to update Xk_all
3816 
3817 
3818   // Init dbdh
3819   int ncomp = ::NCOMP;
3820   switch(::FLAG_SYM)
3821   {
3822     case 1:
3823       V->Type = TENSOR_SYM ;
3824     break;
3825     case 0:
3826       V->Type = TENSOR ;
3827     break;
3828     default:
3829       Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
3830         "for function 'F_dhdb_EB'.\n");
3831     break;
3832   }
3833   double *dbdh; dbdh = new double[ncomp];
3834   for (int n=0; n<ncomp; n++) dbdh[n]=0.;
3835 
3836   switch(::FLAG_JACEVAL) {
3837       case 1:
3838         Tensor_dbdh_ana(h, Xk_all, &params, dbdh); // eval dbdh
3839       break;
3840       case 2:
3841         Tensor_num(Vector_b_EB, h, ::DELTA_0, Xk_all, &params, dbdh); // eval dbdh numerically
3842       break;
3843       default:
3844         Message::Error("Invalid parameter (FLAG_JACEVAL = 1,2) for function 'F_dhdb_EB'.\n"
3845                        "FLAG_JACEVAL = 1 --> analytical Jacobian dbdh\n"
3846                        "FLAG_JACEVAL = 2 --> numerical Jacobian dbdh");
3847       break;
3848   }
3849 
3850   for (int k=0 ; k<ncomp ; k++)
3851     V->Val[k] = dbdh[k] ;
3852 
3853   delete [] dbdh;
3854   delete [] params.kappa;
3855   delete [] params.w;
3856   delete [] params.Xp;
3857 }
3858 
F_dhdb_EB(F_ARG)3859 void F_dhdb_EB(F_ARG)
3860 {
3861   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
3862   // input :
3863   // (A+0)    ->Val = magnetic field -- h
3864   // (A+1+1*k)->Val = material magnetization at previous time step -- Jkp
3865   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3866   // ---------------------------------------------
3867   // output: differential reluctivity -- dhdb
3868 
3869   struct FunctionActive  * D ;
3870   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3871   D = Fct->Active ;
3872   set_sensi_param(D);
3873 
3874   ///* //Init Creation of EB parameters structure
3875   struct params_Cells_EB params;
3876   params.N = D->Case.Interpolation.x[1] ;
3877   params.Ja= D->Case.Interpolation.x[2] ;
3878   params.ha= D->Case.Interpolation.x[3] ;
3879   params.Jb= D->Case.Interpolation.x[4] ;
3880   params.hb= D->Case.Interpolation.x[5] ;
3881 
3882   params.kappa=new double[params.N];
3883   params.w=new double[params.N];
3884   for (int k=0; k<params.N; k++){
3885     params.w[k]     = D->Case.Interpolation.x[6+2*k];
3886     params.kappa[k] = D->Case.Interpolation.x[7+2*k];
3887   }
3888 
3889   params.Xp=new double[3*params.N];
3890   for (int k=0; k<params.N; k++) {
3891     for (int n=0; n<3; n++) {
3892       params.Xp[n+3*k] = (A+1+1*k)->Val[n];
3893     }
3894   }
3895   //End Creation of EB parameters structure
3896 
3897   double h[3];
3898   for (int n=0; n<3; n++)
3899      h[n]  = (A+0)->Val[n];
3900 
3901   double Xk_all[3*params.N],bdummy[3];
3902   Vector_b_EB(h, bdummy, Xk_all, &params); // to update Xk_all
3903 
3904   // Init dbdh
3905   int ncomp = ::NCOMP;
3906   switch(::FLAG_SYM)
3907   {
3908     case 1:
3909       V->Type = TENSOR_SYM ;
3910     break;
3911     case 0:
3912       V->Type = TENSOR ;
3913     break;
3914     default:
3915       Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
3916         "for function 'F_dhdb_EB'.\n");
3917     break;
3918   }
3919   double *dbdh; dbdh = new double[ncomp];
3920   double *dhdb; dhdb = new double[ncomp];
3921   for (int n=0; n<ncomp; n++) {dbdh[n]=0.; dhdb[n]=0.;}
3922 
3923   switch(::FLAG_JACEVAL) {
3924     case 1:
3925       Tensor_dbdh_ana(h, Xk_all, &params, dbdh); // eval dbdh
3926     break;
3927     case 2:
3928       Tensor_num(Vector_b_EB, h, ::DELTA_0, Xk_all, &params, dbdh); // eval dbdh numerically
3929     break;
3930     default:
3931       Message::Error("Invalid parameter (FLAG_JACEVAL = 1,2) for function 'F_dhdb_EB'.\n"
3932                      "FLAG_JACEVAL = 1 --> analytical Jacobian dhdb\n"
3933                      "FLAG_JACEVAL = 2 --> numerical Jacobian dhdb");
3934     break;
3935   }
3936 
3937   switch(::FLAG_SYM)
3938   {
3939     case 1:
3940       Inv_TensorSym3x3(dbdh, dhdb); // dimension, T, invT
3941     break;
3942     case 0:
3943       Inv_Tensor3x3(dbdh, dhdb); // dimension, T, invT
3944     break;
3945     default:
3946       Message::Error("Invalid parameter (FLAG_SYM = 0 or 1)"
3947         "for function 'F_dhdb_EB'.\n");
3948     break;
3949   }
3950 
3951   for (int k=0 ; k<ncomp ; k++)
3952     V->Val[k] = dhdb[k] ;
3953 
3954   delete [] dhdb;
3955   delete [] dbdh;
3956   delete [] params.kappa;
3957   delete [] params.w;
3958   delete [] params.Xp;
3959 }
3960 
3961 //************************************************
3962 // Energy-Based Model - GetDP Functions (DEPRECIATED):
3963 //************************************************
3964 
F_Update_Cell_K(F_ARG)3965 void F_Update_Cell_K(F_ARG) {
3966   // Updating the Cell variable : Jk (for variationnal approach) or hrk (for differential approach)
3967   // ---------------------------------------------
3968   // input:
3969   // (A+0)->Val = number corresponding to the cell studied -- k
3970   // (A+1)->Val = magnetic field -- h
3971   // (A+2)->Val = material magnetization (var) or reversible magnetic field (diff) -- xk // USELESS recomputed inside
3972   // (A+3)->Val = material magnetization (var) or reversible magnetic field (diff) at previous time step -- xkp
3973   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3974   // ---------------------------------------------
3975   // output: updated Jk
3976 
3977   //Message::Warning("Function 'Update_Cell_K[k, {h}, {xk}, {xk}[1] ]' will be depecriated, please replace by 'Cell_EB[k, {h}, {xk}[1]]'");
3978   for (int n=0; n<3; n++) {
3979     (A+2)->Val[n]=(A+3)->Val[n];
3980   }
3981   F_Cell_EB(Fct,A,V);
3982 }
3983 
F_h_Vinch_K(F_ARG)3984 void F_h_Vinch_K(F_ARG){
3985   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
3986   // input :
3987   // (A+0)    ->Val = last computed magnetic field (for example at previous time step -- hp) // usefull for initialization
3988   // (A+1)    ->Val = magnetic induction -- b
3989   // (A+2)    ->Val = magnetic induction corresponding to the last computed magnetic field (for example at previous time step -- bp) // USELESS hp is enhough
3990   // (A+3+2*k)->Val = material magnetization -- Jk // USELESS because recomputed
3991   // (A+4+2*k)->Val = material magnetization at previous time step -- Jkp
3992   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
3993   // ---------------------------------------------
3994   // output: magnetic field -- h
3995 
3996   //Message::Warning("Function 'h_Vinch_K[{h},{b},{b}[1], {xk}, {xk}[1], ...]' will be depecriated, please replace by 'h_EB[{h},{b}, {xk}[1], ...]'");
3997   struct FunctionActive  * D ;
3998   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
3999   D = Fct->Active ;
4000 
4001   int N = D->Case.Interpolation.x[1] ;
4002   for (int k=0; k<N; k++) {
4003     for (int n=0; n<3; n++)
4004       (A+2+1*k)->Val[n]=(A+4+2*k)->Val[n];
4005   }
4006   F_h_EB(Fct,A,V);
4007 }
4008 
F_b_Vinch_K(F_ARG)4009 void F_b_Vinch_K(F_ARG){
4010   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
4011   // input :
4012   // (A+0)    ->Val = magnetic field  -- h
4013   // (A+1+2*k)->Val = material magnetization -- Jk  // USELESS because recomputed
4014   // (A+2+2*k)->Val = material magnetization at previous time step -- Jkp
4015   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
4016   // ---------------------------------------------
4017   // output: magnetic induction -- b
4018   //Message::Warning("Function 'b_Vinch_K[{h}, {xk}, {xk}[1], ...]' will be depecriated, please replace by 'b_EB[{h}, {xk}[1]]'");
4019 
4020   struct FunctionActive  * D ;
4021   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
4022   D = Fct->Active ;
4023 
4024   int N = D->Case.Interpolation.x[1] ;
4025   for (int k=0; k<N; k++) {
4026     for (int n=0; n<3; n++)
4027       (A+1+1*k)->Val[n]=(A+2+2*k)->Val[n];
4028   }
4029   F_b_EB(Fct,A,V);
4030 }
4031 
F_hr_Vinch_K(F_ARG)4032 void F_hr_Vinch_K(F_ARG){
4033   //Message::Warning("Function 'hr_Vinch_K[...]' will be depecriated, please replace by 'hr_EB[...]'");
4034   F_hrev_EB(Fct,A,V);
4035 }
F_Jr_Vinch_K(F_ARG)4036 void F_Jr_Vinch_K(F_ARG){
4037   //Message::Warning("Function 'Jr_Vinch_K[...]' will be depecriated, please replace by 'Jrev_EB[...]'");
4038   F_Jrev_EB(Fct,A,V);
4039 }
F_dbdh_Vinch_K(F_ARG)4040 void F_dbdh_Vinch_K(F_ARG){
4041   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
4042   // input :
4043   // (A+0)    ->Val = magnetic field -- h
4044   // (A+1+2*k)->Val = material magnetization -- Jk // USELESS if recomputed with Vector_b_EB here after
4045   // (A+2+2*k)->Val = material magnetization at previous time step -- Jkp
4046   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
4047   // ---------------------------------------------
4048   // output: differential reluctivity -- dbdh
4049 
4050   //Message::Warning("Function 'dbdh_Vinch_K[{h}, {xk}, {xk}[1], ...]' will be depecriated, please replace by 'dbdh_EB[{h}, {xk}[1], ...]'");
4051   struct FunctionActive  * D ;
4052   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
4053   D = Fct->Active ;
4054 
4055   int N = D->Case.Interpolation.x[1] ;
4056   for (int k=0; k<N; k++) {
4057     for (int n=0; n<3; n++)
4058       (A+1+1*k)->Val[n]=(A+2+2*k)->Val[n];
4059   }
4060   F_dbdh_EB(Fct,A,V);
4061 }
F_dhdb_Vinch_K(F_ARG)4062 void F_dhdb_Vinch_K(F_ARG){
4063   // #define F_ARG   struct Function * Fct, struct Value * A, struct Value * V
4064   // input :
4065   // (A+0)    ->Val = magnetic field -- h
4066   // (A+1+2*k)->Val = material magnetization -- Jk // USELESS if recomputed with Vector_b_EB here after
4067   // (A+2+2*k)->Val = material magnetization at previous time step -- Jkp
4068   // Material parameters: e.g. param_EnergHyst = { dim, N, Ja, ha, w_1, kappa_1, ..., w_N, kappa_N};==> struct FunctionActive *D
4069   // ---------------------------------------------
4070   // output: differential reluctivity -- dhdb
4071 
4072   //Message::Warning("Function 'dhdb_Vinch_K[{h}, {xk}, {xk}[1], ...]' will be depecriated, please replace by 'dhdb_EB[{h}, {xk}[1], ...]'");
4073 
4074   struct FunctionActive  * D ;
4075   if (!Fct->Active)  Fi_InitListX (Fct, A, V) ;
4076   D = Fct->Active ;
4077 
4078   int N = D->Case.Interpolation.x[1] ;
4079   for (int k=0; k<N; k++) {
4080     for (int n=0; n<3; n++)
4081       (A+1+1*k)->Val[n]=(A+2+2*k)->Val[n];
4082   }
4083   F_dhdb_EB(Fct,A,V);
4084 }
4085