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,¶ms);
3536 break;
3537 case 2: // Vector Play Model Case
3538 Vector_Update_hrk_VPM(h,Xk,Xk,¶ms);
3539 break;
3540 case 3: // Full Differential Case
3541 Vector_Update_hrk_DIFF(h,Xk,Xk,¶ms);
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, ¶ms); // 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, ¶ms);
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,¶ms, 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,¶ms, 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, ¶ms); // 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, ¶ms, dbdh); // eval dbdh
3839 break;
3840 case 2:
3841 Tensor_num(Vector_b_EB, h, ::DELTA_0, Xk_all, ¶ms, 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, ¶ms); // 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, ¶ms, dbdh); // eval dbdh
3926 break;
3927 case 2:
3928 Tensor_num(Vector_b_EB, h, ::DELTA_0, Xk_all, ¶ms, 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