2 #include <gsl/gsl_sf_trig.h>
3 #include <hkl/hkl-pseudoaxis-auto.h>
5 /*********************************************/
6 /* methods use to solve numerical pseudoAxes */
7 /*********************************************/
10 * @brief This private method find the degenerated axes.
12 * @param func the gsl_multiroopt_function to test
13 * @param x the starting point
14 * @param f the result of the function evaluation.
16 * with this method we can see if an axis is degenerated or not.
17 * A degenerated axis is an axis with no effect on the function evaluation.
18 * In the Jacobian matrix all elements of a columnn is null.
19 * Once we know this the axis is mark as degenerated and we do not need to
22 static void find_degenerated_axes(HklPseudoAxisEngine
*self
,
23 gsl_multiroot_function
*func
,
24 gsl_vector
const *x
, gsl_vector
const *f
,
30 memset(degenerated
, 0, x
->size
* sizeof(int));
31 J
= gsl_matrix_alloc(x
->size
, f
->size
);
33 gsl_multiroot_fdjacobian(func
, x
, f
, GSL_SQRT_DBL_EPSILON
, J
);
34 for(j
=0; j
<x
->size
&& !degenerated
[j
]; ++j
) {
35 for(i
=0; i
<f
->size
; ++i
)
36 if (fabs(gsl_matrix_get(J
, i
, j
)) > HKL_EPSILON
)
43 hkl_pseudoAxisEngine_fprintf(func->params, stdout);
44 fprintf(stdout, "\n");
45 for(i=0; i<x->size; ++i)
46 fprintf(stdout, " %d", degenerated[i]);
47 for(i=0;i<x->size;++i) {
48 fprintf(stdout, "\n ");
49 for(j=0;j<f->size;++j)
50 fprintf(stdout, " %f", gsl_matrix_get(J, i, j));
52 fprintf(stdout, "\n");
58 * @brief this private method try to find the first solution
60 * @param self the current HklPseudoAxeEngine.
61 * @param f The function to use for the computation.
63 * If a solution was found it also check for degenerated axes.
64 * A degenerated axes is an Axes with no effect on the function.
65 * @see find_degenerated
66 * @return HKL_SUCCESS (0) or HKL_FAIL (-1).
68 static int find_first_geometry(HklPseudoAxisEngine
*self
,
69 gsl_multiroot_function
*f
,
72 gsl_multiroot_fsolver_type
const *T
;
73 gsl_multiroot_fsolver
*s
;
76 double x_data0
[self
->axes_len
];
82 // get the starting point from the geometry
83 // must be put in the auto_set method
84 x
= gsl_vector_alloc(self
->axes_len
);
85 x_data
= (double *)x
->data
;
86 for(i
=0; i
<self
->axes_len
; ++i
)
87 x_data
[i
] = self
->axes
[i
]->config
.value
;
89 // keep a copy of the first axes positions to deal with degenerated axes
90 memcpy(x_data0
, x_data
, self
->axes_len
* sizeof(double));
93 T
= gsl_multiroot_fsolver_hybrid
;
94 s
= gsl_multiroot_fsolver_alloc (T
, self
->axes_len
);
95 gsl_multiroot_fsolver_set (s
, f
, x
);
97 // iterate to find the solution
100 status
= gsl_multiroot_fsolver_iterate(s
);
101 if (status
|| iter
% 1000 == 0) {
102 // Restart from another point.
103 for(i
=0; i
<self
->axes_len
; ++i
)
104 x_data
[i
] = (double)rand() / RAND_MAX
* 180. / M_PI
;
105 gsl_multiroot_fsolver_set(s
, f
, x
);
106 status
= gsl_multiroot_fsolver_iterate(s
);
108 status
= gsl_multiroot_test_residual (s
->f
, HKL_EPSILON
);
109 } while (status
== GSL_CONTINUE
&& iter
< 1000);
111 if (status
!= GSL_CONTINUE
) {
112 find_degenerated_axes(self
, f
, s
->x
, s
->f
, degenerated
);
114 // set the geometry from the gsl_vector
115 // in a futur version the geometry must contain a gsl_vector
117 x_data
= (double *)s
->x
->data
;
118 for(i
=0; i
<self
->axes_len
; ++i
) {
119 HklAxis
*axis
= self
->axes
[i
];
121 axis
->config
.value
= x_data0
[i
];
123 axis
->config
.value
= x_data
[i
];
125 axis
->config
.dirty
= 1;
127 hkl_geometry_update(self
->geometry
);
133 gsl_multiroot_fsolver_free(s
);
139 * @brief This private method change the sector of angles.
141 * @param x The vector of changed angles.
142 * @param x0 The vector of angles to change.
143 * @param sector the sector vector operation.
144 * @param n the size of all vectors.
151 static void change_sector(double x
[], double const x0
[],
152 int const sector
[], size_t n
)
175 * @brief Test if an angle combination is compatible with q function.
177 * @param x The vector of angles to test.
178 * @param function The gsl_multiroot_function used for the test.
179 * @param f a gsl_vector use to compute the result (optimization)
181 static int test_sector(gsl_vector
const *x
,
182 gsl_multiroot_function
*function
,
186 double *f_data
= f
->data
;
188 function
->f(x
, function
->params
, f
);
190 for(i
=0; i
<f
->size
; ++i
)
191 if (fabs(f_data
[i
]) > HKL_EPSILON
)
198 * @brief compute the permutation and test its validity.
200 * @param axes_len number of axes
201 * @param op_len number of operation per axes. (4 for now)
202 * @param p The vector containing the current permutation.
203 * @param axes_idx The index of the axes we are permution.
204 * @param op the current operation to set.
205 * @param f The function for the validity test.
206 * @param x0 The starting point of all geometry permutations.
207 * @param _x a gsl_vector use to compute the sectors (optimization)
208 * @param _f a gsl_vector use during the sector test (optimization)
210 static void perm_r(size_t axes_len
, int op_len
[], int p
[], int axes_idx
,
211 int op
, gsl_multiroot_function
*f
, double x0
[],
212 gsl_vector
*_x
, gsl_vector
*_f
)
217 if (axes_idx
== axes_len
) {
218 double *x_data
= _x
->data
;
219 change_sector(x_data
, x0
, p
, axes_len
);
220 if (HKL_SUCCESS
== test_sector(_x
, f
, _f
))
221 hkl_pseudoAxisEngine_add_geometry(f
->params
, x_data
);
223 for (i
=0; i
<op_len
[axes_idx
]; ++i
)
224 perm_r(axes_len
, op_len
, p
, axes_idx
, i
, f
, x0
, _x
, _f
);
228 * @brief Find all numerical solutions of a mode.
230 * @param self the current HklPseudoAxisEngine
231 * @param function The mode function
233 * @return HKL_SUCCESS (0) or HKL_FAIL (-1)
235 * This method find a first solution with a numerical method from the
236 * GSL library (the multi root solver hybrid). Then it multiplicates the
237 * solutions from this starting point using cosinus/sinus properties.
238 * It addes all valid solutions to the self->geometries.
240 int hkl_pseudoAxeEngine_solve_function(HklPseudoAxisEngine
*self
,
241 HklPseudoAxisEngineFunction function
)
245 size_t n
= self
->axes_len
;
251 gsl_vector
*_x
; /* use to compute sectors in perm_r (avoid copy) */
252 gsl_vector
*_f
; /* use to test sectors in perm_r (avoid copy) */
254 _x
= gsl_vector_alloc(n
);
255 _f
= gsl_vector_alloc(n
);
256 gsl_multiroot_function f
= {function
, self
->axes_len
, self
};
257 res
= find_first_geometry(self
, &f
, degenerated
);
258 if (res
== HKL_SUCCESS
) {
259 memset(p
, 0, sizeof(p
));
260 /* use first solution as starting point for permutations */
262 x0
[i
] = self
->axes
[i
]->config
.value
;
268 for (i
=0; i
<op_len
[0]; ++i
)
269 perm_r(n
, op_len
, p
, 0, i
, &f
, x0
, _x
, _f
);