23 #include <getfem/getfem_generic_assembly_functions_and_operators.h>
25 #include <getfem/getfem_generic_assembly_compile_and_exec.h>
31 extern bool predef_operators_nonlinear_elasticity_initialized;
32 extern bool predef_operators_plasticity_initialized;
33 extern bool predef_operators_contact_initialized;
35 static void ga_node_derivation
36 (ga_tree &tree,
const ga_workspace &workspace,
const mesh &m,
37 pga_tree_node pnode,
const std::string &varname,
38 const std::string &interpolatename,
size_type order,
bool any_trans =
false);
40 static void ga_node_grad(ga_tree &tree,
const ga_workspace &workspace,
41 const mesh &m, pga_tree_node pnode);
42 static bool ga_node_mark_tree_for_grad(pga_tree_node pnode,
43 const ga_workspace &workspace);
44 static void ga_node_analysis(ga_tree &tree,
45 const ga_workspace &workspace,
46 pga_tree_node pnode,
const mesh &me,
47 size_type ref_elt_dim,
bool eval_fixed_size,
48 bool ignore_X,
int option);
51 bool ga_extract_variables(
const pga_tree_node pnode,
52 const ga_workspace &workspace,
54 std::set<var_trans_pair> &vars,
56 bool expand_groups = !ignore_data;
57 bool found_var =
false;
58 if (pnode->node_type == GA_NODE_VAL ||
59 pnode->node_type == GA_NODE_GRAD ||
60 pnode->node_type == GA_NODE_HESS ||
61 pnode->node_type == GA_NODE_DIVERG ||
62 pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
63 pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
64 pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
65 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG ||
66 pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
67 pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
68 pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
69 pnode->node_type == GA_NODE_ELEMENTARY_DIVERG ||
70 pnode->node_type == GA_NODE_SECONDARY_DOMAIN_VAL ||
71 pnode->node_type == GA_NODE_SECONDARY_DOMAIN_GRAD ||
72 pnode->node_type == GA_NODE_SECONDARY_DOMAIN_HESS ||
73 pnode->node_type == GA_NODE_SECONDARY_DOMAIN_DIVERG ||
74 pnode->node_type == GA_NODE_XFEM_PLUS_VAL ||
75 pnode->node_type == GA_NODE_XFEM_PLUS_GRAD ||
76 pnode->node_type == GA_NODE_XFEM_PLUS_HESS ||
77 pnode->node_type == GA_NODE_XFEM_PLUS_DIVERG ||
78 pnode->node_type == GA_NODE_XFEM_MINUS_VAL ||
79 pnode->node_type == GA_NODE_XFEM_MINUS_GRAD ||
80 pnode->node_type == GA_NODE_XFEM_MINUS_HESS ||
81 pnode->node_type == GA_NODE_XFEM_MINUS_DIVERG) {
82 bool group = workspace.variable_group_exists(pnode->name);
83 bool iscte = (!group) && workspace.is_constant(pnode->name);
84 if (!iscte) found_var =
true;
85 if (!ignore_data || !iscte) {
86 if (group && expand_groups) {
87 for (
const std::string &t : workspace.variable_group(pnode->name))
88 vars.insert(var_trans_pair(t, pnode->interpolate_name));
90 vars.insert(var_trans_pair(pnode->name, pnode->interpolate_name));
93 if (pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
94 pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
95 pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
96 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG ||
97 pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST ||
98 pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST ||
99 pnode->node_type == GA_NODE_INTERPOLATE_HESS_TEST ||
100 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST ||
101 pnode->node_type == GA_NODE_INTERPOLATE_X ||
102 pnode->node_type == GA_NODE_INTERPOLATE_ELT_K ||
103 pnode->node_type == GA_NODE_INTERPOLATE_ELT_B ||
104 pnode->node_type == GA_NODE_INTERPOLATE_NORMAL) {
105 workspace.interpolate_transformation(pnode->interpolate_name)
106 ->extract_variables(workspace, vars, ignore_data, m,
107 pnode->interpolate_name);
109 for (
auto&& child : pnode->children)
110 found_var = ga_extract_variables(child, workspace, m,
117 static bool ga_node_mark_tree_for_variable
118 (pga_tree_node pnode,
const ga_workspace &workspace,
const mesh &m,
119 const std::string &varname,
120 const std::string &interpolatename,
bool any_trans =
false) {
122 for (pga_tree_node &child : pnode->children)
123 if (ga_node_mark_tree_for_variable(child, workspace, m,
124 varname, interpolatename, any_trans))
127 bool plain_node(pnode->node_type == GA_NODE_VAL ||
128 pnode->node_type == GA_NODE_GRAD ||
129 pnode->node_type == GA_NODE_HESS ||
130 pnode->node_type == GA_NODE_DIVERG);
131 bool interpolate_node(pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
132 pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
133 pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
134 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG);
135 bool elementary_node(pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
136 pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
137 pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
138 pnode->node_type == GA_NODE_ELEMENTARY_DIVERG);
139 bool secondary_node(pnode->node_type == GA_NODE_SECONDARY_DOMAIN_VAL ||
140 pnode->node_type == GA_NODE_SECONDARY_DOMAIN_GRAD ||
141 pnode->node_type == GA_NODE_SECONDARY_DOMAIN_HESS ||
142 pnode->node_type == GA_NODE_SECONDARY_DOMAIN_DIVERG);
143 bool xfem_node(pnode->node_type == GA_NODE_XFEM_PLUS_VAL ||
144 pnode->node_type == GA_NODE_XFEM_PLUS_GRAD ||
145 pnode->node_type == GA_NODE_XFEM_PLUS_HESS ||
146 pnode->node_type == GA_NODE_XFEM_PLUS_DIVERG ||
147 pnode->node_type == GA_NODE_XFEM_MINUS_VAL ||
148 pnode->node_type == GA_NODE_XFEM_MINUS_GRAD ||
149 pnode->node_type == GA_NODE_XFEM_MINUS_HESS ||
150 pnode->node_type == GA_NODE_XFEM_MINUS_DIVERG);
151 bool interpolate_test_node
152 (pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST ||
153 pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST ||
154 pnode->node_type == GA_NODE_INTERPOLATE_HESS_TEST ||
155 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST);
157 if ((plain_node || interpolate_node || secondary_node ||
158 elementary_node || xfem_node) &&
159 (pnode->name.compare(varname) == 0 &&
160 (any_trans || pnode->interpolate_name.compare(interpolatename) == 0)))
163 if (interpolate_node || interpolate_test_node ||
164 pnode->node_type == GA_NODE_INTERPOLATE_X ||
165 pnode->node_type == GA_NODE_INTERPOLATE_ELT_K ||
166 pnode->node_type == GA_NODE_INTERPOLATE_ELT_B ||
167 pnode->node_type == GA_NODE_INTERPOLATE_NORMAL) {
168 std::set<var_trans_pair> vars;
169 workspace.interpolate_transformation(pnode->interpolate_name)
170 ->extract_variables(workspace, vars,
true,
171 m, pnode->interpolate_name);
172 for (
const var_trans_pair &pair : vars)
173 if (pair.varname.compare(varname) == 0 &&
174 (any_trans || pair.transname.compare(interpolatename) == 0))
177 pnode->marked = marked;
181 static void ga_node_expand_expression_in_place_of_test
182 (ga_tree &tree,
const ga_workspace &workspace,
183 pga_tree_node pnode,
const std::string &varname,
184 pga_tree_node pexpr, ga_tree &grad_expr, ga_tree &hess_expr,
186 bool ignore_X,
int option) {
187 pga_tree_node parent = pnode->parent;
188 for (pga_tree_node &child : pnode->children)
189 ga_node_expand_expression_in_place_of_test
190 (tree, workspace, child, varname, pexpr, grad_expr,
191 hess_expr, order, me, ref_elt_dim, eval_fixed_size, ignore_X, option);
192 const std::string &name = pnode->name;
193 size_type loc_order = pnode->test_function_type;
195 if (loc_order == order && !(name.compare(varname))) {
196 bool need_grad = (pnode->node_type == GA_NODE_GRAD_TEST ||
197 pnode->node_type == GA_NODE_DIVERG_TEST ||
198 pnode->node_type == GA_NODE_HESS_TEST);
199 bool need_hess = (pnode->node_type == GA_NODE_HESS_TEST);
201 if (need_grad && grad_expr.root ==
nullptr) {
202 tree.copy_node(pexpr, grad_expr.root);
203 if (ga_node_mark_tree_for_grad(grad_expr.root, workspace)) {
204 ga_node_grad(grad_expr, workspace, me, grad_expr.root);
205 ga_node_analysis(grad_expr, workspace, grad_expr.root, me,
206 ref_elt_dim, eval_fixed_size, ignore_X, option);
208 bgeot::multi_index mi = grad_expr.root->t.sizes();
209 mi.push_back(me.dim());
210 grad_expr.root->t.adjust_sizes(mi);
211 grad_expr.root->node_type = GA_NODE_ZERO;
212 gmm::clear(grad_expr.root->tensor().as_vector());
213 grad_expr.clear_children(grad_expr.root);
217 if (need_hess && hess_expr.root ==
nullptr) {
218 tree.copy_node(grad_expr.root, hess_expr.root);
219 if (ga_node_mark_tree_for_grad(hess_expr.root, workspace)) {
220 ga_node_grad(hess_expr, workspace, me, hess_expr.root);
221 ga_node_analysis(hess_expr, workspace, hess_expr.root, me,
222 ref_elt_dim, eval_fixed_size, ignore_X, option);
224 bgeot::multi_index mi = hess_expr.root->t.sizes();
225 mi.push_back(me.dim());
226 hess_expr.root->t.adjust_sizes(mi);
227 hess_expr.root->node_type = GA_NODE_ZERO;
228 gmm::clear(hess_expr.root->tensor().as_vector());
229 hess_expr.clear_children(grad_expr.root);
232 switch(pnode->node_type) {
233 case GA_NODE_VAL_TEST:
234 case GA_NODE_GRAD_TEST:
235 case GA_NODE_HESS_TEST:
236 case GA_NODE_DIVERG_TEST:
238 pga_tree_node pnode_new =
nullptr;
239 if (pnode->node_type == GA_NODE_VAL_TEST)
240 tree.copy_node(pexpr, pnode_new);
241 else if (pnode->node_type == GA_NODE_GRAD_TEST ||
242 pnode->node_type == GA_NODE_DIVERG_TEST)
243 tree.copy_node(grad_expr.root, pnode_new);
244 else if (pnode->node_type == GA_NODE_HESS_TEST)
245 tree.copy_node(hess_expr.root, pnode_new);
246 pnode_new->parent = parent;
247 parent->replace_child(pnode, pnode_new);
248 if (pnode->node_type == GA_NODE_DIVERG_TEST) {
249 tree.insert_node(pnode_new, GA_NODE_OP);
250 pnode_new->parent->op_type = GA_TRACE;
256 case GA_NODE_INTERPOLATE_VAL_TEST:
case GA_NODE_INTERPOLATE_GRAD_TEST:
257 case GA_NODE_INTERPOLATE_HESS_TEST:
case GA_NODE_INTERPOLATE_DIVERG_TEST:
258 GMM_ASSERT1(pexpr->node_type == GA_NODE_VAL_TEST,
259 "Sorry, directional derivative does not work for the "
260 "moment with interpolate transformations. Future work.");
261 pnode->name = pexpr->name;
263 case GA_NODE_ELEMENTARY_VAL_TEST:
case GA_NODE_ELEMENTARY_GRAD_TEST:
264 case GA_NODE_ELEMENTARY_HESS_TEST:
case GA_NODE_ELEMENTARY_DIVERG_TEST:
265 GMM_ASSERT1(pexpr->node_type == GA_NODE_VAL_TEST,
266 "Sorry, directional derivative does not work for the "
267 "moment with elementary transformations. Future work.");
268 pnode->name = pexpr->name;
270 case GA_NODE_SECONDARY_DOMAIN_VAL_TEST:
271 case GA_NODE_SECONDARY_DOMAIN_GRAD_TEST:
272 case GA_NODE_SECONDARY_DOMAIN_HESS_TEST:
273 case GA_NODE_SECONDARY_DOMAIN_DIVERG_TEST:
274 GMM_ASSERT1(pexpr->node_type == GA_NODE_VAL_TEST,
275 "Sorry, directional derivative does not work for the "
276 "moment with secondary domains. Future work.");
277 pnode->name = pexpr->name;
279 case GA_NODE_XFEM_PLUS_VAL_TEST:
case GA_NODE_XFEM_PLUS_GRAD_TEST:
280 case GA_NODE_XFEM_PLUS_HESS_TEST:
case GA_NODE_XFEM_PLUS_DIVERG_TEST:
281 case GA_NODE_XFEM_MINUS_VAL_TEST:
case GA_NODE_XFEM_MINUS_GRAD_TEST:
282 case GA_NODE_XFEM_MINUS_HESS_TEST:
case GA_NODE_XFEM_MINUS_DIVERG_TEST:
283 GMM_ASSERT1(pexpr->node_type == GA_NODE_VAL_TEST,
284 "Sorry, directional derivative does not work for the "
285 "moment with Xfem_plus and Xfem_minus operations. "
287 pnode->name = pexpr->name;
299 static scalar_type ga_hash_code(
const std::string &s) {
302 c += sin(M_E+scalar_type(s[i]))+M_PI*M_E*scalar_type(i+1);
306 static scalar_type ga_hash_code(
const base_tensor &t) {
309 c += sin((1.+M_E)*t[i]+M_E*M_E*scalar_type(i+1))+scalar_type(i+1)*M_PI;
313 static scalar_type ga_hash_code(GA_NODE_TYPE e) {
314 return cos(M_E + scalar_type((e == GA_NODE_ZERO) ? GA_NODE_CONSTANT : e));
317 static scalar_type ga_hash_code(
const pga_tree_node pnode) {
318 scalar_type c = ga_hash_code(pnode->node_type);
320 switch (pnode->node_type) {
321 case GA_NODE_CONSTANT:
case GA_NODE_ZERO:
322 c += ga_hash_code(pnode->tensor());
323 if (pnode->test_function_type & 1)
324 c += 34.731 * ga_hash_code(pnode->name_test1);
325 if (pnode->test_function_type & 2)
326 c += 34.731 * ga_hash_code(pnode->name_test2);
329 case GA_NODE_OP: c += scalar_type(pnode->op_type)*M_E*M_PI*M_PI;
break;
330 case GA_NODE_X: c += scalar_type(pnode->nbc1) + M_E*M_PI;
break;
331 case GA_NODE_VAL:
case GA_NODE_GRAD:
332 case GA_NODE_HESS:
case GA_NODE_DIVERG:
333 case GA_NODE_VAL_TEST:
case GA_NODE_GRAD_TEST:
334 case GA_NODE_HESS_TEST:
case GA_NODE_DIVERG_TEST:
335 c += ga_hash_code(pnode->name);
break;
337 case GA_NODE_INTERPOLATE_FILTER:
338 c += 1.73*ga_hash_code(pnode->interpolate_name)
339 + 2.486*double(pnode->nbc1 + 1);
341 case GA_NODE_INTERPOLATE_DERIVATIVE:
342 c += 2.321*ga_hash_code(pnode->interpolate_name_der);
344 case GA_NODE_INTERPOLATE_VAL:
case GA_NODE_INTERPOLATE_GRAD:
345 case GA_NODE_INTERPOLATE_HESS:
case GA_NODE_INTERPOLATE_DIVERG:
346 case GA_NODE_INTERPOLATE_VAL_TEST:
case GA_NODE_INTERPOLATE_GRAD_TEST:
347 case GA_NODE_INTERPOLATE_HESS_TEST:
case GA_NODE_INTERPOLATE_DIVERG_TEST:
348 case GA_NODE_SECONDARY_DOMAIN_VAL:
case GA_NODE_SECONDARY_DOMAIN_GRAD:
349 case GA_NODE_SECONDARY_DOMAIN_HESS:
case GA_NODE_SECONDARY_DOMAIN_DIVERG:
350 case GA_NODE_SECONDARY_DOMAIN_VAL_TEST:
351 case GA_NODE_SECONDARY_DOMAIN_GRAD_TEST:
352 case GA_NODE_SECONDARY_DOMAIN_HESS_TEST:
353 case GA_NODE_SECONDARY_DOMAIN_DIVERG_TEST:
354 c += 1.33*(1.22+ga_hash_code(pnode->name))
355 + 1.66*ga_hash_code(pnode->interpolate_name);
357 case GA_NODE_ELEMENTARY_VAL:
case GA_NODE_ELEMENTARY_GRAD:
358 case GA_NODE_ELEMENTARY_HESS:
case GA_NODE_ELEMENTARY_DIVERG:
359 case GA_NODE_ELEMENTARY_VAL_TEST:
case GA_NODE_ELEMENTARY_GRAD_TEST:
360 case GA_NODE_ELEMENTARY_HESS_TEST:
case GA_NODE_ELEMENTARY_DIVERG_TEST:
361 c += 1.33*(1.22+ga_hash_code(pnode->name))
362 + 2.63*ga_hash_code(pnode->elementary_name)
363 + 3.47*ga_hash_code(pnode->elementary_target);
365 case GA_NODE_XFEM_PLUS_VAL:
case GA_NODE_XFEM_PLUS_GRAD:
366 case GA_NODE_XFEM_PLUS_HESS:
case GA_NODE_XFEM_PLUS_DIVERG:
367 case GA_NODE_XFEM_PLUS_VAL_TEST:
case GA_NODE_XFEM_PLUS_GRAD_TEST:
368 case GA_NODE_XFEM_PLUS_HESS_TEST:
case GA_NODE_XFEM_PLUS_DIVERG_TEST:
369 case GA_NODE_XFEM_MINUS_VAL:
case GA_NODE_XFEM_MINUS_GRAD:
370 case GA_NODE_XFEM_MINUS_HESS:
case GA_NODE_XFEM_MINUS_DIVERG:
371 case GA_NODE_XFEM_MINUS_VAL_TEST:
case GA_NODE_XFEM_MINUS_GRAD_TEST:
372 case GA_NODE_XFEM_MINUS_HESS_TEST:
case GA_NODE_XFEM_MINUS_DIVERG_TEST:
373 c += 1.33*(1.22+ga_hash_code(pnode->name));
375 case GA_NODE_INTERPOLATE_X:
376 case GA_NODE_INTERPOLATE_ELT_K:
case GA_NODE_INTERPOLATE_ELT_B:
377 case GA_NODE_INTERPOLATE_NORMAL:
378 case GA_NODE_SECONDARY_DOMAIN_X:
case GA_NODE_SECONDARY_DOMAIN_NORMAL:
379 c += M_PI*1.33*ga_hash_code(pnode->interpolate_name);
381 case GA_NODE_PREDEF_FUNC:
case GA_NODE_SPEC_FUNC:
case GA_NODE_OPERATOR:
382 c += ga_hash_code(pnode->name)
383 + tanh(scalar_type(pnode->der1)/M_PI + scalar_type(pnode->der2)*M_PI);
390 # define ga_valid_operand(pnode) \
392 if (pnode && (pnode->node_type == GA_NODE_PREDEF_FUNC || \
393 pnode->node_type == GA_NODE_SPEC_FUNC || \
394 pnode->node_type == GA_NODE_NAME || \
395 pnode->node_type == GA_NODE_OPERATOR || \
396 pnode->node_type == GA_NODE_ALLINDICES)) \
397 ga_throw_error(pnode->expr, pnode->pos, "Invalid term"); \
400 static void ga_node_analysis(ga_tree &tree,
401 const ga_workspace &workspace,
402 pga_tree_node pnode,
const mesh &me,
403 size_type ref_elt_dim,
bool eval_fixed_size,
404 bool ignore_X,
int option) {
405 # ifdef GA_PRINT_DEBUG_INFO
406 cout <<
"Analysis of "; ga_print_node(pnode, cout); cout << endl;
408 bool all_cte =
true, all_sc =
true;
409 size_type meshdim = (&me == &dummy_mesh()) ? 1 : me.dim();
410 pnode->symmetric_op =
false;
412 for (
size_type i = 0; i < pnode->children.size(); ++i) {
413 ga_node_analysis(tree, workspace, pnode->children[i], me,
414 ref_elt_dim, eval_fixed_size, ignore_X, option);
415 all_cte = all_cte && (pnode->children[i]->is_constant());
416 all_sc = all_sc && (pnode->children[i]->tensor_proper_size() == 1);
417 if (pnode->children[i]->test_function_type ==
size_type(-1)) {
418 cerr <<
"node : "; ga_print_node(pnode, cerr); cerr << endl;
419 GMM_ASSERT1(
false,
"internal error on child " << i);
421 if (pnode->node_type != GA_NODE_PARAMS)
422 ga_valid_operand(pnode->children[i]);
426 pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
427 pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
428 bgeot::multi_index mi;
429 const bgeot::multi_index &size0 = child0 ? child0->t.sizes() : mi;
430 const bgeot::multi_index &size1 = child1 ? child1->t.sizes() : mi;
431 size_type dim0 = child0 ? child0->tensor_order() : 0;
432 size_type dim1 = child1 ? child1->tensor_order() : 0;
434 const ga_predef_function_tab &PREDEF_FUNCTIONS
436 const ga_predef_operator_tab &PREDEF_OPERATORS
438 const ga_spec_function_tab &SPEC_FUNCTIONS
441 switch (pnode->node_type) {
442 case GA_NODE_PREDEF_FUNC:
case GA_NODE_OPERATOR:
case GA_NODE_SPEC_FUNC:
443 case GA_NODE_CONSTANT:
case GA_NODE_X:
case GA_NODE_ELT_SIZE:
444 case GA_NODE_ELT_K:
case GA_NODE_ELT_B:
case GA_NODE_NORMAL:
445 case GA_NODE_RESHAPE:
case GA_NODE_CROSS_PRODUCT:
446 case GA_NODE_IND_MOVE_LAST:
case GA_NODE_SWAP_IND:
447 case GA_NODE_CONTRACT:
case GA_NODE_INTERPOLATE_X:
448 case GA_NODE_INTERPOLATE_ELT_K:
case GA_NODE_INTERPOLATE_ELT_B:
449 case GA_NODE_INTERPOLATE_NORMAL:
case GA_NODE_SECONDARY_DOMAIN_X:
450 case GA_NODE_SECONDARY_DOMAIN_NORMAL:
451 pnode->test_function_type = 0;
454 case GA_NODE_ALLINDICES:
455 pnode->test_function_type = 0;
459 if (eval_fixed_size && !(workspace.associated_mf(pnode->name))
460 && !(workspace.associated_im_data(pnode->name))) {
461 gmm::copy(workspace.value(pnode->name), pnode->tensor().as_vector());
462 pnode->node_type = GA_NODE_CONSTANT;
466 case GA_NODE_ZERO:
case GA_NODE_GRAD:
467 case GA_NODE_HESS:
case GA_NODE_DIVERG:
468 case GA_NODE_INTERPOLATE_VAL:
case GA_NODE_INTERPOLATE_GRAD:
469 case GA_NODE_INTERPOLATE_HESS:
case GA_NODE_INTERPOLATE_DIVERG:
470 case GA_NODE_ELEMENTARY_VAL:
case GA_NODE_ELEMENTARY_GRAD:
471 case GA_NODE_ELEMENTARY_HESS:
case GA_NODE_ELEMENTARY_DIVERG:
472 case GA_NODE_SECONDARY_DOMAIN_VAL:
case GA_NODE_SECONDARY_DOMAIN_GRAD:
473 case GA_NODE_SECONDARY_DOMAIN_HESS:
case GA_NODE_SECONDARY_DOMAIN_DIVERG:
474 case GA_NODE_XFEM_PLUS_VAL:
case GA_NODE_XFEM_PLUS_GRAD:
475 case GA_NODE_XFEM_PLUS_HESS:
case GA_NODE_XFEM_PLUS_DIVERG:
476 case GA_NODE_XFEM_MINUS_VAL:
case GA_NODE_XFEM_MINUS_GRAD:
477 case GA_NODE_XFEM_MINUS_HESS:
case GA_NODE_XFEM_MINUS_DIVERG:
480 case GA_NODE_VAL_TEST:
case GA_NODE_GRAD_TEST:
481 case GA_NODE_HESS_TEST:
case GA_NODE_DIVERG_TEST:
482 case GA_NODE_INTERPOLATE_VAL_TEST:
case GA_NODE_INTERPOLATE_GRAD_TEST:
483 case GA_NODE_INTERPOLATE_HESS_TEST:
case GA_NODE_INTERPOLATE_DIVERG_TEST:
484 case GA_NODE_INTERPOLATE_DERIVATIVE:
485 case GA_NODE_ELEMENTARY_VAL_TEST:
case GA_NODE_ELEMENTARY_GRAD_TEST:
486 case GA_NODE_ELEMENTARY_HESS_TEST:
case GA_NODE_ELEMENTARY_DIVERG_TEST:
487 case GA_NODE_SECONDARY_DOMAIN_VAL_TEST:
488 case GA_NODE_SECONDARY_DOMAIN_GRAD_TEST:
489 case GA_NODE_SECONDARY_DOMAIN_HESS_TEST:
490 case GA_NODE_SECONDARY_DOMAIN_DIVERG_TEST:
491 case GA_NODE_XFEM_PLUS_VAL_TEST:
case GA_NODE_XFEM_PLUS_GRAD_TEST:
492 case GA_NODE_XFEM_PLUS_HESS_TEST:
case GA_NODE_XFEM_PLUS_DIVERG_TEST:
493 case GA_NODE_XFEM_MINUS_VAL_TEST:
case GA_NODE_XFEM_MINUS_GRAD_TEST:
494 case GA_NODE_XFEM_MINUS_HESS_TEST:
case GA_NODE_XFEM_MINUS_DIVERG_TEST:
496 const mesh_fem *mf = workspace.associated_mf(pnode->name);
497 const im_data *imd = workspace.associated_im_data(pnode->name);
498 size_type t_type = pnode->test_function_type;
500 pnode->name_test1 = pnode->name;
501 pnode->interpolate_name_test1 = pnode->interpolate_name;
502 pnode->interpolate_name_test2 = pnode->name_test2 =
"";
503 pnode->qdim1 = (mf || imd)
504 ? workspace.qdim(pnode->name)
505 : gmm::vect_size(workspace.value(pnode->name));
507 workspace.test1.insert
508 (var_trans_pair(pnode->name_test1,
509 pnode->interpolate_name_test1));
511 ga_throw_error(pnode->expr, pnode->pos,
512 "Invalid null size of variable");
514 pnode->interpolate_name_test1 = pnode->name_test1 =
"";
515 pnode->name_test2 = pnode->name;
516 pnode->interpolate_name_test2 = pnode->interpolate_name;
517 pnode->qdim2 = (mf || imd)
518 ? workspace.qdim(pnode->name)
519 : gmm::vect_size(workspace.value(pnode->name));
521 workspace.test2.insert
522 (var_trans_pair(pnode->name_test2,
523 pnode->interpolate_name_test2));
525 ga_throw_error(pnode->expr, pnode->pos,
526 "Invalid null size of variable");
528 size_type q = workspace.qdim(pnode->name);
530 ga_throw_error(pnode->expr, pnode->pos,
531 "Invalid null size of variable");
533 if (pnode->node_type != GA_NODE_INTERPOLATE_DERIVATIVE) {
535 pnode->init_vector_tensor(1);
536 pnode->tensor()[0] = scalar_type(1);
538 pnode->init_identity_matrix_tensor(q);
540 pnode->test_function_type = t_type;
542 if (pnode->node_type != GA_NODE_INTERPOLATE_DERIVATIVE) {
543 bgeot::multi_index mii = workspace.qdims(pnode->name);
544 if (q == 1 && mii.size() <= 1) {
545 pnode->init_vector_tensor(1);
546 pnode->tensor()[0] = scalar_type(1);
548 mii.insert(mii.begin(), q);
549 pnode->t.set_to_original();
550 pnode->t.adjust_sizes(mii);
551 auto itw = pnode->tensor().begin();
554 *itw++ = (i == j) ? scalar_type(1) : scalar_type(0);
557 pnode->test_function_type = t_type;
562 case GA_NODE_SECONDARY_DOMAIN:
563 pnode->interpolate_name = tree.secondary_domain;
564 if (tree.secondary_domain.size() == 0)
565 ga_throw_error(pnode->expr, pnode->pos,
"Secondary domain used "
566 "in a single domain term.");
568 case GA_NODE_INTERPOLATE:
569 if (pnode->name.compare(
"X") == 0) {
570 if (pnode->node_type == GA_NODE_INTERPOLATE) {
571 pnode->node_type = GA_NODE_INTERPOLATE_X;
572 pnode->init_vector_tensor(meshdim);
574 auto psd = workspace.secondary_domain(tree.secondary_domain);
575 pnode->node_type = GA_NODE_SECONDARY_DOMAIN_X;
576 pnode->init_vector_tensor(psd->mim().linked_mesh().dim());
580 if (pnode->name.compare(
"Normal") == 0) {
581 if (pnode->node_type == GA_NODE_INTERPOLATE) {
582 pnode->node_type = GA_NODE_INTERPOLATE_NORMAL;
583 pnode->init_vector_tensor(meshdim);
585 auto psd = workspace.secondary_domain(tree.secondary_domain);
586 pnode->node_type = GA_NODE_SECONDARY_DOMAIN_NORMAL;
587 pnode->init_vector_tensor(psd->mim().linked_mesh().dim());
591 if (pnode->name.compare(
"element_K") == 0) {
592 if (pnode->node_type == GA_NODE_INTERPOLATE) {
593 pnode->node_type = GA_NODE_INTERPOLATE_ELT_K;
594 if (ref_elt_dim == 1)
595 pnode->init_vector_tensor(meshdim);
597 pnode->init_matrix_tensor(meshdim, ref_elt_dim);
601 if (pnode->name.compare(
"element_B") == 0) {
602 if (pnode->node_type == GA_NODE_INTERPOLATE) {
603 pnode->node_type = GA_NODE_INTERPOLATE_ELT_B;
604 pnode->init_matrix_tensor(ref_elt_dim, meshdim);
609 case GA_NODE_ELEMENTARY:
610 case GA_NODE_XFEM_PLUS:
611 case GA_NODE_XFEM_MINUS:
613 int ndt = ((pnode->node_type == GA_NODE_INTERPOLATE) ? 1 : 0)
614 + ((pnode->node_type == GA_NODE_ELEMENTARY) ? 2 : 0)
615 + ((pnode->node_type == GA_NODE_SECONDARY_DOMAIN) ? 3 : 0)
616 + ((pnode->node_type == GA_NODE_XFEM_PLUS) ? 4 : 0)
617 + ((pnode->node_type == GA_NODE_XFEM_MINUS) ? 5 : 0);
618 GMM_ASSERT1(ndt > 0 && ndt < 6,
"internal error");
619 constexpr std::array<const char*,5>
620 op_name_selector{
"Interpolation",
621 "Elementary_transformation",
625 std::string op__name = op_name_selector.at(ndt-1);
627 std::string name = pnode->name;
628 size_type prefix_id = ga_parse_prefix_operator(name);
629 size_type test = ga_parse_prefix_test(name);
633 name = pnode->elementary_target;
634 ga_parse_prefix_operator(name);
635 ga_parse_prefix_test(name);
636 pnode->elementary_target = name;
640 if (!(workspace.variable_or_group_exists(name)))
641 ga_throw_error(pnode->expr, pnode->pos,
642 "Unknown variable or group of variables \""
645 const mesh_fem *mf = workspace.associated_mf(name);
647 ga_throw_error(pnode->expr, pnode->pos, op__name
648 <<
" can only apply to finite element variables/data");
650 size_type q = workspace.qdim(name), n = mf->linked_mesh().dim();
651 if (!q) ga_throw_error(pnode->expr, pnode->pos,
652 "Invalid null size of variable");
654 bgeot::multi_index mii = workspace.qdims(name);
656 ga_throw_error(pnode->expr, pnode->pos,
657 "Tensor with too many dimensions. Limited to 6");
660 pnode->name_test1 = pnode->name;
661 pnode->interpolate_name_test1 = pnode->interpolate_name;
663 workspace.test1.insert
664 (var_trans_pair(pnode->name_test1,
665 pnode->interpolate_name_test1));
666 pnode->qdim1 = workspace.qdim(name);
668 ga_throw_error(pnode->expr, pnode->pos,
669 "Invalid null size of variable");
670 }
else if (test == 2) {
671 pnode->name_test2 = pnode->name;
672 pnode->interpolate_name_test2 = pnode->interpolate_name;
674 workspace.test2.insert
675 (var_trans_pair(pnode->name_test2,
676 pnode->interpolate_name_test2));
677 pnode->qdim2 = workspace.qdim(name);
679 ga_throw_error(pnode->expr, pnode->pos,
680 "Invalid null size of variable");
683 constexpr std::array<GA_NODE_TYPE,5>
684 node_type_selector_val{GA_NODE_INTERPOLATE_VAL,
685 GA_NODE_ELEMENTARY_VAL,
686 GA_NODE_SECONDARY_DOMAIN_VAL,
687 GA_NODE_XFEM_PLUS_VAL,
688 GA_NODE_XFEM_MINUS_VAL},
689 node_type_selector_val_test{GA_NODE_INTERPOLATE_VAL_TEST,
690 GA_NODE_ELEMENTARY_VAL_TEST,
691 GA_NODE_SECONDARY_DOMAIN_VAL_TEST,
692 GA_NODE_XFEM_PLUS_VAL_TEST,
693 GA_NODE_XFEM_MINUS_VAL_TEST},
694 node_type_selector_grad{GA_NODE_INTERPOLATE_GRAD,
695 GA_NODE_ELEMENTARY_GRAD,
696 GA_NODE_SECONDARY_DOMAIN_GRAD,
697 GA_NODE_XFEM_PLUS_GRAD,
698 GA_NODE_XFEM_MINUS_GRAD},
699 node_type_selector_grad_test{GA_NODE_INTERPOLATE_GRAD_TEST,
700 GA_NODE_ELEMENTARY_GRAD_TEST,
701 GA_NODE_SECONDARY_DOMAIN_GRAD_TEST,
702 GA_NODE_XFEM_PLUS_GRAD_TEST,
703 GA_NODE_XFEM_MINUS_GRAD_TEST},
704 node_type_selector_hess{GA_NODE_INTERPOLATE_HESS,
705 GA_NODE_ELEMENTARY_HESS,
706 GA_NODE_SECONDARY_DOMAIN_HESS,
707 GA_NODE_XFEM_PLUS_HESS,
708 GA_NODE_XFEM_MINUS_HESS},
709 node_type_selector_hess_test{GA_NODE_INTERPOLATE_HESS_TEST,
710 GA_NODE_ELEMENTARY_HESS_TEST,
711 GA_NODE_SECONDARY_DOMAIN_HESS_TEST,
712 GA_NODE_XFEM_PLUS_HESS_TEST,
713 GA_NODE_XFEM_MINUS_HESS_TEST},
714 node_type_selector_div{GA_NODE_INTERPOLATE_DIVERG,
715 GA_NODE_ELEMENTARY_DIVERG,
716 GA_NODE_SECONDARY_DOMAIN_DIVERG,
717 GA_NODE_XFEM_PLUS_DIVERG,
718 GA_NODE_XFEM_MINUS_DIVERG},
719 node_type_selector_div_test{GA_NODE_INTERPOLATE_DIVERG_TEST,
720 GA_NODE_ELEMENTARY_DIVERG_TEST,
721 GA_NODE_SECONDARY_DOMAIN_DIVERG_TEST,
722 GA_NODE_XFEM_PLUS_DIVERG_TEST,
723 GA_NODE_XFEM_MINUS_DIVERG_TEST};
727 pnode->node_type = test ? node_type_selector_val_test[ndt-1]
728 : node_type_selector_val[ndt-1];
730 if (q == 1 && mii.size() <= 1) {
734 mii.insert(mii.begin(), 2);
738 pnode->node_type = test ? node_type_selector_grad_test[ndt-1]
739 : node_type_selector_grad[ndt-1];
741 if (q == 1 && mii.size() <= 1) {
745 mii.insert(mii.begin(), 2);
746 if (n > 1) mii.push_back(n);
748 if (q == 1 && mii.size() == 1)
755 pnode->node_type = test ? node_type_selector_hess_test[ndt-1]
756 : node_type_selector_hess[ndt-1];
758 if (q == 1 && mii.size() <= 1) {
762 mii.insert(mii.begin(), 2);
768 if (q == 1 && mii.size() == 1)
777 ga_throw_error(pnode->expr, pnode->pos,
778 "Divergence operator requires fem qdim ("
779 << q <<
") to be equal to dim (" << n <<
")");
780 pnode->node_type = test ? node_type_selector_div_test[ndt-1]
781 : node_type_selector_div[ndt-1];
783 mii[0] = test ? 2 : 1;
786 pnode->t.adjust_sizes(mii);
787 pnode->test_function_type = test;
790 if (!(workspace.interpolate_transformation_exists
791 (pnode->interpolate_name)))
792 ga_throw_error(pnode->expr, pnode->pos,
793 "Unknown interpolate transformation");
794 }
else if (ndt == 2) {
795 if (!(workspace.elementary_transformation_exists
796 (pnode->elementary_name)))
797 ga_throw_error(pnode->expr, pnode->pos,
798 "Unknown elementary transformation");
799 if (!(workspace.variable_or_group_exists(pnode->elementary_target)))
800 ga_throw_error(pnode->expr, pnode->pos,
"Unknown data or variable "
801 << pnode->elementary_target);
802 const mesh_fem *mft = workspace.associated_mf(name);
804 ga_throw_error(pnode->expr, pnode->pos,
805 "Thir argument of the elementary transformation "
806 "should be a finite element variables/data");
807 }
else if (ndt == 3) {
808 if (!(workspace.secondary_domain_exists
809 (pnode->interpolate_name)))
810 ga_throw_error(pnode->expr, pnode->pos,
811 "Unknown secondary domain");
816 case GA_NODE_INTERPOLATE_FILTER:
818 if (pnode->children.size() == 2) {
819 bool valid = (child1->node_type == GA_NODE_CONSTANT);
820 int n = valid ? int(round(child1->tensor()[0])) : -1;
821 if (n < 0 || n > 100 || child1->tensor_order() > 0)
822 ga_throw_error(pnode->expr, pnode->pos,
"The third argument of "
823 "Interpolate_filter should be a (small) "
824 "non-negative integer.");
826 tree.clear_node(child1);
828 if (!(workspace.interpolate_transformation_exists
829 (pnode->interpolate_name)))
830 ga_throw_error(pnode->expr, pnode->pos,
831 "Unknown interpolate transformation");
832 pnode->t = child0->t;
833 pnode->test_function_type = child0->test_function_type;
834 pnode->name_test1 = child0->name_test1;
835 pnode->name_test2 = child0->name_test2;
836 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
837 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
838 pnode->qdim1 = child0->qdim1;
839 pnode->qdim2 = child0->qdim2;
845 switch(pnode->op_type) {
847 case GA_PLUS:
case GA_MINUS:
849 if (pnode->op_type == GA_PLUS) pnode->symmetric_op =
true;
850 size_type c_size = std::min(size0.size(), size1.size());
851 bool compatible =
true;
854 if (child0->test_function_type &&
855 child1->test_function_type == child0->test_function_type)
856 f_ind = (child0->test_function_type == 3) ? 2:1;
858 for (
size_type i = f_ind; i < c_size; ++i)
859 if (size0[i] != size1[i]) compatible =
false;
860 for (
size_type i = c_size; i < size0.size(); ++i)
861 if (size0[i] != 1) compatible =
false;
862 for (
size_type i = c_size; i < size1.size(); ++i)
863 if (size1[i] != 1) compatible =
false;
866 ga_throw_error(pnode->expr, pnode->pos,
867 "Addition or substraction of expressions of "
868 "different sizes: " << size0 <<
" != " << size1);
869 if (child0->test_function_type || child1->test_function_type) {
872 if (child0->name_test1.compare(child1->name_test1) ||
873 child0->name_test2.compare(child1->name_test2) ||
874 child0->interpolate_name_test1.compare
875 (child1->interpolate_name_test1) ||
876 child0->interpolate_name_test2.compare
877 (child1->interpolate_name_test2))
880 case 1:
case 3:
break;
881 default: GMM_ASSERT1(
false,
"Unknown option");
885 if (child0->test_function_type != child1->test_function_type ||
886 (!compatible && option != 2))
887 ga_throw_error(pnode->expr, pnode->pos,
"Addition or substraction "
888 "of incompatible test functions");
890 pnode->node_type = GA_NODE_CONSTANT;
891 pnode->test_function_type = 0;
892 pnode->tensor() = pnode->children[0]->tensor();
893 if (pnode->op_type == GA_MINUS)
894 pnode->tensor() -= pnode->children[1]->tensor();
896 pnode->tensor() += pnode->children[1]->tensor();
897 tree.clear_children(pnode);
899 pnode->t = child0->t;
900 pnode->test_function_type = child0->test_function_type;
901 pnode->name_test1 = child0->name_test1;
902 pnode->name_test2 = child0->name_test2;
903 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
904 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
905 pnode->qdim1 = child0->qdim1;
906 pnode->qdim2 = child0->qdim2;
909 if (child0->tensor_is_zero()) {
910 if (pnode->op_type == GA_MINUS) {
911 pnode->op_type = GA_UNARY_MINUS;
912 tree.clear_node(child0);
914 tree.replace_node_by_child(pnode, 1);
917 }
else if (child1->tensor_is_zero()) {
918 tree.replace_node_by_child(pnode, 0);
920 }
else if (option == 2 && !compatible) {
921 bool child0_compatible =
true, child1_compatible =
true;
922 if (pnode->test_function_type & 1) {
923 if (child0->name_test1.compare(workspace.selected_test1.varname)
924 || child0->interpolate_name_test1.compare
925 (workspace.selected_test1.transname))
926 child0_compatible =
false;
927 if (child1->name_test1.compare(workspace.selected_test1.varname)
928 || child1->interpolate_name_test1.compare
929 (workspace.selected_test1.transname))
930 child1_compatible =
false;
932 if (pnode->test_function_type & 2) {
933 if (child0->name_test2.compare(workspace.selected_test2.varname)
934 || child0->interpolate_name_test2.compare
935 (workspace.selected_test2.transname))
936 child0_compatible =
false;
937 if (child1->name_test2.compare(workspace.selected_test2.varname)
938 || child1->interpolate_name_test1.compare
939 (workspace.selected_test2.transname))
940 child1_compatible =
false;
942 if (child0_compatible) {
943 tree.replace_node_by_child(pnode, 0);
945 }
else if (child1_compatible) {
946 if (pnode->op_type == GA_MINUS) {
947 pnode->op_type = GA_UNARY_MINUS;
948 pnode->t = child1->t;
949 pnode->test_function_type = child1->test_function_type;
950 pnode->name_test1 = child1->name_test1;
951 pnode->name_test2 = child1->name_test2;
952 pnode->interpolate_name_test1=child1->interpolate_name_test1;
953 pnode->interpolate_name_test2=child1->interpolate_name_test2;
954 pnode->qdim1 = child1->qdim1;
955 pnode->qdim2 = child1->qdim2;
956 tree.clear_node(child0);
958 tree.replace_node_by_child(pnode, 1);
967 case GA_DOTMULT:
case GA_DOTDIV:
969 if (pnode->op_type == GA_DOTMULT) pnode->symmetric_op =
true;
970 bool compatible =
true;
971 if (child0->tensor_proper_size() != child1->tensor_proper_size())
974 if (child0->tensor_proper_size() != 1) {
975 if (child0->tensor_order() != child1->tensor_order())
978 for (
size_type i = 0; i < child0->tensor_order(); ++i)
979 if (child0->tensor_proper_size(i)!=child1->tensor_proper_size(i))
984 ga_throw_error(pnode->expr, pnode->pos,
985 "Arguments of different sizes for .* or ./");
987 if (pnode->op_type == GA_DOTDIV && child1->test_function_type)
988 ga_throw_error(pnode->expr, pnode->pos,
989 "Division by test functions is not allowed");
991 pnode->mult_test(child0, child1);
992 mi = pnode->t.sizes();
993 for (
size_type i = 0; i < child0->tensor_order(); ++i)
994 mi.push_back(child0->tensor_proper_size(i));
995 pnode->t.adjust_sizes(mi);
998 pnode->node_type = GA_NODE_CONSTANT;
999 pnode->test_function_type = 0;
1000 if (pnode->op_type == GA_DOTMULT) {
1001 for (
size_type i = 0; i < child0->tensor().size(); ++i)
1002 pnode->tensor()[i] = child0->tensor()[i] * child1->tensor()[i];
1004 for (
size_type i = 0; i < child0->tensor().size(); ++i) {
1005 if (child1->tensor()[i] == scalar_type(0))
1006 ga_throw_error(pnode->expr, pnode->pos,
"Division by zero.");
1007 pnode->tensor()[i] = child0->tensor()[i] / child1->tensor()[i];
1010 tree.clear_children(pnode);
1012 if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
1014 pnode->node_type = GA_NODE_ZERO;
1015 tree.clear_children(pnode);
1017 if (child1->tensor_is_zero() && pnode->op_type == GA_DOTDIV)
1018 ga_throw_error(pnode->expr, pnode->pos,
"Division by zero.");
1023 case GA_UNARY_MINUS:
1024 pnode->t = child0->t;
1025 pnode->test_function_type = child0->test_function_type;
1026 pnode->name_test1 = child0->name_test1;
1027 pnode->name_test2 = child0->name_test2;
1028 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
1029 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
1030 pnode->qdim1 = child0->qdim1;
1031 pnode->qdim2 = child0->qdim2;
1033 pnode->node_type = GA_NODE_CONSTANT;
1034 pnode->test_function_type = 0;
1035 gmm::scale(pnode->tensor().as_vector(), scalar_type(-1));
1036 tree.clear_children(pnode);
1037 }
else if (child0->node_type == GA_NODE_ZERO) {
1038 tree.replace_node_by_child(pnode, 0);
1045 if (child0->tensor_proper_size() == 1)
1046 { tree.replace_node_by_child(pnode, 0); pnode = child0;
break; }
1048 {
size_type N = mi.back(); mi.back() = 1; mi.push_back(N); }
1049 else std::swap(mi[child0->nb_test_functions()],
1050 mi[child0->nb_test_functions()+1]);
1053 pnode->t.adjust_sizes(mi);
1054 pnode->test_function_type = child0->test_function_type;
1055 pnode->name_test1 = child0->name_test1;
1056 pnode->name_test2 = child0->name_test2;
1057 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
1058 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
1059 pnode->qdim1 = child0->qdim1;
1060 pnode->qdim2 = child0->qdim2;
1061 if (child0->node_type == GA_NODE_ZERO) {
1062 pnode->node_type = GA_NODE_ZERO;
1064 tree.clear_children(pnode);
1065 }
else if (all_cte) {
1066 pnode->node_type = GA_NODE_CONSTANT;
1067 pnode->test_function_type = 0;
1070 for (
size_type i = 0; i < mi.back(); ++i)
1071 pnode->tensor()(0, i) = child0->tensor()[i];
1073 size_type n1 = child0->tensor_proper_size(0);
1074 size_type n2 = child0->tensor_proper_size(1);
1075 size_type nn = child0->tensor().size()/(n1*n2);
1076 auto it = pnode->tensor().begin();
1079 for (
size_type k = 0; k < n2; ++k, ++it)
1080 *it = child0->tensor()[j+k*n1+i*n1*n2];
1081 GA_DEBUG_ASSERT(it == pnode->tensor().end(),
"Wrong sizes");
1083 tree.clear_children(pnode);
1087 case GA_SYM:
case GA_SKEW:
1088 if (child0->tensor_proper_size() != 1 &&
1089 (dim0 != 2 || size0.back() != size0[size0.size()-2]))
1090 ga_throw_error(pnode->expr, pnode->pos,
"Sym and Skew operators are "
1091 "for square matrices only.");
1093 if (child0->tensor_proper_size() == 1) {
1094 if (pnode->op_type == GA_SYM)
1095 { tree.replace_node_by_child(pnode, 0); pnode = child0;
break; }
1097 pnode->node_type = GA_NODE_ZERO;
1099 tree.clear_children(pnode);
1104 pnode->t.adjust_sizes(mi);
1105 pnode->test_function_type = child0->test_function_type;
1106 pnode->name_test1 = child0->name_test1;
1107 pnode->name_test2 = child0->name_test2;
1108 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
1109 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
1110 pnode->qdim1 = child0->qdim1;
1111 pnode->qdim2 = child0->qdim2;
1113 pnode->node_type = GA_NODE_CONSTANT;
1114 pnode->test_function_type = 0;
1115 for (
size_type i = 0; i < mi.back(); ++i)
1116 for (
size_type j = 0; j < mi.back(); ++j)
1117 if (pnode->op_type == GA_SYM)
1118 pnode->tensor()(j, i) = 0.5*(child0->tensor()(j,i)
1119 + child0->tensor()(i,j));
1121 pnode->tensor()(j, i) = 0.5*(child0->tensor()(j,i)
1122 - child0->tensor()(i,j));
1123 tree.clear_children(pnode);
1124 }
else if (child0->node_type == GA_NODE_ZERO) {
1125 pnode->node_type = GA_NODE_ZERO;
1127 tree.clear_children(pnode);
1134 size_type N = (child0->tensor_proper_size() == 1) ? 1 : mi.back();
1136 if (child0->tensor_proper_size() == 1)
1137 { tree.replace_node_by_child(pnode, 0); pnode = child0;
break; }
1139 if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
1140 (dim0 == 2 && mi[mi.size()-2] != N))
1141 ga_throw_error(pnode->expr, pnode->pos,
1142 "Trace operator is for square matrices only.");
1144 if (dim0 == 2) { mi.pop_back(); mi.pop_back(); }
1145 pnode->t.adjust_sizes(mi);
1146 pnode->test_function_type = child0->test_function_type;
1147 pnode->name_test1 = child0->name_test1;
1148 pnode->name_test2 = child0->name_test2;
1149 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
1150 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
1151 pnode->qdim1 = child0->qdim1;
1152 pnode->qdim2 = child0->qdim2;
1154 pnode->node_type = GA_NODE_CONSTANT;
1155 pnode->test_function_type = 0;
1157 pnode->tensor()[0] = scalar_type(0);
1159 pnode->tensor()[0] += child0->tensor()(i,i);
1161 pnode->tensor()[0] += child0->tensor()[0];
1163 tree.clear_children(pnode);
1164 }
else if (child0->node_type == GA_NODE_ZERO) {
1165 pnode->node_type = GA_NODE_ZERO;
1167 tree.clear_children(pnode);
1175 size_type N = (child0->tensor_proper_size() == 1) ? 1 : mi.back();
1177 if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
1178 (dim0 == 2 && mi[mi.size()-2] != N))
1179 ga_throw_error(pnode->expr, pnode->pos,
1180 "Deviator operator is for square matrices only.");
1182 if (child0->tensor_proper_size() == 1) {
1183 pnode->node_type = GA_NODE_ZERO;
1185 tree.clear_children(pnode);
1189 pnode->t.adjust_sizes(mi);
1190 pnode->test_function_type = child0->test_function_type;
1191 pnode->name_test1 = child0->name_test1;
1192 pnode->name_test2 = child0->name_test2;
1193 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
1194 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
1195 pnode->qdim1 = child0->qdim1;
1196 pnode->qdim2 = child0->qdim2;
1198 pnode->node_type = GA_NODE_CONSTANT;
1199 pnode->test_function_type = 0;
1203 pnode->tensor().as_vector());
1205 tr += child0->tensor()(i,i);
1207 pnode->tensor()(i,i) -= tr / scalar_type(N);
1209 pnode->tensor()[0] = scalar_type(0);
1211 tree.clear_children(pnode);
1212 }
else if (child0->node_type == GA_NODE_ZERO) {
1213 pnode->node_type = GA_NODE_ZERO;
1215 tree.clear_children(pnode);
1222 pnode->t = child0->t;
1223 pnode->test_function_type = child0->test_function_type;
1224 pnode->name_test1 = child0->name_test1;
1225 pnode->name_test2 = child0->name_test2;
1226 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
1227 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
1228 pnode->qdim1 = child0->qdim1;
1229 pnode->qdim2 = child0->qdim2;
1231 pnode->node_type = GA_NODE_CONSTANT;
1232 cout <<
"Print constant term "; ga_print_node(child0, cout);
1233 cout <<
": " << pnode->tensor() << endl;
1234 tree.clear_children(pnode);
1235 }
else if (child0->node_type == GA_NODE_ZERO) {
1236 pnode->node_type = GA_NODE_ZERO;
1238 cout <<
"Print zero term "; ga_print_node(child0, cout);
1239 cout <<
": " << pnode->tensor() << endl;
1240 tree.clear_children(pnode);
1247 size_type s0 = dim0 == 0 ? 1 : size0.back();
1248 size_type s1 = dim1 == 0 ? 1 : size1[size1.size()-dim1];
1251 ga_throw_error(pnode->expr, pnode->pos,
1252 "Dot product of expressions of different sizes."
1253 <<
"(" << s0 <<
" != " << s1 <<
"). "
1254 <<
" Sizes of operands: " << size0
1255 <<
" and " << size1);
1256 if (dim0 <= 1 && dim1 <= 1) pnode->symmetric_op =
true;
1257 pnode->mult_test(child0, child1);
1258 if (dim0 > 1 || dim1 > 1) {
1259 mi = pnode->t.sizes();
1261 mi.push_back(child0->tensor_proper_size(i-1));
1263 mi.push_back(child1->tensor_proper_size(i));
1264 pnode->t.adjust_sizes(mi);
1267 if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
1269 pnode->node_type = GA_NODE_ZERO;
1270 tree.clear_children(pnode);
1271 }
else if (all_cte) {
1273 size_type m0 = child0->tensor().size() / s0;
1274 size_type m1 = child1->tensor().size() / s1;
1278 pnode->tensor()[i*m1+j]
1279 += child0->tensor()[i*s0+k] * child1->tensor()[k*m1+j];
1280 pnode->node_type = GA_NODE_CONSTANT;
1281 tree.clear_children(pnode);
1289 : (dim0 == 1 ? size0.back() : size0[size0.size()-2]);
1290 size_type s01 = (dim0 >= 2) ? size0.back() : 1;
1291 size_type s10 = (dim1 == 0) ? 1 : child1->tensor_proper_size(0);
1292 size_type s11 = (dim1 < 2) ? 1 : child1->tensor_proper_size(1);
1293 if (s00 != s10 || s01 != s11)
1294 ga_throw_error(pnode->expr, pnode->pos,
"Frobenius product "
1295 "of expressions of different sizes ("
1296 << s00 <<
"," << s01 <<
" != " << s10 <<
","
1298 <<
" Sizes of arguments (last two): " << size0
1299 <<
" and " << size1);
1300 if (child0->tensor_order() <= 2 && child1->tensor_order() <= 2)
1301 pnode->symmetric_op =
true;
1302 pnode->mult_test(child0, child1);
1303 if (dim0 > 2 || dim1 > 2) {
1304 mi = pnode->t.sizes();
1306 mi.push_back(child0->tensor_proper_size(i));
1308 mi.push_back(child1->tensor_proper_size(i));
1309 pnode->t.adjust_sizes(mi);
1312 if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
1314 pnode->node_type = GA_NODE_ZERO;
1315 tree.clear_children(pnode);
1316 }
else if (all_cte) {
1317 pnode->node_type = GA_NODE_CONSTANT;
1320 for (
size_type i = 0, j = 0; i < child0->tensor().size(); ++i) {
1321 pnode->tensor()[j] += child0->tensor()[i] * child1->tensor()[k];
1322 ++j;
if (j == pnode->tensor().size()) { j = 0; ++k; }
1324 GMM_ASSERT1(k == child1->tensor().size(),
"Internal error");
1325 tree.clear_children(pnode);
1332 pnode->node_type = GA_NODE_CONSTANT;
1333 pnode->test_function_type = 0;
1334 if (child0->tensor().size() == 1 && child1->tensor().size() == 1) {
1335 pnode->init_scalar_tensor
1336 (child0->tensor()[0] * child1->tensor()[0]);
1337 }
else if (child0->tensor().size() == 1) {
1338 pnode->t = child1->t;
1339 gmm::scale(pnode->tensor().as_vector(),
1340 scalar_type(child0->tensor()[0]));
1341 }
else if (child1->tensor().size() == 1) {
1342 pnode->t = child0->t;
1343 gmm::scale(pnode->tensor().as_vector(),
1344 scalar_type(child1->tensor()[0]));
1347 ga_throw_error(pnode->expr, pnode->pos,
"Unauthorized "
1348 "tensor multiplication.");
1350 mi.push_back(child0->tensor().size(i));
1352 mi.push_back(child1->tensor().size(i));
1353 pnode->t.adjust_sizes(mi);
1358 pnode->tensor()[i+j*n0]=child0->tensor()[i]*child1->tensor()[j];
1360 tree.clear_children(pnode);
1362 pnode->mult_test(child0, child1);
1363 mi = pnode->t.sizes();
1364 if (child0->tensor_proper_size() != 1
1365 || child1->tensor_proper_size() != 1) {
1366 if (child0->tensor_proper_size() == 1) {
1368 mi.push_back(child1->tensor_proper_size(i));
1369 }
else if (child1->tensor().size() == 1) {
1371 mi.push_back(child0->tensor_proper_size(i));
1374 ga_throw_error(pnode->expr, pnode->pos,
"Unauthorized "
1375 "tensor multiplication.");
1377 mi.push_back(child0->tensor_proper_size(i));
1379 mi.push_back(child1->tensor_proper_size(i));
1381 pnode->t.adjust_sizes(mi);
1383 if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
1385 pnode->node_type = GA_NODE_ZERO;
1386 tree.clear_children(pnode);
1393 pnode->node_type = GA_NODE_CONSTANT;
1394 pnode->test_function_type = 0;
1395 if (child0->tensor_proper_size() == 1 &&
1396 child1->tensor_proper_size() == 1) {
1397 pnode->init_scalar_tensor(child0->tensor()[0]*child1->tensor()[0]);
1398 }
else if (child0->tensor_proper_size() == 1) {
1399 pnode->t = child1->t;
1400 gmm::scale(pnode->tensor().as_vector(), child0->tensor()[0]);
1401 }
else if (child1->tensor_proper_size() == 1) {
1402 pnode->t = child0->t;
1403 gmm::scale(pnode->tensor().as_vector(), child1->tensor()[0]);
1404 }
else if (dim0 == 2 && dim1 == 1) {
1405 size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
1406 if (n != child1->tensor().size(0))
1407 ga_throw_error(pnode->expr, pnode->pos,
1408 "Incompatible sizes in matrix-vector "
1409 "multiplication (" << n <<
" != "
1410 << child1->tensor().size(0) <<
").");
1411 pnode->init_vector_tensor(m);
1415 pnode->tensor()[i] += child0->tensor()(i,j)*child1->tensor()[j];
1416 }
else if (dim0 == 2 && dim1 == 2) {
1420 if (n != child1->tensor().size(0))
1421 ga_throw_error(pnode->expr, pnode->pos,
1422 "Incompatible sizes in matrix-matrix "
1423 "multiplication (" << n <<
" != "
1424 << child1->tensor().size(0) <<
").");
1425 pnode->init_matrix_tensor(m,p);
1430 pnode->tensor()(i,k) += child0->tensor()(i,j)
1431 * child1->tensor()(j,k);
1433 else if (dim0 == 4 && dim1 == 2) {
1434 size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
1435 size_type o=child0->tensor().size(2), p=child0->tensor().size(3);
1436 if (o != child1->tensor().size(0) || p != child1->tensor().size(1))
1437 ga_throw_error(pnode->expr, pnode->pos,
1438 "Incompatible sizes in tensor-matrix "
1439 "multiplication (" << o <<
"," << p <<
" != "
1440 << child1->tensor().size(0) <<
","
1441 << child1->tensor().size(1) <<
").");
1442 pnode->init_matrix_tensor(m,n);
1448 pnode->tensor()(i,j) += child0->tensor()(i,j,k,l)
1449 * child1->tensor()(k,l);
1450 }
else ga_throw_error(pnode->expr, pnode->pos,
1451 "Unauthorized multiplication.");
1452 tree.clear_children(pnode);
1454 pnode->mult_test(child0, child1);
1455 mi = pnode->t.sizes();
1457 if (child0->tensor_proper_size() == 1 &&
1458 child1->tensor_proper_size() == 1) {
1459 pnode->symmetric_op =
true;
1460 }
else if (child0->tensor_proper_size() == 1) {
1461 pnode->symmetric_op =
true;
1463 mi.push_back(child1->tensor_proper_size(i));
1464 }
else if (child1->tensor_proper_size() == 1) {
1465 pnode->symmetric_op =
true;
1467 mi.push_back(child0->tensor_proper_size(i));
1468 }
else if (child0->tensor_order() == 2 &&
1469 child1->tensor_order() == 1) {
1470 size_type m = child0->tensor_proper_size(0);
1471 size_type n = child0->tensor_proper_size(1);
1473 if (n != child1->tensor_proper_size(0))
1474 ga_throw_error(pnode->expr, pnode->pos,
1475 "Incompatible sizes in matrix-vector "
1476 "multiplication (" << n <<
" != "
1477 << child1->tensor_proper_size(0) <<
").");
1478 }
else if (child0->tensor_order() == 2 &&
1479 child1->tensor_order() == 2) {
1480 size_type m = child0->tensor_proper_size(0);
1481 size_type n = child0->tensor_proper_size(1);
1482 size_type p = child1->tensor_proper_size(1);
1483 mi.push_back(m); mi.push_back(p);
1484 if (n != child1->tensor_proper_size(0))
1485 ga_throw_error(pnode->expr, pnode->pos,
1486 "Incompatible sizes in matrix-matrix "
1487 "multiplication (" << n <<
" != "
1488 << child1->tensor_proper_size(0) <<
").");
1490 else if (pnode->children[0]->tensor_order() == 4 &&
1491 pnode->children[1]->tensor_order() == 2) {
1492 size_type m = child0->tensor_proper_size(0);
1493 size_type n = child0->tensor_proper_size(1);
1494 size_type o = child0->tensor_proper_size(2);
1495 size_type p = child0->tensor_proper_size(3);
1496 mi.push_back(m); mi.push_back(n);
1497 if (o != child1->tensor_proper_size(0) ||
1498 p != child1->tensor_proper_size(1))
1499 ga_throw_error(pnode->expr, pnode->pos,
1500 "Incompatible sizes in tensor-matrix "
1501 "multiplication (" << o <<
"," << p <<
" != "
1502 << child1->tensor_proper_size(0) <<
","
1503 << child1->tensor_proper_size(1) <<
").");
1504 }
else ga_throw_error(pnode->expr, pnode->pos,
1505 "Unauthorized multiplication.");
1506 pnode->t.adjust_sizes(mi);
1508 if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
1510 pnode->node_type = GA_NODE_ZERO;
1511 tree.clear_children(pnode);
1512 }
else if (child0->node_type == GA_NODE_CONSTANT &&
1513 child0->tensor().size() == 1 &&
1514 child0->tensor()[0] == scalar_type(1)) {
1515 tree.replace_node_by_child(pnode, 1);
1517 }
else if (child1->node_type == GA_NODE_CONSTANT &&
1518 child1->tensor().size() == 1 &&
1519 child1->tensor()[0] == scalar_type(1)) {
1520 tree.replace_node_by_child(pnode, 0);
1527 if (child1->tensor_proper_size() > 1)
1528 ga_throw_error(pnode->expr, pnode->pos,
1529 "Only the division by a scalar is allowed. "
1530 "Got a size of " << child1->tensor_proper_size());
1531 if (child1->test_function_type)
1532 ga_throw_error(pnode->expr, pnode->pos,
1533 "Division by test functions is not allowed.");
1534 if (child1->node_type == GA_NODE_CONSTANT &&
1535 child1->tensor()[0] == scalar_type(0))
1536 ga_throw_error(pnode->expr, pnode->children[1]->pos,
1537 "Division by zero");
1539 pnode->t = child0->t;
1540 pnode->test_function_type = child0->test_function_type;
1541 pnode->name_test1 = child0->name_test1;
1542 pnode->name_test2 = child0->name_test2;
1543 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
1544 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
1545 pnode->qdim1 = child0->qdim1;
1546 pnode->qdim2 = child0->qdim2;
1549 pnode->node_type = GA_NODE_CONSTANT;
1550 pnode->t = pnode->children[0]->t;
1551 pnode->test_function_type = 0;
1552 gmm::scale(pnode->tensor().as_vector(),
1553 scalar_type(1) / pnode->children[1]->tensor()[0]);
1554 tree.clear_children(pnode);
1555 }
else if (child0->tensor_is_zero()) {
1557 pnode->node_type = GA_NODE_ZERO;
1558 tree.clear_children(pnode);
1559 }
else if (child1->node_type == GA_NODE_CONSTANT &&
1560 child1->tensor().size() == 1 &&
1561 child1->tensor()[0] == scalar_type(1)) {
1562 tree.replace_node_by_child(pnode, 0);
1567 default:GMM_ASSERT1(
false,
"Unexpected operation. Internal error.");
1571 case GA_NODE_C_MATRIX:
1573 if (!all_sc) ga_throw_error(pnode->expr, pnode->pos,
1574 "Constant vector/matrix/tensor "
1575 "components should be scalar valued.");
1576 GMM_ASSERT1(pnode->children.size() == pnode->tensor_proper_size(),
1579 pnode->test_function_type = 0;
1580 for (
size_type i = 0; i < pnode->children.size(); ++i) {
1581 if (pnode->children[i]->test_function_type) {
1582 if (pnode->test_function_type == 0) {
1583 pnode->test_function_type=pnode->children[i]->test_function_type;
1584 pnode->name_test1 = pnode->children[i]->name_test1;
1585 pnode->name_test2 = pnode->children[i]->name_test2;
1586 pnode->interpolate_name_test1
1587 = pnode->children[i]->interpolate_name_test1;
1588 pnode->interpolate_name_test2
1589 = pnode->children[i]->interpolate_name_test2;
1590 pnode->qdim1 = pnode->children[i]->qdim1;
1591 pnode->qdim2 = pnode->children[i]->qdim2;
1593 if (pnode->test_function_type !=
1594 pnode->children[i]->test_function_type ||
1595 pnode->name_test1.compare(pnode->children[i]->name_test1) ||
1596 pnode->name_test2.compare(pnode->children[i]->name_test2) ||
1597 pnode->interpolate_name_test1.compare
1598 (pnode->children[i]->interpolate_name_test1) ||
1599 pnode->interpolate_name_test2.compare
1600 (pnode->children[i]->interpolate_name_test2))
1601 ga_throw_error(pnode->expr, pnode->pos,
"Inconsistent use of "
1602 "test function in constant matrix.");
1606 int to_add = int(pnode->nb_test_functions() + pnode->nbc1)
1607 - int(pnode->tensor().sizes().size());
1608 GMM_ASSERT1(to_add >= 0 && to_add <= 2,
"Internal error");
1610 mi = pnode->tensor().sizes();
1611 mi.resize(pnode->nbc1+pnode->nb_test_functions());
1612 for (
int i =
int(mi.size()-1); i >= to_add; --i)
1613 mi[i] = mi[i-to_add];
1614 for (
int i = 0; i < to_add; ++i)
1617 if (pnode->test_function_type & 1) {
1618 const mesh_fem *mf1 = workspace.associated_mf(pnode->name_test1);
1619 const im_data *imd1 = workspace.associated_im_data(pnode->name_test1);
1620 if (mf1 == 0 && imd1 == 0)
1621 mi[0] = gmm::vect_size(workspace.value(pnode->name_test1));
1623 mi[0] = workspace.qdim(pnode->name_test1);
1625 if (pnode->test_function_type & 2) {
1626 const mesh_fem *mf2 = workspace.associated_mf(pnode->name_test2);
1627 const im_data *imd2 = workspace.associated_im_data(pnode->name_test2);
1628 if (mf2 == 0 && imd2 == 0)
1629 mi[(pnode->test_function_type & 1) ? 1 : 0]
1630 = gmm::vect_size(workspace.value(pnode->name_test2));
1632 mi[(pnode->test_function_type & 1) ? 1 : 0]
1633 = workspace.qdim(pnode->name_test2);
1635 pnode->tensor().adjust_sizes(mi);
1639 bool all_zero =
true;
1640 for (
size_type i = 0; i < pnode->children.size(); ++i) {
1641 pnode->tensor()[i] = pnode->children[i]->tensor()[0];
1642 if (pnode->tensor()[i] != scalar_type(0)) all_zero =
false;
1645 pnode->node_type = GA_NODE_ZERO;
1647 pnode->node_type = GA_NODE_CONSTANT;
1648 tree.clear_children(pnode);
1656 std::string name = pnode->name;
1658 if (!ignore_X && !(name.compare(
"X"))) {
1659 pnode->node_type = GA_NODE_X;
1661 pnode->init_vector_tensor(meshdim);
1664 if (!(name.compare(
"Diff"))) {
1665 pnode->test_function_type = 0;
1668 if (!(name.compare(
"Grad"))) {
1669 pnode->test_function_type = 0;
1672 if (!(name.compare(
"element_size"))) {
1673 pnode->node_type = GA_NODE_ELT_SIZE;
1674 pnode->init_scalar_tensor(0);
1677 if (!(name.compare(
"Cross_product"))) {
1678 pnode->node_type = GA_NODE_CROSS_PRODUCT;
1679 pnode->test_function_type = 0;
1682 if (!(name.compare(
"element_K"))) {
1683 pnode->node_type = GA_NODE_ELT_K;
1684 if (ref_elt_dim == 1)
1685 pnode->init_vector_tensor(meshdim);
1687 pnode->init_matrix_tensor(meshdim, ref_elt_dim);
1690 if (!(name.compare(
"element_B"))) {
1691 pnode->node_type = GA_NODE_ELT_B;
1692 pnode->init_matrix_tensor(ref_elt_dim, meshdim);
1695 if (!(name.compare(
"Normal"))) {
1696 pnode->node_type = GA_NODE_NORMAL;
1697 pnode->init_vector_tensor(meshdim);
1700 if (!(name.compare(
"Reshape"))) {
1701 pnode->node_type = GA_NODE_RESHAPE;
1702 pnode->init_scalar_tensor(0);
1705 if (!(name.compare(
"Swap_indices"))) {
1706 pnode->node_type = GA_NODE_SWAP_IND;
1707 pnode->init_scalar_tensor(0);
1710 if (!(name.compare(
"Index_move_last"))) {
1711 pnode->node_type = GA_NODE_IND_MOVE_LAST;
1712 pnode->init_scalar_tensor(0);
1715 if (!(name.compare(
"Contract"))) {
1716 pnode->node_type = GA_NODE_CONTRACT;
1717 pnode->init_scalar_tensor(0);
1721 if (name.compare(0, 11,
"Derivative_") == 0) {
1722 name = name.substr(11);
1724 pnode->der1 = 1; pnode->der2 = 0;
1726 size_type d = strtol(name.c_str(), &p, 10);
1730 if (name[s] !=
'_') valid =
false;
else
1731 name = name.substr(s+1);
1733 d = strtol(name.c_str(), &p, 10);
1734 s = p - name.c_str();
1737 if (name[s] !=
'_') valid =
false;
else
1738 name = name.substr(s+1);
1740 if (!valid || pnode->der1 == 0)
1741 ga_throw_error(pnode->expr, pnode->pos,
"Invalid derivative format");
1744 ga_predef_function_tab::const_iterator it=PREDEF_FUNCTIONS.find(name);
1745 if (it != PREDEF_FUNCTIONS.end()) {
1747 pnode->node_type = GA_NODE_PREDEF_FUNC;
1749 pnode->test_function_type = 0;
1751 if (pnode->der1 > it->second.nbargs()
1752 || pnode->der2 > it->second.nbargs())
1753 ga_throw_error(pnode->expr, pnode->pos,
"Invalid derivative.");
1754 const ga_predef_function &F = it->second;
1755 if ((F.ftype() == 0 || F.dtype() == 2) && !(pnode->der2)) {
1756 pnode->name = ((pnode->der1 == 1) ?
1757 F.derivative1() : F.derivative2());
1758 pnode->der1 = pnode->der2 = 0;
1761 }
else if (SPEC_FUNCTIONS.find(name) != SPEC_FUNCTIONS.end()) {
1764 ga_throw_error(pnode->expr, pnode->pos,
"Special functions do not "
1765 "support derivatives.");
1766 pnode->node_type = GA_NODE_SPEC_FUNC;
1768 pnode->test_function_type = 0;
1769 if (!name.compare(
"pi")) {
1770 pnode->node_type = GA_NODE_CONSTANT;
1771 pnode->init_scalar_tensor(M_PI);
1772 }
else if (!name.compare(
"meshdim")) {
1773 pnode->node_type = GA_NODE_CONSTANT;
1774 pnode->init_scalar_tensor(scalar_type(meshdim));
1775 }
else if (!name.compare(
"timestep")) {
1776 pnode->node_type = GA_NODE_CONSTANT;
1777 pnode->init_scalar_tensor(scalar_type(workspace.get_time_step()));
1779 }
else if (PREDEF_OPERATORS.tab.find(name)
1780 != PREDEF_OPERATORS.tab.end()) {
1782 pnode->node_type = GA_NODE_OPERATOR;
1784 pnode->test_function_type = 0;
1789 size_type prefix_id = ga_parse_prefix_operator(name);
1790 size_type test = ga_parse_prefix_test(name);
1792 if (!(workspace.variable_exists(name)))
1793 ga_throw_error(pnode->expr, pnode->pos,
"Unknown variable, "
1794 "function, operator or data \"" + name +
"\"");
1797 ga_throw_error(pnode->expr, pnode->pos,
"Derivative is for "
1798 "functions or operators, not for variables. "
1799 "Use Grad instead.");
1802 const mesh_fem *mf = workspace.associated_mf(name);
1803 const im_data *imd = workspace.associated_im_data(name);
1805 if (test && workspace.is_constant(name) &&
1806 !(workspace.is_disabled_variable(name)))
1807 ga_throw_error(pnode->expr, pnode->pos,
"Test functions of "
1808 "constants are not allowed.");
1810 pnode->name_test1 = name;
1811 pnode->interpolate_name_test1 =
"";
1813 workspace.test1.insert
1814 (var_trans_pair(pnode->name_test1,
1815 pnode->interpolate_name_test1));
1816 pnode->qdim1 = (mf || imd) ? workspace.qdim(name)
1817 : gmm::vect_size(workspace.value(name));
1818 if (!(pnode->qdim1))
1819 ga_throw_error(pnode->expr, pnode->pos,
1820 "Invalid null size of variable");
1821 }
else if (test == 2) {
1822 pnode->name_test2 = name;
1823 pnode->interpolate_name_test2 =
"";
1825 workspace.test2.insert
1826 (var_trans_pair(pnode->name_test2,
1827 pnode->interpolate_name_test2));
1828 pnode->qdim2 = (mf || imd) ? workspace.qdim(name)
1829 : gmm::vect_size(workspace.value(name));
1830 if (!(pnode->qdim2))
1831 ga_throw_error(pnode->expr, pnode->pos,
1832 "Invalid null size of variable");
1837 ga_throw_error(pnode->expr, pnode->pos,
"Gradient, Hessian or "
1838 "Divergence cannot be evaluated for fixed size data.");
1840 pnode->node_type = GA_NODE_VAL_TEST;
1841 else if (eval_fixed_size)
1842 pnode->node_type = GA_NODE_CONSTANT;
1844 pnode->node_type = GA_NODE_VAL;
1846 size_type q = gmm::vect_size(workspace.value(name));
1849 pnode->init_vector_tensor(1);
1850 pnode->tensor()[0] = scalar_type(1);
1853 pnode->init_scalar_tensor(workspace.value(name)[0]);
1856 pnode->init_identity_matrix_tensor(q);
1858 pnode->t.adjust_sizes(workspace.qdims(name));
1859 gmm::copy(workspace.value(name), pnode->tensor().as_vector());
1864 bgeot::multi_index mii = workspace.qdims(name);
1866 if (!q) ga_throw_error(pnode->expr, pnode->pos,
1867 "Invalid null size of variable " << name);
1869 ga_throw_error(pnode->expr, pnode->pos,
1870 "Tensor with too many dimensions. Limited to 6");
1872 ga_throw_error(pnode->expr, pnode->pos,
"Gradient, Hessian or "
1873 "Divergence cannot be evaluated for im data.");
1875 pnode->node_type = test ? GA_NODE_VAL_TEST : GA_NODE_VAL;
1878 if (q == 1 && mii.size() <= 1) {
1879 pnode->init_vector_tensor(1);
1880 pnode->tensor()[0] = scalar_type(1);
1882 mii.insert(mii.begin(), q);
1883 pnode->t.set_to_original();
1884 pnode->t.adjust_sizes(mii);
1885 auto itw = pnode->tensor().begin();
1888 *itw++ = (i == j) ? scalar_type(1) : scalar_type(0);
1891 pnode->t.adjust_sizes(mii);
1895 bgeot::multi_index mii = workspace.qdims(name);
1897 if (!q) ga_throw_error(pnode->expr, pnode->pos,
1898 "Invalid null size of variable " << name);
1900 ga_throw_error(pnode->expr, pnode->pos,
1901 "Tensor with too many dimensions. Limited to 6");
1903 switch (prefix_id) {
1905 pnode->node_type = test ? GA_NODE_VAL_TEST : GA_NODE_VAL;
1908 if (test && q == 1 && mii.size() <= 1) {
1912 mii.insert(mii.begin(), 2);
1915 pnode->node_type = test ? GA_NODE_GRAD_TEST : GA_NODE_GRAD;
1917 if (q == 1 && mii.size() <= 1) {
1921 mii.insert(mii.begin(), 2);
1924 if (mii.size() == 1 && mii[0] == 1) mii[0] = n;
1925 else mii.push_back(n);
1929 pnode->node_type = test ? GA_NODE_HESS_TEST : GA_NODE_HESS;
1931 if (q == 1 && mii.size() <= 1) {
1935 mii.insert(mii.begin(), 2);
1938 if (mii.size() == 1 && mii[0] == 1) mii[0] = n;
1939 else mii.push_back(n);
1944 pnode->node_type = test ? GA_NODE_DIVERG_TEST : GA_NODE_DIVERG;
1946 ga_throw_error(pnode->expr, pnode->pos,
1947 "Divergence operator can only be applied to"
1948 "Fields with qdim (" << q <<
") equal to dim ("
1951 mii[0] = test ? 2 : 1;
1954 pnode->t.adjust_sizes(mii);
1956 pnode->test_function_type = test;
1961 case GA_NODE_PARAMS:
1964 if (child0->node_type == GA_NODE_NAME) {
1965 if (child0->name.compare(
"Grad") == 0) {
1966 # ifdef GA_PRINT_DEBUG_INFO
1967 cout <<
"Compute gradient of ";ga_print_node(child1,cout);cout<<endl;
1969 if (pnode->children.size() != 2)
1970 ga_throw_error(pnode->expr, child0->pos,
1971 "Bad number of parameters for Grad operator");
1972 if (ga_node_mark_tree_for_grad(child1, workspace)) {
1973 ga_node_grad(tree, workspace, me, child1);
1974 ga_node_analysis(tree, workspace, pnode->children[1], me,
1975 ref_elt_dim, eval_fixed_size, ignore_X, option);
1976 child1 = pnode->children[1];
1978 mi = child1->t.sizes(); mi.push_back(meshdim);
1979 child1->t.adjust_sizes(mi);
1980 child1->node_type = GA_NODE_ZERO;
1982 tree.clear_children(child1);
1984 tree.replace_node_by_child(pnode, 1);
1986 }
else if (child0->name.compare(
"Diff") == 0) {
1988 if (pnode->children.size() != 3 && pnode->children.size() != 4)
1989 ga_throw_error(pnode->expr, child0->pos,
1990 "Bad number of parameters for Diff operator");
1991 pga_tree_node child2 = pnode->children[2];
1992 if (child2->node_type != GA_NODE_VAL)
1993 ga_throw_error(pnode->expr, child2->pos,
"Second parameter of "
1994 "Diff operator has to be a variable name");
1995 std::string vardiff = child2->name;
1996 size_type order = child1->test_function_type;
1998 ga_throw_error(pnode->expr, child2->pos,
"Cannot derive further "
1999 "this order two expression");
2001 if (ga_node_mark_tree_for_variable(child1, workspace, me,
2002 vardiff,
"",
true)) {
2003 ga_node_derivation(tree, workspace, me, child1,
2004 vardiff,
"", order+1,
true);
2005 child1 = pnode->children[1];
2006 ga_node_analysis(tree, workspace, child1, me, ref_elt_dim,
2007 eval_fixed_size, ignore_X, option);
2008 child1 = pnode->children[1];
2010 mi = child1->t.sizes(); mi.insert(mi.begin(), 2);
2011 child1->t.adjust_sizes(mi);
2012 child1->node_type = GA_NODE_ZERO;
2013 child1->test_function_type = order ? 3 : 1;
2015 tree.clear_children(child1);
2017 if (pnode->children.size() == 4) {
2018 ga_tree grad_expr, hess_expr;
2019 ga_node_expand_expression_in_place_of_test
2020 (tree, workspace, pnode->children[1], vardiff, pnode->children[3],
2021 grad_expr, hess_expr, order+1, me, ref_elt_dim, eval_fixed_size,
2023 ga_node_analysis(tree, workspace, pnode->children[1], me,
2024 ref_elt_dim, eval_fixed_size, ignore_X, option);
2026 child1 = pnode->children[1];
2027 tree.replace_node_by_child(pnode, 1);
2030 ga_throw_error(pnode->expr, child0->pos,
"Unknown special operator");
2034 else if (child0->node_type == GA_NODE_X) {
2035 child0->init_scalar_tensor(0);
2036 if (pnode->children.size() != 2)
2037 ga_throw_error(pnode->expr, child1->pos,
2038 "X stands for the coordinates on "
2039 "the real elements. It accepts only one index.");
2040 if (!(child1->node_type == GA_NODE_CONSTANT) ||
2041 child1->tensor().size() != 1)
2042 ga_throw_error(pnode->expr, child1->pos,
2043 "Index for X has to be constant and of size 1.");
2044 child0->nbc1 =
size_type(round(child1->tensor()[0]));
2045 if (child0->nbc1 == 0 || child0->nbc1 > meshdim)
2046 ga_throw_error(pnode->expr, child1->pos,
"Index for X not convenient. "
2047 "Found " << child0->nbc1 <<
" with meshdim = "
2049 tree.replace_node_by_child(pnode, 0);
2054 else if (child0->node_type == GA_NODE_RESHAPE) {
2055 if (pnode->children.size() < 3)
2056 ga_throw_error(pnode->expr, child1->pos,
2057 "Not enough parameters for Reshape");
2058 if (pnode->children.size() > 12)
2059 ga_throw_error(pnode->expr, child1->pos,
2060 "Too many parameters for Reshape");
2061 pnode->t = child1->t;
2062 pnode->test_function_type = child1->test_function_type;
2063 pnode->name_test1 = child1->name_test1;
2064 pnode->name_test2 = child1->name_test2;
2065 pnode->interpolate_name_test1 = child1->interpolate_name_test1;
2066 pnode->interpolate_name_test2 = child1->interpolate_name_test2;
2067 pnode->qdim1 = child1->qdim1;
2068 pnode->qdim2 = child1->qdim2;
2070 for (
size_type i = 0; i < pnode->nb_test_functions(); ++i)
2071 mi.push_back(size1[i]);
2073 for (
size_type i = 2; i < pnode->children.size(); ++i) {
2074 if (pnode->children[i]->node_type != GA_NODE_CONSTANT)
2075 ga_throw_error(pnode->expr, pnode->children[i]->pos,
"Reshape sizes "
2076 "should be constant positive integers.");
2077 mi.push_back(
size_type(round(pnode->children[i]->tensor()[0])));
2079 ga_throw_error(pnode->expr, pnode->children[i]->pos,
2080 "Wrong zero size for Reshape.");
2083 for (
size_type i = pnode->nb_test_functions(); i < mi.size(); ++i)
2084 total_size *= mi[i];
2085 if (total_size != pnode->tensor_proper_size())
2086 ga_throw_error(pnode->expr, pnode->pos,
"Invalid sizes for reshape, "
2087 "found a total of " << total_size <<
" should be " <<
2088 pnode->tensor_proper_size() <<
".");
2089 pnode->t.adjust_sizes(mi);
2091 if (child1->node_type == GA_NODE_CONSTANT) {
2092 pnode->node_type = GA_NODE_CONSTANT;
2093 tree.clear_children(pnode);
2094 }
else if (child1->node_type == GA_NODE_ZERO) {
2095 pnode->node_type = GA_NODE_ZERO;
2096 tree.clear_children(pnode);
2101 else if (child0->node_type == GA_NODE_CROSS_PRODUCT) {
2102 if (pnode->children.size() != 3)
2103 ga_throw_error(pnode->expr, child1->pos,
2104 "Wrong number of parameters for Cross_product");
2105 pga_tree_node child2 = pnode->children[2];
2107 if (
false && child1->is_constant() && child2->is_constant()) {
2108 pnode->node_type = GA_NODE_CONSTANT;
2109 pnode->test_function_type = 0;
2110 if (child1->tensor_proper_size() != 3 ||
2111 child2->tensor_proper_size() != 3)
2112 ga_throw_error(pnode->expr, child1->pos,
"Cross_product is only "
2113 "defined on three-dimensional vectors");
2114 pnode->t = child1->t;
2115 base_tensor &t0 = pnode->tensor();
2116 base_tensor &t1 = child1->tensor(), &t2 = child2->tensor();
2117 t0[0] = t1[1]*t2[2] - t1[2]*t2[1];
2118 t0[1] = t1[2]*t2[0] - t1[0]*t2[2];
2119 t0[2] = t1[0]*t2[1] - t1[1]*t2[0];
2120 if (pnode->tensor_is_zero())
2121 pnode->node_type = GA_NODE_ZERO;
2122 tree.clear_children(pnode);
2124 pnode->mult_test(child1, child2);
2125 mi = pnode->t.sizes();
2127 pnode->t.adjust_sizes(mi);
2132 else if (child0->node_type == GA_NODE_SWAP_IND) {
2133 if (pnode->children.size() != 4)
2134 ga_throw_error(pnode->expr, child1->pos,
2135 "Wrong number of parameters for Swap_indices");
2136 pnode->t = child1->t;
2137 pnode->test_function_type = child1->test_function_type;
2138 pnode->name_test1 = child1->name_test1;
2139 pnode->name_test2 = child1->name_test2;
2140 pnode->interpolate_name_test1 = child1->interpolate_name_test1;
2141 pnode->interpolate_name_test2 = child1->interpolate_name_test2;
2142 pnode->qdim1 = child1->qdim1;
2143 pnode->qdim2 = child1->qdim2;
2147 if (pnode->children[i]->node_type != GA_NODE_CONSTANT ||
2148 pnode->children[i]->tensor().size() != 1)
2149 ga_throw_error(pnode->expr, pnode->children[i]->pos,
"Indices "
2150 "for swap should be constant positive integers.");
2151 ind[i] =
size_type(round(pnode->children[i]->tensor()[0]));
2152 if (ind[i] < 1 || ind[i] > child1->tensor_proper_size())
2153 ga_throw_error(pnode->expr, pnode->children[i]->pos,
"Index "
2154 "out of range for Swap_indices.");
2157 if (ind[2] == ind[3]) {
2158 tree.replace_node_by_child(pnode, 1);
2161 mi = pnode->tensor().sizes();
2162 size_type nbtf = child1->nb_test_functions();
2163 std::swap(mi[ind[2]+nbtf], mi[ind[3]+nbtf]);
2164 pnode->t.adjust_sizes(mi);
2166 if (child1->node_type == GA_NODE_CONSTANT) {
2167 pnode->node_type = GA_NODE_CONSTANT;
2168 if (ind[2] > ind[3]) std::swap(ind[2], ind[3]);
2170 for (
size_type i = 0; i < child1->tensor_order(); ++i) {
2171 if (i<ind[2]) ii1 *= child1->tensor_proper_size(i);
2172 if (i>ind[2] && i<ind[3]) ii2 *= child1->tensor_proper_size(i);
2173 if (i>ind[3]) ii3 *= child1->tensor_proper_size(i);
2175 size_type nn1 = child1->tensor_proper_size(ind[2]);
2176 size_type nn2 = child1->tensor_proper_size(ind[3]);
2177 auto it = pnode->tensor().begin();
2182 for (
size_type m = 0; m < ii1; ++m, ++it)
2183 *it = child0->tensor()[m+j*ii1+k*ii1*nn1+l*ii1*nn1*ii2+
2185 tree.clear_children(pnode);
2186 }
else if (child1->node_type == GA_NODE_ZERO) {
2187 pnode->node_type = GA_NODE_ZERO;
2188 tree.clear_children(pnode);
2194 else if (child0->node_type == GA_NODE_IND_MOVE_LAST) {
2195 if (pnode->children.size() != 3)
2196 ga_throw_error(pnode->expr, child1->pos,
2197 "Wrong number of parameters for Index_move_last");
2198 pnode->t = child1->t;
2199 pnode->test_function_type = child1->test_function_type;
2200 pnode->name_test1 = child1->name_test1;
2201 pnode->name_test2 = child1->name_test2;
2202 pnode->interpolate_name_test1 = child1->interpolate_name_test1;
2203 pnode->interpolate_name_test2 = child1->interpolate_name_test2;
2204 pnode->qdim1 = child1->qdim1;
2205 pnode->qdim2 = child1->qdim2;
2208 if (pnode->children[2]->node_type != GA_NODE_CONSTANT ||
2209 pnode->children[2]->tensor().size() != 1)
2210 ga_throw_error(pnode->expr, pnode->children[2]->pos,
"Index for "
2211 "Index_move_last should be constant positive integers.");
2212 ind =
size_type(round(pnode->children[2]->tensor()[0]));
2213 if (ind < 1 || ind > child1->tensor_proper_size())
2214 ga_throw_error(pnode->expr, pnode->children[2]->pos,
"Index "
2215 "out of range for Index_move_last.");
2217 if (ind == child1->tensor_order()) {
2218 tree.replace_node_by_child(pnode, 1);
2221 mi = pnode->tensor().sizes();
2222 size_type nbtf = child1->nb_test_functions();
2223 for (
size_type i = ind; i < child1->tensor_order(); ++i)
2224 std::swap(mi[i-1+nbtf], mi[i+nbtf]);
2225 pnode->t.adjust_sizes(mi);
2227 if (child1->node_type == GA_NODE_CONSTANT) {
2228 pnode->node_type = GA_NODE_CONSTANT;
2231 for (
size_type i = 0; i < child1->tensor_order(); ++i) {
2232 if (i<ind) ii1 *= child1->tensor_proper_size(i);
2233 if (i>ind) ii2 *= child1->tensor_proper_size(i);
2235 size_type nn = child1->tensor_proper_size(ind);
2236 auto it = pnode->tensor().begin();
2239 for (
size_type k = 0; k < ii1; ++k, ++it)
2240 *it = child0->tensor()[k+i*ii1+j*ii1*nn];
2241 tree.clear_children(pnode);
2242 }
else if (child1->node_type == GA_NODE_ZERO) {
2243 pnode->node_type = GA_NODE_ZERO;
2244 tree.clear_children(pnode);
2250 else if (child0->node_type == GA_NODE_CONTRACT) {
2251 std::vector<size_type> ind(2), indsize(2);
2252 if (pnode->children.size() == 4)
2253 { ind[0] = 2; ind[1] = 3; }
2254 else if (pnode->children.size() == 5)
2255 { ind[0] = 2; ind[1] = 4; }
2256 else if (pnode->children.size() == 7) {
2259 ind[0] = 2; ind[1] = 3; ind[2] = 5; ind[3] = 6;
2263 for (
size_type i = 1; i < pnode->children.size(); ++i) {
2265 if (pnode->children[i]->node_type != GA_NODE_CONSTANT ||
2266 pnode->children[i]->tensor().size() != 1)
2267 ga_throw_error(pnode->children[i]->expr, pnode->children[i]->pos,
2268 "Invalid parameter for Contract. "
2269 "Should be an index number.");
2270 ind[kk] =
size_type(round(pnode->children[i]->tensor()[0]));
2271 order = pnode->children[ll]->tensor_order();
2272 if (ind[kk] < 1 || ind[kk] > order)
2273 ga_throw_error(pnode->children[i]->expr, pnode->children[i]->pos,
2274 "Parameter out of range for Contract (should be "
2275 "between 1 and " << order <<
")");
2277 indsize[kk] = pnode->children[ll]->tensor_proper_size(ind[kk]);
2278 if (kk >= ind.size()/2 && indsize[kk] != indsize[kk-ind.size()/2])
2279 ga_throw_error(child0->expr, child0->pos,
2280 "Invalid parameters for Contract. Cannot "
2281 "contract on indices of different sizes");
2286 if (pnode->children.size() == 4) {
2288 pnode->test_function_type = child1->test_function_type;
2289 pnode->name_test1 = child1->name_test1;
2290 pnode->name_test2 = child1->name_test2;
2291 pnode->interpolate_name_test1 = child1->interpolate_name_test1;
2292 pnode->interpolate_name_test2 = child1->interpolate_name_test2;
2293 pnode->qdim1 = child1->qdim1;
2294 pnode->qdim2 = child1->qdim2;
2298 ga_throw_error(child0->expr, child0->pos,
2299 "Invalid parameters for Contract. Repeated index.");
2302 for (
size_type i = 0; i < pnode->nb_test_functions(); ++i)
2303 mi.push_back(size1[i]);
2305 if (i != i1 && i != i2)
2306 mi.push_back(child1->tensor_proper_size(i));
2307 pnode->t.adjust_sizes(mi);
2309 if (child1->node_type == GA_NODE_CONSTANT) {
2311 if (i1 > i2) std::swap(i1, i2);
2315 if (i < i1) ii1 *= child1->tensor_proper_size(i);
2316 if (i > i1 && i < i2) ii2 *= child1->tensor_proper_size(i);
2317 if (i > i2) ii3 *= child1->tensor_proper_size(i);
2320 auto it = pnode->tensor().begin();
2323 for (
size_type k = 0; k < ii1; ++k, ++it) {
2324 *it = scalar_type(0);
2325 size_type pre_ind = k+j*ii1*nn+i*ii1*nn*ii2*nn;
2327 *it += child1->tensor()[pre_ind+n*ii1+n*ii1*nn*ii2];
2330 pnode->node_type = GA_NODE_CONSTANT;
2331 tree.clear_children(pnode);
2332 }
else if (child1->node_type == GA_NODE_ZERO) {
2333 pnode->node_type = GA_NODE_ZERO;
2334 tree.clear_children(pnode);
2337 }
else if (pnode->children.size() == 5) {
2339 pga_tree_node child2 = pnode->children[3];
2340 pnode->mult_test(child1, child2);
2343 mi = pnode->tensor().sizes();
2345 if (i != i1) mi.push_back(child1->tensor_proper_size(i));
2347 if (i != i2) mi.push_back(child2->tensor_proper_size(i));
2348 pnode->t.adjust_sizes(mi);
2350 if (child1->node_type == GA_NODE_CONSTANT &&
2351 child2->node_type == GA_NODE_CONSTANT) {
2352 size_type ii1 = 1, ii2 = 1, ii3 = 1, ii4 = 1;
2355 if (i < i1) ii1 *= child1->tensor_proper_size(i);
2356 if (i > i1) ii2 *= child1->tensor_proper_size(i);
2359 if (i < i2) ii3 *= child2->tensor_proper_size(i);
2360 if (i > i2) ii4 *= child2->tensor_proper_size(i);
2363 auto it = pnode->tensor().begin();
2367 for (
size_type l = 0; l < ii1; ++l, ++it) {
2368 *it = scalar_type(0);
2370 *it += child1->tensor()[l+n*ii1+k*ii1*nn]
2371 * child2->tensor()[j+n*ii3+i*ii3*nn];
2374 }
else if (child1->tensor_is_zero() || child2->tensor_is_zero()) {
2375 pnode->node_type = GA_NODE_ZERO;
2376 tree.clear_children(pnode);
2379 }
else if (pnode->children.size() == 7) {
2381 pga_tree_node child2 = pnode->children[4];
2382 pnode->mult_test(child1, child2);
2383 if (ind[0] == ind[1] || ind[2] == ind[3])
2384 ga_throw_error(child0->expr, child0->pos,
2385 "Invalid parameters for Contract. Repeated index.");
2387 size_type i1 = ind[0], i2 = ind[1], i3 = ind[2], i4 = ind[3];
2388 mi = pnode->tensor().sizes();
2390 if (i != i1 && i != i2) mi.push_back(child1->tensor_proper_size(i));
2392 if (i != i3 && i != i4) mi.push_back(child2->tensor_proper_size(i));
2393 pnode->t.adjust_sizes(mi);
2395 if (child1->tensor_is_zero() || child2->tensor_is_zero()) {
2396 pnode->node_type = GA_NODE_ZERO;
2397 tree.clear_children(pnode);
2398 }
else if (child1->node_type == GA_NODE_CONSTANT &&
2399 child2->node_type == GA_NODE_CONSTANT) {
2400 size_type nn1 = indsize[0], nn2 = indsize[1];
2402 { std::swap(i1, i2); std::swap(i3, i4); std::swap(nn1, nn2); }
2404 size_type ii1 = 1, ii2 = 1, ii3 = 1, ii4 = 1, ii5 = 1, ii6 = 1;
2406 if (i < i1) ii1 *= child1->tensor_proper_size(i);
2407 if (i > i1 && i < i2) ii2 *= child1->tensor_proper_size(i);
2408 if (i > i2) ii3 *= child1->tensor_proper_size(i);
2411 if (i < i3 && i < i4) ii4 *= child2->tensor_proper_size(i);
2412 if ((i > i3 && i < i4) || (i > i4 && i < i3))
2413 ii5 *= child2->tensor_proper_size(i);
2414 if (i > i3 && i > i4) ii6 *= child2->tensor_proper_size(i);
2417 auto it = pnode->tensor().begin();
2419 if (i3 < i4) std::swap(m1, m2);
2425 for (
size_type p = 0; p < ii1; ++p, ++it) {
2426 *it = scalar_type(0);
2427 size_type q1 = p+m*ii1*nn1+l*ii1*nn1*ii2*nn2;
2428 size_type q2 = k+j*ii4*nn1+i*ii4*nn1*ii5*nn2;
2431 *it += child1->tensor()[q1+n1*ii1+n2*ii1*nn1*ii2]
2432 * child2->tensor()[q2+n1*m1+n2*m2];
2436 ga_throw_error(pnode->expr, child1->pos,
2437 "Wrong number of parameters for Contract");
2441 else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
2443 for (
size_type i = 1; i < pnode->children.size(); ++i)
2444 ga_valid_operand(pnode->children[i]);
2445 std::string name = child0->name;
2446 ga_predef_function_tab::const_iterator it = PREDEF_FUNCTIONS.find(name);
2447 const ga_predef_function &F = it->second;
2449 if (nbargs+1 != pnode->children.size()) {
2450 ga_throw_error(pnode->expr, pnode->pos,
"Bad number of arguments "
2451 "for predefined function " << name <<
". Found "
2452 << pnode->children.size()-1 <<
", should be "<<nbargs <<
".");
2454 pnode->test_function_type = 0;
2455 pga_tree_node child2 = (nbargs == 2) ? pnode->children[2] : child1;
2456 all_cte = child1->node_type == GA_NODE_CONSTANT;
2458 all_cte = all_cte && (child2->node_type == GA_NODE_CONSTANT);
2459 if (child1->test_function_type || child2->test_function_type)
2460 ga_throw_error(pnode->expr, pnode->pos,
"Test functions cannot be "
2461 "passed as argument of a predefined function.");
2466 size_type s2 = (nbargs == 2) ? child2->tensor().size() : s1;
2467 if (s1 != s2 && (s1 != 1 || s2 != 1))
2468 ga_throw_error(pnode->expr, pnode->pos,
2469 "Invalid argument size for a scalar function. "
2470 "Size of first argument: " << s1 <<
2471 ". Size of second argument: " << s2 <<
".");
2474 pnode->t = child1->t;
2477 pnode->t = child1->t;
2478 }
else if (s1 == 1) {
2479 pnode->t = child2->t;
2481 pnode->t = child1->t;
2487 GMM_ASSERT1(
false,
"Sorry, to be done");
2488 pnode->node_type = GA_NODE_CONSTANT;
2491 pnode->tensor()[i] = F(child1->tensor()[i]);
2495 pnode->tensor()[i] = F(child1->tensor()[i],
2496 child2->tensor()[i]);
2497 }
else if (s1 == 1) {
2499 pnode->tensor()[i] = F(child1->tensor()[0],
2500 child2->tensor()[i]);
2503 pnode->tensor()[i] = F(child1->tensor()[i],
2504 child2->tensor()[0]);
2507 tree.clear_children(pnode);
2512 else if (child0->node_type == GA_NODE_SPEC_FUNC) {
2514 for (
size_type i = 1; i < pnode->children.size(); ++i)
2515 ga_valid_operand(pnode->children[i]);
2516 if (pnode->children.size() != 2)
2517 ga_throw_error(pnode->expr, pnode->pos,
2518 "One and only one argument is allowed for function "
2521 if (!(child0->name.compare(
"qdim"))) {
2522 if (child1->node_type != GA_NODE_VAL)
2523 ga_throw_error(pnode->expr, pnode->pos,
"The argument of qdim "
2524 "function can only be a variable name.");
2525 pnode->node_type = GA_NODE_CONSTANT;
2526 pnode->init_scalar_tensor(scalar_type(workspace.qdim(child1->name)));
2527 if (pnode->tensor()[0] <= 0)
2528 ga_throw_error(pnode->expr, pnode->pos,
2529 "Invalid null size of variable");
2530 }
else if (!(child0->name.compare(
"qdims"))) {
2531 if (child1->node_type != GA_NODE_VAL)
2532 ga_throw_error(pnode->expr, pnode->pos,
"The argument of qdim "
2533 "function can only be a variable name.");
2534 pnode->node_type = GA_NODE_CONSTANT;
2535 bgeot::multi_index mii = workspace.qdims(child1->name);
2537 ga_throw_error(pnode->expr, pnode->pos,
2538 "Tensor with too much dimensions. Limited to 6");
2539 if (mii.size() == 0 || scalar_type(mii[0]) <= 0)
2540 ga_throw_error(pnode->expr, pnode->pos,
2541 "Invalid null size of variable");
2542 if (mii.size() == 1)
2543 pnode->init_scalar_tensor(scalar_type(mii[0]));
2544 if (mii.size() >= 1) {
2545 pnode->init_vector_tensor(mii.size());
2546 for (
size_type i = 0; i < mii.size(); ++i)
2547 pnode->tensor()[i] = scalar_type(mii[i]);
2549 }
else if (!(child0->name.compare(
"Id"))) {
2550 bool valid = (child1->node_type == GA_NODE_CONSTANT);
2551 int n = valid ? int(round(child1->tensor()[0])) : -1;
2552 if (n <= 0 || n > 100 || child1->tensor_order() > 0)
2553 ga_throw_error(pnode->expr, pnode->pos,
"The argument of Id "
2554 "should be a (small) positive integer.");
2555 pnode->node_type = GA_NODE_CONSTANT;
2557 pnode->init_scalar_tensor(scalar_type(1));
2559 pnode->init_matrix_tensor(n,n);
2561 for (
int i = 0; i < n; ++i) pnode->tensor()(i,i) = scalar_type(1);
2563 }
else ga_throw_error(pnode->expr, pnode->children[0]->pos,
2564 "Unknown special function.");
2565 tree.clear_children(pnode);
2569 else if (child0->node_type == GA_NODE_OPERATOR) {
2571 for (
size_type i = 1; i < pnode->children.size(); ++i)
2572 ga_valid_operand(pnode->children[i]);
2574 ga_nonlinear_operator::arg_list args;
2575 for (
size_type i = 1; i < pnode->children.size(); ++i) {
2577 && (pnode->children[i]->node_type == GA_NODE_CONSTANT);
2578 args.push_back(&(pnode->children[i]->tensor()));
2579 if (pnode->children[i]->node_type == GA_NODE_ALLINDICES)
2580 ga_throw_error(pnode->expr, pnode->children[i]->pos,
2581 "Colon operator is not allowed in nonlinear "
2583 if (pnode->children[i]->test_function_type)
2584 ga_throw_error(pnode->expr, pnode->pos,
"Test functions cannot be "
2585 "passed as argument of a nonlinear operator.");
2586 if (pnode->children[i]->tensor_order() > 2)
2587 ga_throw_error(pnode->expr, pnode->pos,
2588 "Sorry, arguments to nonlinear operators should "
2589 "only be scalar, vector or matrices");
2591 ga_predef_operator_tab::T::const_iterator it
2592 = PREDEF_OPERATORS.tab.find(child0->name);
2593 const ga_nonlinear_operator &OP = *(it->second);
2595 if (!(OP.result_size(args, mi)))
2596 ga_throw_error(pnode->expr, pnode->pos,
2597 "Wrong number or wrong size of arguments for the "
2598 "call of nonlinear operator " + child0->name);
2600 pnode->test_function_type = 0;
2602 if (child0->der1 > args.size() || child0->der2 > args.size())
2603 ga_throw_error(pnode->expr, child0->pos,
2604 "Invalid derivative number for nonlinear operator "
2607 if (child0->der1 && child0->der2 == 0) {
2608 for (
size_type i = 0; i < args[child0->der1-1]->sizes().size(); ++i)
2609 mi.push_back(args[child0->der1-1]->sizes()[i]);
2610 pnode->t.adjust_sizes(mi);
2612 pnode->node_type = GA_NODE_CONSTANT;
2613 OP.derivative(args, child0->der1, pnode->tensor());
2614 tree.clear_children(pnode);
2616 }
else if (child0->der1 && child0->der2) {
2617 for (
size_type i = 0; i < args[child0->der1-1]->sizes().size(); ++i)
2618 mi.push_back(args[child0->der1-1]->sizes()[i]);
2619 for (
size_type i = 0; i < args[child0->der2-1]->sizes().size(); ++i)
2620 mi.push_back(args[child0->der2-1]->sizes()[i]);
2621 pnode->t.adjust_sizes(mi);
2623 pnode->node_type = GA_NODE_CONSTANT;
2624 OP.second_derivative(args, child0->der1, child0->der2,
2626 tree.clear_children(pnode);
2629 pnode->t.adjust_sizes(mi);
2631 pnode->node_type = GA_NODE_CONSTANT;
2632 OP.value(args, pnode->tensor());
2633 tree.clear_children(pnode);
2640 all_cte = (child0->node_type == GA_NODE_CONSTANT);
2641 if (pnode->children.size() != child0->tensor_order() + 1)
2642 ga_throw_error(pnode->expr, pnode->pos,
"Bad number of indices.");
2643 for (
size_type i = 1; i < pnode->children.size(); ++i)
2644 if (pnode->children[i]->node_type != GA_NODE_ALLINDICES &&
2645 (pnode->children[i]->node_type != GA_NODE_CONSTANT ||
2646 pnode->children[i]->tensor().size() != 1))
2647 ga_throw_error(pnode->expr, pnode->children[i]->pos,
2648 "Indices should be constant integers or colon.");
2650 bgeot::multi_index mi1(size0.size()), mi2, indices;
2651 for (
size_type i = 0; i < child0->tensor_order(); ++i) {
2652 if (pnode->children[i+1]->node_type == GA_NODE_ALLINDICES) {
2653 mi2.push_back(child0->tensor_proper_size(i));
2654 indices.push_back(i);
2657 mi1[i] =
size_type(round(pnode->children[i+1]->tensor()[0])-1);
2658 if (mi1[i] >= child0->tensor_proper_size(i))
2659 ga_throw_error(pnode->expr, pnode->children[i+1]->pos,
2660 "Index out of range, " << mi1[i]+1
2661 <<
". Should be between 1 and "
2662 << child0->tensor_proper_size(i) <<
".");
2666 for (
size_type i = 0; i < child0->nb_test_functions(); ++i)
2667 mi.push_back(child0->t.sizes()[i]);
2668 for (
size_type i = 0; i < mi2.size(); ++i) mi.push_back(mi2[i]);
2669 pnode->t.adjust_sizes(mi);
2670 pnode->test_function_type = child0->test_function_type;
2671 pnode->name_test1 = child0->name_test1;
2672 pnode->name_test2 = child0->name_test2;
2673 pnode->interpolate_name_test1 = child0->interpolate_name_test1;
2674 pnode->interpolate_name_test2 = child0->interpolate_name_test2;
2675 pnode->qdim1 = child0->qdim1;
2676 pnode->qdim2 = child0->qdim2;
2678 if (child0->tensor_is_zero()) {
2680 pnode->node_type = GA_NODE_ZERO;
2681 tree.clear_children(pnode);
2682 }
else if (all_cte) {
2683 pnode->node_type = GA_NODE_CONSTANT;
2684 for (bgeot::multi_index mi3(mi2.size()); !mi3.finished(mi2);
2685 mi3.incrementation(mi2)) {
2686 for (
size_type j = 0; j < mi2.size(); ++j) {
2687 mi1[indices[j]] = mi3[j];
2689 pnode->tensor()(mi3) = pnode->children[0]->tensor()(mi1);
2691 tree.clear_children(pnode);
2696 default:GMM_ASSERT1(
false,
"Unexpected node type " << pnode->node_type
2697 <<
" in semantic analysis. Internal error.");
2699 pnode->hash_value = ga_hash_code(pnode);
2700 for (
size_type i = 0; i < pnode->children.size(); ++i) {
2701 pnode->hash_value += (pnode->children[i]->hash_value)
2702 * 1.0101*(pnode->symmetric_op ? scalar_type(1) : scalar_type(1+i));
2704 pnode->hash_value = sin(1.2003*pnode->hash_value);
2708 void ga_semantic_analysis(ga_tree &tree,
2709 const ga_workspace &workspace,
2712 bool eval_fixed_size,
2713 bool ignore_X,
int option) {
2714 GMM_ASSERT1(predef_operators_nonlinear_elasticity_initialized &&
2715 predef_operators_plasticity_initialized &&
2716 predef_operators_contact_initialized,
"Internal error");
2719 # ifdef GA_PRINT_DEBUG_INFO
2720 cout <<
"Begin semantic analysis with ";
2721 ga_print_node(tree.root, cout); cout << endl;
2724 if (option == 1) { workspace.test1.clear(); workspace.test2.clear(); }
2725 ga_node_analysis(tree, workspace, tree.root, m, ref_elt_dim,
2726 eval_fixed_size, ignore_X, option);
2727 if (tree.root && option == 2) {
2728 if (((tree.root->test_function_type & 1) &&
2729 (tree.root->name_test1.compare(workspace.selected_test1.varname)
2730 || tree.root->interpolate_name_test1.compare
2731 (workspace.selected_test1.transname)))
2733 ((tree.root->test_function_type & 2) &&
2734 (tree.root->name_test2.compare(workspace.selected_test2.varname)
2735 || tree.root->interpolate_name_test2.compare
2736 (workspace.selected_test2.transname))))
2739 ga_valid_operand(tree.root);
2740 # ifdef GA_PRINT_DEBUG_INFO
2741 cout <<
"End of semantic analysis : ";
2743 ga_print_node(tree.root, cout);
2749 void ga_extract_factor(ga_tree &result_tree, pga_tree_node pnode,
2750 pga_tree_node &new_pnode) {
2751 result_tree.clear();
2752 result_tree.copy_node(pnode, result_tree.root);
2753 new_pnode = result_tree.root;
2755 bool minus_sign =
false;
2757 pga_tree_node pnode_child = pnode;
2758 pnode = pnode->parent;
2762 size_type nbch = pnode->children.size();
2763 pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
2764 pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
2766 switch (pnode->node_type) {
2769 switch(pnode->op_type) {
2774 if (child1 == pnode_child) minus_sign = !(minus_sign);
2777 case GA_UNARY_MINUS:
case GA_QUOTE:
case GA_SYM:
case GA_SKEW:
2778 case GA_TRACE:
case GA_DEVIATOR:
case GA_PRINT:
2780 result_tree.insert_node(result_tree.root, pnode->node_type);
2781 result_tree.root->op_type = pnode->op_type;
2782 result_tree.root->pos = pnode->pos;
2783 result_tree.root->expr = pnode->expr;
2785 case GA_DOT:
case GA_MULT:
case GA_COLON:
case GA_TMULT:
2786 case GA_DOTMULT:
case GA_DIV:
case GA_DOTDIV:
2788 result_tree.insert_node(result_tree.root, pnode->node_type);
2789 result_tree.root->op_type = pnode->op_type;
2790 result_tree.root->pos = pnode->pos;
2791 result_tree.root->expr = pnode->expr;
2792 result_tree.root->children.resize(2,
nullptr);
2793 if (child0 == pnode_child) {
2794 result_tree.copy_node(child1, result_tree.root->children[1]);
2795 result_tree.root->accept_child(1);
2796 }
else if (child1 == pnode_child) {
2797 std::swap(result_tree.root->children[1],
2798 result_tree.root->children[0]);
2799 result_tree.copy_node(child0, result_tree.root->children[0]);
2800 result_tree.root->accept_child(0);
2801 }
else GMM_ASSERT1(
false,
"Corrupted tree");
2803 default: GMM_ASSERT1(
false,
"Unexpected operation. Internal error.");
2807 case GA_NODE_PARAMS:
2808 if (child0->node_type == GA_NODE_RESHAPE) {
2809 GMM_ASSERT1(child1 == pnode_child,
"Cannot extract a factor of a "
2810 "Reshape size parameter");
2812 result_tree.insert_node(result_tree.root, pnode->node_type);
2813 result_tree.root->pos = pnode->pos;
2814 result_tree.root->expr = pnode->expr;
2815 result_tree.root->children.resize(pnode->children.size(),
nullptr);
2816 std::swap(result_tree.root->children[1],
2817 result_tree.root->children[0]);
2818 for (
size_type i = 0; i < pnode->children.size(); ++i)
2820 result_tree.copy_node(pnode->children[i],
2821 result_tree.root->children[i]);
2822 result_tree.root->accept_child(i);
2824 }
else if (child0->node_type == GA_NODE_CROSS_PRODUCT) {
2825 pga_tree_node child2 = pnode->children[2];
2826 result_tree.insert_node(result_tree.root, pnode->node_type);
2827 result_tree.root->pos = pnode->pos;
2828 result_tree.root->expr = pnode->expr;
2829 result_tree.root->children.resize(3,
nullptr);
2830 if (child1 == pnode_child) {
2831 std::swap(result_tree.root->children[1],
2832 result_tree.root->children[0]);
2833 result_tree.copy_node(pnode->children[0],
2834 result_tree.root->children[0]);
2835 result_tree.root->accept_child(0);
2836 result_tree.copy_node(pnode->children[2],
2837 result_tree.root->children[2]);
2838 result_tree.root->accept_child(2);
2839 }
else if (child2 == pnode_child) {
2840 std::swap(result_tree.root->children[2],
2841 result_tree.root->children[0]);
2842 result_tree.copy_node(pnode->children[0],
2843 result_tree.root->children[0]);
2844 result_tree.root->accept_child(0);
2845 result_tree.copy_node(pnode->children[1],
2846 result_tree.root->children[1]);
2847 result_tree.root->accept_child(1);
2848 }
else GMM_ASSERT1(
false,
"Corrupted tree");
2849 }
else if (child0->node_type == GA_NODE_SWAP_IND) {
2850 GMM_ASSERT1(child1 == pnode_child,
"Cannot extract a factor of a "
2851 "Swap_indices size parameter");
2853 result_tree.insert_node(result_tree.root, pnode->node_type);
2854 result_tree.root->pos = pnode->pos;
2855 result_tree.root->expr = pnode->expr;
2856 result_tree.root->children.resize(pnode->children.size(),
nullptr);
2857 for (
size_type i = 0; i < pnode->children.size(); ++i)
2858 if (pnode->children[i] == pnode_child)
2859 std::swap(result_tree.root->children[i],
2860 result_tree.root->children[0]);
2861 for (
size_type i = 0; i < pnode->children.size(); ++i)
2862 if (pnode->children[i] != pnode_child) {
2863 result_tree.copy_node(pnode->children[i],
2864 result_tree.root->children[i]);
2865 result_tree.root->accept_child(i);
2867 }
else if (child0->node_type == GA_NODE_IND_MOVE_LAST) {
2868 GMM_ASSERT1(child1 == pnode_child,
"Cannot extract a factor of a "
2869 "Index_move_last size parameter");
2871 result_tree.insert_node(result_tree.root, pnode->node_type);
2872 result_tree.root->pos = pnode->pos;
2873 result_tree.root->expr = pnode->expr;
2874 result_tree.root->children.resize(pnode->children.size(),
nullptr);
2875 for (
size_type i = 0; i < pnode->children.size(); ++i)
2876 if (pnode->children[i] == pnode_child)
2877 std::swap(result_tree.root->children[i],
2878 result_tree.root->children[0]);
2879 for (
size_type i = 0; i < pnode->children.size(); ++i)
2880 if (pnode->children[i] != pnode_child) {
2881 result_tree.copy_node(pnode->children[i],
2882 result_tree.root->children[i]);
2883 result_tree.root->accept_child(i);
2885 }
else if (child0->node_type == GA_NODE_CONTRACT) {
2887 result_tree.insert_node(result_tree.root, pnode->node_type);
2888 result_tree.root->pos = pnode->pos;
2889 result_tree.root->expr = pnode->expr;
2890 result_tree.root->children.resize(pnode->children.size(),
nullptr);
2891 for (
size_type i = 0; i < pnode->children.size(); ++i)
2892 if (pnode->children[i] == pnode_child)
2893 std::swap(result_tree.root->children[i],
2894 result_tree.root->children[0]);
2895 for (
size_type i = 0; i < pnode->children.size(); ++i)
2896 if (pnode->children[i] != pnode_child) {
2897 result_tree.copy_node(pnode->children[i],
2898 result_tree.root->children[i]);
2899 result_tree.root->accept_child(i);
2902 GMM_ASSERT1(
false,
"Cannot extract a factor which is a parameter "
2903 "of a nonlinear operator/function");
2906 case GA_NODE_C_MATRIX:
2907 result_tree.insert_node(result_tree.root, pnode->node_type);
2908 result_tree.root->pos = pnode->pos;
2909 result_tree.root->expr = pnode->expr;
2910 result_tree.root->children.resize(pnode->children.size());
2911 for (
size_type i = 0; i < pnode->children.size(); ++i)
2912 if (pnode_child == pnode->children[i]) {
2913 result_tree.root->children[i] = result_tree.root->children[0];
2914 result_tree.root->children[0] = 0;
2917 for (
size_type i = 0; i < pnode->children.size(); ++i) {
2918 if (pnode_child == pnode->children[i]) {
2920 =
new ga_tree_node(GA_NODE_ZERO, pnode->pos, pnode->expr);
2921 pnode->children[i]->init_scalar_tensor(scalar_type(0));
2922 pnode->accept_child(i);
2927 default: GMM_ASSERT1(
false,
"Unexpected node type " << pnode->node_type
2928 <<
" in extract constant term. Internal error.");
2931 pnode_child = pnode;
2932 pnode = pnode->parent;
2936 result_tree.insert_node(result_tree.root, GA_NODE_OP);
2937 result_tree.root->op_type = GA_UNARY_MINUS;
2938 result_tree.root->pos = pnode->children[0]->pos;
2939 result_tree.root->expr = pnode->children[0]->expr;
2943 bool ga_node_extract_constant_term
2944 (ga_tree &tree, pga_tree_node pnode,
const ga_workspace &workspace,
2946 bool is_constant =
true;
2947 size_type nbch = pnode->children.size();
2948 pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
2950 bool child_0_is_constant = (nbch <= 0) ? true :
2951 ga_node_extract_constant_term(tree, pnode->children[0], workspace, m);
2952 bool child_1_is_constant = (nbch <= 1) ?
true :
2953 ga_node_extract_constant_term(tree, pnode->children[1], workspace, m);
2955 switch (pnode->node_type) {
2956 case GA_NODE_ZERO: is_constant =
false;
break;
2958 case GA_NODE_ELEMENTARY_VAL_TEST:
case GA_NODE_ELEMENTARY_GRAD_TEST:
2959 case GA_NODE_ELEMENTARY_HESS_TEST:
case GA_NODE_ELEMENTARY_DIVERG_TEST:
2960 case GA_NODE_SECONDARY_DOMAIN_VAL_TEST:
2961 case GA_NODE_SECONDARY_DOMAIN_GRAD_TEST:
2962 case GA_NODE_SECONDARY_DOMAIN_HESS_TEST:
2963 case GA_NODE_SECONDARY_DOMAIN_DIVERG_TEST:
2964 case GA_NODE_XFEM_PLUS_VAL_TEST:
case GA_NODE_XFEM_PLUS_GRAD_TEST:
2965 case GA_NODE_XFEM_PLUS_HESS_TEST:
case GA_NODE_XFEM_PLUS_DIVERG_TEST:
2966 case GA_NODE_XFEM_MINUS_VAL_TEST:
case GA_NODE_XFEM_MINUS_GRAD_TEST:
2967 case GA_NODE_XFEM_MINUS_HESS_TEST:
case GA_NODE_XFEM_MINUS_DIVERG_TEST:
2968 case GA_NODE_VAL_TEST:
case GA_NODE_GRAD_TEST:
case GA_NODE_PREDEF_FUNC:
2969 case GA_NODE_HESS_TEST:
case GA_NODE_DIVERG_TEST:
case GA_NODE_RESHAPE:
2970 case GA_NODE_CROSS_PRODUCT:
2971 case GA_NODE_SWAP_IND:
case GA_NODE_IND_MOVE_LAST:
case GA_NODE_CONTRACT:
2972 case GA_NODE_ELT_SIZE:
case GA_NODE_ELT_K:
case GA_NODE_ELT_B:
2973 case GA_NODE_CONSTANT:
case GA_NODE_X:
case GA_NODE_NORMAL:
2974 case GA_NODE_SECONDARY_DOMAIN_X:
case GA_NODE_SECONDARY_DOMAIN_NORMAL:
2975 case GA_NODE_OPERATOR:
2976 is_constant =
true;
break;
2978 case GA_NODE_ELEMENTARY_VAL:
case GA_NODE_ELEMENTARY_GRAD:
2979 case GA_NODE_ELEMENTARY_HESS:
case GA_NODE_ELEMENTARY_DIVERG:
2980 case GA_NODE_SECONDARY_DOMAIN_VAL:
case GA_NODE_SECONDARY_DOMAIN_GRAD:
2981 case GA_NODE_SECONDARY_DOMAIN_HESS:
case GA_NODE_SECONDARY_DOMAIN_DIVERG:
2982 case GA_NODE_XFEM_PLUS_VAL:
case GA_NODE_XFEM_PLUS_GRAD:
2983 case GA_NODE_XFEM_PLUS_HESS:
case GA_NODE_XFEM_PLUS_DIVERG:
2984 case GA_NODE_XFEM_MINUS_VAL:
case GA_NODE_XFEM_MINUS_GRAD:
2985 case GA_NODE_XFEM_MINUS_HESS:
case GA_NODE_XFEM_MINUS_DIVERG:
2986 case GA_NODE_VAL:
case GA_NODE_GRAD:
case GA_NODE_HESS:
2987 case GA_NODE_DIVERG:
2988 is_constant = workspace.is_constant(pnode->name);
2991 case GA_NODE_INTERPOLATE_VAL:
2992 case GA_NODE_INTERPOLATE_GRAD:
2993 case GA_NODE_INTERPOLATE_HESS:
2994 case GA_NODE_INTERPOLATE_DIVERG:
2996 if (!(workspace.is_constant(pnode->name))) {
2997 is_constant =
false;
break;
2999 std::set<var_trans_pair> vars;
3000 workspace.interpolate_transformation(pnode->interpolate_name)
3001 ->extract_variables(workspace, vars,
true, m,
3002 pnode->interpolate_name);
3003 for (
const var_trans_pair &var : vars) {
3004 if (!(workspace.is_constant(var.varname)))
3005 { is_constant =
false;
break; }
3010 case GA_NODE_INTERPOLATE_FILTER:
3011 if (!child_0_is_constant) {
3012 is_constant =
false;
3016 case GA_NODE_INTERPOLATE_VAL_TEST:
3017 case GA_NODE_INTERPOLATE_GRAD_TEST:
3018 case GA_NODE_INTERPOLATE_DIVERG_TEST:
3019 case GA_NODE_INTERPOLATE_HESS_TEST:
3020 case GA_NODE_INTERPOLATE_X:
3021 case GA_NODE_INTERPOLATE_ELT_K:
case GA_NODE_INTERPOLATE_ELT_B:
3022 case GA_NODE_INTERPOLATE_NORMAL:
3023 case GA_NODE_INTERPOLATE_DERIVATIVE:
3025 std::set<var_trans_pair> vars;
3026 workspace.interpolate_transformation(pnode->interpolate_name)
3027 ->extract_variables(workspace, vars,
true, m,
3028 pnode->interpolate_name);
3029 for (
const var_trans_pair &var : vars) {
3030 if (!(workspace.is_constant(var.varname)))
3031 { is_constant =
false;
break; }
3037 switch(pnode->op_type) {
3038 case GA_PLUS:
case GA_MINUS:
3039 if (!child_0_is_constant && !child_1_is_constant)
3040 { is_constant =
false;
break; }
3043 case GA_UNARY_MINUS:
case GA_QUOTE:
case GA_SYM:
case GA_SKEW:
3044 case GA_TRACE:
case GA_DEVIATOR:
case GA_PRINT:
3045 is_constant = child_0_is_constant;
3048 case GA_DOT:
case GA_MULT:
case GA_COLON:
case GA_TMULT:
3049 case GA_DOTMULT:
case GA_DIV:
case GA_DOTDIV:
3050 is_constant = (child_0_is_constant && child_1_is_constant);
3053 default: GMM_ASSERT1(
false,
"Unexpected operation. Internal error.");
3057 case GA_NODE_C_MATRIX:
3058 for (
size_type i = 0; i < pnode->children.size(); ++i) {
3059 if (!(ga_node_extract_constant_term(tree, pnode->children[i],
3061 { is_constant =
false;
break; }
3065 case GA_NODE_PARAMS:
3066 if (child0->node_type == GA_NODE_RESHAPE ||
3067 child0->node_type == GA_NODE_SWAP_IND ||
3068 child0->node_type == GA_NODE_IND_MOVE_LAST) {
3069 is_constant = child_1_is_constant;
3070 }
else if (child0->node_type == GA_NODE_CROSS_PRODUCT) {
3071 bool child_2_is_constant
3072 = ga_node_extract_constant_term(tree,pnode->children[2],workspace,m);
3073 is_constant = (child_1_is_constant && child_2_is_constant);
3074 }
else if (child0->node_type == GA_NODE_CONTRACT) {
3075 for (
size_type i = 1; i < pnode->children.size(); ++i) {
3076 if (!(ga_node_extract_constant_term(tree, pnode->children[i],
3078 { is_constant =
false;
break; }
3080 }
else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
3081 for (
size_type i = 1; i < pnode->children.size(); ++i) {
3082 if (!(ga_node_extract_constant_term(tree, pnode->children[i],
3084 { is_constant =
false;
break; }
3086 }
else if (child0->node_type == GA_NODE_SPEC_FUNC) {
3087 GMM_ASSERT1(
false,
"internal error");
3088 }
else if (child0->node_type == GA_NODE_OPERATOR) {
3089 for (
size_type i = 1; i < pnode->children.size(); ++i) {
3090 if (!(ga_node_extract_constant_term(tree, pnode->children[i],
3092 { is_constant =
false;
break; }
3095 is_constant = child_0_is_constant;
3099 default: GMM_ASSERT1(
false,
"Unexpected node type " << pnode->node_type
3100 <<
" in extract constant term. Internal error.");
3104 pnode->node_type = GA_NODE_ZERO;
3105 tree.clear_children(pnode);
3115 static std::string ga_extract_one_Neumann_term
3116 (
const std::string &varname,
3117 ga_workspace &workspace, pga_tree_node pnode) {
3119 const mesh_fem *mf = workspace.associated_mf(varname);
3120 GMM_ASSERT1(mf,
"Works only with fem variables.");
3121 size_type meshdim = mf->linked_mesh().dim();
3123 pga_tree_node new_pnode =
nullptr;
3124 ga_extract_factor(factor, pnode, new_pnode);
3126 pga_tree_node nnew_pnode = new_pnode;
3128 int cas = new_pnode->node_type == GA_NODE_GRAD_TEST ? 0 : 1;
3130 if (cas == 0 && new_pnode->parent &&
3131 new_pnode->parent->node_type == GA_NODE_OP &&
3132 new_pnode->parent->op_type == GA_TRACE) {
3134 nnew_pnode = new_pnode->parent;
3137 pga_tree_node colon_pnode =
nullptr;
3138 bool quote_before_colon =
false;
3146 while (nnew_pnode->parent) {
3147 pga_tree_node previous_node = nnew_pnode;
3148 nnew_pnode = nnew_pnode->parent;
3150 if (nnew_pnode->node_type == GA_NODE_OP &&
3151 nnew_pnode->op_type == GA_MULT &&
3152 nnew_pnode->children[0] == previous_node &&
3153 nnew_pnode->children[1]->tensor_proper_size() == 1) {
3154 }
else if (nnew_pnode->node_type == GA_NODE_OP &&
3155 nnew_pnode->op_type == GA_MULT &&
3156 nnew_pnode->children[1] == previous_node &&
3157 nnew_pnode->children[0]->tensor_proper_size() == 1) {
3159 }
else if (nnew_pnode->node_type == GA_NODE_OP &&
3160 nnew_pnode->op_type == GA_DIV &&
3161 nnew_pnode->children[0] == previous_node &&
3162 nnew_pnode->children[1]->tensor_proper_size() == 1) {
3164 }
else if (nnew_pnode->node_type == GA_NODE_OP &&
3165 nnew_pnode->op_type == GA_COLON &&
3166 nnew_pnode->children[0] == previous_node &&
3167 nnew_pnode->children[1]->tensor_order() == 2 &&
3168 colon_pnode == 0 && cas == 0) {
3169 std::swap(nnew_pnode->children[0], nnew_pnode->children[1]);
3170 colon_pnode = nnew_pnode;
3171 }
else if (nnew_pnode->node_type == GA_NODE_OP &&
3172 nnew_pnode->op_type == GA_COLON &&
3173 nnew_pnode->children[1] == previous_node &&
3174 nnew_pnode->children[0]->tensor_order() == 2 &&
3175 colon_pnode == 0 && cas == 0) {
3176 colon_pnode = nnew_pnode;
3177 }
else if (nnew_pnode->node_type == GA_NODE_OP &&
3178 nnew_pnode->op_type == GA_QUOTE &&
3179 colon_pnode == 0 && cas == 0 && !quote_before_colon) {
3180 quote_before_colon =
true;
3184 if (ok && cas == 0 && !colon_pnode) ok =
false;
3187 new_pnode->node_type = GA_NODE_NORMAL;
3188 result =
"(" + ga_tree_to_string(factor) +
")";
3192 new_pnode->node_type = GA_NODE_NORMAL;
3193 colon_pnode->op_type = GA_MULT;
3194 if (quote_before_colon) {
3195 factor.insert_node(colon_pnode->children[0], GA_NODE_OP);
3196 colon_pnode->children[0]->op_type = GA_QUOTE;
3197 nnew_pnode = new_pnode->parent;
3198 while(nnew_pnode->node_type != GA_NODE_OP ||
3199 nnew_pnode->op_type != GA_QUOTE)
3200 nnew_pnode = nnew_pnode->parent;
3201 factor.replace_node_by_child(nnew_pnode,0);
3205 new_pnode->node_type = GA_NODE_NORMAL;
3208 new_pnode->parent->node_type = GA_NODE_NORMAL;
3209 factor.clear_children(new_pnode->parent);
3212 result =
"(" + ga_tree_to_string(factor) +
")";
3218 bgeot::multi_index mi(2); mi[0] = N; mi[1] = meshdim;
3221 factor.clear_children(new_pnode);
3222 new_pnode->node_type = GA_NODE_C_MATRIX;
3223 new_pnode->t.adjust_sizes(mi);
3224 new_pnode->children.resize(N*meshdim);
3226 for (
size_type k = 0; k < meshdim; ++k) {
3228 pga_tree_node param_node = new_pnode->children[k*N+j]
3229 =
new ga_tree_node(GA_NODE_PARAMS, pnode->pos, pnode->expr);
3230 new_pnode->accept_child(k+j*meshdim);
3231 param_node->children.resize(2);
3232 param_node->children[0]
3233 =
new ga_tree_node(GA_NODE_NORMAL, pnode->pos, pnode->expr);
3234 param_node->accept_child(0);
3235 param_node->children[1]
3236 =
new ga_tree_node(GA_NODE_CONSTANT, pnode->pos, pnode->expr);
3237 param_node->accept_child(1);
3238 param_node->children[1]->init_scalar_tensor(scalar_type(k));
3241 new_pnode->children[k+j*meshdim]
3242 =
new ga_tree_node(GA_NODE_ZERO, pnode->pos, pnode->expr);
3243 new_pnode->children[k+j*meshdim]
3244 ->init_scalar_tensor(scalar_type(0));
3245 new_pnode->accept_child(k+j*meshdim);
3249 result +=
"(" + ga_tree_to_string(factor) +
")";
3250 if (i < N-1) result +=
";";
3253 GMM_TRACE2(
"Warning, generic Neumann term used: " << result);
3260 void ga_extract_Neumann_term
3261 (
const ga_tree &tree,
const std::string &varname,
3262 ga_workspace &workspace, pga_tree_node pnode, std::string &result) {
3264 for (
size_type i = 0; i < pnode->children.size(); ++i)
3265 ga_extract_Neumann_term(tree, varname, workspace,
3266 pnode->children[i], result);
3268 switch (pnode->node_type) {
3269 case GA_NODE_DIVERG_TEST:
case GA_NODE_GRAD_TEST:
3270 case GA_NODE_ELEMENTARY_GRAD_TEST:
case GA_NODE_ELEMENTARY_DIVERG_TEST:
3271 if (pnode->name.compare(varname) == 0) {
3272 if (result.size()) result +=
" + ";
3273 result += ga_extract_one_Neumann_term(varname, workspace, pnode);
3276 case GA_NODE_INTERPOLATE_GRAD_TEST:
case GA_NODE_INTERPOLATE_DIVERG_TEST:
3277 if (pnode->name.compare(varname) == 0)
3278 GMM_ASSERT1(
false,
"Do not know how to extract a "
3279 "Neumann term with an interpolate transformation");
3281 case GA_NODE_SECONDARY_DOMAIN_GRAD_TEST:
3282 case GA_NODE_SECONDARY_DOMAIN_DIVERG_TEST:
3283 if (pnode->name.compare(varname) == 0)
3284 GMM_ASSERT1(
false,
"Do not know how to extract a "
3285 "Neumann term with an two-domain term");
3298 static void ga_node_derivation(ga_tree &tree,
const ga_workspace &workspace,
3300 pga_tree_node pnode,
3301 const std::string &varname,
3302 const std::string &interpolatename,
3305 size_type nbch = pnode->children.size();
3306 pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
3307 pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
3308 bool mark0 = ((nbch > 0) ? child0->marked :
false);
3309 bool mark1 = ((nbch > 1) ? child1->marked :
false);
3310 bgeot::multi_index mi;
3312 const ga_predef_function_tab &PREDEF_FUNCTIONS
3315 switch (pnode->node_type) {
3316 case GA_NODE_VAL:
case GA_NODE_GRAD:
3317 case GA_NODE_HESS:
case GA_NODE_DIVERG:
3318 mi.resize(1); mi[0] = 2;
3319 for (
size_type i = 0; i < pnode->tensor_order(); ++i)
3320 mi.push_back(pnode->tensor_proper_size(i));
3321 pnode->t.adjust_sizes(mi);
3322 if (pnode->node_type == GA_NODE_VAL)
3323 pnode->node_type = GA_NODE_VAL_TEST;
3324 else if (pnode->node_type == GA_NODE_GRAD)
3325 pnode->node_type = GA_NODE_GRAD_TEST;
3326 else if (pnode->node_type == GA_NODE_HESS)
3327 pnode->node_type = GA_NODE_HESS_TEST;
3328 else if (pnode->node_type == GA_NODE_DIVERG)
3329 pnode->node_type = GA_NODE_DIVERG_TEST;
3330 pnode->test_function_type = order;
3333 case GA_NODE_INTERPOLATE_VAL:
3334 case GA_NODE_INTERPOLATE_GRAD:
3335 case GA_NODE_INTERPOLATE_HESS:
3336 case GA_NODE_INTERPOLATE_DIVERG:
3338 bool is_val(pnode->node_type == GA_NODE_INTERPOLATE_VAL);
3339 bool is_grad(pnode->node_type == GA_NODE_INTERPOLATE_GRAD);
3340 bool is_hess(pnode->node_type == GA_NODE_INTERPOLATE_HESS);
3341 bool is_diverg(pnode->node_type == GA_NODE_INTERPOLATE_DIVERG);
3343 bool ivar = (pnode->name.compare(varname) == 0 &&
3345 pnode->interpolate_name.compare(interpolatename) == 0));
3346 bool itrans = !ivar;
3348 std::set<var_trans_pair> vars;
3349 workspace.interpolate_transformation(pnode->interpolate_name)
3350 ->extract_variables(workspace, vars,
true, m,
3351 pnode->interpolate_name);
3352 for (
const var_trans_pair &var : vars) {
3353 if (var.varname.compare(varname) == 0 &&
3354 var.transname.compare(interpolatename) == 0)
3359 pga_tree_node pnode_trans = pnode;
3361 GMM_ASSERT1(!itrans,
"Sorry, cannot derive a hessian once more");
3362 }
else if (itrans && ivar) {
3363 tree.duplicate_with_addition(pnode);
3364 pnode_trans = pnode->parent->children[1];
3369 for (
size_type i = 0; i < pnode->tensor_order(); ++i)
3370 mi.push_back(pnode->tensor_proper_size(i));
3371 pnode->t.adjust_sizes(mi);
3373 pnode->node_type = GA_NODE_INTERPOLATE_VAL_TEST;
3375 pnode->node_type = GA_NODE_INTERPOLATE_GRAD_TEST;
3377 pnode->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
3379 pnode->node_type = GA_NODE_INTERPOLATE_DIVERG_TEST;
3380 pnode->test_function_type = order;
3385 const mesh_fem *mf = workspace.associated_mf(pnode_trans->name);
3386 size_type q = workspace.qdim(pnode_trans->name);
3388 bgeot::multi_index mii = workspace.qdims(pnode_trans->name);
3391 pnode_trans->node_type = GA_NODE_INTERPOLATE_GRAD;
3392 else if (is_grad || is_diverg)
3393 pnode_trans->node_type = GA_NODE_INTERPOLATE_HESS;
3396 if (q == 1 && mii.size() <= 1)
3399 if (is_grad || is_diverg) mii.push_back(n);
3401 pnode_trans->t.adjust_sizes(mii);
3402 tree.duplicate_with_operation(pnode_trans,
3403 (n > 1) ? GA_DOT : GA_MULT);
3404 pga_tree_node pnode_der = pnode_trans->parent->children[1];
3405 pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
3409 pnode_der->init_vector_tensor(qv);
3411 pnode_der->init_matrix_tensor(qv, n);
3412 pnode_der->test_function_type = order;
3413 pnode_der->name = varname;
3414 pnode_der->interpolate_name_der = pnode_der->interpolate_name;
3415 pnode_der->interpolate_name = interpolatename;
3418 tree.insert_node(pnode_trans->parent, GA_NODE_OP);
3419 pga_tree_node pnode_tr = pnode_trans->parent->parent;
3420 pnode_tr->op_type = GA_TRACE;
3421 pnode_tr->init_vector_tensor(2);
3430 case GA_NODE_INTERPOLATE_VAL_TEST:
3431 case GA_NODE_INTERPOLATE_GRAD_TEST:
3432 case GA_NODE_INTERPOLATE_DIVERG_TEST:
3434 bool is_val(pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST);
3435 bool is_grad(pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST);
3436 bool is_diverg(pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST);
3438 pga_tree_node pnode_trans = pnode;
3439 const mesh_fem *mf = workspace.associated_mf(pnode_trans->name);
3440 size_type q = workspace.qdim(pnode_trans->name);
3443 bgeot::multi_index mii = workspace.qdims(pnode_trans->name);
3445 pnode_trans->node_type = GA_NODE_INTERPOLATE_GRAD_TEST;
3446 else if (is_grad || is_diverg)
3447 pnode_trans->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
3449 if (q == 1 && mii.size() <= 1)
3451 mii.insert(mii.begin(), 2);
3454 if (is_grad || is_diverg) mii.push_back(n);
3456 pnode_trans->t.adjust_sizes(mii);
3458 tree.duplicate_with_operation(pnode_trans,
3459 (n > 1 ? GA_DOT : GA_MULT));
3460 pga_tree_node pnode_der = pnode_trans->parent->children[1];
3461 pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
3463 pnode_der->init_vector_tensor(2);
3465 pnode_der->init_matrix_tensor(2, n);
3466 pnode_der->test_function_type = order;
3467 pnode_der->name = varname;
3468 pnode_der->interpolate_name_der = pnode_der->interpolate_name;
3469 pnode_der->interpolate_name = interpolatename;
3472 tree.insert_node(pnode_trans->parent, GA_NODE_OP);
3473 pga_tree_node pnode_tr = pnode_trans->parent->parent;
3474 pnode_tr->op_type = GA_TRACE;
3475 pnode_tr->init_vector_tensor(2);
3483 case GA_NODE_INTERPOLATE_HESS_TEST:
3484 GMM_ASSERT1(
false,
"Sorry, cannot derive a hessian once more");
3487 case GA_NODE_INTERPOLATE_X:
3490 pga_tree_node pnode_der = pnode;
3491 pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
3493 pnode_der->init_vector_tensor(2);
3495 pnode_der->init_matrix_tensor(2, n);
3496 pnode_der->test_function_type = order;
3497 pnode_der->name = varname;
3498 pnode_der->interpolate_name_der = pnode_der->interpolate_name;
3499 pnode_der->interpolate_name = interpolatename;
3503 case GA_NODE_INTERPOLATE_ELT_K:
3504 GMM_ASSERT1(
false,
"Sorry, cannot derive the interpolated element_K");
3507 case GA_NODE_INTERPOLATE_ELT_B:
3508 GMM_ASSERT1(
false,
"Sorry, cannot derive the interpolated element_B");
3511 case GA_NODE_INTERPOLATE_NORMAL:
3512 GMM_ASSERT1(
false,
"Sorry, cannot derive the interpolated Normal");
3515 case GA_NODE_INTERPOLATE_DERIVATIVE:
3516 GMM_ASSERT1(
false,
"Sorry, second order transformation derivative "
3517 "not taken into account");
3520 case GA_NODE_INTERPOLATE_FILTER:
3521 ga_node_derivation(tree, workspace, m, child0, varname,
3522 interpolatename, order, any_trans);
3525 case GA_NODE_SECONDARY_DOMAIN_VAL:
3526 case GA_NODE_SECONDARY_DOMAIN_GRAD:
3527 case GA_NODE_SECONDARY_DOMAIN_HESS:
3528 case GA_NODE_SECONDARY_DOMAIN_DIVERG:
3529 case GA_NODE_ELEMENTARY_VAL:
3530 case GA_NODE_ELEMENTARY_GRAD:
3531 case GA_NODE_ELEMENTARY_HESS:
3532 case GA_NODE_ELEMENTARY_DIVERG:
3533 case GA_NODE_XFEM_PLUS_VAL:
3534 case GA_NODE_XFEM_PLUS_GRAD:
3535 case GA_NODE_XFEM_PLUS_HESS:
3536 case GA_NODE_XFEM_PLUS_DIVERG:
3537 case GA_NODE_XFEM_MINUS_VAL:
3538 case GA_NODE_XFEM_MINUS_GRAD:
3539 case GA_NODE_XFEM_MINUS_HESS:
3540 case GA_NODE_XFEM_MINUS_DIVERG:
3541 mi.resize(1); mi[0] = 2;
3542 for (
size_type i = 0; i < pnode->tensor_order(); ++i)
3543 mi.push_back(pnode->tensor_proper_size(i));
3544 pnode->t.adjust_sizes(mi);
3545 switch(pnode->node_type) {
3546 case GA_NODE_SECONDARY_DOMAIN_VAL:
3547 pnode->node_type = GA_NODE_SECONDARY_DOMAIN_VAL_TEST;
break;
3548 case GA_NODE_SECONDARY_DOMAIN_GRAD:
3549 pnode->node_type = GA_NODE_SECONDARY_DOMAIN_GRAD_TEST;
break;
3550 case GA_NODE_SECONDARY_DOMAIN_HESS:
3551 pnode->node_type = GA_NODE_SECONDARY_DOMAIN_HESS_TEST;
break;
3552 case GA_NODE_SECONDARY_DOMAIN_DIVERG:
3553 pnode->node_type = GA_NODE_SECONDARY_DOMAIN_DIVERG_TEST;
break;
3554 case GA_NODE_ELEMENTARY_VAL:
3555 pnode->node_type = GA_NODE_ELEMENTARY_VAL_TEST;
break;
3556 case GA_NODE_ELEMENTARY_GRAD:
3557 pnode->node_type = GA_NODE_ELEMENTARY_GRAD_TEST;
break;
3558 case GA_NODE_ELEMENTARY_HESS:
3559 pnode->node_type = GA_NODE_ELEMENTARY_HESS_TEST;
break;
3560 case GA_NODE_ELEMENTARY_DIVERG:
3561 pnode->node_type = GA_NODE_ELEMENTARY_DIVERG_TEST;
break;
3562 case GA_NODE_XFEM_PLUS_VAL:
3563 pnode->node_type = GA_NODE_XFEM_PLUS_VAL_TEST;
break;
3564 case GA_NODE_XFEM_PLUS_GRAD:
3565 pnode->node_type = GA_NODE_XFEM_PLUS_GRAD_TEST;
break;
3566 case GA_NODE_XFEM_PLUS_HESS:
3567 pnode->node_type = GA_NODE_XFEM_PLUS_HESS_TEST;
break;
3568 case GA_NODE_XFEM_PLUS_DIVERG:
3569 pnode->node_type = GA_NODE_XFEM_PLUS_DIVERG_TEST;
break;
3570 case GA_NODE_XFEM_MINUS_VAL:
3571 pnode->node_type = GA_NODE_XFEM_MINUS_VAL_TEST;
break;
3572 case GA_NODE_XFEM_MINUS_GRAD:
3573 pnode->node_type = GA_NODE_XFEM_MINUS_GRAD_TEST;
break;
3574 case GA_NODE_XFEM_MINUS_HESS:
3575 pnode->node_type = GA_NODE_XFEM_MINUS_HESS_TEST;
break;
3576 case GA_NODE_XFEM_MINUS_DIVERG:
3577 pnode->node_type = GA_NODE_XFEM_MINUS_DIVERG_TEST;
break;
3578 default : GMM_ASSERT1(
false,
"internal error");
3580 pnode->test_function_type = order;
3584 switch(pnode->op_type) {
3585 case GA_PLUS:
case GA_MINUS:
3586 if (mark0 && mark1) {
3587 ga_node_derivation(tree, workspace, m, child0, varname,
3588 interpolatename, order, any_trans);
3589 ga_node_derivation(tree, workspace, m, child1, varname,
3590 interpolatename, order, any_trans);
3592 ga_node_derivation(tree, workspace, m, child0, varname,
3593 interpolatename, order, any_trans);
3594 tree.replace_node_by_child(pnode, 0);
3596 ga_node_derivation(tree, workspace, m, child1, varname,
3597 interpolatename, order, any_trans);
3598 if (pnode->op_type == GA_MINUS) {
3599 pnode->op_type = GA_UNARY_MINUS;
3600 tree.clear_node(child0);
3603 tree.replace_node_by_child(pnode, 1);
3607 case GA_UNARY_MINUS:
case GA_QUOTE:
case GA_SYM:
case GA_SKEW:
3608 case GA_TRACE:
case GA_DEVIATOR:
case GA_PRINT:
3609 ga_node_derivation(tree, workspace, m, child0, varname,
3610 interpolatename, order, any_trans);
3613 case GA_DOT:
case GA_MULT:
case GA_COLON:
case GA_TMULT:
3615 if (mark0 && mark1) {
3616 if (sub_tree_are_equal(child0, child1, workspace, 0) &&
3617 (pnode->op_type != GA_MULT || child0->tensor_order() < 2) &&
3618 (pnode->op_type != GA_DOT || child0->tensor_order() < 2)) {
3619 ga_node_derivation(tree, workspace, m, child1, varname,
3620 interpolatename, order, any_trans);
3621 tree.insert_node(pnode, GA_NODE_OP);
3622 pnode->parent->op_type = GA_MULT;
3623 tree.add_child(pnode->parent);
3624 pnode->parent->children[1]->node_type = GA_NODE_CONSTANT;
3625 pnode->parent->children[1]->init_scalar_tensor(scalar_type(2));
3627 tree.duplicate_with_addition(pnode);
3628 if ((pnode->op_type == GA_COLON && child0->tensor_order() == 2) ||
3629 (pnode->op_type == GA_DOT && child0->tensor_order() == 1 &&
3630 child1->tensor_order() == 1) ||
3631 pnode->op_type == GA_DOTMULT ||
3632 (child0->tensor_proper_size()== 1 &&
3633 child1->tensor_proper_size()== 1))
3634 std::swap(pnode->children[0], pnode->children[1]);
3635 ga_node_derivation(tree, workspace, m, child0, varname,
3636 interpolatename, order, any_trans);
3637 ga_node_derivation(tree, workspace, m,
3638 pnode->parent->children[1]->children[1],
3639 varname, interpolatename, order, any_trans);
3642 ga_node_derivation(tree, workspace, m, child0, varname,
3643 interpolatename, order, any_trans);
3645 ga_node_derivation(tree, workspace, m, child1, varname,
3646 interpolatename, order, any_trans);
3649 case GA_DIV:
case GA_DOTDIV:
3651 if (pnode->children[0]->node_type == GA_NODE_CONSTANT)
3652 gmm::scale(pnode->children[0]->tensor().as_vector(),
3656 tree.duplicate_with_substraction(pnode);
3657 ga_node_derivation(tree, workspace, m, child0, varname,
3658 interpolatename, order, any_trans);
3659 pnode = pnode->parent->children[1];
3661 tree.insert_node(pnode, GA_NODE_OP);
3662 pnode->parent->op_type = GA_UNARY_MINUS;
3665 tree.insert_node(pnode->children[1], GA_NODE_PARAMS);
3666 pga_tree_node pnode_param = pnode->children[1];
3667 tree.add_child(pnode_param);
3668 std::swap(pnode_param->children[0], pnode_param->children[1]);
3669 pnode_param->children[0]->node_type = GA_NODE_PREDEF_FUNC;
3670 pnode_param->children[0]->name =
"sqr";
3671 tree.insert_node(pnode, GA_NODE_OP);
3672 pga_tree_node pnode_mult = pnode->parent;
3673 if (pnode->op_type == GA_DOTDIV)
3674 pnode_mult->op_type = GA_DOTMULT;
3676 pnode_mult->op_type = GA_MULT;
3677 pnode_mult->children.resize(2,
nullptr);
3678 tree.copy_node(pnode_param->children[1], pnode_mult->children[1]);
3679 pnode_mult->accept_child(1);
3680 ga_node_derivation(tree, workspace, m, pnode_mult->children[1],
3681 varname, interpolatename, order, any_trans);
3683 ga_node_derivation(tree, workspace, m, child0, varname,
3684 interpolatename, order, any_trans);
3688 default: GMM_ASSERT1(
false,
"Unexpected operation. Internal error.");
3692 case GA_NODE_C_MATRIX:
3693 for (
size_type i = 0; i < pnode->children.size(); ++i) {
3694 if (pnode->children[i]->marked)
3695 ga_node_derivation(tree, workspace, m, pnode->children[i],
3696 varname, interpolatename, order, any_trans);
3698 pnode->children[i]->init_scalar_tensor(scalar_type(0));
3699 pnode->children[i]->node_type = GA_NODE_ZERO;
3700 tree.clear_children(pnode->children[i]);
3705 case GA_NODE_PARAMS:
3706 if (child0->node_type == GA_NODE_RESHAPE ||
3707 child0->node_type == GA_NODE_SWAP_IND||
3708 child0->node_type == GA_NODE_IND_MOVE_LAST) {
3709 ga_node_derivation(tree, workspace, m, pnode->children[1],
3710 varname, interpolatename, order, any_trans);
3711 }
else if (child0->node_type == GA_NODE_CROSS_PRODUCT) {
3712 pga_tree_node child2 = pnode->children[2];
3713 bool mark2 = child2->marked;
3714 if (mark1 && mark2) {
3715 tree.duplicate_with_addition(pnode);
3716 ga_node_derivation(tree, workspace, m, child1, varname,
3717 interpolatename, order, any_trans);
3718 ga_node_derivation(tree, workspace, m,
3719 pnode->parent->children[1]->children[2],
3720 varname, interpolatename, order, any_trans);
3722 ga_node_derivation(tree, workspace, m, child1, varname,
3723 interpolatename, order, any_trans);
3725 ga_node_derivation(tree, workspace, m, child2, varname,
3726 interpolatename, order, any_trans);
3727 }
else if (child0->node_type == GA_NODE_CONTRACT) {
3729 if (pnode->children.size() == 4) {
3730 ga_node_derivation(tree, workspace, m, pnode->children[1],
3731 varname, interpolatename, order, any_trans);
3732 }
else if (pnode->children.size() == 5 || pnode->children.size() == 7) {
3733 size_type n2 = (pnode->children.size()==5) ? 3 : 4;
3734 pga_tree_node child2 = pnode->children[n2];
3736 if (mark1 && child2->marked) {
3737 tree.duplicate_with_addition(pnode);
3738 ga_node_derivation(tree, workspace, m, child1, varname,
3739 interpolatename, order, any_trans);
3740 ga_node_derivation(tree, workspace, m,
3741 pnode->parent->children[1]->children[n2],
3742 varname, interpolatename, order, any_trans);
3744 ga_node_derivation(tree, workspace, m, child1, varname,
3745 interpolatename, order, any_trans);
3747 ga_node_derivation(tree, workspace, m, child2, varname,
3748 interpolatename, order, any_trans);
3750 }
else GMM_ASSERT1(
false,
"internal error");
3751 }
else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
3752 std::string name = child0->name;
3753 ga_predef_function_tab::const_iterator it = PREDEF_FUNCTIONS.find(name);
3754 const ga_predef_function &F = it->second;
3756 if (F.nbargs() == 1) {
3757 switch (F.dtype()) {
3759 GMM_ASSERT1(
false,
"Cannot derive function " << child0->name
3760 <<
". No derivative provided or not derivable function.");
3763 child0->name = F.derivative1();
3767 child0->name =
"DER_PDFUNC_" + child0->name;
3769 ga_define_function(child0->name, 1, F.derivative1());
3771 std::string expr = ga_derivative_scalar_function(F.expr(),
"t");
3772 ga_define_function(child0->name, 1, expr);
3776 ga_predef_function_tab::const_iterator
3777 itp = PREDEF_FUNCTIONS.find(child0->name);
3778 const ga_predef_function &Fp = itp->second;
3779 if (Fp.is_affine(
"t")) {
3780 scalar_type b = Fp(scalar_type(0));
3781 scalar_type a = Fp(scalar_type(1)) - b;
3782 pnode->node_type = GA_NODE_OP;
3783 pnode->op_type = GA_MULT;
3784 child0->init_scalar_tensor(a);
3785 child0->node_type = ((a == scalar_type(0)) ?
3786 GA_NODE_ZERO : GA_NODE_CONSTANT);
3787 if (b != scalar_type(0)) {
3788 tree.insert_node(pnode, GA_NODE_OP);
3789 pnode->parent->op_type = (b > 0) ? GA_PLUS : GA_MINUS;
3790 tree.add_child(pnode->parent);
3791 pga_tree_node pnode_cte = pnode->parent->children[1];
3792 pnode_cte->node_type = GA_NODE_CONSTANT;
3793 pnode_cte->t = pnode->t;
3794 std::fill(pnode_cte->tensor().begin(),
3795 pnode_cte->tensor().end(), gmm::abs(b));
3796 pnode = pnode->parent;
3802 if (pnode->children.size() >= 2) {
3803 tree.insert_node(pnode, GA_NODE_OP);
3804 pga_tree_node pnode_op = pnode->parent;
3805 if (child1->tensor_order() == 0)
3806 pnode_op->op_type = GA_MULT;
3808 pnode_op->op_type = GA_DOTMULT;
3809 pnode_op->children.resize(2,
nullptr);
3810 tree.copy_node(child1, pnode_op->children[1]);
3811 pnode_op->accept_child(1);
3812 ga_node_derivation(tree, workspace, m, pnode_op->children[1],
3813 varname, interpolatename, order, any_trans);
3816 pga_tree_node child2 = pnode->children[2];
3817 pga_tree_node pg2 = pnode;
3819 if (child1->marked && child2->marked) {
3820 tree.duplicate_with_addition(pnode);
3821 pg2 = pnode->parent->children[1];
3824 if (child1->marked) {
3825 switch (F.dtype()) {
3827 GMM_ASSERT1(
false,
"Cannot derive function " << child0->name
3828 <<
". No derivative provided");
3831 child0->name = F.derivative1();
3834 child0->name =
"DER_PDFUNC1_" + child0->name;
3835 ga_define_function(child0->name, 2, F.derivative1());
3838 child0->name =
"DER_PDFUNC1_" + child0->name;
3839 std::string expr = ga_derivative_scalar_function(F.expr(),
"t");
3840 ga_define_function(child0->name, 2, expr);
3843 tree.insert_node(pnode, GA_NODE_OP);
3844 pga_tree_node pnode_op = pnode->parent;
3845 if (child1->tensor_order() == 0)
3846 pnode_op->op_type = GA_MULT;
3848 pnode_op->op_type = GA_DOTMULT;
3849 pnode_op->children.resize(2,
nullptr);
3850 tree.copy_node(child1, pnode_op->children[1]);
3851 pnode_op->accept_child(1);
3852 ga_node_derivation(tree, workspace, m, pnode_op->children[1],
3853 varname, interpolatename, order, any_trans);
3855 if (child2->marked) {
3857 child0 = pnode->children[0]; child1 = pnode->children[1];
3858 child2 = pnode->children[2];
3860 switch (F.dtype()) {
3862 GMM_ASSERT1(
false,
"Cannot derive function " << child0->name
3863 <<
". No derivative provided");
3866 child0->name = F.derivative2();
3869 child0->name =
"DER_PDFUNC2_" + child0->name;
3870 ga_define_function(child0->name, 2, F.derivative2());
3873 child0->name =
"DER_PDFUNC2_" + child0->name;
3874 std::string expr = ga_derivative_scalar_function(F.expr(),
"u");
3875 ga_define_function(child0->name, 2, expr);
3878 tree.insert_node(pnode, GA_NODE_OP);
3879 pga_tree_node pnode_op = pnode->parent;
3880 if (child2->tensor_order() == 0)
3881 pnode_op->op_type = GA_MULT;
3883 pnode_op->op_type = GA_DOTMULT;
3884 pnode_op->children.resize(2,
nullptr);
3885 tree.copy_node(child2, pnode_op->children[1]);
3886 pnode_op->accept_child(1);
3887 ga_node_derivation(tree, workspace, m, pnode_op->children[1],
3888 varname, interpolatename, order, any_trans);
3891 }
else if (child0->node_type == GA_NODE_SPEC_FUNC) {
3892 GMM_ASSERT1(
false,
"internal error");
3893 }
else if (child0->node_type == GA_NODE_OPERATOR) {
3895 GMM_ASSERT1(
false,
"Error in derivation of the assembly string. "
3896 "Cannot derive again operator " << child0->name);
3899 for (
size_type i = 1; i < pnode->children.size(); ++i)
3900 if (pnode->children[i]->marked) ++nbargs_der;
3901 pga_tree_node pnode2 = 0;
3904 for (
size_type i = 1; i < pnode->children.size(); ++i) {
3905 if (pnode->children[i]->marked) {
3907 if (j != nbargs_der) {
3908 tree.insert_node(pnode, GA_NODE_OP);
3909 pga_tree_node pnode_op = pnode->parent;
3910 pnode_op->node_type = GA_NODE_OP;
3911 pnode_op->op_type = GA_PLUS;
3912 pnode_op->children.resize(2,
nullptr);
3913 tree.copy_node(pnode, pnode_op->children[1]);
3914 pnode_op->accept_child(1);
3915 pnode2 = pnode_op->children[1];
3917 else pnode2 = pnode;
3920 pnode2->children[0]->der2 = i;
3922 pnode2->children[0]->der1 = i;
3923 tree.insert_node(pnode2, GA_NODE_OP);
3924 pga_tree_node pnode_op = pnode2->parent;
3926 size_type red = pnode->children[i]->tensor_order();
3928 case 0 : pnode_op->op_type = GA_MULT;
break;
3929 case 1 : pnode_op->op_type = GA_DOT;
break;
3930 case 2 : pnode_op->op_type = GA_COLON;
break;
3931 default: GMM_ASSERT1(
false,
"Error in derivation of the assembly "
3932 "string. Bad reduction order.")
3934 pnode_op->children.resize(2,
nullptr);
3935 tree.copy_node(pnode->children[i], pnode_op->children[1]);
3936 pnode_op->accept_child(1);
3937 ga_node_derivation(tree, workspace, m, pnode_op->children[1],
3938 varname, interpolatename, order, any_trans);
3940 if (pnode2->children[0]->name.compare(
"Norm_sqr") == 0
3941 && pnode2->children[0]->der1 == 1) {
3942 pnode2->node_type = GA_NODE_OP;
3943 pnode2->op_type = GA_MULT;
3944 pnode2->children[0]->node_type = GA_NODE_CONSTANT;
3945 pnode2->children[0]->init_scalar_tensor(scalar_type(2));
3953 ga_node_derivation(tree, workspace, m, child0, varname,
3954 interpolatename, order, any_trans);
3958 default: GMM_ASSERT1(
false,
"Unexpected node type " << pnode->node_type
3959 <<
" in derivation. Internal error.");
3965 void ga_derivative(ga_tree &tree,
const ga_workspace &workspace,
3966 const mesh &m,
const std::string &varname,
3967 const std::string &interpolatename,
size_type order) {
3968 # ifdef GA_PRINT_DEBUG_INFO
3969 cout <<
"Derivation with respect to " << varname <<
" : "
3970 << ga_tree_to_string(tree) << endl;
3972 if (!(tree.root))
return;
3973 if (ga_node_mark_tree_for_variable(tree.root, workspace, m, varname,
3975 ga_node_derivation(tree, workspace, m, tree.root, varname,
3976 interpolatename, order);
3979 # ifdef GA_PRINT_DEBUG_INFO
3980 cout <<
"Derivation result : " << ga_tree_to_string(tree) << endl;
3990 static bool ga_node_mark_tree_for_grad(pga_tree_node pnode,
3991 const ga_workspace &workspace) {
3992 bool marked =
false;
3993 for (
size_type i = 0; i < pnode->children.size(); ++i)
3994 if (ga_node_mark_tree_for_grad(pnode->children[i], workspace))
3997 bool plain_node(pnode->node_type == GA_NODE_VAL ||
3998 pnode->node_type == GA_NODE_GRAD ||
3999 pnode->node_type == GA_NODE_HESS ||
4000 pnode->node_type == GA_NODE_DIVERG);
4001 bool test_node(pnode->node_type == GA_NODE_VAL_TEST ||
4002 pnode->node_type == GA_NODE_GRAD_TEST ||
4003 pnode->node_type == GA_NODE_HESS_TEST ||
4004 pnode->node_type == GA_NODE_DIVERG_TEST);
4005 bool interpolate_node(pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
4006 pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
4007 pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
4008 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG);
4009 bool elementary_node(pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
4010 pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
4011 pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
4012 pnode->node_type == GA_NODE_ELEMENTARY_DIVERG);
4013 bool xfem_node(pnode->node_type == GA_NODE_XFEM_PLUS_VAL ||
4014 pnode->node_type == GA_NODE_XFEM_PLUS_GRAD ||
4015 pnode->node_type == GA_NODE_XFEM_PLUS_HESS ||
4016 pnode->node_type == GA_NODE_XFEM_PLUS_DIVERG ||
4017 pnode->node_type == GA_NODE_XFEM_MINUS_VAL ||
4018 pnode->node_type == GA_NODE_XFEM_MINUS_GRAD ||
4019 pnode->node_type == GA_NODE_XFEM_MINUS_HESS ||
4020 pnode->node_type == GA_NODE_XFEM_MINUS_DIVERG);
4021 bool interpolate_test_node
4022 (pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST ||
4023 pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST ||
4024 pnode->node_type == GA_NODE_INTERPOLATE_HESS_TEST ||
4025 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST);
4027 if ((plain_node || test_node || interpolate_node ||
4028 elementary_node || xfem_node) &&
4029 (workspace.associated_mf(pnode->name) != 0)) marked =
true;
4031 if (pnode->node_type == GA_NODE_X ||
4032 pnode->node_type == GA_NODE_NORMAL) marked =
true;
4034 if ((interpolate_node || interpolate_test_node) &&
4035 (workspace.associated_mf(pnode->name) != 0)) marked =
true;
4037 if (pnode->node_type == GA_NODE_INTERPOLATE_X ||
4038 pnode->node_type == GA_NODE_INTERPOLATE_ELT_K ||
4039 pnode->node_type == GA_NODE_INTERPOLATE_ELT_B ||
4040 pnode->node_type == GA_NODE_INTERPOLATE_NORMAL) marked =
true;
4042 pnode->marked = marked;
4046 static void ga_node_grad(ga_tree &tree,
const ga_workspace &workspace,
4047 const mesh &m, pga_tree_node pnode) {
4048 # ifdef GA_PRINT_DEBUG_INFO
4049 cout <<
"Gradient of "; ga_print_node(pnode, cout); cout << endl;
4051 size_type meshdim = (&m == &dummy_mesh()) ? 1 : m.dim();
4052 size_type nbch = pnode->children.size();
4053 pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
4054 pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
4055 bool mark0 = ((nbch > 0) ? child0->marked :
false);
4056 bool mark1 = ((nbch > 1) ? child1->marked :
false);
4057 bgeot::multi_index mi;
4059 const ga_predef_function_tab &PREDEF_FUNCTIONS
4062 switch (pnode->node_type) {
4063 case GA_NODE_VAL:
case GA_NODE_VAL_TEST:
4064 if (pnode->node_type == GA_NODE_VAL)
4065 pnode->node_type = GA_NODE_GRAD;
4067 pnode->node_type = GA_NODE_GRAD_TEST;
4068 mi = pnode->tensor().sizes();
4069 if (mi.back() != 1) mi.push_back(m.dim());
else mi.back() = m.dim();
4070 pnode->t.adjust_sizes(mi);
4072 case GA_NODE_GRAD:
case GA_NODE_GRAD_TEST:
4073 if (pnode->node_type == GA_NODE_GRAD)
4074 pnode->node_type = GA_NODE_HESS;
4076 pnode->node_type = GA_NODE_HESS_TEST;
4077 mi = pnode->tensor().sizes();
4078 if (mi.back() != 1) mi.push_back(m.dim());
else mi.back() = m.dim();
4079 pnode->t.adjust_sizes(mi);
4081 case GA_NODE_HESS:
case GA_NODE_HESS_TEST:
4082 GMM_ASSERT1(
false,
"Sorry, cannot derive an Hessian once more");
4084 case GA_NODE_DIVERG:
case GA_NODE_DIVERG_TEST:
4085 if (pnode->node_type == GA_NODE_DIVERG)
4086 pnode->node_type = GA_NODE_HESS;
4088 pnode->node_type = GA_NODE_HESS_TEST;
4089 mi = pnode->tensor().sizes();
4090 mi.pop_back(), mi.push_back(m.dim());
4091 if (m.dim() > 1) mi.push_back(m.dim());
4092 pnode->t.adjust_sizes(mi);
4093 tree.duplicate_with_operation(pnode, GA_COLON);
4095 pnode = pnode->parent;
4096 child1 = pnode->children[1];
4097 child1->init_matrix_tensor(meshdim, meshdim);
4100 child1->tensor()(i,i) = scalar_type(1);
4101 child1->node_type = GA_NODE_CONSTANT;
4104 case GA_NODE_INTERPOLATE_HESS_TEST:
4105 case GA_NODE_INTERPOLATE_HESS:
4106 case GA_NODE_SECONDARY_DOMAIN_HESS_TEST:
4107 case GA_NODE_SECONDARY_DOMAIN_HESS:
4108 GMM_ASSERT1(
false,
"Sorry, cannot derive a hessian once more");
4111 case GA_NODE_INTERPOLATE_VAL:
4112 case GA_NODE_INTERPOLATE_GRAD:
4113 case GA_NODE_INTERPOLATE_DIVERG:
4114 case GA_NODE_INTERPOLATE_VAL_TEST:
4115 case GA_NODE_INTERPOLATE_GRAD_TEST:
4116 case GA_NODE_INTERPOLATE_DIVERG_TEST:
4117 case GA_NODE_INTERPOLATE_X:
4119 std::string &tname = pnode->interpolate_name;
4120 auto ptrans = workspace.interpolate_transformation(tname);
4121 std::string expr_trans = ptrans->expression();
4122 if (expr_trans.size() == 0)
4123 GMM_ASSERT1(
false,
"Sorry, the gradient of tranformation "
4124 << tname <<
" cannot be calculated. "
4125 "The gradient computation is available only for "
4126 "transformations having an explicit expression");
4129 ga_read_string(expr_trans, trans_tree, workspace.macro_dictionary());
4130 ga_semantic_analysis(trans_tree, workspace, m,
4131 ref_elt_dim_of_mesh(m, -1),
false,
false, 1);
4132 if (trans_tree.root) {
4133 ga_node_grad(trans_tree, workspace, m, trans_tree.root);
4134 ga_semantic_analysis(trans_tree, workspace, m,
4135 ref_elt_dim_of_mesh(m, -1),
false,
false, 1);
4137 GMM_ASSERT1(trans_tree.root->tensor().sizes().size() == 2,
4138 "Problem in transformation" << tname);
4139 size_type trans_dim = trans_tree.root->tensor().sizes()[1];
4141 tree.duplicate_with_operation(pnode, GA_DOT);
4143 if (pnode->node_type == GA_NODE_INTERPOLATE_VAL) {
4144 pnode->node_type = GA_NODE_INTERPOLATE_GRAD;
4145 mi = pnode->tensor().sizes();
4146 if (mi.back() != 1) mi.push_back(trans_dim);
4147 else mi.back() = trans_dim;
4148 pnode->t.adjust_sizes(mi);
4149 }
else if (pnode->node_type == GA_NODE_INTERPOLATE_GRAD) {
4150 pnode->node_type = GA_NODE_INTERPOLATE_HESS;
4151 mi = pnode->tensor().sizes();
4152 if (mi.back() != 1) mi.push_back(trans_dim);
4153 else mi.back() = trans_dim;
4154 pnode->t.adjust_sizes(mi);
4155 }
else if (pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST) {
4156 pnode->node_type = GA_NODE_INTERPOLATE_GRAD_TEST;
4157 mi = pnode->tensor().sizes();
4158 if (mi.back() != 1) mi.push_back(trans_dim);
4159 else mi.back() = trans_dim;
4160 pnode->t.adjust_sizes(mi);
4161 }
else if (pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST) {
4162 pnode->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
4163 mi = pnode->tensor().sizes();
4164 if (mi.back() != 1) mi.push_back(trans_dim);
4165 else mi.back() = trans_dim;
4166 pnode->t.adjust_sizes(mi);
4167 }
else if (pnode->node_type == GA_NODE_INTERPOLATE_DIVERG ||
4168 pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST) {
4169 if (pnode->node_type == GA_NODE_INTERPOLATE_DIVERG)
4170 pnode->node_type = GA_NODE_INTERPOLATE_HESS;
4172 pnode->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
4173 mi = pnode->tensor().sizes();
4174 mi.pop_back(), mi.push_back(trans_dim);
4175 if (trans_dim > 1) mi.push_back(trans_dim);
4176 pnode->t.adjust_sizes(mi);
4177 tree.duplicate_with_operation(pnode, GA_COLON);
4179 pnode = pnode->parent;
4180 child1 = pnode->children[1];
4181 child1->init_matrix_tensor(trans_dim, trans_dim);
4183 for (
size_type i = 0; i < trans_dim; ++i)
4184 child1->tensor()(i,i) = scalar_type(1);
4185 child1->node_type = GA_NODE_CONSTANT;
4186 }
else if (pnode->node_type == GA_NODE_INTERPOLATE_X) {
4187 pnode->node_type = GA_NODE_CONSTANT;
4189 pnode->init_vector_tensor(trans_dim);
4191 pnode->tensor()[pnode->nbc1-1] = scalar_type(1);
4193 pnode->init_matrix_tensor(trans_dim, trans_dim);
4195 for (
size_type i = 0; i < trans_dim; ++i)
4196 pnode->tensor()(i,i) = scalar_type(1);
4200 tree.clear_node_rec(pnode->parent->children[1]);
4201 pnode->parent->children[1] =
nullptr;
4202 tree.copy_node(trans_tree.root, pnode->parent->children[1]);
4203 pnode->parent->accept_child(1);
4205 pnode->node_type = GA_NODE_ZERO;
4206 mi = pnode->tensor().sizes();
4207 mi.push_back(m.dim());
4214 pnode->node_type = GA_NODE_CONSTANT;
4216 pnode->init_vector_tensor(meshdim);
4218 pnode->tensor()[pnode->nbc1-1] = scalar_type(1);
4220 pnode->init_matrix_tensor(meshdim, meshdim);
4223 pnode->tensor()(i,i) = scalar_type(1);
4227 case GA_NODE_NORMAL:
4228 case GA_NODE_INTERPOLATE_NORMAL:
4229 GMM_ASSERT1(
false,
"Sorry, Gradient of Normal vector not implemented");
4232 case GA_NODE_ELT_K:
case GA_NODE_ELT_B:
4233 case GA_NODE_INTERPOLATE_ELT_K:
case GA_NODE_INTERPOLATE_ELT_B:
4234 GMM_ASSERT1(
false,
"Sorry, Gradient of element_K or element_B "
4238 case GA_NODE_INTERPOLATE_DERIVATIVE:
4239 GMM_ASSERT1(
false,
"Sorry, gradient of the derivative of a "
4240 "tranformation not implemented");
4243 case GA_NODE_INTERPOLATE_FILTER:
4244 ga_node_grad(tree, workspace, m, child0);
4247 case GA_NODE_ELEMENTARY_VAL:
case GA_NODE_ELEMENTARY_VAL_TEST:
4248 case GA_NODE_XFEM_PLUS_VAL:
case GA_NODE_XFEM_PLUS_VAL_TEST:
4249 case GA_NODE_XFEM_MINUS_VAL:
case GA_NODE_XFEM_MINUS_VAL_TEST:
4250 case GA_NODE_ELEMENTARY_GRAD:
case GA_NODE_ELEMENTARY_GRAD_TEST:
4251 case GA_NODE_XFEM_PLUS_GRAD:
case GA_NODE_XFEM_PLUS_GRAD_TEST:
4252 case GA_NODE_XFEM_MINUS_GRAD:
case GA_NODE_XFEM_MINUS_GRAD_TEST:
4254 static const std::map<GA_NODE_TYPE, GA_NODE_TYPE>
4256 { {GA_NODE_ELEMENTARY_VAL, GA_NODE_ELEMENTARY_GRAD},
4257 {GA_NODE_ELEMENTARY_VAL_TEST, GA_NODE_ELEMENTARY_GRAD_TEST},
4258 {GA_NODE_ELEMENTARY_GRAD, GA_NODE_ELEMENTARY_HESS},
4259 {GA_NODE_ELEMENTARY_GRAD_TEST, GA_NODE_ELEMENTARY_HESS_TEST},
4260 {GA_NODE_XFEM_PLUS_VAL, GA_NODE_XFEM_PLUS_GRAD},
4261 {GA_NODE_XFEM_PLUS_VAL_TEST, GA_NODE_XFEM_PLUS_GRAD_TEST},
4262 {GA_NODE_XFEM_PLUS_GRAD, GA_NODE_XFEM_PLUS_HESS},
4263 {GA_NODE_XFEM_PLUS_GRAD_TEST, GA_NODE_XFEM_PLUS_HESS_TEST},
4264 {GA_NODE_XFEM_MINUS_VAL, GA_NODE_XFEM_MINUS_GRAD},
4265 {GA_NODE_XFEM_MINUS_VAL_TEST, GA_NODE_XFEM_MINUS_GRAD_TEST},
4266 {GA_NODE_XFEM_MINUS_GRAD, GA_NODE_XFEM_MINUS_HESS},
4267 {GA_NODE_XFEM_MINUS_GRAD_TEST, GA_NODE_XFEM_MINUS_HESS_TEST}
4269 pnode->node_type = replacement_table.at(pnode->node_type);
4271 mi = pnode->tensor().sizes();
4273 mi.back() = m.dim();
4275 mi.push_back(m.dim());
4276 pnode->t.adjust_sizes(mi);
4278 case GA_NODE_ELEMENTARY_HESS:
case GA_NODE_ELEMENTARY_HESS_TEST:
4279 case GA_NODE_XFEM_PLUS_HESS:
case GA_NODE_XFEM_PLUS_HESS_TEST:
4280 case GA_NODE_XFEM_MINUS_HESS:
case GA_NODE_XFEM_MINUS_HESS_TEST:
4281 GMM_ASSERT1(
false,
"Sorry, cannot derive an Hessian once more");
4283 case GA_NODE_ELEMENTARY_DIVERG:
case GA_NODE_ELEMENTARY_DIVERG_TEST:
4284 case GA_NODE_XFEM_PLUS_DIVERG:
case GA_NODE_XFEM_PLUS_DIVERG_TEST:
4285 case GA_NODE_XFEM_MINUS_DIVERG:
case GA_NODE_XFEM_MINUS_DIVERG_TEST:
4287 static const std::map<GA_NODE_TYPE, GA_NODE_TYPE>
4289 { {GA_NODE_ELEMENTARY_DIVERG, GA_NODE_ELEMENTARY_HESS},
4290 {GA_NODE_ELEMENTARY_DIVERG_TEST, GA_NODE_ELEMENTARY_HESS_TEST},
4291 {GA_NODE_XFEM_PLUS_DIVERG, GA_NODE_XFEM_PLUS_HESS},
4292 {GA_NODE_XFEM_PLUS_DIVERG_TEST, GA_NODE_XFEM_PLUS_HESS_TEST},
4293 {GA_NODE_XFEM_MINUS_DIVERG, GA_NODE_XFEM_MINUS_HESS},
4294 {GA_NODE_XFEM_MINUS_DIVERG_TEST, GA_NODE_XFEM_MINUS_HESS_TEST}
4296 pnode->node_type = replacement_table.at(pnode->node_type);
4298 mi = pnode->tensor().sizes();
4300 mi.push_back(m.dim());
4302 mi.push_back(m.dim());
4303 pnode->t.adjust_sizes(mi);
4304 tree.duplicate_with_operation(pnode, GA_COLON);
4306 pnode = pnode->parent;
4307 child1 = pnode->children[1];
4308 child1->init_matrix_tensor(meshdim, meshdim);
4311 child1->tensor()(i,i) = scalar_type(1);
4312 child1->node_type = GA_NODE_CONSTANT;
4316 switch(pnode->op_type) {
4317 case GA_PLUS:
case GA_MINUS:
4318 if (mark0 && mark1) {
4319 ga_node_grad(tree, workspace, m, child0);
4320 ga_node_grad(tree, workspace, m, child1);
4322 ga_node_grad(tree, workspace, m, child0);
4323 tree.replace_node_by_child(pnode, 0);
4325 ga_node_grad(tree, workspace, m, child1);
4326 if (pnode->op_type == GA_MINUS) {
4327 pnode->op_type = GA_UNARY_MINUS;
4328 tree.clear_node(child0);
4331 tree.replace_node_by_child(pnode, 1);
4335 case GA_UNARY_MINUS:
case GA_PRINT:
4336 ga_node_grad(tree, workspace, m, child0);
4340 if (child0->tensor_order() == 1) {
4341 size_type nn = child0->tensor_proper_size(0);
4342 ga_node_grad(tree, workspace, m, child0);
4343 pnode->node_type = GA_NODE_PARAMS;
4344 tree.add_child(pnode);
4345 std::swap(pnode->children[0], pnode->children[1]);
4346 pnode->children[0]->node_type = GA_NODE_RESHAPE;
4347 tree.add_child(pnode); tree.add_child(pnode); tree.add_child(pnode);
4348 pnode->children[2]->node_type = GA_NODE_CONSTANT;
4349 pnode->children[3]->node_type = GA_NODE_CONSTANT;
4350 pnode->children[4]->node_type = GA_NODE_CONSTANT;
4351 pnode->children[2]->init_scalar_tensor(scalar_type(1));
4352 pnode->children[3]->init_scalar_tensor(scalar_type(nn));
4353 pnode->children[4]->init_scalar_tensor(scalar_type(m.dim()));
4355 ga_node_grad(tree, workspace, m, child0);
4361 if (pnode->op_type == GA_SYM) {
4362 tree.replace_node_by_child(pnode, 0);
4363 tree.duplicate_with_addition(child0);
4365 tree.replace_node_by_child(pnode, 0);
4366 tree.duplicate_with_substraction(child0);
4368 tree.insert_node(child0->parent, GA_NODE_OP);
4369 tree.add_child(child0->parent->parent);
4370 child0->parent->parent->op_type = GA_MULT;
4371 child0->parent->parent->children[1]->node_type = GA_NODE_CONSTANT;
4372 child0->parent->parent->children[1]->init_scalar_tensor(0.5);
4373 tree.insert_node(child0->parent->children[1], GA_NODE_OP);
4374 child0->parent->children[1]->op_type = GA_QUOTE;
4375 ga_node_grad(tree, workspace, m, child0);
4376 ga_node_grad(tree, workspace, m,
4377 child0->parent->children[1]->children[0]);
4381 ga_node_grad(tree, workspace, m, child0);
4382 pnode->node_type = GA_NODE_PARAMS;
4383 tree.add_child(pnode);
4384 std::swap(pnode->children[0], pnode->children[1]);
4385 pnode->children[0]->node_type = GA_NODE_NAME;
4386 pnode->children[0]->name =
"Contract";
4387 tree.add_child(pnode); tree.add_child(pnode);
4388 pnode->children[2]->node_type = GA_NODE_CONSTANT;
4389 pnode->children[3]->node_type = GA_NODE_CONSTANT;
4390 pnode->children[2]->init_scalar_tensor(scalar_type(1));
4391 pnode->children[3]->init_scalar_tensor(scalar_type(2));
4396 tree.duplicate_with_substraction(child0);
4397 child1 = child0->parent->children[1];
4398 tree.insert_node(child1, GA_NODE_OP);
4399 child1->parent->op_type = GA_TRACE;
4400 tree.insert_node(child1->parent, GA_NODE_OP);
4401 child1->parent->parent->op_type = GA_TMULT;
4402 tree.add_child(child1->parent->parent);
4403 std::swap(child1->parent->parent->children[0],
4404 child1->parent->parent->children[1]);
4405 pga_tree_node pid = child1->parent->parent->children[0];
4406 tree.duplicate_with_operation(pid, GA_DIV);
4407 pid->parent->children[1]->node_type = GA_NODE_CONSTANT;
4408 pid->parent->children[1]->init_scalar_tensor(m.dim());
4409 pid->node_type = GA_NODE_PARAMS;
4410 tree.add_child(pid); tree.add_child(pid);
4411 pid->children[0]->node_type = GA_NODE_NAME;
4412 pid->children[0]->name =
"Id";
4413 pid->children[1]->node_type = GA_NODE_CONSTANT;
4414 pid->children[1]->init_scalar_tensor(m.dim());
4415 ga_node_grad(tree, workspace, m, child0);
4416 child1->parent->marked =
true;
4417 ga_node_grad(tree, workspace, m, child1->parent);
4418 tree.replace_node_by_child(pnode, 0);
4423 case GA_DOT:
case GA_MULT:
case GA_DOTMULT:
case GA_COLON:
case GA_TMULT:
4425 pga_tree_node pg1(0), pg2(0);
4426 if (mark0 && mark1) {
4427 if (sub_tree_are_equal(child0, child1, workspace, 0) &&
4428 (pnode->op_type != GA_MULT || child0->tensor_order() < 2) &&
4429 (pnode->op_type != GA_DOT || child0->tensor_order() < 2)) {
4431 tree.insert_node(pnode, GA_NODE_OP);
4432 pnode->parent->op_type = GA_MULT;
4433 tree.add_child(pnode->parent);
4434 pnode->parent->children[1]->node_type = GA_NODE_CONSTANT;
4435 pnode->parent->children[1]->init_scalar_tensor(scalar_type(2));
4437 tree.duplicate_with_addition(pnode);
4439 pg2 = pnode->parent->children[1];
4441 }
else if (mark0) pg1 = pnode;
else pg2 = pnode;
4444 if ((pg1->op_type == GA_COLON && child0->tensor_order() == 2) ||
4445 (pg1->op_type == GA_DOT && child0->tensor_order() == 1 &&
4446 child1->tensor_order() == 1) ||
4447 pg1->op_type == GA_DOTMULT ||
4448 (child0->tensor_proper_size()== 1 ||
4449 child1->tensor_proper_size()== 1)) {
4450 std::swap(pg1->children[0], pg1->children[1]);
4453 if (pnode->op_type == GA_MULT || pnode->op_type == GA_COLON ||
4454 pnode->op_type == GA_DOT) {
4455 if ((pg1->children[0]->tensor_order() <= 2 &&
4456 pnode->op_type == GA_MULT) ||
4457 pnode->op_type == GA_DOT) {
4458 nred = pg1->children[0]->tensor_order();
4459 pg1->node_type = GA_NODE_PARAMS;
4460 tree.add_child(pg1);tree.add_child(pg1);tree.add_child(pg1);
4461 std::swap(pg1->children[1], pg1->children[3]);
4462 std::swap(pg1->children[0], pg1->children[1]);
4463 pg1->children[0]->node_type = GA_NODE_NAME;
4464 pg1->children[0]->name =
"Contract";
4465 pg1->children[2]->node_type = GA_NODE_CONSTANT;
4466 pg1->children[2]->init_scalar_tensor
4467 (scalar_type(pg1->children[1]->tensor_order()));
4468 pg1->children[4]->node_type = GA_NODE_CONSTANT;
4469 pg1->children[4]->init_scalar_tensor(scalar_type(1));
4470 ga_node_grad(tree, workspace, m, pg1->children[1]);
4472 nred = pg1->children[0]->tensor_order()-1;
4473 pg1->node_type = GA_NODE_PARAMS;
4474 tree.add_child(pg1);tree.add_child(pg1);tree.add_child(pg1);
4475 tree.add_child(pg1);tree.add_child(pg1);
4476 std::swap(pg1->children[1], pg1->children[4]);
4477 std::swap(pg1->children[0], pg1->children[1]);
4478 pg1->children[0]->node_type = GA_NODE_NAME;
4479 pg1->children[0]->name =
"Contract";
4480 pg1->children[2]->node_type = GA_NODE_CONSTANT;
4481 pg1->children[2]->init_scalar_tensor
4482 (scalar_type(pg1->children[1]->tensor_order()-1));
4483 pg1->children[3]->node_type = GA_NODE_CONSTANT;
4484 pg1->children[3]->init_scalar_tensor
4485 (scalar_type(pg1->children[1]->tensor_order()));
4486 pg1->children[5]->node_type = GA_NODE_CONSTANT;
4487 pg1->children[5]->init_scalar_tensor(scalar_type(1));
4488 pg1->children[6]->node_type = GA_NODE_CONSTANT;
4489 pg1->children[6]->init_scalar_tensor(scalar_type(2));
4490 ga_node_grad(tree, workspace, m, pg1->children[1]);
4492 }
else if (pnode->op_type == GA_TMULT) {
4493 nred = pg1->children[0]->tensor_order()+1;
4494 ga_node_grad(tree, workspace, m, pg1->children[0]);
4495 }
else GMM_ASSERT1(
false,
"internal error");
4496 tree.insert_node(pg1, GA_NODE_PARAMS);
4497 tree.add_child(pg1->parent);
4498 tree.add_child(pg1->parent);
4499 std::swap(pg1->parent->children[0], pg1->parent->children[1]);
4500 pg1->parent->children[0]->node_type = GA_NODE_IND_MOVE_LAST;
4501 pg1->parent->children[2]->node_type = GA_NODE_CONSTANT;
4502 pg1->parent->children[2]->init_scalar_tensor(scalar_type(nred));
4507 for (; pg2||pg1;pg2=pg1, pg1=0) {
4509 if (pnode->op_type == GA_MULT || pnode->op_type == GA_COLON ||
4510 pnode->op_type == GA_DOT) {
4511 if (pg2->children[1]->tensor_proper_size() == 1) {
4512 if (pg2->children[0]->tensor_proper_size() == 1)
4513 pg2->op_type = GA_MULT;
4515 pg2->op_type = GA_TMULT;
4516 ga_node_grad(tree, workspace, m, pg2->children[1]);
4517 }
else if (pg2->children[0]->tensor_proper_size() == 1) {
4518 pg2->op_type = GA_MULT;
4519 ga_node_grad(tree, workspace, m, pg2->children[1]);
4520 }
else if ((pg2->children[0]->tensor_order() <= 2 &&
4521 pnode->op_type == GA_MULT) ||
4522 pnode->op_type == GA_DOT) {
4523 pg2->op_type = GA_DOT;
4524 ga_node_grad(tree, workspace, m, pg2->children[1]);
4526 pg2->node_type = GA_NODE_PARAMS;
4527 tree.add_child(pg2);tree.add_child(pg2);tree.add_child(pg2);
4528 tree.add_child(pg2);tree.add_child(pg2);
4529 std::swap(pg2->children[1], pg2->children[4]);
4530 std::swap(pg2->children[0], pg2->children[1]);
4531 pg2->children[0]->node_type = GA_NODE_NAME;
4532 pg2->children[0]->name =
"Contract";
4533 pg2->children[2]->node_type = GA_NODE_CONSTANT;
4534 pg2->children[2]->init_scalar_tensor
4535 (scalar_type(pg2->children[4]->tensor_order()-1));
4536 pg2->children[3]->node_type = GA_NODE_CONSTANT;
4537 pg2->children[3]->init_scalar_tensor
4538 (scalar_type(pg2->children[4]->tensor_order()));
4539 pg2->children[5]->node_type = GA_NODE_CONSTANT;
4540 pg2->children[5]->init_scalar_tensor(scalar_type(1));
4541 pg2->children[6]->node_type = GA_NODE_CONSTANT;
4542 pg2->children[6]->init_scalar_tensor(scalar_type(2));
4543 ga_node_grad(tree, workspace, m, pg2->children[4]);
4545 }
else if (pnode->op_type == GA_TMULT) {
4546 ga_node_grad(tree, workspace, m, pg2->children[1]);
4547 }
else if (pnode->op_type == GA_DOTMULT) {
4548 if (pg2->children[0]->tensor_proper_size() == 1) {
4549 pg2->op_type = GA_MULT;
4550 ga_node_grad(tree, workspace, m, pg2->children[1]);
4552 tree.insert_node(pg2->children[0], GA_NODE_OP);
4553 tree.add_child(pg2->children[0], GA_NODE_CONSTANT);
4554 pg2->children[0]->op_type = GA_TMULT;
4555 pg2->children[0]->children[1]->init_vector_tensor(m.dim());
4556 gmm::fill(pg2->children[0]->children[1]->tensor().as_vector(),
4558 ga_node_grad(tree, workspace, m, pg2->children[1]);
4566 case GA_DIV:
case GA_DOTDIV:
4568 pga_tree_node pg1 = child0;
4570 if (pnode->children[0]->node_type == GA_NODE_CONSTANT) {
4571 gmm::scale(pnode->children[0]->tensor().as_vector(),
4576 tree.duplicate_with_substraction(pnode);
4577 pnode = pnode->parent->children[1];
4580 tree.insert_node(pnode, GA_NODE_OP);
4581 pnode->parent->op_type = GA_UNARY_MINUS;
4585 tree.insert_node(pnode->children[1], GA_NODE_PARAMS);
4586 pga_tree_node pnode_param = pnode->children[1];
4587 tree.add_child(pnode_param);
4588 std::swap(pnode_param->children[0], pnode_param->children[1]);
4589 pnode_param->children[0]->node_type = GA_NODE_PREDEF_FUNC;
4590 pnode_param->children[0]->name =
"sqr";
4591 tree.insert_node(pnode, GA_NODE_OP);
4592 pga_tree_node pnode_mult = pnode->parent;
4593 if (pnode->op_type == GA_DOTDIV) {
4594 pnode_mult->op_type = GA_DOTMULT;
4595 tree.insert_node(pnode_mult->children[0], GA_NODE_OP);
4596 pga_tree_node ptmult = pnode_mult->children[0];
4597 ptmult->op_type = GA_TMULT;
4598 tree.add_child(ptmult, GA_NODE_CONSTANT);
4599 ptmult->children[1]->init_vector_tensor(m.dim());
4600 gmm::fill(ptmult->children[1]->tensor().as_vector(),
4603 pnode_mult->op_type = GA_TMULT;
4605 pnode_mult->children.resize(2,
nullptr);
4606 tree.copy_node(pnode_param->children[1],
4607 pnode_mult->children[1]);
4608 pnode_mult->accept_child(1);
4609 ga_node_grad(tree, workspace, m, pnode_mult->children[1]);
4613 ga_node_grad(tree, workspace, m, pg1);
4614 if (pnode->op_type == GA_DOTDIV) {
4615 tree.insert_node(pg1->parent->children[1], GA_NODE_OP);
4616 pga_tree_node ptmult = pg1->parent->children[1];
4617 ptmult->op_type = GA_TMULT;
4618 tree.add_child(ptmult, GA_NODE_CONSTANT);
4619 ptmult->children[1]->init_vector_tensor(m.dim());
4620 gmm::fill(ptmult->children[1]->tensor().as_vector(),
4626 default: GMM_ASSERT1(
false,
"Unexpected operation. Internal error.");
4630 case GA_NODE_C_MATRIX:
4632 for (
size_type i = 0; i < pnode->children.size(); ++i) {
4633 if (pnode->children[i]->marked)
4634 ga_node_grad(tree, workspace, m, pnode->children[i]);
4636 pnode->children[i]->init_scalar_tensor(scalar_type(0));
4637 pnode->children[i]->node_type = GA_NODE_ZERO;
4638 tree.clear_children(pnode->children[i]);
4642 size_type orgsize = pnode->children.size();
4643 mi = pnode->tensor().sizes();
4644 mi.push_back(m.dim());
4646 pnode->tensor().adjust_sizes(mi);
4648 pnode->children.resize(orgsize*m.dim(),
nullptr);
4649 for (
size_type i = orgsize; i < pnode->children.size(); ++i) {
4650 tree.copy_node(pnode->children[i % orgsize],
4651 pnode->children[i]);
4652 pnode->accept_child(i);
4654 for (
size_type i = 0; i < pnode->children.size(); ++i) {
4655 pga_tree_node child = pnode->children[i];
4656 if (child->node_type != GA_NODE_ZERO) {
4657 tree.insert_node(child, GA_NODE_PARAMS);
4658 tree.add_child(child->parent, GA_NODE_CONSTANT);
4659 child->parent->children[1]
4660 ->init_scalar_tensor(scalar_type(1+i/orgsize));
4667 case GA_NODE_PARAMS:
4668 if (child0->node_type == GA_NODE_RESHAPE) {
4669 ga_node_grad(tree, workspace, m, pnode->children[1]);
4670 tree.add_child(pnode, GA_NODE_CONSTANT);
4671 pnode->children.back()->init_scalar_tensor(scalar_type(m.dim()));
4672 }
else if (child0->node_type == GA_NODE_CROSS_PRODUCT) {
4673 GMM_ASSERT1(
false,
"Sorry, the gradient of a cross product"
4674 "has not been implemented. To be done.");
4675 }
else if (child0->node_type == GA_NODE_IND_MOVE_LAST) {
4676 size_type order = pnode->tensor_order();
4677 ga_node_grad(tree, workspace, m, pnode->children[1]);
4678 tree.insert_node(pnode, GA_NODE_PARAMS);
4679 tree.add_child(pnode->parent);
4680 tree.add_child(pnode->parent);
4681 tree.add_child(pnode->parent);
4682 std::swap(pnode->parent->children[0], pnode->parent->children[1]);
4683 pnode->parent->children[0]->node_type = GA_NODE_SWAP_IND;
4684 pnode->parent->children[2]->node_type = GA_NODE_CONSTANT;
4685 pnode->parent->children[3]->node_type = GA_NODE_CONSTANT;
4686 pnode->parent->children[2]->init_scalar_tensor(scalar_type(order));
4687 pnode->parent->children[3]->init_scalar_tensor(scalar_type(order+1));
4688 }
else if (child0->node_type == GA_NODE_SWAP_IND) {
4689 ga_node_grad(tree, workspace, m, pnode->children[1]);
4690 }
else if (child0->node_type == GA_NODE_CONTRACT) {
4693 if (pnode->children.size() == 5) ch2 = 3;
4694 if (pnode->children.size() == 7) ch2 = 4;
4695 mark1 = pnode->children[ch2]->marked;
4697 if (pnode->children.size() == 4) {
4698 ga_node_grad(tree, workspace, m, pnode->children[1]);
4700 pga_tree_node pg1(pnode), pg2(pnode);
4701 if (mark0 && mark1) {
4702 tree.duplicate_with_addition(pnode);
4703 pg2 = pnode->parent->children[1];
4706 size_type nred = pg1->children[1]->tensor_order();
4707 if (pnode->children.size() == 7) nred--;
4708 ga_node_grad(tree, workspace, m, pg1->children[1]);
4709 tree.insert_node(pg1, GA_NODE_PARAMS);
4710 tree.add_child(pg1->parent);
4711 tree.add_child(pg1->parent);
4712 std::swap(pg1->parent->children[0], pg1->parent->children[1]);
4713 pg1->parent->children[0]->node_type = GA_NODE_IND_MOVE_LAST;
4714 pg1->parent->children[2]->node_type = GA_NODE_CONSTANT;
4715 pg1->parent->children[2]->init_scalar_tensor(scalar_type(nred));
4718 ga_node_grad(tree, workspace, m, pg2->children[ch2]);
4722 }
else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
4723 std::string name = child0->name;
4724 ga_predef_function_tab::const_iterator it = PREDEF_FUNCTIONS.find(name);
4725 const ga_predef_function &F = it->second;
4727 if (F.nbargs() == 1) {
4728 switch (F.dtype()) {
4730 GMM_ASSERT1(
false,
"Cannot derive function " << child0->name
4731 <<
". No derivative provided or not derivable function.");
4734 child0->name = F.derivative1();
4738 child0->name =
"DER_PDFUNC_" + child0->name;
4740 ga_define_function(child0->name, 1, F.derivative1());
4742 std::string expr=ga_derivative_scalar_function(F.expr(),
"t");
4743 ga_define_function(child0->name, 1, expr);
4747 ga_predef_function_tab::const_iterator
4748 itp = PREDEF_FUNCTIONS.find(child0->name);
4749 const ga_predef_function &Fp = itp->second;
4750 if (Fp.is_affine(
"t")) {
4751 scalar_type b = Fp(scalar_type(0));
4752 scalar_type a = Fp(scalar_type(1)) - b;
4753 pnode->node_type = GA_NODE_OP;
4754 pnode->op_type = GA_MULT;
4755 child0->init_scalar_tensor(a);
4756 child0->node_type = ((a == scalar_type(0)) ?
4757 GA_NODE_ZERO : GA_NODE_CONSTANT);
4758 if (b != scalar_type(0)) {
4759 tree.insert_node(pnode, GA_NODE_OP);
4760 pnode->parent->op_type = (b > 0) ? GA_PLUS : GA_MINUS;
4761 tree.add_child(pnode->parent);
4762 pga_tree_node pnode_cte = pnode->parent->children[1];
4763 pnode_cte->node_type = GA_NODE_CONSTANT;
4764 pnode_cte->t = pnode->t;
4765 std::fill(pnode_cte->tensor().begin(),
4766 pnode_cte->tensor().end(), gmm::abs(b));
4767 pnode = pnode->parent;
4773 if (pnode->children.size() >= 2) {
4774 tree.insert_node(pnode, GA_NODE_OP);
4775 pga_tree_node pnode_op = pnode->parent;
4776 if (child1->tensor_order() == 0)
4777 pnode_op->op_type = GA_MULT;
4779 pnode_op->op_type = GA_DOTMULT;
4780 tree.insert_node(pnode, GA_NODE_OP);
4781 pnode->parent->op_type = GA_TMULT;
4782 tree.add_child(pnode->parent, GA_NODE_CONSTANT);
4783 pnode->parent->children[1]->init_vector_tensor(m.dim());
4784 gmm::fill(pnode->parent->children[1]->tensor().as_vector(),
4787 pnode_op->children.resize(2,
nullptr);
4788 tree.copy_node(child1, pnode_op->children[1]);
4789 pnode_op->accept_child(1);
4790 ga_node_grad(tree, workspace, m, pnode_op->children[1]);
4793 pga_tree_node child2 = pnode->children[2];
4794 pga_tree_node pg2 = pnode;
4796 if (child1->marked && child2->marked) {
4797 tree.duplicate_with_addition(pnode);
4798 pg2 = pnode->parent->children[1];
4801 if (child1->marked) {
4802 switch (F.dtype()) {
4804 GMM_ASSERT1(
false,
"Cannot derive function " << child0->name
4805 <<
". No derivative provided");
4808 child0->name = F.derivative1();
4811 child0->name =
"DER_PDFUNC1_" + child0->name;
4812 ga_define_function(child0->name, 2, F.derivative1());
4815 child0->name =
"DER_PDFUNC1_" + child0->name;
4816 std::string expr = ga_derivative_scalar_function(F.expr(),
"t");
4817 ga_define_function(child0->name, 2, expr);
4820 tree.insert_node(pnode, GA_NODE_OP);
4821 pga_tree_node pnode_op = pnode->parent;
4822 if (child1->tensor_order() == 0)
4823 pnode_op->op_type = GA_MULT;
4825 pnode_op->op_type = GA_DOTMULT;
4826 tree.insert_node(pnode, GA_NODE_OP);
4827 pnode->parent->op_type = GA_TMULT;
4828 tree.add_child(pnode->parent, GA_NODE_CONSTANT);
4829 pnode->parent->children[1]->init_vector_tensor(m.dim());
4830 gmm::fill(pnode->parent->children[1]->tensor().as_vector(),
4833 pnode_op->children.resize(2,
nullptr);
4834 tree.copy_node(child1, pnode_op->children[1]);
4835 pnode_op->accept_child(1);
4836 ga_node_grad(tree, workspace, m, pnode_op->children[1]);
4838 if (child2->marked) {
4840 child0 = pnode->children[0]; child1 = pnode->children[1];
4841 child2 = pnode->children[2];
4843 switch (F.dtype()) {
4845 GMM_ASSERT1(
false,
"Cannot derive function " << child0->name
4846 <<
". No derivative provided");
4849 child0->name = F.derivative2();
4852 child0->name =
"DER_PDFUNC2_" + child0->name;
4853 ga_define_function(child0->name, 2, F.derivative2());
4856 child0->name =
"DER_PDFUNC2_" + child0->name;
4857 std::string expr = ga_derivative_scalar_function(F.expr(),
"u");
4858 ga_define_function(child0->name, 2, expr);
4861 tree.insert_node(pnode, GA_NODE_OP);
4862 pga_tree_node pnode_op = pnode->parent;
4863 if (child2->tensor_order() == 0)
4864 pnode_op->op_type = GA_MULT;
4866 pnode_op->op_type = GA_DOTMULT;
4867 tree.insert_node(pnode, GA_NODE_OP);
4868 pnode->parent->op_type = GA_TMULT;
4869 tree.add_child(pnode->parent, GA_NODE_CONSTANT);
4870 pnode->parent->children[1]->init_vector_tensor(m.dim());
4871 gmm::fill(pnode->parent->children[1]->tensor().as_vector(),
4874 pnode_op->children.resize(2,
nullptr);
4875 tree.copy_node(child2, pnode_op->children[1]);
4876 pnode_op->accept_child(1);
4877 ga_node_grad(tree, workspace, m, pnode_op->children[1]);
4880 }
else if (child0->node_type == GA_NODE_SPEC_FUNC) {
4881 GMM_ASSERT1(
false,
"internal error");
4882 }
else if (child0->node_type == GA_NODE_OPERATOR) {
4884 GMM_ASSERT1(
false,
"Error in derivation of the assembly string. "
4885 "Cannot derive again operator " << child0->name);
4888 for (
size_type i = 1; i < pnode->children.size(); ++i)
4889 if (pnode->children[i]->marked) ++nbargs_der;
4890 pga_tree_node pnode2 = 0;
4893 for (
size_type i = 1; i < pnode->children.size(); ++i) {
4894 if (pnode->children[i]->marked) {
4896 if (j != nbargs_der) {
4897 tree.insert_node(pnode, GA_NODE_OP);
4898 pga_tree_node pnode_op = pnode->parent;
4899 pnode_op->node_type = GA_NODE_OP;
4900 pnode_op->op_type = GA_PLUS;
4901 pnode_op->children.resize(2,
nullptr);
4902 tree.copy_node(pnode, pnode_op->children[1]);
4903 pnode_op->accept_child(1);
4904 pnode2 = pnode_op->children[1];
4906 else pnode2 = pnode;
4909 pnode2->children[0]->der2 = i;
4911 pnode2->children[0]->der1 = i;
4912 tree.insert_node(pnode2, GA_NODE_OP);
4913 pga_tree_node pnode_op = pnode2->parent;
4915 size_type red = pnode->children[i]->tensor_order();
4917 case 0 : pnode_op->op_type = GA_MULT;
break;
4918 case 1 : pnode_op->op_type = GA_DOT;
break;
4919 case 2 : pnode_op->op_type = GA_COLON;
break;
4920 default: GMM_ASSERT1(
false,
"Error in derivation of the assembly "
4921 "string. Bad reduction order.")
4923 pnode_op->children.resize(2,
nullptr);
4924 tree.copy_node(pnode->children[i], pnode_op->children[1]);
4925 pnode_op->accept_child(1);
4926 ga_node_grad(tree, workspace, m, pnode_op->children[1]);
4928 if (pnode2->children[0]->name.compare(
"Norm_sqr") == 0
4929 && pnode2->children[0]->der1 == 1) {
4930 pnode2->node_type = GA_NODE_OP;
4931 pnode2->op_type = GA_MULT;
4932 pnode2->children[0]->node_type = GA_NODE_CONSTANT;
4933 pnode2->children[0]->init_scalar_tensor(scalar_type(2));
4938 ga_node_grad(tree, workspace, m, child0);
4939 tree.add_child(pnode, GA_NODE_ALLINDICES);
4944 default: GMM_ASSERT1(
false,
"Unexpected node type " << pnode->node_type
4945 <<
" in gradient. Internal error.");
4947 # ifdef GA_PRINT_DEBUG_INFO
4948 cout <<
"End of gradient of "; ga_print_node(pnode, cout); cout << endl;
4965 static void ga_replace_test_by_cte(pga_tree_node pnode,
bool full_replace) {
4966 for (
size_type i = 0; i < pnode->children.size(); ++i)
4967 ga_replace_test_by_cte(pnode->children[i], full_replace);
4968 GMM_ASSERT1(pnode->node_type != GA_NODE_GRAD_TEST,
"Invalid tree");
4969 GMM_ASSERT1(pnode->node_type != GA_NODE_HESS_TEST,
"Invalid tree");
4970 GMM_ASSERT1(pnode->node_type != GA_NODE_DIVERG_TEST,
"Invalid tree");
4971 if (pnode->node_type == GA_NODE_VAL_TEST) {
4972 pnode->node_type = GA_NODE_CONSTANT;
4973 if (full_replace) pnode->init_scalar_tensor(scalar_type(1));
4977 std::string ga_derivative_scalar_function(
const std::string &expr,
4978 const std::string &var) {
4979 base_vector t(1), u(1);
4980 ga_workspace workspace;
4981 workspace.add_fixed_size_variable(
"t", gmm::sub_interval(0,1), t);
4982 workspace.add_fixed_size_variable(
"u", gmm::sub_interval(0,1), u);
4983 workspace.add_function_expression(expr);
4984 GMM_ASSERT1(workspace.nb_trees() <= 1,
"Internal error");
4985 if (workspace.nb_trees()) {
4986 ga_tree tree = *(workspace.tree_info(0).ptree);
4987 ga_derivative(tree, workspace, dummy_mesh(), var,
"", 1);
4989 ga_replace_test_by_cte(tree.root,
true);
4990 ga_semantic_analysis(tree, workspace, dummy_mesh(), 1,
4993 return ga_tree_to_string(tree);
4997 static bool ga_node_is_affine(
const pga_tree_node pnode) {
4999 size_type nbch = pnode->children.size();
5000 pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
5001 pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
5002 bool mark0 = ((nbch > 0) ? child0->marked :
false);
5003 bool mark1 = ((nbch > 1) ? child1->marked :
false);
5005 switch (pnode->node_type) {
5006 case GA_NODE_VAL:
case GA_NODE_GRAD:
5007 case GA_NODE_HESS:
case GA_NODE_DIVERG:
5008 case GA_NODE_INTERPOLATE_VAL:
case GA_NODE_INTERPOLATE_GRAD:
5009 case GA_NODE_INTERPOLATE_HESS:
case GA_NODE_INTERPOLATE_DIVERG:
5010 case GA_NODE_INTERPOLATE_DERIVATIVE:
5011 case GA_NODE_ELEMENTARY_VAL:
case GA_NODE_ELEMENTARY_GRAD:
5012 case GA_NODE_ELEMENTARY_HESS:
case GA_NODE_ELEMENTARY_DIVERG:
5013 case GA_NODE_SECONDARY_DOMAIN_VAL:
case GA_NODE_SECONDARY_DOMAIN_GRAD:
5014 case GA_NODE_SECONDARY_DOMAIN_HESS:
case GA_NODE_SECONDARY_DOMAIN_DIVERG:
5015 case GA_NODE_XFEM_PLUS_VAL:
case GA_NODE_XFEM_PLUS_GRAD:
5016 case GA_NODE_XFEM_PLUS_HESS:
case GA_NODE_XFEM_PLUS_DIVERG:
5017 case GA_NODE_XFEM_MINUS_VAL:
case GA_NODE_XFEM_MINUS_GRAD:
5018 case GA_NODE_XFEM_MINUS_HESS:
case GA_NODE_XFEM_MINUS_DIVERG:
5020 case GA_NODE_INTERPOLATE_FILTER:
5021 return ga_node_is_affine(child0);
5023 switch(pnode->op_type) {
5024 case GA_PLUS:
case GA_MINUS:
5026 return ga_node_is_affine(child0) &&
5027 ga_node_is_affine(child1);
5028 if (mark0)
return ga_node_is_affine(child0);
5029 return ga_node_is_affine(child1);
5031 case GA_UNARY_MINUS:
case GA_QUOTE:
case GA_SYM:
case GA_SKEW:
5032 case GA_TRACE:
case GA_DEVIATOR:
case GA_PRINT:
5033 return ga_node_is_affine(child0);
5035 case GA_DOT:
case GA_MULT:
case GA_COLON:
case GA_TMULT:
5037 if (mark0 && mark1)
return false;
5038 if (mark0)
return ga_node_is_affine(child0);
5039 return ga_node_is_affine(child1);
5041 case GA_DIV:
case GA_DOTDIV:
5042 if (mark1)
return false;
5043 if (mark0)
return ga_node_is_affine(child0);
5046 default: GMM_ASSERT1(
false,
"Unexpected operation. Internal error.");
5050 case GA_NODE_C_MATRIX:
5051 for (
size_type i = 0; i < pnode->children.size(); ++i)
5052 if (pnode->children[i]->marked &&
5053 !(ga_node_is_affine(pnode->children[i])))
5057 case GA_NODE_PARAMS:
5058 if (child0->node_type == GA_NODE_RESHAPE ||
5059 child0->node_type == GA_NODE_SWAP_IND ||
5060 child0->node_type == GA_NODE_IND_MOVE_LAST)
5061 return ga_node_is_affine(child1);
5062 if (child0->node_type == GA_NODE_CROSS_PRODUCT) {
5063 pga_tree_node child2 = pnode->children[2];
5064 bool mark2 = child2->marked;
5065 if (mark1 && mark2)
return false;
5066 if (mark1)
return ga_node_is_affine(child1);
5067 return ga_node_is_affine(child2);
5069 if (child0->node_type == GA_NODE_CONTRACT) {
5070 if (pnode->children.size() == 4) {
5071 return ga_node_is_affine(child1);
5072 }
else if (pnode->children.size() == 5) {
5073 if (mark1 && pnode->children[3]->marked)
return false;
5074 if (mark1)
return ga_node_is_affine(child1);
5075 return ga_node_is_affine(pnode->children[3]);
5076 }
else if (pnode->children.size() == 7) {
5077 if (mark1 && pnode->children[4]->marked)
return false;
5078 if (mark1)
return ga_node_is_affine(child1);
5079 return ga_node_is_affine(pnode->children[4]);
5082 if (child0->node_type == GA_NODE_PREDEF_FUNC)
5084 if (child0->node_type == GA_NODE_OPERATOR)
5086 return ga_node_is_affine(child0);
5088 default: GMM_ASSERT1(
false,
"Unexpected node type " << pnode->node_type
5089 <<
" in derivation. Internal error.");
5093 bool ga_is_affine(
const ga_tree &tree,
const ga_workspace &workspace,
5094 const std::string &varname,
5095 const std::string &interpolatename) {
5096 const mesh &m = dummy_mesh();
5097 if (tree.root && ga_node_mark_tree_for_variable(tree.root, workspace, m,
5098 varname, interpolatename))
5099 return ga_node_is_affine(tree.root);
static T & instance()
Instance from the current thread.
Semantic analysis of assembly trees and semantic manipulations.
void copy(const L1 &l1, L2 &l2)
*/
void fill(L &l, typename gmm::linalg_traits< L >::value_type x)
*/
void clear(L &l)
clear (fill with zeros) a vector or matrix.
size_t size_type
used as the common size type in the library
GEneric Tool for Finite Element Methods.