[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Getfem-commits] (no subject)
From: |
Yves Renard |
Subject: |
[Getfem-commits] (no subject) |
Date: |
Fri, 27 Apr 2018 07:13:25 -0400 (EDT) |
branch: devel-yves-generic-assembly-modifs
commit 764aa535c3bc4d970d15414fdf619c536edbdfee
Author: Yves Renard <address@hidden>
Date: Fri Apr 27 13:12:45 2018 +0200
splitting of the giant file getfem_generic_assembly.cc, work in progress
---
src/Makefile.am | 7 +
src/getfem/getfem_generic_assembly.h | 4 +-
.../getfem_generic_assembly_compile_and_exec.h | 217 +
...tfem_generic_assembly_functions_and_operators.h | 111 +
src/getfem/getfem_generic_assembly_semantic.h | 117 +
src/getfem/getfem_generic_assembly_tree.h | 472 +
src/getfem_generic_assembly.cc | 14944 ++++++-------------
...fem_generic_assembly_functions_and_operators.cc | 645 +
src/getfem_generic_assembly_semantic.cc | 3187 ++++
src/getfem_generic_assembly_tree.cc | 1597 ++
10 files changed, 10830 insertions(+), 10471 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index d5700cf..30ed222 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -110,6 +110,10 @@ nobase_include_HEADERS =
\
getfem/getfem_assembling.h \
getfem/getfem_assembling_tensors.h \
getfem/getfem_generic_assembly.h \
+ getfem/getfem_generic_assembly_tree.h \
+ getfem/getfem_generic_assembly_functions_and_operators.h \
+ getfem/getfem_generic_assembly_semantic.h \
+ getfem/getfem_generic_assembly_compile_and_exec.h \
getfem/getfem_context.h \
getfem/getfem_config.h \
getfem/getfem_interpolation.h \
@@ -220,6 +224,9 @@ SRC = \
getfem_export.cc \
getfem_assembling_tensors.cc \
getfem_generic_assembly.cc \
+ getfem_generic_assembly_tree.cc \
+ getfem_generic_assembly_functions_and_operators.cc \
+ getfem_generic_assembly_semantic.cc \
getfem_mesher.cc \
getfem_fourth_order.cc \
getfem_nonlinear_elasticity.cc \
diff --git a/src/getfem/getfem_generic_assembly.h
b/src/getfem/getfem_generic_assembly.h
index 045451c..1d8d1b9 100644
--- a/src/getfem/getfem_generic_assembly.h
+++ b/src/getfem/getfem_generic_assembly.h
@@ -72,7 +72,9 @@ namespace getfem {
typedef gmm::row_matrix<model_complex_sparse_vector>
model_complex_row_sparse_matrix;
-
+ // 0 : ok
+ // 1 : function or operator name or "X"
+ // 2 : reserved prefix Grad, Hess, Div, Test and Test2
int ga_check_name_validity(const std::string &name);
//=========================================================================
diff --git a/src/getfem/getfem_generic_assembly_compile_and_exec.h
b/src/getfem/getfem_generic_assembly_compile_and_exec.h
new file mode 100644
index 0000000..66f8757
--- /dev/null
+++ b/src/getfem/getfem_generic_assembly_compile_and_exec.h
@@ -0,0 +1,217 @@
+/*===========================================================================
+
+ Copyright (C) 2013-2018 Yves Renard
+
+ This file is a part of GetFEM++
+
+ GetFEM++ is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, you may use this file as it is a part of a free
+ software library without restriction. Specifically, if other files
+ instantiate templates or use macros or inline functions from this file,
+ or you compile this file and link it with other files to produce an
+ executable, this file does not by itself cause the resulting executable
+ to be covered by the GNU Lesser General Public License. This exception
+ does not however invalidate any other reasons why the executable file
+ might be covered by the GNU Lesser General Public License.
+
+===========================================================================*/
+
+/** @file getfem_generic_assembly_tree.h
+ @author Yves Renard <address@hidden>
+ @date November 18, 2013.
+ @brief Compilation and execution operations. */
+
+
+#ifndef GETFEM_GENERIC_ASSEMBLY_COMP_EXEC_H__
+#define GETFEM_GENERIC_ASSEMBLY_COMP_EXEC_H__
+
+#include "getfem/getfem_generic_assembly_semantic.h"
+
+namespace getfem {
+
+ class ga_if_hierarchy : public std::vector<size_type> {
+
+ public:
+ void increment() { (back())++; }
+ void child_of(const ga_if_hierarchy &gih)
+ { *this = gih; push_back(0); }
+ bool is_compatible(const std::list<ga_if_hierarchy> &gihl) {
+
+ std::list<ga_if_hierarchy>::const_iterator it = gihl.begin();
+ for (; it != gihl.end(); ++it) {
+ if (it->size() <= size()) {
+ bool ok = true;
+ for (size_type i = 0; i+1 < it->size(); ++i)
+ if ((*it)[i] != (*this)[i]) { ok = false; break; }
+ if (it->back() > (*this)[it->size()-1]) { ok = false; break; }
+ if (ok) return true;
+ }
+ }
+ return false;
+ }
+
+ ga_if_hierarchy() : std::vector<size_type>(1) { (*this)[0] = 0; }
+ };
+
+
+ struct ga_instruction {
+ virtual int exec() = 0;
+ virtual ~ga_instruction() {};
+ };
+
+ typedef std::shared_ptr<ga_instruction> pga_instruction;
+ typedef std::vector<pga_instruction> ga_instruction_list;
+
+
+ struct gauss_pt_corresp { // For neighbour interpolation transformation
+ bgeot::pgeometric_trans pgt1, pgt2;
+ papprox_integration pai;
+ std::vector<size_type> nodes;
+ };
+
+ bool operator <(const gauss_pt_corresp &gpc1,
+ const gauss_pt_corresp &gpc2) {
+ if (gpc1.pai != gpc2.pai)
+ return (gpc1.pai < gpc2.pai );
+ if (gpc1.nodes.size() != gpc2.nodes.size())
+ return (gpc1.nodes.size() < gpc2.nodes.size());
+ for (size_type i = 0; i < gpc1.nodes.size(); ++i)
+ if (gpc1.nodes[i] != gpc2.nodes[i])
+ return (gpc1.nodes[i] < gpc2.nodes[i]);
+ if (gpc1.pgt1 != gpc2.pgt1)
+ return (gpc1.pgt1 < gpc2.pgt1);
+ if (gpc1.pgt2 != gpc2.pgt2)
+ return (gpc1.pgt2 < gpc2.pgt2);
+ return false;
+ }
+
+ struct ga_instruction_set {
+
+ papprox_integration pai; // Current approximation method
+ fem_interpolation_context ctx; // Current fem interpolation context.
+ base_small_vector Normal; // Outward unit normal vector to the
+ // boundary in case of boundary integration
+ scalar_type elt_size; // Estimate of the diameter of the element
+ // if needed.
+ bool need_elt_size;
+ scalar_type coeff; // Coefficient for the Gauss point
+ size_type nbpt, ipt; // Number and index of Gauss point
+ bgeot::geotrans_precomp_pool gp_pool;
+ fem_precomp_pool fp_pool;
+ std::map<gauss_pt_corresp, bgeot::pstored_point_tab> neighbour_corresp;
+
+ struct region_mim : std::pair<const mesh_im *, const mesh_region *> {
+ const mesh_im* mim() const { return this->first; }
+ const mesh_region* region() const { return this->second; }
+ region_mim(const mesh_im *mim_, const mesh_region *region_) :
+ std::pair<const mesh_im *, const mesh_region *>(mim_, region_) {}
+ };
+
+ std::map<std::string, const base_vector *> extended_vars;
+ std::map<std::string, base_vector> really_extended_vars;
+ std::map<std::string, gmm::sub_interval> var_intervals;
+ size_type nb_dof, max_dof;
+
+ struct variable_group_info {
+ const mesh_fem *mf;
+ gmm::sub_interval Ir, In;
+ scalar_type alpha;
+ const base_vector *U;
+ const std::string *varname;
+ variable_group_info() : mf(0), U(0), varname(0) {}
+ };
+
+ struct interpolate_info {
+ size_type pt_type;
+ bool has_ctx;
+ const mesh *m;
+ fem_interpolation_context ctx;
+ base_node pt_y;
+ base_small_vector Normal;
+ base_matrix G;
+ std::map<std::string, variable_group_info> groups_info;
+ std::map<var_trans_pair, base_tensor> derivatives;
+ std::map<const mesh_fem *, pfem_precomp> pfps;
+ };
+
+ struct elementary_trans_info {
+ base_matrix M;
+ const mesh_fem *mf;
+ size_type icv;
+ };
+
+ std::set<std::string> transformations;
+
+ struct region_mim_instructions {
+
+ const mesh *m;
+ ga_if_hierarchy current_hierarchy;
+ std::map<std::string, base_vector> local_dofs;
+ std::map<const mesh_fem *, pfem_precomp> pfps;
+ std::map<const mesh_fem *, base_tensor> base;
+ std::map<const mesh_fem *, std::list<ga_if_hierarchy>> base_hierarchy;
+ std::map<const mesh_fem *, base_tensor> grad;
+ std::map<const mesh_fem *, std::list<ga_if_hierarchy>> grad_hierarchy;
+ std::map<const mesh_fem *, base_tensor> hess;
+ std::map<const mesh_fem *, std::list<ga_if_hierarchy>> hess_hierarchy;
+
+ std::map<const mesh_fem *, base_tensor>
+ xfem_plus_base, xfem_plus_grad, xfem_plus_hess,
+ xfem_minus_base, xfem_minus_grad, xfem_minus_hess;
+ std::map<const mesh_fem *, std::list<ga_if_hierarchy>>
+ xfem_plus_base_hierarchy, xfem_plus_grad_hierarchy,
+ xfem_plus_hess_hierarchy, xfem_minus_base_hierarchy,
+ xfem_minus_grad_hierarchy, xfem_minus_hess_hierarchy;
+
+ std::map<std::string, std::set<std::string>> transformations;
+ std::set<std::string> transformations_der;
+ std::map<std::string, interpolate_info> interpolate_infos;
+ std::map<std::string, elementary_trans_info> elementary_trans_infos;
+
+ // Instructions being executed at the first Gauss point after
+ // a change of integration method only.
+ ga_instruction_list begin_instructions;
+ // Instructions executed once per element
+ ga_instruction_list elt_instructions;
+ // Instructions executed on each integration/interpolation point
+ ga_instruction_list instructions;
+ std::map<scalar_type, std::list<pga_tree_node> > node_list;
+
+ region_mim_instructions(): m(0) {}
+ };
+
+ std::list<ga_tree> trees; // The trees are stored mainly because they
+ // contain the intermediary tensors.
+ std::list<ga_tree> interpolation_trees;
+
+ typedef std::map<region_mim, region_mim_instructions> instructions_set;
+
+ instructions_set whole_instructions;
+
+ ga_instruction_set() { max_dof = nb_dof = 0; need_elt_size = false; ipt=0;
}
+ };
+
+
+ void ga_exec(ga_instruction_set &gis, ga_workspace &workspace);
+ void ga_function_exec(ga_instruction_set &gis);
+ void ga_compile(ga_workspace &workspace, ga_instruction_set &gis,
+ size_type order);
+ void ga_compile_function(ga_workspace &workspace,
+ ga_instruction_set &gis, bool scalar);
+
+} /* end of namespace */
+
+
+#endif /* GETFEM_GENERIC_ASSEMBLY_COMP_EXEC_H__ */
diff --git a/src/getfem/getfem_generic_assembly_functions_and_operators.h
b/src/getfem/getfem_generic_assembly_functions_and_operators.h
new file mode 100644
index 0000000..9039a7c
--- /dev/null
+++ b/src/getfem/getfem_generic_assembly_functions_and_operators.h
@@ -0,0 +1,111 @@
+/*===========================================================================
+
+ Copyright (C) 2013-2018 Yves Renard
+
+ This file is a part of GetFEM++
+
+ GetFEM++ is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, you may use this file as it is a part of a free
+ software library without restriction. Specifically, if other files
+ instantiate templates or use macros or inline functions from this file,
+ or you compile this file and link it with other files to produce an
+ executable, this file does not by itself cause the resulting executable
+ to be covered by the GNU Lesser General Public License. This exception
+ does not however invalidate any other reasons why the executable file
+ might be covered by the GNU Lesser General Public License.
+
+===========================================================================*/
+
+/** @file getfem_generic_assembly_tree.h
+ @author Yves Renard <address@hidden>
+ @date November 18, 2013.
+ @brief Definition of functions and basic operators of the assembly
language
+ */
+
+
+#ifndef GETFEM_GENERIC_ASSEMBLY_FUNC_OP_H__
+#define GETFEM_GENERIC_ASSEMBLY_FUNC_OP_H__
+
+#include "getfem/getfem_generic_assembly_tree.h"
+
+namespace getfem {
+
+ struct ga_instruction_set;
+ using instruction_set = omp_distribute<ga_instruction_set>;
+
+ class ga_predef_function {
+ size_type ftype_; // 0 : C++ function with C++ derivative(s)
+ // 1 : function defined by an string expression.
+
+ size_type dtype_; // 0 : no derivative(s)
+ // 1 : derivative(s) given by C++ functions
+ // 2 : derivatives(s) given by string expression(s)
+ // 3 : derivatives(s) to be symbolically computed.
+ size_type nbargs_; // One or two arguments
+ pscalar_func_onearg f1_; // Function pointer for a one argument function
+ pscalar_func_twoargs f2_; // Function pointer for a two arguments function
+ std::string expr_;
+ std::string derivative1_, derivative2_;
+ mutable omp_distribute<base_vector> t, u;
+ mutable omp_distribute<ga_workspace> workspace;
+ copyable_ptr<instruction_set> gis;
+
+ friend void ga_define_function(const std::string &name, size_type nbargs,
+ const std::string &expr,
+ const std::string &der1,
+ const std::string &der2);
+ friend void ga_define_function(const std::string &name,
+ pscalar_func_onearg f,
+ const std::string &der);
+ friend void ga_define_function(const std::string &name,
+ pscalar_func_twoargs f,
+ const std::string &der1,
+ const std::string &der2);
+ public:
+ scalar_type operator()(scalar_type t_, scalar_type u_ = 0.) const;
+
+ bool is_affine(const std::string &varname) const;
+
+ size_type ftype() const {return ftype_;}
+ size_type dtype() const {return dtype_;}
+ size_type nbargs() const {return nbargs_;}
+ const std::string &derivative1() const {return derivative1_;}
+ const std::string &derivative2() const {return derivative2_;}
+ const std::string &expr() const {return expr_;}
+ pscalar_func_onearg f1() const {return f1_;}
+ pscalar_func_twoargs f2() const {return f2_;}
+
+ ga_predef_function() : expr_(""), derivative1_(""),
+ derivative2_(""), gis(nullptr) {}
+ ga_predef_function(pscalar_func_onearg f, size_type dtype__ = 0,
+ const std::string &der = "")
+ : ftype_(0), dtype_(dtype__), nbargs_(1), f1_(f), expr_(""),
+ derivative1_(der), derivative2_("") {}
+ ga_predef_function(pscalar_func_twoargs f, size_type dtype__ = 0,
+ const std::string &der1 = "",
+ const std::string &der2 = "")
+ : ftype_(0), dtype_(dtype__), nbargs_(2), f2_(f),
+ expr_(""), derivative1_(der1), derivative2_(der2), gis(nullptr) {}
+ ga_predef_function(const std::string &expr__)
+ : ftype_(1), dtype_(3), nbargs_(1), expr_(expr__),
+ derivative1_(""), derivative2_(""), t(1, 0.), u(1, 0.), gis(nullptr) {}
+ };
+
+ typedef std::map<std::string, ga_predef_function> ga_predef_function_tab;
+
+} /* end of namespace */
+
+
+#endif /* GETFEM_GENERIC_ASSEMBLY_FUNC_OP_H__ */
diff --git a/src/getfem/getfem_generic_assembly_semantic.h
b/src/getfem/getfem_generic_assembly_semantic.h
new file mode 100644
index 0000000..0c3939a
--- /dev/null
+++ b/src/getfem/getfem_generic_assembly_semantic.h
@@ -0,0 +1,117 @@
+/*===========================================================================
+
+ Copyright (C) 2013-2018 Yves Renard
+
+ This file is a part of GetFEM++
+
+ GetFEM++ is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, you may use this file as it is a part of a free
+ software library without restriction. Specifically, if other files
+ instantiate templates or use macros or inline functions from this file,
+ or you compile this file and link it with other files to produce an
+ executable, this file does not by itself cause the resulting executable
+ to be covered by the GNU Lesser General Public License. This exception
+ does not however invalidate any other reasons why the executable file
+ might be covered by the GNU Lesser General Public License.
+
+===========================================================================*/
+
+/** @file getfem_generic_assembly_semantic.h
+ @author Yves Renard <address@hidden>
+ @date November 18, 2013.
+ @brief Semantic analysis of assembly trees and semantic manipulations.
+ */
+
+
+#ifndef GETFEM_GENERIC_ASSEMBLY_SEMANTIC_H__
+#define GETFEM_GENERIC_ASSEMBLY_SEMANTIC_H__
+
+#include "getfem/getfem_generic_assembly_tree.h"
+
+
+namespace getfem {
+
+ /* Performs the semantic analysis, tree simplification and tree enrichment
+ - Control tensor sizes for operations, operator or function call
+ - Compute all constant operations (i.e. non element dependent)
+ - Build a ready to use tree for derivation/compilation
+ option = 0 : strict analysis,
+ 1 : do not complain about incompatible test functions but
+ store them,
+ 2 : cut incompatible test function branches with respect to the
+ one in workspace.selected_pair
+ 3 : do not complain about incompatible test functions neither
+ store them.
+ */
+ void ga_semantic_analysis(const std::string &expr, ga_tree &tree,
+ const ga_workspace &workspace,
+ size_type meshdim,
+ size_type ref_elt_dim,
+ bool eval_fixed_size,
+ bool ignore_X, int option);
+
+ /* Extract the variables used in a sub-tree, ignoring or not the data.
+ Variable groups are taken into account. Return if at least one variable
+ as been detected or not */
+ bool ga_extract_variables(const pga_tree_node pnode,
+ const ga_workspace &workspace,
+ const mesh &m,
+ std::set<var_trans_pair> &vars,
+ bool ignore_data);
+
+ /* Extract a sub tree which consists of the corresponding node and of
+ the terms multiplying this term, but not the term in addition.
+ The aim is to expand an expression is a sum of elementary factors.
+ Complains if a nonlinear term is encountered. */
+ void ga_extract_factor(ga_tree &result_tree, pga_tree_node pnode,
+ pga_tree_node &new_pnode);
+
+ /* Extract the constant term of degree 1 expressions. */
+ bool ga_node_extract_constant_term
+ (ga_tree &tree, pga_tree_node pnode, const ga_workspace &workspace,
+ const mesh &m);
+
+ /* Extract the Neumann term of an assembly tree with respect to a variable.
*/
+ void ga_extract_Neumann_term
+ (ga_tree &tree, const std::string &varname,
+ ga_workspace &workspace, pga_tree_node pnode, std::string &result);
+
+
+ /* Derivation of the tree with respect to a variable.
+ The tree is modified and should be copied first and passed to
+ ga_semantic_analysis after for enrichment. */
+ void ga_derivative(ga_tree &tree, const ga_workspace &workspace,
+ const mesh &m, const std::string &varname,
+ const std::string &interpolatename,
+ size_type order);
+
+ std::string ga_derivative_scalar_function(const std::string &expr,
+ const std::string &var);
+
+ bool ga_is_affine(const ga_tree &tree, const ga_workspace &workspace,
+ const std::string &varname,
+ const std::string &interpolatename);
+
+ // Function of internal use
+ inline size_type ref_elt_dim_of_mesh(const mesh &m) {
+ return m.convex_index().card() ?
+ m.trans_of_convex(m.convex_index().first())->dim() : size_type(0);
+ }
+
+
+} /* end of namespace */
+
+
+#endif /* GETFEM_GENERIC_ASSEMBLY_TREE_H__ */
diff --git a/src/getfem/getfem_generic_assembly_tree.h
b/src/getfem/getfem_generic_assembly_tree.h
new file mode 100644
index 0000000..85b99dd
--- /dev/null
+++ b/src/getfem/getfem_generic_assembly_tree.h
@@ -0,0 +1,472 @@
+/*===========================================================================
+
+ Copyright (C) 2013-2018 Yves Renard
+
+ This file is a part of GetFEM++
+
+ GetFEM++ is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ As a special exception, you may use this file as it is a part of a free
+ software library without restriction. Specifically, if other files
+ instantiate templates or use macros or inline functions from this file,
+ or you compile this file and link it with other files to produce an
+ executable, this file does not by itself cause the resulting executable
+ to be covered by the GNU Lesser General Public License. This exception
+ does not however invalidate any other reasons why the executable file
+ might be covered by the GNU Lesser General Public License.
+
+===========================================================================*/
+
+/** @file getfem_generic_assembly_tree.h
+ @author Yves Renard <address@hidden>
+ @date November 18, 2013.
+ @brief Definition of the syntax tree and basic operations on it.
+ Internal header for the generic assembly language part.
+ */
+
+
+#ifndef GETFEM_GENERIC_ASSEMBLY_TREE_H__
+#define GETFEM_GENERIC_ASSEMBLY_TREE_H__
+
+#include "getfem/getfem_generic_assembly.h"
+#include "getfem/getfem_models.h"
+#include "gmm/gmm_blas.h"
+#include <iomanip>
+#include "getfem/getfem_omp.h"
+#include "getfem/dal_singleton.h"
+#include "getfem/bgeot_rtree.h"
+#include "getfem/bgeot_geotrans_inv.h"
+#include "getfem/getfem_copyable_ptr.h"
+#ifndef _WIN32
+extern "C"{
+#include <unistd.h>
+}
+#endif
+
+// #define GA_USES_BLAS // not so interesting, at least for debian blas
+
+// #define GA_DEBUG_INFO(a) { cout << a << endl; }
+#define GA_DEBUG_INFO(a)
+
+#define GA_DEBUG_ASSERT(a, b) GMM_ASSERT1(a, b)
+// #define GA_DEBUG_ASSERT(a, b)
+
+#if 1
+# define GA_TIC
+# define GA_TOC(a)
+# define GA_TOCTIC(a)
+#else
+# define GA_TIC scalar_type _ga_time_ = gmm::uclock_sec();
+# define GA_TOC(a) { cout <<(a)<<" : "<<gmm::uclock_sec()-_ga_time_<< endl; }
+# define GA_TOCTIC(a) { GA_TOC(a); _ga_time_ = gmm::uclock_sec(); }
+#endif
+
+namespace getfem {
+
+ // Basic token types (basic language components)
+ enum GA_TOKEN_TYPE {
+ GA_INVALID = 0, // invalid token
+ GA_END, // string end
+ GA_NAME, // A variable or user defined nonlinear function name
+ GA_SCALAR, // A real number
+ GA_PLUS, // '+'
+ GA_MINUS, // '-'
+ GA_UNARY_MINUS, // '-'
+ GA_MULT, // '*'
+ GA_DIV, // '/'
+ GA_COLON, // ':'
+ GA_QUOTE, // ''' transpose
+ GA_SYM, // 'Sym' operator
+ GA_SKEW, // 'Skew' operator
+ GA_TRACE, // 'Trace' operator
+ GA_DEVIATOR, // 'Deviator' operator
+ GA_INTERPOLATE, // 'Interpolate' operation
+ GA_INTERPOLATE_FILTER, // 'Interpolate_filter' operation
+ GA_ELEMENTARY, // 'Elementary' operation (operation at the element level)
+ GA_XFEM_PLUS, // �valuation on the + side of a level-set for
fem_level_set
+ GA_XFEM_MINUS, // �valuation on the - side of a level-set for
fem_level_set
+ GA_PRINT, // 'Print' Print the tensor
+ GA_DOT, // '.'
+ GA_DOTMULT, // '.*' componentwise multiplication
+ GA_DOTDIV, // './' componentwise division
+ GA_TMULT, // '@' tensor product
+ GA_COMMA, // ','
+ GA_DCOMMA, // ',,'
+ GA_SEMICOLON, // ';'
+ GA_DSEMICOLON, // ';;'
+ GA_LPAR, // '('
+ GA_RPAR, // ')'
+ GA_LBRACKET, // '['
+ GA_RBRACKET, // ']'
+ GA_NB_TOKEN_TYPE
+ };
+
+ // Detects Grad_, Hess_ or Div_
+ size_type ga_parse_prefix_operator(std::string &name);
+ // Detects Test_ and Test2_
+ size_type ga_parse_prefix_test(std::string &name);
+
+ // Types of nodes for the syntax tree
+ enum GA_NODE_TYPE {
+ GA_NODE_VOID = 0,
+ GA_NODE_OP,
+ GA_NODE_PREDEF_FUNC,
+ GA_NODE_SPEC_FUNC,
+ GA_NODE_OPERATOR,
+ GA_NODE_CONSTANT,
+ GA_NODE_NAME,
+ GA_NODE_PARAMS,
+ GA_NODE_RESHAPE,
+ GA_NODE_ALLINDICES,
+ GA_NODE_C_MATRIX,
+ GA_NODE_X,
+ GA_NODE_ELT_SIZE,
+ GA_NODE_ELT_K,
+ GA_NODE_ELT_B,
+ GA_NODE_NORMAL,
+ GA_NODE_VAL,
+ GA_NODE_GRAD,
+ GA_NODE_HESS,
+ GA_NODE_DIVERG,
+ GA_NODE_VAL_TEST,
+ GA_NODE_GRAD_TEST,
+ GA_NODE_HESS_TEST,
+ GA_NODE_DIVERG_TEST,
+ GA_NODE_INTERPOLATE,
+ GA_NODE_INTERPOLATE_FILTER,
+ GA_NODE_INTERPOLATE_VAL,
+ GA_NODE_INTERPOLATE_GRAD,
+ GA_NODE_INTERPOLATE_HESS,
+ GA_NODE_INTERPOLATE_DIVERG,
+ GA_NODE_INTERPOLATE_VAL_TEST,
+ GA_NODE_INTERPOLATE_GRAD_TEST,
+ GA_NODE_INTERPOLATE_HESS_TEST,
+ GA_NODE_INTERPOLATE_DIVERG_TEST,
+ GA_NODE_INTERPOLATE_X,
+ GA_NODE_INTERPOLATE_NORMAL,
+ GA_NODE_INTERPOLATE_DERIVATIVE,
+ GA_NODE_ELEMENTARY,
+ GA_NODE_ELEMENTARY_VAL,
+ GA_NODE_ELEMENTARY_GRAD,
+ GA_NODE_ELEMENTARY_HESS,
+ GA_NODE_ELEMENTARY_DIVERG,
+ GA_NODE_ELEMENTARY_VAL_TEST,
+ GA_NODE_ELEMENTARY_GRAD_TEST,
+ GA_NODE_ELEMENTARY_HESS_TEST,
+ GA_NODE_ELEMENTARY_DIVERG_TEST,
+ GA_NODE_XFEM_PLUS,
+ GA_NODE_XFEM_PLUS_VAL,
+ GA_NODE_XFEM_PLUS_GRAD,
+ GA_NODE_XFEM_PLUS_HESS,
+ GA_NODE_XFEM_PLUS_DIVERG,
+ GA_NODE_XFEM_PLUS_VAL_TEST,
+ GA_NODE_XFEM_PLUS_GRAD_TEST,
+ GA_NODE_XFEM_PLUS_HESS_TEST,
+ GA_NODE_XFEM_PLUS_DIVERG_TEST,
+ GA_NODE_XFEM_MINUS,
+ GA_NODE_XFEM_MINUS_VAL,
+ GA_NODE_XFEM_MINUS_GRAD,
+ GA_NODE_XFEM_MINUS_HESS,
+ GA_NODE_XFEM_MINUS_DIVERG,
+ GA_NODE_XFEM_MINUS_VAL_TEST,
+ GA_NODE_XFEM_MINUS_GRAD_TEST,
+ GA_NODE_XFEM_MINUS_HESS_TEST,
+ GA_NODE_XFEM_MINUS_DIVERG_TEST,
+ GA_NODE_ZERO};
+
+ // Print error message indicating the position in the assembly string
+ void ga_throw_error_msg(const std::string &expr, size_type pos,
+ const std::string &msg);
+
+# define ga_throw_error(expr, pos, msg) \
+ { std::stringstream ss; ss << msg; \
+ ga_throw_error_msg(expr, pos, ss.str()); \
+ GMM_ASSERT1(false, "Error in assembly string" ); \
+ }
+
+ // Structure for the tensor associated with a tree node
+ struct assembly_tensor {
+ bool is_copied;
+ int sparsity_; // 0: plain, 1: vectorized base, 2: vectorised grad, ...
+ size_type qdim_; // Dimension of the vectorization for sparsity tensors
+ base_tensor t;
+ assembly_tensor *tensor_copied;
+
+ const base_tensor &org_tensor() const
+ { return is_copied ? tensor_copied->org_tensor() : t; }
+ base_tensor &org_tensor()
+ { return is_copied ? tensor_copied->org_tensor() : t; }
+
+ const base_tensor &tensor() const
+ { return (is_copied ? tensor_copied->tensor() : t); }
+
+ base_tensor &tensor()
+ { return (is_copied ? tensor_copied->tensor() : t); }
+
+ void set_sparsity(int sp, size_type q)
+ { sparsity_ = sp; qdim_ = q; }
+
+ size_type qdim() { return is_copied ? tensor_copied->qdim() : qdim_; }
+
+ int sparsity() const
+ { return is_copied ? tensor_copied->sparsity() : sparsity_; }
+
+ inline void set_to_original() { is_copied = false; }
+ inline void set_to_copy(assembly_tensor &t_) {
+ is_copied = true; sparsity_ = t_.sparsity_; qdim_ = t_.qdim_;
+ t = t_.org_tensor(); tensor_copied = &(t_);
+ }
+
+ inline void adjust_sizes(const bgeot::multi_index &ssizes)
+ { t.adjust_sizes(ssizes); }
+
+ inline void adjust_sizes()
+ { if (t.sizes().size() || t.size() != 1) t.init(); }
+
+ inline void adjust_sizes(size_type i)
+ { if (t.sizes().size() != 1 || t.sizes()[0] != i) t.init(i); }
+
+ inline void adjust_sizes(size_type i, size_type j) {
+ if (t.sizes().size() != 2 || t.sizes()[0] != i || t.sizes()[1] != j)
+ t.init(i, j);
+ }
+
+ inline void adjust_sizes(size_type i, size_type j, size_type k) {
+ if (t.sizes().size() != 3 || t.sizes()[0] != i || t.sizes()[1] != j
+ || t.sizes()[2] != k)
+ t.init(i, j, k);
+ }
+ inline void adjust_sizes(size_type i, size_type j,
+ size_type k, size_type l) {
+ if (t.sizes().size() != 3 || t.sizes()[0] != i || t.sizes()[1] != j
+ || t.sizes()[2] != k || t.sizes()[3] != l)
+ t.init(i, j, k, l);
+ }
+
+ void init_scalar_tensor(scalar_type v)
+ { set_to_original(); t.adjust_sizes(); t[0] = v; }
+
+ void init_vector_tensor(size_type d)
+ { set_to_original(); t.adjust_sizes(d); }
+
+ void init_matrix_tensor(size_type n, size_type m)
+ { set_to_original(); t.adjust_sizes(n, m); }
+
+ void init_third_order_tensor(size_type n, size_type m, size_type l)
+ { set_to_original(); t.adjust_sizes(n, m, l); }
+
+ void init_fourth_order_tensor(size_type n, size_type m,
+ size_type l, size_type k)
+ { set_to_original(); t.adjust_sizes(n, m, l, k); }
+
+ const bgeot::multi_index &sizes() const { return t.sizes(); }
+
+ assembly_tensor()
+ : is_copied(false), sparsity_(0), qdim_(0), tensor_copied(0) {}
+ };
+
+ struct ga_tree_node;
+ typedef ga_tree_node *pga_tree_node;
+
+ struct ga_tree_node {
+ GA_NODE_TYPE node_type;
+ GA_TOKEN_TYPE op_type;
+ assembly_tensor t;
+ size_type test_function_type; // -1 = undetermined
+ // 0 = no test function,
+ // 1 = first order, 2 = second order,
+ // 3 = both with always first order in first
+ std::string name_test1, name_test2; // variable names corresponding to test
+ // functions when test_function_type > 0.
+ std::string interpolate_name_test1, interpolate_name_test2; // name
+ // of interpolation transformation if any
+ size_type qdim1, qdim2; // Qdims when test_function_type > 0.
+ size_type nbc1, nbc2, nbc3; // For explicit matrices and x.
+ size_type pos; // Position of the first character in string
+ std::string name; // variable/constant/function/operator name
+ std::string interpolate_name; // For Interpolate : name of transformation
+ std::string interpolate_name_der; // For Interpolate derivative:
+ // name of transformation
+ std::string elementary_name; // For Elementary_transformation :
+ // name of transformation
+ size_type der1, der2; // For functions and nonlinear operators,
+ // optional derivative or second derivative.
+ bool symmetric_op;
+ pga_tree_node parent; // Parent node
+ std::vector<pga_tree_node> children; // Children nodes
+ scalar_type hash_value; // Hash value to identify nodes.
+ bool marked; // For specific use of some algorithms
+
+ inline const base_tensor &tensor() const { return t.tensor(); }
+ inline base_tensor &tensor() { return t.tensor(); }
+ int sparsity() const { return t.sparsity(); }
+
+ inline size_type nb_test_functions() const {
+ if (test_function_type == size_type(-1)) return 0;
+ return test_function_type - (test_function_type >= 2 ? 1 : 0);
+ }
+
+ inline size_type tensor_order() const
+ { return t.sizes().size() - nb_test_functions(); }
+
+ inline size_type tensor_test_size() const {
+ size_type st = nb_test_functions();
+ return (st >= 1 ? t.sizes()[0] : 1) * (st == 2 ? t.sizes()[1] : 1);
+ }
+
+ inline size_type tensor_proper_size() const
+ { return t.org_tensor().size() / tensor_test_size(); }
+
+ inline size_type tensor_proper_size(size_type i) const
+ { return t.sizes()[nb_test_functions()+i]; }
+
+
+ void mult_test(const pga_tree_node n0, const pga_tree_node n1,
+ const std::string &expr);
+
+ bool tensor_is_zero() {
+ if (node_type == GA_NODE_ZERO) return true;
+ if (node_type != GA_NODE_CONSTANT) return false;
+ for (size_type i = 0; i < tensor().size(); ++i)
+ if (tensor()[i] != scalar_type(0)) return false;
+ return true;
+ }
+
+ inline void init_scalar_tensor(scalar_type v)
+ { t.init_scalar_tensor(v); test_function_type = 0; }
+
+ inline void init_vector_tensor(size_type d)
+ { t.init_vector_tensor(d); test_function_type = 0; }
+
+ inline void init_matrix_tensor(size_type n, size_type m)
+ { t.init_matrix_tensor(n, m); test_function_type = 0; }
+
+ inline void init_third_order_tensor(size_type n, size_type m, size_type l)
+ { t.init_third_order_tensor(n, m, l); test_function_type = 0; }
+
+ inline void init_fourth_order_tensor(size_type n, size_type m,
+ size_type l, size_type k)
+ { t.init_fourth_order_tensor(n, m, l, k); test_function_type = 0; }
+
+ inline void adopt_child(pga_tree_node new_child)
+ { children.push_back(new_child); children.back()->parent = this; }
+
+ inline void replace_child(pga_tree_node oldchild,
+ pga_tree_node newchild) {
+ bool found = false;
+ for (pga_tree_node &child : children)
+ if (child == oldchild) { child = newchild; found = true; }
+ GMM_ASSERT1(found, "Internal error");
+ }
+
+ ga_tree_node()
+ : node_type(GA_NODE_VOID), test_function_type(-1), qdim1(0), qdim2(0),
+ nbc1(0), nbc2(0), nbc3(0), pos(0), der1(0), der2(0),
+ symmetric_op(false), hash_value(0) {}
+ ga_tree_node(GA_NODE_TYPE ty, size_type p)
+ : node_type(ty), test_function_type(-1),
+ qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
+ pos(p), der1(0), der2(0), symmetric_op(false), hash_value(0) {}
+ ga_tree_node(scalar_type v, size_type p)
+ : node_type(GA_NODE_CONSTANT), test_function_type(-1),
+ qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
+ pos(p), der1(0), der2(0), symmetric_op(false),
+ hash_value(0)
+ { init_scalar_tensor(v); }
+ ga_tree_node(const char *n, size_type l, size_type p)
+ : node_type(GA_NODE_NAME), test_function_type(-1),
+ qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
+ pos(p), name(n, l), der1(0), der2(0), symmetric_op(false),
+ hash_value(0) {}
+ ga_tree_node(GA_TOKEN_TYPE op, size_type p)
+ : node_type(GA_NODE_OP), op_type(op), test_function_type(-1),
+ qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
+ pos(p), der1(0), der2(0), symmetric_op(false),
+ hash_value(0) {}
+ };
+
+# define ga_valid_operand(expr, pnode) \
+ { \
+ if (pnode && (pnode->node_type == GA_NODE_PREDEF_FUNC || \
+ pnode->node_type == GA_NODE_SPEC_FUNC || \
+ pnode->node_type == GA_NODE_NAME || \
+ pnode->node_type == GA_NODE_OPERATOR || \
+ pnode->node_type == GA_NODE_ALLINDICES)) \
+ ga_throw_error(expr, pnode->pos, "Invalid term"); \
+ }
+
+ struct ga_tree {
+ pga_tree_node root, current_node;
+
+ void add_scalar(scalar_type val, size_type pos);
+ void add_allindices(size_type pos);
+ void add_name(const char *name, size_type length, size_type pos);
+ void add_sub_tree(ga_tree &sub_tree);
+ void add_params(size_type pos);
+ void add_matrix(size_type pos);
+ void zip_matrix(const pga_tree_node source_node);
+ void add_op(GA_TOKEN_TYPE op_type, size_type pos);
+ void clear_node_rec(pga_tree_node pnode);
+ void clear_node(pga_tree_node pnode);
+ void clear() { clear_node_rec(root); root = current_node = nullptr; }
+ void clear_children(pga_tree_node pnode);
+ void replace_node_by_child(pga_tree_node pnode, size_type i);
+ void copy_node(pga_tree_node pnode, pga_tree_node parent,
+ pga_tree_node &child);
+ void duplicate_with_operation(pga_tree_node pnode, GA_TOKEN_TYPE op_type);
+ void duplicate_with_addition(pga_tree_node pnode)
+ { duplicate_with_operation(pnode, GA_PLUS); }
+ void duplicate_with_subtraction(pga_tree_node pnode)
+ { duplicate_with_operation(pnode, GA_MINUS); }
+ void insert_node(pga_tree_node pnode, GA_NODE_TYPE node_type);
+ void add_child(pga_tree_node pnode)
+ { pga_tree_node newnode=new ga_tree_node(); pnode->adopt_child(newnode); }
+ void swap(ga_tree &tree)
+ { std::swap(root, tree.root); std::swap(current_node, tree.current_node); }
+
+ ga_tree() : root(nullptr), current_node(nullptr) {}
+
+ ga_tree(const ga_tree &tree) : root(nullptr), current_node(nullptr)
+ { if (tree.root) copy_node(tree.root, nullptr, root); }
+
+ ga_tree &operator = (const ga_tree &tree)
+ { clear(); if (tree.root) copy_node(tree.root,nullptr,root); return *this;
}
+
+ ~ga_tree() { clear(); }
+ };
+
+ // Test equality or equivalence of two sub trees.
+ // version = 0 : strict equality
+ // 1 : give the same result
+ // 2 : give the same result with transposition of test functions
+ bool sub_tree_are_equal
+ (const pga_tree_node pnode1, const pga_tree_node pnode2,
+ const ga_workspace &workspace, int version);
+
+ // Transform the expression of a node and its sub-nodes in the equivalent
+ // assembly string sent to ostream str
+ void ga_print_node(const pga_tree_node pnode,
+ std::ostream &str);
+ // The same for the whole tree, the result is a std::string
+ std::string ga_tree_to_string(const ga_tree &tree);
+
+ // Syntax analysis of an assembly string. Conversion to a tree.
+ // No semantic analysis is done. The tree can be inconsistent.
+ void ga_read_string(const std::string &expr, ga_tree &tree);
+
+
+} /* end of namespace */
+
+
+#endif /* GETFEM_GENERIC_ASSEMBLY_TREE_H__ */
diff --git a/src/getfem_generic_assembly.cc b/src/getfem_generic_assembly.cc
index e07617a..41ba5de 100644
--- a/src/getfem_generic_assembly.cc
+++ b/src/getfem_generic_assembly.cc
@@ -1,6 +1,6 @@
/*===========================================================================
- Copyright (C) 2013-2017 Yves Renard
+ Copyright (C) 2013-2018 Yves Renard
This file is a part of GetFEM++
@@ -19,57 +19,9 @@
===========================================================================*/
-#include "getfem/getfem_generic_assembly.h"
-#include "getfem/getfem_models.h"
-#include "gmm/gmm_blas.h"
-#include <iomanip>
-#include "getfem/getfem_omp.h"
-#include "getfem/dal_singleton.h"
-#include "getfem/bgeot_rtree.h"
-#include "getfem/bgeot_geotrans_inv.h"
-#include "getfem/getfem_copyable_ptr.h"
-#ifndef _WIN32
-extern "C"{
-#include <unistd.h>
-}
-#endif
-
-/**
- Providing for special Math functions unavailable on Intel or MSVS C++
- compilers
-*/
-
-#if defined(_MSC_VER) && _MSC_VER < 1800
-#include <boost/math/special_functions/acosh.hpp>
-#include <boost/math/special_functions/asinh.hpp>
-#include <boost/math/special_functions/atanh.hpp>
-#include <boost/math/special_functions/erf.hpp>
-typedef double (*BoostMathFunction)(double);
-BoostMathFunction const acosh = boost::math::acosh<double>;
-BoostMathFunction const asinh = boost::math::asinh<double>;
-BoostMathFunction const atanh = boost::math::atanh<double>;
-BoostMathFunction const erf = boost::math::erf<double>;
-BoostMathFunction const erfc = boost::math::erfc<double>;
-#endif
-
-
-// #define GA_USES_BLAS // not so interesting, at least for debian blas
-
-// #define GA_DEBUG_INFO(a) { cout << a << endl; }
-#define GA_DEBUG_INFO(a)
-
-#define GA_DEBUG_ASSERT(a, b) GMM_ASSERT1(a, b)
-// #define GA_DEBUG_ASSERT(a, b)
-
-#if 1
-# define GA_TIC
-# define GA_TOC(a)
-# define GA_TOCTIC(a)
-#else
-# define GA_TIC scalar_type _ga_time_ = gmm::uclock_sec();
-# define GA_TOC(a) { cout <<(a)<<" : "<<gmm::uclock_sec()-_ga_time_<< endl; }
-# define GA_TOCTIC(a) { GA_TOC(a); _ga_time_ = gmm::uclock_sec(); }
-#endif
+#include "getfem/getfem_generic_assembly_tree.h"
+#include "getfem/getfem_generic_assembly_semantic.h"
+#include "getfem/getfem_generic_assembly_compile_and_exec.h"
namespace getfem {
@@ -77,10156 +29,5173 @@ namespace getfem {
extern bool predef_operators_plasticity_initialized;
extern bool predef_operators_contact_initialized;
- base_matrix& __mat_aux1()
- {
- DEFINE_STATIC_THREAD_LOCAL(base_matrix, m);
- return m;
- }
-
//=========================================================================
- // Lexical analysis for the generic assembly language
+ // Instructions for compilation: basic optimized operations on tensors
//=========================================================================
- // Basic token types
- enum GA_TOKEN_TYPE {
- GA_INVALID = 0, // invalid token
- GA_END, // string end
- GA_NAME, // A variable or user defined nonlinear function name
- GA_SCALAR, // A real number
- GA_PLUS, // '+'
- GA_MINUS, // '-'
- GA_UNARY_MINUS, // '-'
- GA_MULT, // '*'
- GA_DIV, // '/'
- GA_COLON, // ':'
- GA_QUOTE, // ''' transpose
- GA_SYM, // 'Sym' operator
- GA_SKEW, // 'Skew' operator
- GA_TRACE, // 'Trace' operator
- GA_DEVIATOR, // 'Deviator' operator
- GA_INTERPOLATE, // 'Interpolate' operation
- GA_INTERPOLATE_FILTER, // 'Interpolate_filter' operation
- GA_ELEMENTARY, // 'Elementary' operation (operation at the element level)
- GA_XFEM_PLUS, // �valuation on the + side of a level-set for
fem_level_set
- GA_XFEM_MINUS, // �valuation on the - side of a level-set for
fem_level_set
- GA_PRINT, // 'Print' Print the tensor
- GA_DOT, // '.'
- GA_DOTMULT, // '.*' componentwise multiplication
- GA_DOTDIV, // './' componentwise division
- GA_TMULT, // '@' tensor product
- GA_COMMA, // ','
- GA_DCOMMA, // ',,'
- GA_SEMICOLON, // ';'
- GA_DSEMICOLON, // ';;'
- GA_LPAR, // '('
- GA_RPAR, // ')'
- GA_LBRACKET, // '['
- GA_RBRACKET, // ']'
- GA_NB_TOKEN_TYPE
- };
-
- static GA_TOKEN_TYPE ga_char_type[256];
- static int ga_operator_priorities[GA_NB_TOKEN_TYPE];
-
- // Initialize ga_char_type and ga_operator_priorities arrays
- static bool init_ga_char_type() {
- for (int i = 0; i < 256; ++i) ga_char_type[i] = GA_INVALID;
- ga_char_type['+'] = GA_PLUS; ga_char_type['-'] = GA_MINUS;
- ga_char_type['*'] = GA_MULT; ga_char_type['/'] = GA_DIV;
- ga_char_type[':'] = GA_COLON; ga_char_type['\''] = GA_QUOTE;
- ga_char_type['.'] = GA_DOT; ga_char_type['@'] = GA_TMULT;
- ga_char_type[','] = GA_COMMA; ga_char_type[';'] = GA_SEMICOLON;
- ga_char_type['('] = GA_LPAR; ga_char_type[')'] = GA_RPAR;
- ga_char_type['['] = GA_LBRACKET; ga_char_type[']'] = GA_RBRACKET;
- ga_char_type['_'] = GA_NAME;
- for (unsigned i = 'a'; i <= 'z'; ++i) ga_char_type[i] = GA_NAME;
- for (unsigned i = 'A'; i <= 'Z'; ++i) ga_char_type[i] = GA_NAME;
- for (unsigned i = '0'; i <= '9'; ++i) ga_char_type[i] = GA_SCALAR;
-
- for (unsigned i = 0; i < GA_NB_TOKEN_TYPE; ++i)
- ga_operator_priorities[i] = 0;
- ga_operator_priorities[GA_PLUS] = 1;
- ga_operator_priorities[GA_MINUS] = 1;
- ga_operator_priorities[GA_MULT] = 2;
- ga_operator_priorities[GA_DIV] = 2;
- ga_operator_priorities[GA_COLON] = 2;
- ga_operator_priorities[GA_DOT] = 2;
- ga_operator_priorities[GA_DOTMULT] = 2;
- ga_operator_priorities[GA_DOTDIV] = 2;
- ga_operator_priorities[GA_TMULT] = 2;
- ga_operator_priorities[GA_QUOTE] = 3;
- ga_operator_priorities[GA_UNARY_MINUS] = 3;
- ga_operator_priorities[GA_SYM] = 4;
- ga_operator_priorities[GA_SKEW] = 4;
- ga_operator_priorities[GA_TRACE] = 4;
- ga_operator_priorities[GA_DEVIATOR] = 4;
- ga_operator_priorities[GA_PRINT] = 4;
-
- return true;
- }
-
- static bool ga_initialized = init_ga_char_type();
-
- // Get the next token in the string at position 'pos' end return its type
- static GA_TOKEN_TYPE ga_get_token(const std::string &expr,
- size_type &pos,
- size_type &token_pos,
- size_type &token_length) {
- bool fdot = false, fE = false;
- GMM_ASSERT1(ga_initialized, "Internal error");
-
- // Ignore white spaces
- while (expr[pos] == ' ' && pos < expr.size()) ++pos;
- token_pos = pos;
- token_length = 0;
-
- // Detecting end of expression
- if (pos >= expr.size()) return GA_END;
-
- // Treating the different cases (Operation, name or number)
- GA_TOKEN_TYPE type = ga_char_type[unsigned(expr[pos])];
- ++pos; ++token_length;
- switch (type) {
- case GA_DOT:
- if (pos >= expr.size()) return type;
- if (expr[pos] == '*') { ++pos; ++token_length; return GA_DOTMULT; }
- if (expr[pos] == '/') { ++pos; ++token_length; return GA_DOTDIV; }
- if (ga_char_type[unsigned(expr[pos])] != GA_SCALAR)
- return type;
- fdot = true; type = GA_SCALAR;
- case GA_SCALAR:
- while (pos < expr.size()) {
- GA_TOKEN_TYPE ctype = ga_char_type[unsigned(expr[pos])];
- switch (ctype) {
- case GA_DOT:
- if (fdot) return type;
- fdot = true; ++pos; ++token_length;
- break;
- case GA_NAME:
- if (fE || (expr[pos] != 'E' && expr[pos] != 'e')) return type;
- fE = true; fdot = true; ++pos; ++token_length;
- if (pos < expr.size()) {
- if (expr[pos] == '+' || expr[pos] == '-')
- { ++pos; ++token_length; }
- }
- if (pos >= expr.size()
- || ga_char_type[unsigned(expr[pos])] != GA_SCALAR)
- return GA_INVALID;
- break;
- case GA_SCALAR:
- ++pos; ++token_length; break;
- default:
- return type;
- }
+ struct ga_instruction_extract_local_im_data : public ga_instruction {
+ base_tensor &t;
+ const im_data &imd;
+ papprox_integration &pai;
+ const base_vector &U;
+ const fem_interpolation_context &ctx;
+ size_type qdim, cv_old;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: extract local im data");
+ size_type cv = ctx.convex_num();
+ if (cv != cv_old) {
+ cv_old = cv;
+ GMM_ASSERT1(imd.linked_mesh_im().int_method_of_element(cv)
+ ->approx_method() == pai, "Im data have to be used only "
+ "on their original integration method.");
}
- return type;
- case GA_NAME:
- while (pos < expr.size()) {
- GA_TOKEN_TYPE ctype = ga_char_type[unsigned(expr[pos])];
- if (ctype != GA_SCALAR && ctype != GA_NAME) break;
- ++pos; ++token_length;
- }
- if (expr.compare(token_pos, token_length, "Sym") == 0)
- return GA_SYM;
- if (expr.compare(token_pos, token_length, "Skew") == 0)
- return GA_SKEW;
- if (expr.compare(token_pos, token_length, "Trace") == 0)
- return GA_TRACE;
- if (expr.compare(token_pos, token_length, "Deviator") == 0)
- return GA_DEVIATOR;
- if (expr.compare(token_pos, token_length, "Interpolate") == 0)
- return GA_INTERPOLATE;
- if (expr.compare(token_pos, token_length, "Interpolate_filter") == 0)
- return GA_INTERPOLATE_FILTER;
- if (expr.compare(token_pos, token_length,
- "Elementary_transformation") == 0)
- return GA_ELEMENTARY;
- if (expr.compare(token_pos, token_length, "Xfem_plus") == 0)
- return GA_XFEM_PLUS;
- if (expr.compare(token_pos, token_length, "Xfem_minus") == 0)
- return GA_XFEM_MINUS;
- if (expr.compare(token_pos, token_length, "Print") == 0)
- return GA_PRINT;
- return type;
- case GA_COMMA:
- if (pos < expr.size() &&
- ga_char_type[unsigned(expr[pos])] == GA_COMMA) {
- ++pos; return GA_DCOMMA;
- }
- return type;
- case GA_SEMICOLON:
- if (pos < expr.size() &&
- ga_char_type[unsigned(expr[pos])] == GA_SEMICOLON) {
- ++pos; return GA_DSEMICOLON;
- }
- return type;
- default: return type;
- }
- }
-
-
- //=========================================================================
- // Tree structure for syntax analysis
- //=========================================================================
-
- static void ga_throw_error_msg(const std::string &expr, size_type pos,
- const std::string &msg) {
- int length_before = 70, length_after = 70;
- if (expr.size()) {
- int first = std::max(0, int(pos)-length_before);
- int last = std::min(int(pos)+length_after, int(expr.size()));
- if (last - first < length_before+length_after)
- first = std::max(0, int(pos)-length_before
- -(length_before+length_after-last+first));
- if (last - first < length_before+length_after)
- last = std::min(int(pos)+length_after
- +(length_before+length_after-last+first),
- int(expr.size()));
- if (first > 0) cerr << "...";
- cerr << expr.substr(first, last-first);
- if (last < int(expr.size())) cerr << "...";
- cerr << endl;
- if (first > 0) cerr << " ";
- if (int(pos) > first)
- cerr << std::setfill ('-') << std::setw(int(pos)-first) << '-'
- << std::setfill (' ');
- cerr << "^" << endl;
- }
- cerr << msg << endl;
- }
-
-#define ga_throw_error(expr, pos, msg) \
- { std::stringstream ss; ss << msg; \
- ga_throw_error_msg(expr, pos, ss.str()); \
- GMM_ASSERT1(false, "Error in assembly string" ); \
- }
-
- enum GA_NODE_TYPE {
- GA_NODE_VOID = 0,
- GA_NODE_OP,
- GA_NODE_PREDEF_FUNC,
- GA_NODE_SPEC_FUNC,
- GA_NODE_OPERATOR,
- GA_NODE_CONSTANT,
- GA_NODE_NAME,
- GA_NODE_PARAMS,
- GA_NODE_RESHAPE,
- GA_NODE_ALLINDICES,
- GA_NODE_C_MATRIX,
- GA_NODE_X,
- GA_NODE_ELT_SIZE,
- GA_NODE_ELT_K,
- GA_NODE_ELT_B,
- GA_NODE_NORMAL,
- GA_NODE_VAL,
- GA_NODE_GRAD,
- GA_NODE_HESS,
- GA_NODE_DIVERG,
- GA_NODE_VAL_TEST,
- GA_NODE_GRAD_TEST,
- GA_NODE_HESS_TEST,
- GA_NODE_DIVERG_TEST,
- GA_NODE_INTERPOLATE,
- GA_NODE_INTERPOLATE_FILTER,
- GA_NODE_INTERPOLATE_VAL,
- GA_NODE_INTERPOLATE_GRAD,
- GA_NODE_INTERPOLATE_HESS,
- GA_NODE_INTERPOLATE_DIVERG,
- GA_NODE_INTERPOLATE_VAL_TEST,
- GA_NODE_INTERPOLATE_GRAD_TEST,
- GA_NODE_INTERPOLATE_HESS_TEST,
- GA_NODE_INTERPOLATE_DIVERG_TEST,
- GA_NODE_INTERPOLATE_X,
- GA_NODE_INTERPOLATE_NORMAL,
- GA_NODE_INTERPOLATE_DERIVATIVE,
- GA_NODE_ELEMENTARY,
- GA_NODE_ELEMENTARY_VAL,
- GA_NODE_ELEMENTARY_GRAD,
- GA_NODE_ELEMENTARY_HESS,
- GA_NODE_ELEMENTARY_DIVERG,
- GA_NODE_ELEMENTARY_VAL_TEST,
- GA_NODE_ELEMENTARY_GRAD_TEST,
- GA_NODE_ELEMENTARY_HESS_TEST,
- GA_NODE_ELEMENTARY_DIVERG_TEST,
- GA_NODE_XFEM_PLUS,
- GA_NODE_XFEM_PLUS_VAL,
- GA_NODE_XFEM_PLUS_GRAD,
- GA_NODE_XFEM_PLUS_HESS,
- GA_NODE_XFEM_PLUS_DIVERG,
- GA_NODE_XFEM_PLUS_VAL_TEST,
- GA_NODE_XFEM_PLUS_GRAD_TEST,
- GA_NODE_XFEM_PLUS_HESS_TEST,
- GA_NODE_XFEM_PLUS_DIVERG_TEST,
- GA_NODE_XFEM_MINUS,
- GA_NODE_XFEM_MINUS_VAL,
- GA_NODE_XFEM_MINUS_GRAD,
- GA_NODE_XFEM_MINUS_HESS,
- GA_NODE_XFEM_MINUS_DIVERG,
- GA_NODE_XFEM_MINUS_VAL_TEST,
- GA_NODE_XFEM_MINUS_GRAD_TEST,
- GA_NODE_XFEM_MINUS_HESS_TEST,
- GA_NODE_XFEM_MINUS_DIVERG_TEST,
- GA_NODE_ZERO};
-
- struct assembly_tensor {
- bool is_copied;
- int sparsity_; // 0: plain, 1: vectorized base, 2: vectorised grad, ...
- size_type qdim_; // Dimension of the vectorization for sparsity tensors
- base_tensor t;
- assembly_tensor *tensor_copied;
-
- const base_tensor &org_tensor() const
- { return is_copied ? tensor_copied->org_tensor() : t; }
- base_tensor &org_tensor()
- { return is_copied ? tensor_copied->org_tensor() : t; }
-
- const base_tensor &tensor() const
- { return (is_copied ? tensor_copied->tensor() : t); }
-
- base_tensor &tensor()
- { return (is_copied ? tensor_copied->tensor() : t); }
-
- void set_sparsity(int sp, size_type q)
- { sparsity_ = sp; qdim_ = q; }
-
- size_type qdim() { return is_copied ? tensor_copied->qdim() : qdim_; }
-
- int sparsity() const
- { return is_copied ? tensor_copied->sparsity() : sparsity_; }
-
- inline void set_to_original() { is_copied = false; }
- inline void set_to_copy(assembly_tensor &t_) {
- is_copied = true; sparsity_ = t_.sparsity_; qdim_ = t_.qdim_;
- t = t_.org_tensor(); tensor_copied = &(t_);
- }
-
- inline void adjust_sizes(const bgeot::multi_index &ssizes)
- { t.adjust_sizes(ssizes); }
-
- inline void adjust_sizes()
- { if (t.sizes().size() || t.size() != 1) t.init(); }
-
- inline void adjust_sizes(size_type i)
- { if (t.sizes().size() != 1 || t.sizes()[0] != i) t.init(i); }
-
- inline void adjust_sizes(size_type i, size_type j) {
- if (t.sizes().size() != 2 || t.sizes()[0] != i || t.sizes()[1] != j)
- t.init(i, j);
- }
-
- inline void adjust_sizes(size_type i, size_type j, size_type k) {
- if (t.sizes().size() != 3 || t.sizes()[0] != i || t.sizes()[1] != j
- || t.sizes()[2] != k)
- t.init(i, j, k);
- }
- inline void adjust_sizes(size_type i, size_type j,
- size_type k, size_type l) {
- if (t.sizes().size() != 3 || t.sizes()[0] != i || t.sizes()[1] != j
- || t.sizes()[2] != k || t.sizes()[3] != l)
- t.init(i, j, k, l);
- }
-
- void init_scalar_tensor(scalar_type v)
- { set_to_original(); t.adjust_sizes(); t[0] = v; }
-
- void init_vector_tensor(size_type d)
- { set_to_original(); t.adjust_sizes(d); }
-
- void init_matrix_tensor(size_type n, size_type m)
- { set_to_original(); t.adjust_sizes(n, m); }
-
- void init_third_order_tensor(size_type n, size_type m, size_type l)
- { set_to_original(); t.adjust_sizes(n, m, l); }
-
- void init_fourth_order_tensor(size_type n, size_type m,
- size_type l, size_type k)
- { set_to_original(); t.adjust_sizes(n, m, l, k); }
-
- const bgeot::multi_index &sizes() const { return t.sizes(); }
-
- assembly_tensor()
- : is_copied(false), sparsity_(0), qdim_(0), tensor_copied(0) {}
- };
-
- struct ga_tree_node;
- typedef ga_tree_node *pga_tree_node;
-
- struct ga_tree_node {
- GA_NODE_TYPE node_type;
- GA_TOKEN_TYPE op_type;
- assembly_tensor t;
- size_type test_function_type; // -1 = undetermined
- // 0 = no test function,
- // 1 = first order, 2 = second order,
- // 3 = both with always first order in first
- std::string name_test1, name_test2; // variable names corresponding to test
- // functions when test_function_type > 0.
- std::string interpolate_name_test1, interpolate_name_test2; // name
- // of interpolation transformation if any
- size_type qdim1, qdim2; // Qdims when test_function_type > 0.
- size_type nbc1, nbc2, nbc3; // For explicit matrices and x.
- size_type pos; // Position of the first character in string
- std::string name; // variable/constant/function/operator name
- std::string interpolate_name; // For Interpolate : name of transformation
- std::string interpolate_name_der; // For Interpolate derivative:
- // name of transformation
- std::string elementary_name; // For Elementary_transformation :
- // name of transformation
- size_type der1, der2; // For functions and nonlinear operators,
- // optional derivative or second derivative.
- bool symmetric_op;
- pga_tree_node parent; // Parent node
- std::vector<pga_tree_node> children; // Children nodes
- scalar_type hash_value; // Hash value to identify nodes.
- bool marked; // For specific use of some algorithms
-
- inline const base_tensor &tensor() const { return t.tensor(); }
- inline base_tensor &tensor() { return t.tensor(); }
- int sparsity() const { return t.sparsity(); }
-
- inline size_type nb_test_functions() const {
- if (test_function_type == size_type(-1)) return 0;
- return test_function_type - (test_function_type >= 2 ? 1 : 0);
+ size_type ipt = imd.filtered_index_of_point(cv, ctx.ii());
+ GMM_ASSERT1(ipt != size_type(-1),
+ "Im data with no data on the current integration point.");
+ auto it = U.begin()+ipt*qdim;
+ std::copy(it, it+qdim, t.begin());
+ return 0;
}
+ ga_instruction_extract_local_im_data
+ (base_tensor &t_, const im_data &imd_, const base_vector &U_,
+ papprox_integration &pai_, const fem_interpolation_context &ctx_,
+ size_type qdim_)
+ : t(t_), imd(imd_), pai(pai_), U(U_), ctx(ctx_), qdim(qdim_),
+ cv_old(-1) {}
+ };
- inline size_type tensor_order() const
- { return t.sizes().size() - nb_test_functions(); }
-
- inline size_type tensor_test_size() const {
- size_type st = nb_test_functions();
- return (st >= 1 ? t.sizes()[0] : 1) * (st == 2 ? t.sizes()[1] : 1);
+ struct ga_instruction_slice_local_dofs : public ga_instruction {
+ const mesh_fem &mf;
+ const base_vector &U;
+ const fem_interpolation_context &ctx;
+ base_vector &coeff;
+ size_type qmult1, qmult2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: Slice local dofs");
+ GMM_ASSERT1(qmult1 != 0 && qmult2 != 0, "Internal error");
+ slice_vector_on_basic_dof_of_element(mf, U, ctx.convex_num(),
+ coeff, qmult1, qmult2);
+ return 0;
}
+ ga_instruction_slice_local_dofs(const mesh_fem &mf_, const base_vector &U_,
+ const fem_interpolation_context &ctx_,
+ base_vector &coeff_,
+ size_type qmult1_, size_type qmult2_)
+ : mf(mf_), U(U_), ctx(ctx_), coeff(coeff_),
+ qmult1(qmult1_), qmult2(qmult2_) {}
+ };
- inline size_type tensor_proper_size() const
- { return t.org_tensor().size() / tensor_test_size(); }
-
- inline size_type tensor_proper_size(size_type i) const
- { return t.sizes()[nb_test_functions()+i]; }
-
-
- void mult_test(const pga_tree_node n0, const pga_tree_node n1,
- const std::string &expr) {
- size_type test0 = n0->test_function_type, test1 = n1->test_function_type;
- if (test0 && test1 && (test0 == test1 ||
- test0 >= 3 || test1 >= 3))
- ga_throw_error(expr, pos,
- "Incompatibility of test functions in product.");
- GMM_ASSERT1(test0 != size_type(-1) && test1 != size_type(-1),
- "internal error");
-
- test_function_type = test0 + test1;
-
- size_type st = nb_test_functions();
- bgeot::multi_index mi(st);
-
- switch (test0) {
- case 1: mi[0] = n0->t.sizes()[0]; break;
- case 2: mi[st-1] = n0->t.sizes()[0]; break;
- case 3: mi[0] = n0->t.sizes()[0]; mi[1] = n0->t.sizes()[1]; break;
- }
- switch (test1) {
- case 1: mi[0] = n1->t.sizes()[0]; break;
- case 2: mi[st-1] = n1->t.sizes()[0]; break;
- case 3: mi[0] = n1->t.sizes()[0]; mi[1] = n1->t.sizes()[1]; break;
- }
-
- if (n0->name_test1.size()) {
- name_test1 = n0->name_test1; qdim1 = n0->qdim1;
- interpolate_name_test1 = n0->interpolate_name_test1;
- } else {
- name_test1 = n1->name_test1; qdim1 = n1->qdim1;
- interpolate_name_test1 = n1->interpolate_name_test1;
- }
+ struct ga_instruction_update_pfp : public ga_instruction {
+ const mesh_fem &mf;
+ const fem_interpolation_context &ctx;
+ fem_precomp_pool &fp_pool;
+ pfem_precomp &pfp;
- if (n0->name_test2.size()) {
- name_test2 = n0->name_test2; qdim2 = n0->qdim2;
- interpolate_name_test2 = n0->interpolate_name_test2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: Pfp update");
+ if (ctx.have_pgp()) {
+ size_type cv = ctx.is_convex_num_valid()
+ ? ctx.convex_num() : mf.convex_index().first_true();
+ pfem pf = mf.fem_of_element(cv);
+ if (!pfp || pf != pfp->get_pfem() ||
+ ctx.pgp()->get_ppoint_tab() != pfp->get_ppoint_tab()) {
+ pfp = fp_pool(pf, ctx.pgp()->get_ppoint_tab());
+ }
} else {
- name_test2 = n1->name_test2; qdim2 = n1->qdim2;
- interpolate_name_test2 = n1->interpolate_name_test2;
+ pfp = 0;
}
- t.adjust_sizes(mi);
- }
-
- bool tensor_is_zero() {
- if (node_type == GA_NODE_ZERO) return true;
- if (node_type != GA_NODE_CONSTANT) return false;
- for (size_type i = 0; i < tensor().size(); ++i)
- if (tensor()[i] != scalar_type(0)) return false;
- return true;
+ return 0;
}
- inline void init_scalar_tensor(scalar_type v)
- { t.init_scalar_tensor(v); test_function_type = 0; }
-
- inline void init_vector_tensor(size_type d)
- { t.init_vector_tensor(d); test_function_type = 0; }
-
- inline void init_matrix_tensor(size_type n, size_type m)
- { t.init_matrix_tensor(n, m); test_function_type = 0; }
-
- inline void init_third_order_tensor(size_type n, size_type m, size_type l)
- { t.init_third_order_tensor(n, m, l); test_function_type = 0; }
+ ga_instruction_update_pfp(const mesh_fem &mf_, pfem_precomp &pfp_,
+ const fem_interpolation_context &ctx_,
+ fem_precomp_pool &fp_pool_)
+ : mf(mf_), ctx(ctx_), fp_pool(fp_pool_), pfp(pfp_) {}
+ };
- inline void init_fourth_order_tensor(size_type n, size_type m,
- size_type l, size_type k)
- { t.init_fourth_order_tensor(n, m, l, k); test_function_type = 0; }
+ struct ga_instruction_first_ind_tensor : public ga_instruction {
+ base_tensor &t;
+ const fem_interpolation_context &ctx;
+ size_type qdim;
+ const mesh_fem *mfn, **mfg;
- inline void adopt_child(pga_tree_node new_child) {
- children.push_back(new_child);
- children.back()->parent = this;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: adapt first index of tensor");
+ const mesh_fem &mf = *(mfg ? *mfg : mfn);
+ GA_DEBUG_ASSERT(mfg ? *mfg : mfn, "Internal error");
+ size_type cv_1 = ctx.is_convex_num_valid()
+ ? ctx.convex_num() : mf.convex_index().first_true();
+ pfem pf = mf.fem_of_element(cv_1);
+ GMM_ASSERT1(pf, "An element without finite element method defined");
+ size_type Qmult = qdim / pf->target_dim();
+ size_type s = pf->nb_dof(cv_1) * Qmult;
+ if (t.sizes()[0] != s)
+ { bgeot::multi_index mi = t.sizes(); mi[0] = s; t.adjust_sizes(mi); }
+ return 0;
}
- inline void replace_child(pga_tree_node oldchild,
- pga_tree_node newchild) {
- bool found = false;
- for (pga_tree_node &child : children)
- if (child == oldchild) {
- child = newchild;
- found = true;
- }
- GMM_ASSERT1(found, "Internal error");
- }
-
- ga_tree_node()
- : node_type(GA_NODE_VOID), test_function_type(-1), qdim1(0), qdim2(0),
- nbc1(0), nbc2(0), nbc3(0), pos(0), der1(0), der2(0),
- symmetric_op(false), hash_value(0) {}
- ga_tree_node(GA_NODE_TYPE ty, size_type p)
- : node_type(ty), test_function_type(-1),
- qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
- pos(p), der1(0), der2(0), symmetric_op(false), hash_value(0) {}
- ga_tree_node(scalar_type v, size_type p)
- : node_type(GA_NODE_CONSTANT), test_function_type(-1),
- qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
- pos(p), der1(0), der2(0), symmetric_op(false),
- hash_value(0)
- { init_scalar_tensor(v); }
- ga_tree_node(const char *n, size_type l, size_type p)
- : node_type(GA_NODE_NAME), test_function_type(-1),
- qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
- pos(p), name(n, l), der1(0), der2(0), symmetric_op(false),
- hash_value(0) {}
- ga_tree_node(GA_TOKEN_TYPE op, size_type p)
- : node_type(GA_NODE_OP), op_type(op), test_function_type(-1),
- qdim1(0), qdim2(0), nbc1(0), nbc2(0), nbc3(0),
- pos(p), der1(0), der2(0), symmetric_op(false),
- hash_value(0) {}
- };
-
- struct ga_tree {
- pga_tree_node root, current_node;
-
- void add_scalar(scalar_type val, size_type pos) {
- while (current_node && current_node->node_type != GA_NODE_OP)
- current_node = current_node->parent;
- if (current_node) {
- current_node->adopt_child(new ga_tree_node(val, pos));
- current_node = current_node->children.back();
- }
- else {
- GMM_ASSERT1(root == nullptr, "Invalid tree operation");
- current_node = root = new ga_tree_node(val, pos);
- root->parent = nullptr;
- }
- }
+ ga_instruction_first_ind_tensor(base_tensor &t_,
+ const fem_interpolation_context &ctx_,
+ size_type qdim_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_)
+ : t(t_), ctx(ctx_), qdim(qdim_), mfn(mfn_), mfg(mfg_) {}
+ };
- void add_allindices(size_type pos) {
- while (current_node && current_node->node_type != GA_NODE_OP)
- current_node = current_node->parent;
- if (current_node) {
- current_node->adopt_child(new ga_tree_node(GA_NODE_ALLINDICES, pos));
- current_node = current_node->children.back();
- }
- else {
- GMM_ASSERT1(root == nullptr, "Invalid tree operation");
- current_node = root = new ga_tree_node(GA_NODE_ALLINDICES, pos);
- root->parent = nullptr;
- }
- }
+ struct ga_instruction_second_ind_tensor
+ : public ga_instruction_first_ind_tensor {
- void add_name(const char *name, size_type length, size_type pos) {
- while (current_node && current_node->node_type != GA_NODE_OP)
- current_node = current_node->parent;
- if (current_node) {
- current_node->adopt_child(new ga_tree_node(name, length, pos));
- current_node = current_node->children.back();
- }
- else {
- GMM_ASSERT1(root == nullptr, "Invalid tree operation");
- current_node = root = new ga_tree_node(name, length, pos);
- root->parent = nullptr;
- }
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: adapt second index of tensor");
+ const mesh_fem &mf = *(mfg ? *mfg : mfn);
+ size_type cv_1 = ctx.is_convex_num_valid()
+ ? ctx.convex_num() : mf.convex_index().first_true();
+ pfem pf = mf.fem_of_element(cv_1);
+ GMM_ASSERT1(pf, "An element without finite element methode defined");
+ size_type Qmult = qdim / pf->target_dim();
+ size_type s = pf->nb_dof(cv_1) * Qmult;
+ if (t.sizes()[1] != s)
+ { bgeot::multi_index mi = t.sizes(); mi[1] = s; t.adjust_sizes(mi); }
+ return 0;
}
- void add_sub_tree(ga_tree &sub_tree) {
- if (current_node &&
- (current_node->node_type == GA_NODE_PARAMS ||
- current_node->node_type == GA_NODE_INTERPOLATE_FILTER ||
- current_node->node_type == GA_NODE_C_MATRIX)) {
- GMM_ASSERT1(sub_tree.root, "Invalid tree operation");
- current_node->adopt_child(sub_tree.root);
- } else {
- GMM_ASSERT1(sub_tree.root, "Invalid tree operation");
- while (current_node && current_node->node_type != GA_NODE_OP)
- current_node = current_node->parent;
- if (current_node) {
- current_node->adopt_child(sub_tree.root);
- current_node = sub_tree.root;
- }
- else {
- GMM_ASSERT1(root == nullptr, "Invalid tree operation");
- current_node = root = sub_tree.root;
- root->parent = nullptr;
- }
- }
- sub_tree.root = sub_tree.current_node = nullptr;
- }
+ ga_instruction_second_ind_tensor(base_tensor &t_,
+ fem_interpolation_context &ctx_,
+ size_type qdim_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_)
+ : ga_instruction_first_ind_tensor(t_, ctx_, qdim_, mfn_, mfg_) {}
- void add_params(size_type pos) {
- GMM_ASSERT1(current_node, "internal error");
- while (current_node && current_node->parent &&
- current_node->parent->node_type == GA_NODE_OP &&
- ga_operator_priorities[current_node->parent->op_type] >= 4)
- current_node = current_node->parent;
- pga_tree_node new_node = new ga_tree_node(GA_NODE_PARAMS, pos);
- new_node->parent = current_node->parent;
- if (current_node->parent)
- current_node->parent->replace_child(current_node, new_node);
- else
- root = new_node;
- new_node->adopt_child(current_node);
- current_node = new_node;
- }
+ };
- void add_matrix(size_type pos) {
- while (current_node && current_node->node_type != GA_NODE_OP)
- current_node = current_node->parent;
- if (current_node) {
- current_node->adopt_child(new ga_tree_node(GA_NODE_C_MATRIX, pos));
- current_node = current_node->children.back();
- }
- else {
- GMM_ASSERT1(root == nullptr, "Invalid tree operation");
- current_node = root = new ga_tree_node(GA_NODE_C_MATRIX, pos);
- root->parent = nullptr;
- }
- current_node->nbc1 = current_node->nbc2 = current_node->nbc3 = 0;
- }
-
- void zip_matrix(const pga_tree_node source_node) {
- GMM_ASSERT1(current_node->node_type == GA_NODE_C_MATRIX &&
- source_node->node_type == GA_NODE_C_MATRIX,
- "Internal error");
- size_type target_size = current_node->children.size();
- size_type source_size = source_node->children.size();
- size_type last_dim_size = target_size/source_size;
- GMM_ASSERT1(target_size == source_size*last_dim_size,
- "Internal error, " << target_size << " != " <<
- source_size << "*" << last_dim_size);
- std::vector<pga_tree_node> new_children;
- for (size_type i = 0; i < source_size; ++i) {
- for (size_type j = 0; j < last_dim_size; ++j)
- new_children.push_back(current_node->children[i*last_dim_size+j]);
- new_children.push_back(source_node->children[i]);
- source_node->children[i]->parent = current_node;
- }
- source_node->children.resize(0); // so that the destructor of source_node
- // will not destruct the children
- current_node->children = new_children;
- }
-
- void add_op(GA_TOKEN_TYPE op_type, size_type pos) {
- while (current_node && current_node->parent &&
- current_node->parent->node_type == GA_NODE_OP &&
- ga_operator_priorities[current_node->parent->op_type]
- >= ga_operator_priorities[op_type])
- current_node = current_node->parent;
- pga_tree_node new_node = new ga_tree_node(op_type, pos);
- if (current_node) {
- if (op_type == GA_UNARY_MINUS
- || op_type == GA_SYM || op_type == GA_SKEW
- || op_type == GA_TRACE || op_type == GA_DEVIATOR
- || op_type == GA_PRINT) {
- current_node->adopt_child(new_node);
- } else {
- new_node->parent = current_node->parent;
- if (current_node->parent)
- current_node->parent->replace_child(current_node, new_node);
- else
- root = new_node;
- new_node->adopt_child(current_node);
- }
- } else {
- if (root) new_node->adopt_child(root);
- root = new_node;
- root->parent = nullptr;
- }
- current_node = new_node;
- }
+ struct ga_instruction_two_first_ind_tensor : public ga_instruction {
+ base_tensor &t;
+ const fem_interpolation_context &ctx1, &ctx2;
+ size_type qdim1;
+ const mesh_fem *mfn1, **mfg1;
+ size_type qdim2;
+ const mesh_fem *mfn2, **mfg2;
- void clear_node_rec(pga_tree_node pnode) {
- if (pnode) {
- for (pga_tree_node &child : pnode->children)
- clear_node_rec(child);
- delete pnode;
- current_node = nullptr;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: adapt two first indices of tensor");
+ const mesh_fem &mf1 = *(mfg1 ? *mfg1 : mfn1);
+ const mesh_fem &mf2 = *(mfg2 ? *mfg2 : mfn2);
+ size_type cv_1 = ctx1.is_convex_num_valid()
+ ? ctx1.convex_num() : mf1.convex_index().first_true();
+ size_type cv_2 = ctx2.is_convex_num_valid()
+ ? ctx2.convex_num() : mf2.convex_index().first_true();
+ pfem pf1 = mf1.fem_of_element(cv_1);
+ GMM_ASSERT1(pf1, "An element without finite element method defined");
+ pfem pf2 = mf2.fem_of_element(cv_2);
+ GMM_ASSERT1(pf2, "An element without finite element method defined");
+ size_type Qmult1 = qdim1 / pf1->target_dim();
+ size_type s1 = pf1->nb_dof(cv_1) * Qmult1;
+ size_type Qmult2 = qdim2 / pf2->target_dim();
+ size_type s2 = pf2->nb_dof(cv_2) * Qmult2;
+ if (t.sizes()[0] != s1 || t.sizes()[1] != s2) {
+ bgeot::multi_index mi = t.sizes();
+ mi[0] = s1; mi[1] = s2;
+ t.adjust_sizes(mi);
}
+ return 0;
}
- void clear_node(pga_tree_node pnode) {
- if (pnode) {
- pga_tree_node parent = pnode->parent;
- if (parent) { // keep all siblings of pnode
- size_type j = 0;
- for (pga_tree_node &sibling : parent->children)
- if (sibling != pnode)
- parent->children[j++] = sibling;
- parent->children.resize(j);
- } else
- root = nullptr;
- }
- clear_node_rec(pnode);
- }
+ ga_instruction_two_first_ind_tensor
+ (base_tensor &t_, const fem_interpolation_context &ctx1_,
+ const fem_interpolation_context &ctx2_,
+ size_type qdim1_, const mesh_fem *mfn1_, const mesh_fem **mfg1_,
+ size_type qdim2_, const mesh_fem *mfn2_, const mesh_fem **mfg2_)
+ : t(t_), ctx1(ctx1_), ctx2(ctx2_), qdim1(qdim1_), mfn1(mfn1_),
+ mfg1(mfg1_), qdim2(qdim2_), mfn2(mfn2_), mfg2(mfg2_) {}
+ };
- void clear() {
- clear_node_rec(root);
- root = current_node = nullptr;
- }
- void clear_children(pga_tree_node pnode) {
- for (pga_tree_node &child : pnode->children)
- clear_node_rec(child);
- pnode->children.resize(0);
- }
+ struct ga_instruction_X_component : public ga_instruction {
+ scalar_type &t;
+ const fem_interpolation_context &ctx;
+ size_type n;
- void replace_node_by_child(pga_tree_node pnode, size_type i) {
- GMM_ASSERT1(i < pnode->children.size(), "Internal error");
- pga_tree_node child = pnode->children[i];
- child->parent = pnode->parent;
- if (pnode->parent)
- pnode->parent->replace_child(pnode, child);
- else
- root = child;
- current_node = nullptr;
- for (pga_tree_node &sibling : pnode->children)
- if (sibling != child) clear_node_rec(sibling);
- delete pnode;
- }
-
- void copy_node(pga_tree_node pnode, pga_tree_node parent,
- pga_tree_node &child) {
- GMM_ASSERT1(child == nullptr, "Internal error");
- child = new ga_tree_node();
- *child = *pnode;
- child->parent = parent;
- for (pga_tree_node &grandchild : child->children)
- grandchild = nullptr;
- for (size_type j = 0; j < child->children.size(); ++j)
- copy_node(pnode->children[j], child, child->children[j]);
- }
-
- void duplicate_with_operation(pga_tree_node pnode,
- GA_TOKEN_TYPE op_type) {
- pga_tree_node newop = new ga_tree_node(op_type, pnode->pos);
- newop->children.resize(2, nullptr);
- newop->children[0] = pnode;
- newop->parent = pnode->parent;
- if (pnode->parent)
- pnode->parent->replace_child(pnode, newop);
- else
- root = newop;
- pnode->parent = newop;
- copy_node(pnode, newop, newop->children[1]);
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: X component");
+ t = ctx.xreal()[n];
+ return 0;
}
- void duplicate_with_addition(pga_tree_node pnode) {
- duplicate_with_operation(pnode, GA_PLUS);
- }
+ ga_instruction_X_component
+ (scalar_type &t_, const fem_interpolation_context &ctx_, size_type n_)
+ : t(t_), ctx(ctx_), n(n_) {}
+ };
- void duplicate_with_subtraction(pga_tree_node pnode) {
- duplicate_with_operation(pnode, GA_MINUS);
- }
+ struct ga_instruction_X : public ga_instruction {
+ base_tensor &t;
+ const fem_interpolation_context &ctx;
- void insert_node(pga_tree_node pnode, GA_NODE_TYPE node_type) {
- pga_tree_node newnode = new ga_tree_node();
- newnode->node_type = node_type;
- newnode->parent = pnode->parent;
- if (pnode->parent)
- pnode->parent->replace_child(pnode, newnode);
- else
- root = newnode;
- newnode->adopt_child(pnode);
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: X");
+ GA_DEBUG_ASSERT(t.size() == ctx.xreal().size(), "dimensions mismatch");
+ gmm::copy(ctx.xreal(), t.as_vector());
+ return 0;
}
- void add_child(pga_tree_node pnode) {
- pga_tree_node newnode = new ga_tree_node();
- pnode->adopt_child(newnode);
- }
+ ga_instruction_X(base_tensor &t_, const fem_interpolation_context &ctx_)
+ : t(t_), ctx(ctx_) {}
+ };
- void swap(ga_tree &tree)
- { std::swap(root, tree.root); std::swap(current_node, tree.current_node); }
-
- ga_tree() : root(nullptr), current_node(nullptr) {}
+ struct ga_instruction_copy_small_vect : public ga_instruction {
+ base_tensor &t;
+ const base_small_vector &vec;
- ga_tree(const ga_tree &tree) : root(nullptr), current_node(nullptr)
- { if (tree.root) copy_node(tree.root, nullptr, root); }
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: copy small vector");
+ GMM_ASSERT1(t.size() == vec.size(), "Invalid vector size.");
+ gmm::copy(vec, t.as_vector());
+ return 0;
+ }
+ ga_instruction_copy_small_vect(base_tensor &t_,
+ const base_small_vector &vec_)
+ : t(t_), vec(vec_) {}
+ };
- ga_tree &operator = (const ga_tree &tree)
- { clear(); if (tree.root) copy_node(tree.root, nullptr, root); return
*this; }
+ struct ga_instruction_copy_Normal : public ga_instruction_copy_small_vect {
- ~ga_tree() { clear(); }
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: Normal");
+ GMM_ASSERT1(t.size() == vec.size(), "Invalid outward unit normal "
+ "vector. Possible reasons: not on boundary or "
+ "transformation failed.");
+ gmm::copy(vec, t.as_vector());
+ return 0;
+ }
+ ga_instruction_copy_Normal(base_tensor &t_,
+ const base_small_vector &Normal_)
+ : ga_instruction_copy_small_vect(t_, Normal_) {}
};
+ struct ga_instruction_element_size : public ga_instruction {
+ base_tensor &t;
+ scalar_type &es;
- // Test equality or equivalence of two sub trees.
- // version = 0 : strict equality
- // 1 : give the same result
- // 2 : give the same result with transposition of test functions
- static bool sub_tree_are_equal
- (const pga_tree_node pnode1, const pga_tree_node pnode2,
- const ga_workspace &workspace, int version) {
- size_type ntype1 = pnode1->node_type;
- if (ntype1 == GA_NODE_ZERO) ntype1 = GA_NODE_CONSTANT;
- size_type ntype2 = pnode2->node_type;
- if (ntype2 == GA_NODE_ZERO) ntype2 = GA_NODE_CONSTANT;
-
- if (ntype1 != ntype2) return false;
- if (pnode1->children.size() != pnode2->children.size()) return false;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: element_size");
+ GMM_ASSERT1(t.size() == 1, "Invalid element size.");
+ t[0] = es;
+ return 0;
+ }
+ ga_instruction_element_size(base_tensor &t_, scalar_type &es_)
+ : t(t_), es(es_) {}
+ };
- switch(ntype1) {
- case GA_NODE_OP:
- if (pnode1->op_type != pnode2->op_type) return false;
- if (pnode1->symmetric_op != pnode2->symmetric_op) return false;
- break;
- case GA_NODE_OPERATOR:
- if (pnode1->der1 != pnode2->der1 || pnode1->der2 != pnode2->der2)
- return false;
- case GA_NODE_PREDEF_FUNC: case GA_NODE_SPEC_FUNC:
- if (pnode1->name.compare(pnode2->name)) return false;
- break;
- case GA_NODE_CONSTANT: case GA_NODE_ZERO:
- if (pnode1->tensor().size() != pnode2->tensor().size()) return false;
-
- switch(version) {
- case 0: case 1:
- if (pnode1->test_function_type != pnode2->test_function_type)
- return false;
- if ((pnode1->test_function_type & 1) &&
- pnode1->name_test1.compare(pnode2->name_test1) != 0)
- return false;
- if ((pnode1->test_function_type & 2) &&
- pnode1->name_test2.compare(pnode2->name_test2) != 0)
- return false;
- break;
- case 2:
- if ((pnode1->test_function_type == 1 &&
- pnode2->test_function_type == 1) ||
- (pnode1->test_function_type == 2 &&
- pnode2->test_function_type == 2))
- return false;
- if ((pnode1->test_function_type & 1) &&
- pnode1->name_test1.compare(pnode2->name_test2) != 0)
- return false;
- if ((pnode1->test_function_type & 2) &&
- pnode1->name_test2.compare(pnode2->name_test1) != 0)
- return false;
- break;
- }
- if (pnode1->tensor().size() != 1 &&
- pnode1->t.sizes().size() != pnode2->t.sizes().size()) return false;
- for (size_type i = 0; i < pnode1->t.sizes().size(); ++i)
- if (pnode1->t.sizes()[i] != pnode2->t.sizes()[i]) return false;
- for (size_type i = 0; i < pnode1->tensor().size(); ++i)
- if (gmm::abs(pnode1->tensor()[i] - pnode2->tensor()[i]) > 1E-25)
- return false;
- break;
- case GA_NODE_C_MATRIX:
- if (pnode1->nbc1 != pnode2->nbc1 || pnode1->nbc2 != pnode2->nbc2 ||
- pnode1->nbc3 != pnode2->nbc3)
- return false;
- break;
- case GA_NODE_INTERPOLATE_FILTER:
- if (pnode1->interpolate_name.compare(pnode2->interpolate_name) ||
- pnode1->nbc1 != pnode2->nbc1)
- return false;
- break;
- case GA_NODE_INTERPOLATE_X: case GA_NODE_INTERPOLATE_NORMAL:
- if (pnode1->interpolate_name.compare(pnode2->interpolate_name))
- return false;
- break;
- case GA_NODE_INTERPOLATE_DERIVATIVE:
- if (pnode1->interpolate_name_der.compare(pnode2->interpolate_name_der))
- return false;
- // The test continues with what follows
- case GA_NODE_INTERPOLATE_VAL_TEST: case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_HESS_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
- case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
- case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
- case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
- case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
- case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
- case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
- if (pnode1->interpolate_name.compare(pnode2->interpolate_name) ||
- pnode1->elementary_name.compare(pnode2->elementary_name))
- return false;
- // The test continues with what follows
- case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST:
- case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST:
- {
- const mesh_fem *mf1 = workspace.associated_mf(pnode1->name);
- const mesh_fem *mf2 = workspace.associated_mf(pnode2->name);
- switch (version) {
- case 0:
- if (pnode1->name.compare(pnode2->name) ||
- pnode1->test_function_type != pnode2->test_function_type)
- return false;
- break;
- case 1:
- if (mf1 != mf2 ||
- workspace.qdim(pnode1->name) != workspace.qdim(pnode2->name) ||
- pnode1->test_function_type != pnode2->test_function_type)
- return false;
- break;
- case 2:
- if (mf1 != mf2 ||
- workspace.qdim(pnode1->name) != workspace.qdim(pnode2->name) ||
- pnode1->test_function_type == pnode2->test_function_type)
- return false;
- break;
- }
- }
- break;
- case GA_NODE_VAL: case GA_NODE_GRAD:
- case GA_NODE_HESS: case GA_NODE_DIVERG:
- if (pnode1->name.compare(pnode2->name)) return false;
- break;
- case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
- case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
- if (pnode1->interpolate_name.compare(pnode2->interpolate_name) ||
- pnode1->elementary_name.compare(pnode2->elementary_name) ||
- pnode1->name.compare(pnode2->name))
- return false;
- break;
- case GA_NODE_X:
- if (pnode1->nbc1 != pnode2->nbc1) return false;
- break;
+ struct ga_instruction_element_K : public ga_instruction {
+ base_tensor &t;
+ const fem_interpolation_context &ctx;
- default:break;
- }
-
- if (version && ntype1 == GA_NODE_OP && pnode1->symmetric_op) {
- if (sub_tree_are_equal(pnode1->children[0], pnode2->children[0],
- workspace, version) &&
- sub_tree_are_equal(pnode1->children[1], pnode2->children[1],
- workspace, version))
- return true;
- if (sub_tree_are_equal(pnode1->children[1], pnode2->children[0],
- workspace, version) &&
- sub_tree_are_equal(pnode1->children[0], pnode2->children[1],
- workspace, version) )
- return true;
- return false;
- } else {
- for (size_type i = 0; i < pnode1->children.size(); ++i)
- if (!(sub_tree_are_equal(pnode1->children[i], pnode2->children[i],
- workspace, version)))
- return false;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: element_K");
+ GMM_ASSERT1(t.size() == (ctx.K()).size(), "Invalid tensor size.");
+ gmm::copy(ctx.K().as_vector(), t.as_vector());
+ return 0;
}
- return true;
- }
-
- static void verify_tree(const pga_tree_node pnode,
- const pga_tree_node parent) {
- GMM_ASSERT1(pnode->parent == parent,
- "Invalid tree node " << pnode->node_type);
- for (pga_tree_node &child : pnode->children)
- verify_tree(child, pnode);
- }
+ ga_instruction_element_K(base_tensor &t_,
+ const fem_interpolation_context &ct)
+ : t(t_), ctx(ct) {}
+ };
+ struct ga_instruction_element_B : public ga_instruction {
+ base_tensor &t;
+ const fem_interpolation_context &ctx;
-#define ga_valid_operand(expr, pnode) \
- { \
- if (pnode && (pnode->node_type == GA_NODE_PREDEF_FUNC || \
- pnode->node_type == GA_NODE_SPEC_FUNC || \
- pnode->node_type == GA_NODE_NAME || \
- pnode->node_type == GA_NODE_OPERATOR || \
- pnode->node_type == GA_NODE_ALLINDICES)) \
- ga_throw_error(expr, pnode->pos, "Invalid term"); \
- }
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: element_B");
+ GMM_ASSERT1(t.size() == (ctx.B()).size(), "Invalid tensor size.");
+ gmm::copy(ctx.B().as_vector(), t.as_vector());
+ return 0;
+ }
+ ga_instruction_element_B(base_tensor &t_,
+ const fem_interpolation_context &ct)
+ : t(t_), ctx(ct) {}
+ };
- static void ga_print_constant_tensor(const pga_tree_node pnode,
- std::ostream &str) {
- size_type nt = pnode->nb_test_functions(); // for printing zero tensors
- switch (pnode->tensor_order()) {
- case 0:
- str << (nt ? scalar_type(0) : pnode->tensor()[0]);
- break;
+ struct ga_instruction_val_base : public ga_instruction {
+ base_tensor &t;
+ fem_interpolation_context &ctx;
+ const mesh_fem &mf;
+ const pfem_precomp &pfp;
- case 1:
- str << "[";
- for (size_type i = 0; i < pnode->tensor_proper_size(0); ++i) {
- if (i != 0) str << "; ";
- str << (nt ? scalar_type(0) : pnode->tensor()[i]);
+ virtual int exec() { // --> t(ndof,target_dim)
+ GA_DEBUG_INFO("Instruction: compute value of base functions");
+ // if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ // else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ // GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ // ctx.base_value(t);
+ if (ctx.have_pgp()) ctx.pfp_base_value(t, pfp);
+ else {
+ ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ ctx.base_value(t);
}
- str << "]";
- break;
+ return 0;
+ }
- case 2: case 3: case 4:
- {
- size_type ii(0);
- size_type n0 = pnode->tensor_proper_size(0);
- size_type n1 = pnode->tensor_proper_size(1);
- size_type n2 = ((pnode->tensor_order() > 2) ?
- pnode->tensor_proper_size(2) : 1);
- size_type n3 = ((pnode->tensor_order() > 3) ?
- pnode->tensor_proper_size(3) : 1);
- if (n3 > 1) str << "[";
- for (size_type l = 0; l < n3; ++l) {
- if (l != 0) str << ",";
- if (n2 > 1) str << "[";
- for (size_type k = 0; k < n2; ++k) {
- if (k != 0) str << ",";
- if (n1 > 1) str << "[";
- for (size_type j = 0; j < n1; ++j) {
- if (j != 0) str << ",";
- if (n0 > 1) str << "[";
- for (size_type i = 0; i < n0; ++i) {
- if (i != 0) str << ",";
- str << (nt ? scalar_type(0) : pnode->tensor()[ii++]);
- }
- if (n0 > 1) str << "]";
- }
- if (n1 > 1) str << "]";
- }
- if (n2 > 1) str << "]";
- }
- if (n3 > 1) str << "]";
- }
- break;
+ ga_instruction_val_base(base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, const pfem_precomp &pfp_)
+ : t(tt), ctx(ct), mf(mf_), pfp(pfp_) {}
+ };
- case 5: case 6:
- str << "Reshape([";
- for (size_type i = 0; i < pnode->tensor_proper_size(); ++i) {
- if (i != 0) str << "; ";
- str << (nt ? scalar_type(0) : pnode->tensor()[i]);
- }
- str << "]";
- for (size_type i = 0; i < pnode->tensor_order(); ++i) {
- if (i != 0) str << ", ";
- str << pnode->tensor_proper_size(i);
- }
- str << ")";
- break;
+ struct ga_instruction_xfem_plus_val_base : public ga_instruction {
+ base_tensor &t;
+ fem_interpolation_context &ctx;
+ const mesh_fem &mf;
+ pfem_precomp &pfp;
- default: GMM_ASSERT1(false, "Invalid tensor dimension");
+ virtual int exec() { // --> t(ndof,target_dim)
+ GA_DEBUG_INFO("Instruction: compute value of base functions");
+ if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ int old_xfem_side = ctx.xfem_side();
+ ctx.set_xfem_side(1);
+ ctx.base_value(t);
+ ctx.set_xfem_side(old_xfem_side);
+ return 0;
}
- GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
- }
- static void ga_print_node(const pga_tree_node pnode,
- std::ostream &str) {
- if (!pnode) return;
- long prec = str.precision(16);
+ ga_instruction_xfem_plus_val_base(base_tensor &tt,
+ fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : t(tt), ctx(ct), mf(mf_), pfp(pfp_) {}
+ };
- bool is_interpolate(false), is_elementary(false);
- bool is_xfem_plus(false), is_xfem_minus(false);
- switch(pnode->node_type) {
- case GA_NODE_INTERPOLATE:
- case GA_NODE_INTERPOLATE_FILTER:
- case GA_NODE_INTERPOLATE_X:
- case GA_NODE_INTERPOLATE_NORMAL:
- case GA_NODE_INTERPOLATE_VAL:
- case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_INTERPOLATE_HESS:
- case GA_NODE_INTERPOLATE_DIVERG:
- case GA_NODE_INTERPOLATE_VAL_TEST:
- case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_HESS_TEST:
- case GA_NODE_INTERPOLATE_DIVERG_TEST:
- str << "Interpolate(";
- is_interpolate = true;
- break;
- case GA_NODE_ELEMENTARY:
- case GA_NODE_ELEMENTARY_VAL:
- case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_ELEMENTARY_HESS:
- case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_ELEMENTARY_VAL_TEST:
- case GA_NODE_ELEMENTARY_GRAD_TEST:
- case GA_NODE_ELEMENTARY_HESS_TEST:
- case GA_NODE_ELEMENTARY_DIVERG_TEST:
- is_elementary = true;
- str << "Elementary_transformation(";
- break;
- case GA_NODE_XFEM_PLUS:
- case GA_NODE_XFEM_PLUS_VAL:
- case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_PLUS_HESS:
- case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_PLUS_VAL_TEST:
- case GA_NODE_XFEM_PLUS_GRAD_TEST:
- case GA_NODE_XFEM_PLUS_HESS_TEST:
- case GA_NODE_XFEM_PLUS_DIVERG_TEST:
- is_xfem_plus = true;
- str << "Xfem_plus(";
- break;
- case GA_NODE_XFEM_MINUS:
- case GA_NODE_XFEM_MINUS_VAL:
- case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_XFEM_MINUS_HESS:
- case GA_NODE_XFEM_MINUS_DIVERG:
- case GA_NODE_XFEM_MINUS_VAL_TEST:
- case GA_NODE_XFEM_MINUS_GRAD_TEST:
- case GA_NODE_XFEM_MINUS_HESS_TEST:
- case GA_NODE_XFEM_MINUS_DIVERG_TEST:
- is_xfem_minus = true;
- str << "Xfem_minus(";
- break;
- default:
- break;
- }
+ struct ga_instruction_xfem_minus_val_base : public ga_instruction {
+ base_tensor &t;
+ fem_interpolation_context &ctx;
+ const mesh_fem &mf;
+ pfem_precomp &pfp;
- switch(pnode->node_type) {
- case GA_NODE_GRAD:
- case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_ELEMENTARY_GRAD_TEST:
- case GA_NODE_XFEM_PLUS_GRAD_TEST:
- case GA_NODE_XFEM_MINUS_GRAD_TEST:
- str << "Grad_";
- break;
- case GA_NODE_HESS:
- case GA_NODE_INTERPOLATE_HESS:
- case GA_NODE_ELEMENTARY_HESS:
- case GA_NODE_XFEM_PLUS_HESS:
- case GA_NODE_XFEM_MINUS_HESS:
- case GA_NODE_HESS_TEST:
- case GA_NODE_INTERPOLATE_HESS_TEST:
- case GA_NODE_ELEMENTARY_HESS_TEST:
- case GA_NODE_XFEM_PLUS_HESS_TEST:
- case GA_NODE_XFEM_MINUS_HESS_TEST:
- str << "Hess_";
- break;
- case GA_NODE_DIVERG:
- case GA_NODE_INTERPOLATE_DIVERG:
- case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_MINUS_DIVERG:
- case GA_NODE_DIVERG_TEST:
- case GA_NODE_INTERPOLATE_DIVERG_TEST:
- case GA_NODE_ELEMENTARY_DIVERG_TEST:
- case GA_NODE_XFEM_PLUS_DIVERG_TEST:
- case GA_NODE_XFEM_MINUS_DIVERG_TEST:
- str << "Div_";
- break;
- default:
- break;
+ virtual int exec() { // --> t(ndof,target_dim)
+ GA_DEBUG_INFO("Instruction: compute value of base functions");
+ if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ int old_xfem_side = ctx.xfem_side();
+ ctx.set_xfem_side(-1);
+ ctx.base_value(t);
+ ctx.set_xfem_side(old_xfem_side);
+ return 0;
}
- switch(pnode->node_type) {
- case GA_NODE_OP:
- {
- bool par = false;
- if (pnode->parent) {
- if (pnode->parent->node_type == GA_NODE_OP &&
- (ga_operator_priorities[pnode->op_type] >= 2 ||
- ga_operator_priorities[pnode->op_type]
- < ga_operator_priorities[pnode->parent->op_type]))
- par = true;
- if (pnode->parent->node_type == GA_NODE_PARAMS) par = true;
- }
+ ga_instruction_xfem_minus_val_base
+ (base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : t(tt), ctx(ct), mf(mf_), pfp(pfp_) {}
+ };
+ struct ga_instruction_grad_base : public ga_instruction_val_base {
- if (par) str << "(";
- if (pnode->op_type == GA_UNARY_MINUS) {
- GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
- str << "-"; ga_print_node(pnode->children[0], str);
- } else if (pnode->op_type == GA_QUOTE) {
- GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
- ga_print_node(pnode->children[0], str); str << "'";
- } else if (pnode->op_type == GA_SYM) {
- GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
- str << "Sym("; ga_print_node(pnode->children[0], str); str << ")";
- } else if (pnode->op_type == GA_SKEW) {
- GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
- str << "Skew("; ga_print_node(pnode->children[0], str); str << ")";
- } else if (pnode->op_type == GA_TRACE) {
- GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
- str << "Trace("; ga_print_node(pnode->children[0], str); str << ")";
- } else if (pnode->op_type == GA_DEVIATOR) {
- GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree with "
- << pnode->children.size() << " children instead of 1");
- str << "Deviator("; ga_print_node(pnode->children[0], str); str<<")";
- } else if (pnode->op_type == GA_PRINT) {
- GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
- str << "Print("; ga_print_node(pnode->children[0], str); str << ")";
- } else {
- // GMM_ASSERT1(pnode->children.size() == 2, "Invalid tree");
- if (!par && pnode->op_type == GA_MULT &&
- (pnode->children.size() == 1 ||
- pnode->test_function_type == size_type(-1) ||
- (pnode->children[0]->tensor_order() == 4 &&
- pnode->children[1]->tensor_order() == 2)))
- { par = true; str << "("; }
- ga_print_node(pnode->children[0], str);
- switch (pnode->op_type) {
- case GA_PLUS: str << "+"; break;
- case GA_MINUS: str << "-"; break;
- case GA_MULT: str << "*"; break;
- case GA_DIV: str << "/"; break;
- case GA_COLON: str << ":"; break;
- case GA_DOT: str << "."; break;
- case GA_DOTMULT: str << ".*"; break;
- case GA_DOTDIV: str << "./"; break;
- case GA_TMULT: str << "@"; break;
- default: GMM_ASSERT1(false, "Invalid or not taken into account "
- "operation");
- }
- if (pnode->children.size() >= 2)
- ga_print_node(pnode->children[1], str);
- else
- str << "(unknown second argument)";
- }
- if (par) str << ")";
+ virtual int exec() { // --> t(ndof,target_dim,N)
+ GA_DEBUG_INFO("Instruction: compute gradient of base functions");
+ // if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ // else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ // GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ // ctx.grad_base_value(t);
+ if (ctx.have_pgp()) ctx.pfp_grad_base_value(t, pfp);
+ else {
+ ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ ctx.grad_base_value(t);
}
- break;
+ return 0;
+ }
- case GA_NODE_X:
- if (pnode->nbc1) str << "X(" << pnode->nbc1 << ")"; else str << "X";
- break;
- case GA_NODE_ELT_SIZE: str << "element_size"; break;
- case GA_NODE_ELT_K: str << "element_K"; break;
- case GA_NODE_ELT_B: str << "element_B"; break;
- case GA_NODE_NORMAL: str << "Normal"; break;
- case GA_NODE_INTERPOLATE_FILTER:
- str << "Interpolate_filter(" << pnode->interpolate_name << ",";
- ga_print_node(pnode->children[0], str);
- if (pnode->children.size() == 2)
- { str << ","; ga_print_node(pnode->children[1], str); }
- else if (pnode->nbc1 != size_type(-1)) str << "," << pnode->nbc1;
- str << ")";
- break;
- case GA_NODE_INTERPOLATE_X:
- str << "X";
- break;
- case GA_NODE_INTERPOLATE_NORMAL:
- str << "Normal";
- break;
- case GA_NODE_INTERPOLATE_DERIVATIVE:
- str << (pnode->test_function_type == 1 ? "Test_" : "Test2_")
- << "Interpolate_derivative(" << pnode->interpolate_name_der << ","
- << pnode->interpolate_name << "," << pnode->name << ")";
- break;
- case GA_NODE_INTERPOLATE:
- case GA_NODE_ELEMENTARY:
- case GA_NODE_XFEM_PLUS:
- case GA_NODE_XFEM_MINUS:
- case GA_NODE_VAL:
- case GA_NODE_INTERPOLATE_VAL:
- case GA_NODE_ELEMENTARY_VAL:
- case GA_NODE_XFEM_PLUS_VAL:
- case GA_NODE_XFEM_MINUS_VAL:
- case GA_NODE_GRAD:
- case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_HESS:
- case GA_NODE_INTERPOLATE_HESS:
- case GA_NODE_ELEMENTARY_HESS:
- case GA_NODE_XFEM_PLUS_HESS:
- case GA_NODE_XFEM_MINUS_HESS:
- case GA_NODE_DIVERG:
- case GA_NODE_INTERPOLATE_DIVERG:
- case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_MINUS_DIVERG:
- str << pnode->name;
- break;
- case GA_NODE_VAL_TEST:
- case GA_NODE_INTERPOLATE_VAL_TEST:
- case GA_NODE_ELEMENTARY_VAL_TEST:
- case GA_NODE_XFEM_PLUS_VAL_TEST:
- case GA_NODE_XFEM_MINUS_VAL_TEST:
- case GA_NODE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_ELEMENTARY_GRAD_TEST:
- case GA_NODE_XFEM_PLUS_GRAD_TEST:
- case GA_NODE_XFEM_MINUS_GRAD_TEST:
- case GA_NODE_HESS_TEST:
- case GA_NODE_INTERPOLATE_HESS_TEST:
- case GA_NODE_ELEMENTARY_HESS_TEST:
- case GA_NODE_XFEM_PLUS_HESS_TEST:
- case GA_NODE_XFEM_MINUS_HESS_TEST:
- case GA_NODE_DIVERG_TEST:
- case GA_NODE_INTERPOLATE_DIVERG_TEST:
- case GA_NODE_ELEMENTARY_DIVERG_TEST:
- case GA_NODE_XFEM_PLUS_DIVERG_TEST:
- case GA_NODE_XFEM_MINUS_DIVERG_TEST:
- str << (pnode->test_function_type == 1 ? "Test_" : "Test2_")
- << pnode->name;
- break;
- case GA_NODE_SPEC_FUNC: str << pnode->name; break;
- case GA_NODE_OPERATOR:
- case GA_NODE_PREDEF_FUNC:
- if (pnode->der1) {
- str << "Derivative_" << pnode->der1 << "_";
- if (pnode->der2) str << pnode->der2 << "_";
- }
- str << pnode->name; break;
- case GA_NODE_ZERO:
- GMM_ASSERT1(pnode->test_function_type != size_type(-1),
- "Internal error");
- if (pnode->test_function_type) str << "(";
- ga_print_constant_tensor(pnode, str);
- if (pnode->name_test1.size()) {
- GMM_ASSERT1(pnode->qdim1 > 0, "Internal error");
- if (pnode->qdim1 == 1)
- str << "*Test_" << pnode->name_test1;
- else {
- str << "*(Reshape(Test_" << pnode->name_test1 << ","
- << pnode->qdim1<< ")(1))";
- }
- }
- if (pnode->name_test2.size()) {
- GMM_ASSERT1(pnode->qdim2 > 0, "Internal error");
- if (pnode->qdim2 == 1)
- str << "*Test2_" << pnode->name_test2;
- else {
- str << "*(Reshape(Test2_" << pnode->name_test2 << ","
- << pnode->qdim2<< ")(1))";
- }
- }
- if (pnode->test_function_type) str << ")";
- break;
+ ga_instruction_grad_base(base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : ga_instruction_val_base(tt, ct, mf_, pfp_)
+ {}
+ };
- case GA_NODE_CONSTANT:
- ga_print_constant_tensor(pnode, str);
- break;
+ struct ga_instruction_xfem_plus_grad_base : public ga_instruction_val_base {
- case GA_NODE_ALLINDICES:
- str << ":";
- GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
- break;
+ virtual int exec() { // --> t(ndof,target_dim,N)
+ GA_DEBUG_INFO("Instruction: compute gradient of base functions");
+ if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ int old_xfem_side = ctx.xfem_side();
+ ctx.set_xfem_side(1);
+ ctx.grad_base_value(t);
+ ctx.set_xfem_side(old_xfem_side);
+ return 0;
+ }
- case GA_NODE_PARAMS:
- GMM_ASSERT1(pnode->children.size(), "Invalid tree");
- ga_print_node(pnode->children[0], str);
- str << "(";
- for (size_type i = 1; i < pnode->children.size(); ++i) {
- if (i > 1) str << ", ";
- ga_print_node(pnode->children[i], str);
- }
- str << ")";
- break;
-
- case GA_NODE_NAME:
- str << pnode->name;
- GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
- break;
-
- case GA_NODE_RESHAPE:
- str << "Reshape";
- GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
- break;
+ ga_instruction_xfem_plus_grad_base
+ (base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : ga_instruction_val_base(tt, ct, mf_, pfp_)
+ {}
+ };
- case GA_NODE_C_MATRIX:
- {
- GMM_ASSERT1(pnode->children.size(), "Invalid tree");
- size_type nbc1 = pnode->nbc1;
- size_type nbc2 = pnode->nbc2;
- size_type nbc3 = pnode->nbc3;
- size_type nbcl = pnode->children.size()/(nbc1*nbc2*nbc3);
- if (nbc1 > 1) str << "[";
- for (size_type i1 = 0; i1 < nbc1; ++i1) {
- if (i1 != 0) str << ",";
- if (nbc2 > 1) str << "[";
- for (size_type i2 = 0; i2 < nbc2; ++i2) {
- if (i2 != 0) str << ",";
- if (nbc3 > 1) str << "[";
- for (size_type i3 = 0; i3 < nbc3; ++i3) {
- if (i3 != 0) str << ",";
- if (nbcl > 1) str << "[";
- for (size_type i4 = 0; i4 < nbcl; ++i4) {
- if (i4 != 0) str << ",";
- size_type ii = ((i4*nbc3 + i3)*nbc2 + i2)*nbc1 + i1;
- ga_print_node(pnode->children[ii], str);
- }
- if (nbcl > 1) str << "]";
- }
- if (nbc3 > 1) str << "]";
- }
- if (nbc2 > 1) str << "]";
- }
- if (nbc1 > 1) str << "]";
- }
- break;
+ struct ga_instruction_xfem_minus_grad_base : public ga_instruction_val_base {
- default:
- str << "Invalid or not taken into account node type "
- << pnode->node_type;
- break;
+ virtual int exec() { // --> t(ndof,target_dim,N)
+ GA_DEBUG_INFO("Instruction: compute gradient of base functions");
+ if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ int old_xfem_side = ctx.xfem_side();
+ ctx.set_xfem_side(-1);
+ ctx.grad_base_value(t);
+ ctx.set_xfem_side(old_xfem_side);
+ return 0;
}
- if (is_interpolate)
- str << "," << pnode->interpolate_name << ")";
- else if (is_elementary)
- str << "," << pnode->elementary_name << ")";
- else if (is_xfem_plus || is_xfem_minus)
- str << ")";
-
- str.precision(prec);
- }
-
- std::string ga_tree_to_string(const ga_tree &tree) {
- std::stringstream str;
- str.precision(16);
- if (tree.root) verify_tree(tree.root, 0);
- if (tree.root) ga_print_node(tree.root, str); else str << "0";
- return str.str();
- }
-
+ ga_instruction_xfem_minus_grad_base
+ (base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : ga_instruction_val_base(tt, ct, mf_, pfp_)
+ {}
+ };
- size_type ga_parse_prefix_operator(std::string &name) {
- if (name.size() >= 5 && name.compare(0, 5, "Grad_") == 0)
- { name = name.substr(5); return 1; }
- else if (name.size() >= 5 && name.compare(0, 5, "Hess_") == 0)
- { name = name.substr(5); return 2; }
- else if (name.size() >= 4 && name.compare(0, 4, "Div_") == 0)
- { name = name.substr(4); return 3; }
- return 0;
- }
- size_type ga_parse_prefix_test(std::string &name) {
- if (name.size() >= 5 && name.compare(0, 5, "Test_") == 0)
- { name = name.substr(5); return 1; }
- else if (name.size() >= 6 && name.compare(0, 6, "Test2_") == 0)
- { name = name.substr(6); return 2; }
- return 0;
- }
+ struct ga_instruction_hess_base : public ga_instruction_val_base {
+ virtual int exec() { // --> t(ndof,target_dim,N*N)
+ GA_DEBUG_INFO("Instruction: compute Hessian of base functions");
+ if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ ctx.hess_base_value(t);
+ return 0;
+ }
- //=========================================================================
- // Syntax analysis for the generic assembly langage
- //=========================================================================
+ ga_instruction_hess_base(base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : ga_instruction_val_base(tt, ct, mf_, pfp_)
+ {}
+ };
- // Read a term with an (implicit) pushdown automaton.
- static GA_TOKEN_TYPE ga_read_term(const std::string &expr, size_type &pos,
- ga_tree &tree) {
- size_type token_pos, token_length;
- GA_TOKEN_TYPE t_type;
- int state = 1; // 1 = reading term, 2 = reading after term
+ struct ga_instruction_xfem_plus_hess_base : public ga_instruction_val_base {
- for (;;) {
+ virtual int exec() { // --> t(ndof,target_dim,N*N)
+ GA_DEBUG_INFO("Instruction: compute Hessian of base functions");
+ if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ int old_xfem_side = ctx.xfem_side();
+ ctx.set_xfem_side(1);
+ ctx.hess_base_value(t);
+ ctx.set_xfem_side(old_xfem_side);
+ return 0;
+ }
- t_type = ga_get_token(expr, pos, token_pos, token_length);
+ ga_instruction_xfem_plus_hess_base
+ (base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : ga_instruction_val_base(tt, ct, mf_, pfp_)
+ {}
+ };
- switch (state) {
+ struct ga_instruction_xfem_minus_hess_base : public ga_instruction_val_base {
- case 1:
- switch (t_type) {
- case GA_SCALAR:
- {
- char *endptr; const char *nptr = &(expr[token_pos]);
- scalar_type s_read = ::strtod(nptr, &endptr);
- if (endptr == nptr)
- ga_throw_error(expr, token_pos, "Bad numeric format.");
- tree.add_scalar(s_read, token_pos);
- }
- state = 2; break;
-
- case GA_COLON:
- tree.add_allindices(token_pos);
- state = 2; break;
-
- case GA_NAME:
- tree.add_name(&(expr[token_pos]), token_length, token_pos);
- state = 2; break;
-
- case GA_MINUS: // unary -
- tree.add_op(GA_UNARY_MINUS, token_pos);
- case GA_PLUS: // unary +
- state = 1; break;
-
- case GA_SYM:
- tree.add_op(GA_SYM, token_pos);
- state = 1; break;
-
- case GA_SKEW:
- tree.add_op(GA_SKEW, token_pos);
- state = 1; break;
-
- case GA_TRACE:
- tree.add_op(GA_TRACE, token_pos);
- state = 1; break;
-
- case GA_DEVIATOR:
- tree.add_op(GA_DEVIATOR, token_pos);
- state = 1; break;
-
- case GA_INTERPOLATE:
- {
- tree.add_scalar(scalar_type(0), token_pos);
- tree.current_node->node_type = GA_NODE_INTERPOLATE;
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_LPAR)
- ga_throw_error(expr, pos-1, "Missing interpolate arguments.");
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_NAME)
- ga_throw_error(expr, pos,
- "First argument of Interpolate should be a "
- "variable, test function, X or Normal.");
- tree.current_node->name = std::string(&(expr[token_pos]),
- token_length);
-
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_COMMA)
- ga_throw_error(expr, pos, "Bad format for Interpolate "
- "arguments.");
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_NAME)
- ga_throw_error(expr, pos,
- "Second argument of Interpolate should be a "
- "transformation name.");
- tree.current_node->interpolate_name
- = std::string(&(expr[token_pos]), token_length);
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_RPAR)
- ga_throw_error(expr, pos-1, "Missing a parenthesis after "
- "interpolate arguments.");
- state = 2;
- }
- break;
+ virtual int exec() { // --> t(ndof,target_dim,N*N)
+ GA_DEBUG_INFO("Instruction: compute Hessian of base functions");
+ if (ctx.have_pgp()) ctx.set_pfp(pfp);
+ else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
+ GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
+ int old_xfem_side = ctx.xfem_side();
+ ctx.set_xfem_side(-1);
+ ctx.hess_base_value(t);
+ ctx.set_xfem_side(old_xfem_side);
+ return 0;
+ }
- case GA_ELEMENTARY:
- {
- tree.add_scalar(scalar_type(0), token_pos);
- tree.current_node->node_type = GA_NODE_ELEMENTARY;
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_LPAR)
- ga_throw_error(expr, pos-1,
- "Missing Elementary_transformation arguments.");
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_NAME)
- ga_throw_error(expr, pos,
- "First argument of Elementary_transformation "
- "should be a variable or a test function.");
- tree.current_node->name = std::string(&(expr[token_pos]),
- token_length);
-
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_COMMA)
- ga_throw_error(expr, pos, "Bad format for "
- "Elementary_transformation arguments.");
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_NAME)
- ga_throw_error(expr, pos,
- "Second argument of Elementary_transformation "
- "should be a transformation name.");
- tree.current_node->elementary_name
- = std::string(&(expr[token_pos]), token_length);
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_RPAR)
- ga_throw_error(expr, pos-1, "Missing a parenthesis after "
- "Elementary_transformation arguments.");
- state = 2;
- }
- break;
+ ga_instruction_xfem_minus_hess_base
+ (base_tensor &tt, fem_interpolation_context &ct,
+ const mesh_fem &mf_, pfem_precomp &pfp_)
+ : ga_instruction_val_base(tt, ct, mf_, pfp_)
+ {}
+ };
- case GA_XFEM_PLUS:
- {
- tree.add_scalar(scalar_type(0), token_pos);
- tree.current_node->node_type = GA_NODE_XFEM_PLUS;
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_LPAR)
- ga_throw_error(expr, pos-1,
- "Missing Xfem_plus arguments.");
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_NAME)
- ga_throw_error(expr, pos,
- "The argument of Xfem_plus should be a "
- "variable or a test function.");
- tree.current_node->name = std::string(&(expr[token_pos]),
- token_length);
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_RPAR)
- ga_throw_error(expr, pos-1, "Missing a parenthesis after "
- "Xfem_plus argument.");
- state = 2;
- }
- break;
+ struct ga_instruction_val : public ga_instruction {
+ scalar_type &a;
+ base_tensor &t;
+ const base_tensor &Z;
+ const base_vector &coeff;
+ size_type qdim;
+ // Z(ndof,target_dim), coeff(Qmult,ndof) --> t(target_dim*Qmult)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: variable value");
+ size_type ndof = Z.sizes()[0];
+ if (!ndof) { gmm::clear(t.as_vector()); return 0; }
+ GA_DEBUG_ASSERT(t.size() == qdim, "dimensions mismatch");
- case GA_XFEM_MINUS:
- {
- tree.add_scalar(scalar_type(0), token_pos);
- tree.current_node->node_type = GA_NODE_XFEM_MINUS;
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_LPAR)
- ga_throw_error(expr, pos-1,
- "Missing Xfem_minus arguments.");
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_NAME)
- ga_throw_error(expr, pos,
- "The argument of Xfem_minus should be a "
- "variable or a test function.");
- tree.current_node->name = std::string(&(expr[token_pos]),
- token_length);
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_RPAR)
- ga_throw_error(expr, pos-1, "Missing a parenthesis after "
- "Xfem_minus argument.");
- state = 2;
+ if (qdim == 1) {
+ GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof,
+ "Wrong size for coeff vector");
+ auto itc = coeff.begin(); auto itZ = Z.begin();
+ a = (*itc++) * (*itZ++);
+ while (itc != coeff.end()) a += (*itc++) * (*itZ++);
+ } else {
+ size_type target_dim = Z.sizes()[1];
+ if (target_dim == 1) {
+ GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*qdim,
+ "Wrong size for coeff vector");
+ auto itc = coeff.begin(); auto itZ = Z.begin();
+ for (auto it = t.begin(); it != t.end(); ++it)
+ *it = (*itc++) * (*itZ);
+ ++itZ;
+ for (size_type j = 1; j < ndof; ++j, ++itZ) {
+ for (auto it = t.begin(); it != t.end(); ++it)
+ *it += (*itc++) * (*itZ);
}
- break;
+ } else {
+ size_type Qmult = qdim / target_dim;
+ GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*Qmult,
+ "Wrong size for coeff vector");
- case GA_INTERPOLATE_FILTER:
- {
- tree.add_scalar(scalar_type(0), token_pos);
- tree.current_node->node_type = GA_NODE_INTERPOLATE_FILTER;
- tree.current_node->nbc1 = size_type(-1);
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_LPAR)
- ga_throw_error(expr, pos-1, "Missing interpolate arguments.");
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_NAME)
- ga_throw_error(expr, pos, "First argument of Interpolate_filter "
- "should be a transformation name.");
- tree.current_node->interpolate_name
- = std::string(&(expr[token_pos]), token_length);
- t_type = ga_get_token(expr, pos, token_pos, token_length);
- if (t_type != GA_COMMA)
- ga_throw_error(expr,pos,
- "Bad format for Interpolate_filter arguments.");
- ga_tree sub_tree;
- t_type = ga_read_term(expr, pos, sub_tree);
- if (t_type != GA_RPAR && t_type != GA_COMMA)
- ga_throw_error(expr, pos-1,
- "Bad format for Interpolate_filter arguments.");
- tree.add_sub_tree(sub_tree);
- if (t_type == GA_COMMA) {
- ga_tree sub_tree2;
- t_type = ga_read_term(expr, pos, sub_tree2);
- tree.add_sub_tree(sub_tree2);
+ gmm::clear(t.as_vector());
+ auto itc = coeff.begin();
+ for (size_type j = 0; j < ndof; ++j) {
+ auto it = t.begin();
+ for (size_type q = 0; q < Qmult; ++q, ++itc) {
+ for (size_type r = 0; r < target_dim; ++r)
+ *it++ += (*itc) * Z[j + r*ndof];
}
- if (t_type != GA_RPAR)
- ga_throw_error(expr, pos-1, "Unbalanced parenthesis.");
- state = 2;
- }
- break;
-
- case GA_PRINT:
- tree.add_op(GA_PRINT, token_pos);
- state = 1; break;
-
- case GA_LPAR: // Parenthesed expression
- {
- ga_tree sub_tree;
- GA_TOKEN_TYPE r_type;
- r_type = ga_read_term(expr, pos, sub_tree);
- if (r_type != GA_RPAR)
- ga_throw_error(expr, pos-1, "Unbalanced parenthesis.");
- tree.add_sub_tree(sub_tree);
- state = 2;
- }
- break;
-
- case GA_LBRACKET: // Explicit vector/matrix or tensor
- {
- ga_tree sub_tree;
- GA_TOKEN_TYPE r_type;
- size_type nbc1(0), nbc2(0), nbc3(0), n1(0), n2(0), n3(0);
- size_type tensor_order(1);
- bool foundcomma(false), foundsemi(false), nested_format(false);
-
- tree.add_matrix(token_pos);
- do {
- r_type = ga_read_term(expr, pos, sub_tree);
-
- if (sub_tree.root->node_type == GA_NODE_C_MATRIX) {
- // nested format
- if (r_type != GA_COMMA && r_type != GA_RBRACKET)
- // in the nested format only "," and "]" are expected
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.")
- else if (sub_tree.root->nbc3 != 1)
- // the sub-tensor to be merged cannot be of fourth order
- ga_throw_error(expr, pos-1, "Definition of explicit "
- "tensors is limitted to the fourth order. "
- "Limit exceeded.")
- else if (foundsemi || // Cannot mix with the non-nested format.
- (sub_tree.root->children.size() > 1 &&
- // The sub-tensor cannot be a column vector [a;b],
- sub_tree.root->nbc1 == 1))
- // the nested format only accepts row vectors [a,b]
- // and converts them to column vectors internally
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.") // (see
below)
-
- // convert a row vector [a,b] to a column vector [a;b]
- if (sub_tree.root->children.size() == sub_tree.root->nbc1)
- sub_tree.root->nbc1 = 1;
-
- nested_format = true;
-
- size_type sub_tensor_order = 3;
- if (sub_tree.root->nbc1 == 1)
- sub_tensor_order = 1;
- else if (sub_tree.root->nbc2 == 1)
- sub_tensor_order = 2;
-
- if (tensor_order == 1) {
- if (nbc1 != 0 || nbc2 != 0 || nbc3 != 0)
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.");
- nbc1 = 1;
- nbc2 = sub_tree.root->nbc1;
- nbc3 = sub_tree.root->nbc2;
- tensor_order = sub_tensor_order + 1;
- } else {
- if ((tensor_order != sub_tensor_order + 1) ||
- (tensor_order > 2 && nbc2 != sub_tree.root->nbc1) ||
- (tensor_order > 3 && nbc3 != sub_tree.root->nbc2))
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.");
- nbc1 += 1;
- }
-
- tree.zip_matrix(sub_tree.root);
- sub_tree.clear();
- if (r_type == GA_RBRACKET) {
- tree.current_node->nbc1 = nbc1;
- tree.current_node->nbc2 = nbc2;
- tree.current_node->nbc3 = nbc3;
- }
-
- } else {
-
- // non-nested format
-
- tree.add_sub_tree(sub_tree);
-
- ++n1; ++n2; ++n3;
- if (tensor_order < 2) ++nbc1;
- if (tensor_order < 3) ++nbc2;
- if (tensor_order < 4) ++nbc3;
-
- if (r_type == GA_COMMA) {
- if (!foundcomma && tensor_order > 1)
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.");
- foundcomma = true;
- } else if (r_type == GA_SEMICOLON) {
- if (n1 != nbc1)
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.");
- n1 = 0;
- tensor_order = std::max(tensor_order, size_type(2));
- } else if (r_type == GA_DCOMMA) {
- if (n1 != nbc1 || n2 != nbc2)
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.");
- foundsemi = true;
- n2 = n1 = 0;
- tensor_order = std::max(tensor_order, size_type(3));
- } else if (r_type == GA_DSEMICOLON) {
- if (n1 != nbc1 || n2 != nbc2 || n3 != nbc3 ||
- tensor_order < 3)
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.");
- n3 = n2 = n1 = 0;
- tensor_order = std::max(tensor_order, size_type(4));
- } else if (r_type == GA_RBRACKET) {
- if (n1 != nbc1 || n2 != nbc2 || n3 != nbc3 ||
- tensor_order == 3)
- ga_throw_error(expr, pos-1, "Bad explicit "
- "vector/matrix/tensor format.");
- tree.current_node->nbc1 = nbc1;
- if (tensor_order == 4) {
- tree.current_node->nbc2 = nbc2/nbc1;
- tree.current_node->nbc3 = nbc3/nbc2;
- } else {
- tree.current_node->nbc2 = tree.current_node->nbc3 = 1;
- }
- } else {
- ga_throw_error(expr, pos-1, "The explicit "
- "vector/matrix/tensor components should be "
- "separated by ',', ';', ',,' and ';;' and "
- "be ended by ']'.");
- }
- }
-
- } while (r_type != GA_RBRACKET);
-
- state = 2;
- }
- break;
-
- default:
- ga_throw_error(expr, token_pos, "Unexpected token.");
- }
- break;
-
- case 2:
- switch (t_type) {
- case GA_PLUS: case GA_MINUS: case GA_MULT: case GA_DIV:
- case GA_COLON: case GA_DOT: case GA_DOTMULT: case GA_DOTDIV:
- case GA_TMULT:
- tree.add_op(t_type, token_pos);
- state = 1; break;
- case GA_QUOTE:
- tree.add_op(t_type, token_pos);
- state = 2; break;
- case GA_END: case GA_RPAR: case GA_COMMA: case GA_DCOMMA:
- case GA_RBRACKET: case GA_SEMICOLON: case GA_DSEMICOLON:
- return t_type;
- case GA_LPAR: // Parameter list
- {
- ga_tree sub_tree;
- GA_TOKEN_TYPE r_type;
- tree.add_params(token_pos);
- do {
- r_type = ga_read_term(expr, pos, sub_tree);
- if (r_type != GA_RPAR && r_type != GA_COMMA)
- ga_throw_error(expr, pos-((r_type != GA_END)?1:0),
- "Parameters should be separated "
- "by ',' and parameter list ended by ')'.");
- tree.add_sub_tree(sub_tree);
- } while (r_type != GA_RPAR);
- state = 2;
}
- break;
-
- default:
- ga_throw_error(expr, token_pos, "Unexpected token.");
}
- break;
- }
- }
-
- return GA_INVALID;
- }
-
- // Syntax analysis of a string. Conversion to a tree.
- void ga_read_string(const std::string &expr, ga_tree &tree) {
- size_type pos = 0, token_pos, token_length;
- tree.clear();
- GA_TOKEN_TYPE t = ga_get_token(expr, pos, token_pos, token_length);
- if (t == GA_END) return;
- pos = 0;
- t = ga_read_term(expr, pos, tree);
- switch (t) {
- case GA_RPAR: ga_throw_error(expr, pos-1, "Unbalanced parenthesis.");
- case GA_RBRACKET: ga_throw_error(expr, pos-1, "Unbalanced braket.");
- case GA_END: break;
- default: ga_throw_error(expr, pos-1, "Unexpected token.");
- }
- }
-
- // Small tool to make basic substitutions into an assembly string
- std::string ga_substitute(const std::string &expr,
- const std::map<std::string, std::string> &dict) {
- if (dict.size()) {
- size_type pos = 0, token_pos, token_length;
- std::stringstream exprs;
-
- while (true) {
- GA_TOKEN_TYPE t_type = ga_get_token(expr, pos, token_pos,
token_length);
- if (t_type == GA_END) return exprs.str();
- std::string name(&(expr[token_pos]), token_length);
- if (t_type == GA_NAME && dict.find(name) != dict.end())
- exprs << dict.at(name); else exprs << name;
}
+ return 0;
}
- return expr;
- }
-
- //=========================================================================
- // Structure to gather instructions
- //=========================================================================
- class ga_if_hierarchy : public std::vector<size_type> {
+ ga_instruction_val(base_tensor &tt, const base_tensor &Z_,
+ const base_vector &co, size_type q)
+ : a(tt[0]), t(tt), Z(Z_), coeff(co), qdim(q) {}
+ };
- public:
- void increment() { (back())++; }
- void child_of(const ga_if_hierarchy &gih)
- { *this = gih; push_back(0); }
- bool is_compatible(const std::list<ga_if_hierarchy> &gihl) {
-
- std::list<ga_if_hierarchy>::const_iterator it = gihl.begin();
- for (; it != gihl.end(); ++it) {
- if (it->size() <= size()) {
- bool ok = true;
- for (size_type i = 0; i+1 < it->size(); ++i)
- if ((*it)[i] != (*this)[i]) { ok = false; break; }
- if (it->back() > (*this)[it->size()-1]) { ok = false; break; }
- if (ok) return true;
+ struct ga_instruction_grad : public ga_instruction_val {
+ // Z(ndof,target_dim,N), coeff(Qmult,ndof) --> t(target_dim*Qmult,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: gradient");
+ size_type ndof = Z.sizes()[0];
+ if (!ndof) { gmm::clear(t.as_vector()); return 0; }
+ size_type N = Z.sizes()[2];
+ if (qdim == 1) {
+ GA_DEBUG_ASSERT(t.size() == N, "dimensions mismatch");
+ GA_DEBUG_ASSERT(coeff.size() == ndof, "Wrong size for coeff vector");
+ auto itZ = Z.begin();
+ for (auto it = t.begin(); it != t.end(); ++it) {
+ auto itc = coeff.begin();
+ *it = (*itc++) * (*itZ++);
+ while (itc != coeff.end()) *it += (*itc++) * (*itZ++);
+ }
+ } else {
+ size_type target_dim = Z.sizes()[1];
+ if (target_dim == 1) {
+ GA_DEBUG_ASSERT(t.size() == N*qdim, "dimensions mismatch");
+ GA_DEBUG_ASSERT(coeff.size() == ndof*qdim,
+ "Wrong size for coeff vector");
+ for (size_type q = 0; q < qdim; ++q) {
+ auto itZ = Z.begin(); auto it = t.begin() + q;
+ for (size_type k = 0; k < N; ++k) {
+ if (k) it += qdim;
+ auto itc = coeff.begin() + q;
+ *it = (*itc) * (*itZ++);
+ for (size_type j = 1; j < ndof; ++j)
+ { itc += qdim; *it += (*itc) * (*itZ++); }
+ }
+ }
+ } else {
+ size_type Qmult = qdim / target_dim;
+ GA_DEBUG_ASSERT(t.size() == N*qdim, "dimensions mismatch");
+ GA_DEBUG_ASSERT(coeff.size() == ndof*Qmult,
+ "Wrong size for coeff vector");
+ gmm::clear(t.as_vector());
+ for (size_type q = 0; q < Qmult; ++q) {
+ auto itZ = Z.begin();
+ for (size_type k = 0; k < N; ++k)
+ for (size_type r = 0; r < target_dim; ++r)
+ for (size_type j = 0; j < ndof; ++j)
+ t[r + q*target_dim + k*qdim] += coeff[j*Qmult+q] * (*itZ++);
+ }
}
}
- return false;
+ return 0;
}
- ga_if_hierarchy() : std::vector<size_type>(1) { (*this)[0] = 0; }
- };
-
-
- struct ga_instruction {
- virtual int exec() = 0;
- virtual ~ga_instruction() {};
- };
-
- typedef std::shared_ptr<ga_instruction> pga_instruction;
- typedef std::vector<pga_instruction> ga_instruction_list;
+ ga_instruction_grad(base_tensor &tt, const base_tensor &Z_,
+ const base_vector &co, size_type q)
+ : ga_instruction_val(tt, Z_, co, q)
+ {}
- struct gauss_pt_corresp { // For neighbour interpolation transformation
- bgeot::pgeometric_trans pgt1, pgt2;
- papprox_integration pai;
- std::vector<size_type> nodes;
};
- bool operator <(const gauss_pt_corresp &gpc1,
- const gauss_pt_corresp &gpc2) {
- if (gpc1.pai != gpc2.pai)
- return (gpc1.pai < gpc2.pai );
- if (gpc1.nodes.size() != gpc2.nodes.size())
- return (gpc1.nodes.size() < gpc2.nodes.size());
- for (size_type i = 0; i < gpc1.nodes.size(); ++i)
- if (gpc1.nodes[i] != gpc2.nodes[i])
- return (gpc1.nodes[i] < gpc2.nodes[i]);
- if (gpc1.pgt1 != gpc2.pgt1)
- return (gpc1.pgt1 < gpc2.pgt1);
- if (gpc1.pgt2 != gpc2.pgt2)
- return (gpc1.pgt2 < gpc2.pgt2);
- return false;
- }
-
- struct ga_instruction_set {
-
- papprox_integration pai; // Current approximation method
- fem_interpolation_context ctx; // Current fem interpolation context.
- base_small_vector Normal; // Outward unit normal vector to the
- // boundary in case of boundary integration
- scalar_type elt_size; // Estimate of the diameter of the element
- // if needed.
- bool need_elt_size;
- scalar_type coeff; // Coefficient for the Gauss point
- size_type nbpt, ipt; // Number and index of Gauss point
- bgeot::geotrans_precomp_pool gp_pool;
- fem_precomp_pool fp_pool;
- std::map<gauss_pt_corresp, bgeot::pstored_point_tab> neighbour_corresp;
-
- struct region_mim : std::pair<const mesh_im *, const mesh_region *> {
- const mesh_im* mim() const { return this->first; }
- const mesh_region* region() const { return this->second; }
- region_mim(const mesh_im *mim_, const mesh_region *region_) :
- std::pair<const mesh_im *, const mesh_region *>(mim_, region_) {}
- };
-
- std::map<std::string, const base_vector *> extended_vars;
- std::map<std::string, base_vector> really_extended_vars;
- std::map<std::string, gmm::sub_interval> var_intervals;
- size_type nb_dof, max_dof;
-
- struct variable_group_info {
- const mesh_fem *mf;
- gmm::sub_interval Ir, In;
- scalar_type alpha;
- const base_vector *U;
- const std::string *varname;
- variable_group_info() : mf(0), U(0), varname(0) {}
- };
-
- struct interpolate_info {
- size_type pt_type;
- bool has_ctx;
- const mesh *m;
- fem_interpolation_context ctx;
- base_node pt_y;
- base_small_vector Normal;
- base_matrix G;
- std::map<std::string, variable_group_info> groups_info;
- std::map<var_trans_pair, base_tensor> derivatives;
- std::map<const mesh_fem *, pfem_precomp> pfps;
- };
-
- struct elementary_trans_info {
- base_matrix M;
- const mesh_fem *mf;
- size_type icv;
- };
-
- std::set<std::string> transformations;
-
- struct region_mim_instructions {
-
- const mesh *m;
- ga_if_hierarchy current_hierarchy;
- std::map<std::string, base_vector> local_dofs;
- std::map<const mesh_fem *, pfem_precomp> pfps;
- std::map<const mesh_fem *, base_tensor> base;
- std::map<const mesh_fem *, std::list<ga_if_hierarchy>> base_hierarchy;
- std::map<const mesh_fem *, base_tensor> grad;
- std::map<const mesh_fem *, std::list<ga_if_hierarchy>> grad_hierarchy;
- std::map<const mesh_fem *, base_tensor> hess;
- std::map<const mesh_fem *, std::list<ga_if_hierarchy>> hess_hierarchy;
-
- std::map<const mesh_fem *, base_tensor>
- xfem_plus_base, xfem_plus_grad, xfem_plus_hess,
- xfem_minus_base, xfem_minus_grad, xfem_minus_hess;
- std::map<const mesh_fem *, std::list<ga_if_hierarchy>>
- xfem_plus_base_hierarchy, xfem_plus_grad_hierarchy,
- xfem_plus_hess_hierarchy, xfem_minus_base_hierarchy,
- xfem_minus_grad_hierarchy, xfem_minus_hess_hierarchy;
-
- std::map<std::string, std::set<std::string>> transformations;
- std::set<std::string> transformations_der;
- std::map<std::string, interpolate_info> interpolate_infos;
- std::map<std::string, elementary_trans_info> elementary_trans_infos;
-
- // Instructions being executed at the first Gauss point after
- // a change of integration method only.
- ga_instruction_list begin_instructions;
- // Instructions executed once per element
- ga_instruction_list elt_instructions;
- // Instructions executed on each integration/interpolation point
- ga_instruction_list instructions;
- std::map<scalar_type, std::list<pga_tree_node> > node_list;
-
- region_mim_instructions(): m(0) {}
- };
-
- std::list<ga_tree> trees; // The trees are stored mainly because they
- // contain the intermediary tensors.
- std::list<ga_tree> interpolation_trees;
-
- typedef std::map<region_mim, region_mim_instructions> instructions_set;
-
- instructions_set whole_instructions;
-
- ga_instruction_set() { max_dof = nb_dof = 0; need_elt_size = false; ipt=0;
}
- };
-
-
- //=========================================================================
- // Structure dealing with predefined special functions
- // such as mesh_dim, pi, qdim ...
- //=========================================================================
-
- typedef std::set<std::string> ga_spec_function_tab;
- static ga_spec_function_tab SPEC_FUNCTIONS;
-
- //=========================================================================
- // Structure dealing with predefined scalar functions.
- //=========================================================================
-
- static void ga_semantic_analysis(const std::string &, ga_tree &,
- const ga_workspace &, size_type, size_type,
- bool, bool, int option = 0);
- static void ga_node_analysis(const std::string &, ga_tree &,
- const ga_workspace &, pga_tree_node, size_type,
- size_type, bool, bool, int);
- static void ga_derivative(ga_tree &, const ga_workspace &, const mesh &,
- const std::string &, const std::string &,
- size_type);
- static void ga_exec(ga_instruction_set &gis, ga_workspace &workspace);
- static void ga_function_exec(ga_instruction_set &gis);
- static void ga_compile(ga_workspace &workspace, ga_instruction_set &gis,
- size_type order);
- static void ga_compile_function(ga_workspace &workspace,
- ga_instruction_set &gis, bool scalar);
- static std::string ga_derivative_scalar_function(const std::string &expr,
- const std::string &var);
- static bool ga_is_affine(const ga_tree &tree, const ga_workspace &workspace,
- const std::string &varname,
- const std::string &interpolatename);
-
- using instruction_set = omp_distribute<ga_instruction_set>;
-
- class ga_predef_function {
- size_type ftype_; // 0 : C++ function with C++ derivative(s)
- // 1 : function defined by an string expression.
-
- size_type dtype_; // 0 : no derivative(s)
- // 1 : derivative(s) given by C++ functions
- // 2 : derivatives(s) given by string expression(s)
- // 3 : derivatives(s) to be symbolically computed.
- size_type nbargs_; // One or two arguments
- pscalar_func_onearg f1_; // Function pointer for a one argument function
- pscalar_func_twoargs f2_; // Function pointer for a two arguments function
- std::string expr_;
- std::string derivative1_, derivative2_;
- mutable omp_distribute<base_vector> t, u;
- mutable omp_distribute<ga_workspace> workspace;
- copyable_ptr<instruction_set> gis;
-
- friend void ga_define_function(const std::string &name, size_type nbargs,
- const std::string &expr,
- const std::string &der1,
- const std::string &der2);
- friend void ga_define_function(const std::string &name,
- pscalar_func_onearg f,
- const std::string &der);
- friend void ga_define_function(const std::string &name,
- pscalar_func_twoargs f,
- const std::string &der1,
- const std::string &der2);
- public:
- scalar_type operator()(scalar_type t_, scalar_type u_ = 0.) const {
- switch(ftype_) {
- case 0:
- if (nbargs_ == 2)
- return (*f2_)(t_, u_);
- else
- return (*f1_)(t_);
- break;
- case 1:
- t.thrd_cast()[0] = t_; u.thrd_cast()[0] = u_;
- workspace.thrd_cast().assembled_potential() = scalar_type(0);
- ga_function_exec(*gis);
- return workspace.thrd_cast().assembled_potential();
- break;
- }
- return 0.;
- }
-
- bool is_affine(const std::string &varname) const {
- if (ftype_ == 1) {
- for (size_type i = 0; i < workspace.thrd_cast().nb_trees(); ++i) {
- const ga_workspace::tree_description &
- td = workspace.thrd_cast().tree_info(i);
- if (!(ga_is_affine(*(td.ptree), workspace, varname, "")))
- return false;
+ struct ga_instruction_hess : public ga_instruction_val {
+ // Z(ndof,target_dim,N*N), coeff(Qmult,ndof) --> t(target_dim*Qmult,N,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: Hessian");
+ size_type ndof = Z.sizes()[0];
+ if (!ndof) { gmm::clear(t.as_vector()); return 0; }
+ size_type NN = gmm::sqr(t.sizes().back());
+ GA_DEBUG_ASSERT(NN == Z.sizes()[2], "Internal error");
+ if (qdim == 1) {
+ GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof,
+ "Wrong size for coeff vector");
+ auto it = Z.begin(); auto itt = t.begin();
+ for (size_type kl = 0; kl < NN; ++kl, ++itt) {
+ *itt = scalar_type(0);
+ for (auto itc = coeff.begin(); itc != coeff.end(); ++itc, ++it)
+ *itt += (*itc) * (*it);
}
- return true;
- }
- return false;
- }
-
- size_type ftype() const {return ftype_;}
- size_type dtype() const {return dtype_;}
- size_type nbargs() const {return nbargs_;}
- const std::string &derivative1() const {return derivative1_;}
- const std::string &derivative2() const {return derivative2_;}
- const std::string &expr() const {return expr_;}
- pscalar_func_onearg f1() const {return f1_;}
- pscalar_func_twoargs f2() const {return f2_;}
-
- ga_predef_function() : expr_(""), derivative1_(""),
- derivative2_(""), gis(nullptr) {}
- ga_predef_function(pscalar_func_onearg f, size_type dtype__ = 0,
- const std::string &der = "")
- : ftype_(0), dtype_(dtype__), nbargs_(1), f1_(f), expr_(""),
- derivative1_(der), derivative2_("") {}
- ga_predef_function(pscalar_func_twoargs f, size_type dtype__ = 0,
- const std::string &der1 = "",
- const std::string &der2 = "")
- : ftype_(0), dtype_(dtype__), nbargs_(2), f2_(f),
- expr_(""), derivative1_(der1), derivative2_(der2), gis(nullptr) {}
- ga_predef_function(const std::string &expr__)
- : ftype_(1), dtype_(3), nbargs_(1), expr_(expr__),
- derivative1_(""), derivative2_(""), t(1, 0.), u(1, 0.), gis(nullptr) {}
- };
-
-
-
- static scalar_type ga_Heaviside(scalar_type t) { return (t >= 0.) ? 1.: 0.; }
- static scalar_type ga_pos_part(scalar_type t) { return (t >= 0.) ? t : 0.; }
- static scalar_type ga_reg_pos_part(scalar_type t, scalar_type eps)
- { return (t >= eps) ? t-eps/2. : ((t <= 0) ? 0. : t*t/(2.*eps)); }
- static scalar_type ga_der_reg_pos_part(scalar_type t, scalar_type eps)
- { return (t >= eps) ? 1. : ((t <= 0) ? 0. : t/eps); }
- static scalar_type ga_der2_reg_pos_part(scalar_type t, scalar_type eps)
- { return (t >= eps) ? 0. : ((t <= 0) ? 0. : 1./eps); }
-
-
- static scalar_type ga_half_sqr_pos_part(scalar_type t)
- { return (t >= 0.) ? 0.5*t*t : 0.; }
- static scalar_type ga_neg_part(scalar_type t) { return (t >= 0.) ? 0. : -t; }
- static scalar_type ga_half_sqr_neg_part(scalar_type t)
- { return (t >= 0.) ? 0. : 0.5*t*t; }
- static scalar_type ga_sinc(scalar_type t) {// cardinal sine function sin(t)/t
- if (gmm::abs(t) < 1E-4) {
- scalar_type t2 = t*t;
- return 1-t2/6.+ t2*t2/120.;
- } else {
- return sin(t)/t;
- }
- }
- static scalar_type ga_sqr(scalar_type t) { return t*t; }
- static scalar_type ga_max(scalar_type t, scalar_type u)
- { return std::max(t,u); }
- static scalar_type ga_min(scalar_type t, scalar_type u)
- { return std::min(t,u); }
- static scalar_type ga_abs(scalar_type t) { return gmm::abs(t); }
- static scalar_type ga_sign(scalar_type t) { return (t >= 0.) ? 1.: -1.; }
-
- // Derivatives of predefined functions
- static scalar_type ga_der_sinc(scalar_type t) {
- if (gmm::abs(t) < 1E-4) {
- scalar_type t2 = t*t;
- return -t/3. + t*t2/30. -t*t2*t2/840.;
- } else {
- return (t*cos(t) - sin(t))/(t*t);
- }
- }
- static scalar_type ga_der2_sinc(scalar_type t) {
- if (gmm::abs(t) < 1E-4) {
- scalar_type t2 = t*t;
- return -1./3. + t2/10. -t2*t2/168.;
- } else {
- return ((2. - t*t)*sin(t) - 2.*t*cos(t))/(t*t*t);
+ GMM_ASSERT1(itt == t.end(), "dimensions mismatch");
+ } else {
+ size_type target_dim = Z.sizes()[1];
+ if (target_dim == 1) {
+ GA_DEBUG_ASSERT(t.size() == NN*qdim, "dimensions mismatch");
+ GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*qdim,
+ "Wrong size for coeff vector");
+ gmm::clear(t.as_vector());
+ for (size_type q = 0; q < qdim; ++q) {
+ base_tensor::const_iterator it = Z.begin();
+ for (size_type kl = 0; kl < NN; ++kl)
+ for (size_type j = 0; j < ndof; ++j, ++it)
+ t[q + kl*qdim] += coeff[j*qdim+q] * (*it);
+ }
+ } else {
+ size_type Qmult = qdim / target_dim;
+ GA_DEBUG_ASSERT(t.size() == NN*qdim, "dimensions mismatch");
+ GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*Qmult,
+ "Wrong size for coeff vector");
+ gmm::clear(t.as_vector());
+ for (size_type q = 0; q < Qmult; ++q) {
+ base_tensor::const_iterator it = Z.begin();
+ for (size_type kl = 0; kl < NN; ++kl)
+ for (size_type r = 0; r < target_dim; ++r)
+ for (size_type j = 0; j < ndof; ++j, ++it)
+ t[r + q*target_dim + kl*qdim] += coeff[j*Qmult+q] * (*it);
+ }
+ }
+ }
+ return 0;
}
- }
- static scalar_type ga_der_sqrt(scalar_type t) { return 0.5/sqrt(t); }
- // static scalar_type ga_der_sqr(scalar_type t) { return 2*t; }
- static scalar_type ga_der_t_pow(scalar_type t, scalar_type u)
- { return u*pow(t,u-1.); }
- static scalar_type ga_der_u_pow(scalar_type t, scalar_type u)
- { return pow(t,u)*log(gmm::abs(t)); }
- static scalar_type ga_der_log(scalar_type t) { return 1./t; }
- static scalar_type ga_der_log10(scalar_type t) { return 1./(t*log(10.)); }
- static scalar_type ga_der_tanh(scalar_type t)
- { return 1.-gmm::sqr(tanh(t)); }
- static scalar_type ga_der_asinh(scalar_type t)
- { return 1./(sqrt(t*t+1.)); }
- static scalar_type ga_der_acosh(scalar_type t)
- { return 1./(sqrt(t*t-1.)); }
- static scalar_type ga_der_atanh(scalar_type t)
- { return 1./(1.-t*t); }
- static scalar_type ga_der_cos(scalar_type t)
- { return -sin(t); }
- static scalar_type ga_der_tan(scalar_type t)
- { return 1.+gmm::sqr(tan(t)); }
- static scalar_type ga_der_asin(scalar_type t)
- { return 1./(sqrt(1.-t*t)); }
- static scalar_type ga_der_acos(scalar_type t)
- { return -1./(sqrt(1.-t*t)); }
- static scalar_type ga_der_atan(scalar_type t)
- { return 1./(1.+t*t); }
- static scalar_type ga_der_t_atan2(scalar_type t, scalar_type u)
- { return u/(t*t+u*u); }
- static scalar_type ga_der_u_atan2(scalar_type t, scalar_type u)
- { return -t/(t*t+u*u); }
- static scalar_type ga_der_erf(scalar_type t)
- { return exp(-t*t)*2./sqrt(M_PI); }
- static scalar_type ga_der_erfc(scalar_type t)
- { return -exp(-t*t)*2./sqrt(M_PI); }
- static scalar_type ga_der_neg_part(scalar_type t)
- { return (t >= 0) ? 0. : -1.; }
- static scalar_type ga_der_t_max(scalar_type t, scalar_type u)
- { return (t-u >= 0) ? 1. : 0.; }
- static scalar_type ga_der_u_max(scalar_type t, scalar_type u)
- { return (u-t >= 0) ? 1. : 0.; }
-
-
- typedef std::map<std::string, ga_predef_function> ga_predef_function_tab;
-
- //=========================================================================
- // Structure dealing with predefined operators.
- //=========================================================================
- static void ga_init_scalar(bgeot::multi_index &mi) { mi.resize(0); }
- static void ga_init_square_matrix(bgeot::multi_index &mi, size_type N)
- { mi.resize(2); mi[0] = mi[1] = N; }
-
- // Norm Operator
- struct norm_operator : public ga_nonlinear_operator {
- bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
- if (args.size() != 1 || args[0]->sizes().size() > 2) return false;
- ga_init_scalar(sizes);
- return true;
- }
+ ga_instruction_hess(base_tensor &tt, const base_tensor &Z_,
+ const base_vector &co, size_type q)
+ : ga_instruction_val(tt, Z_, co, q)
+ {}
+ };
- void value(const arg_list &args, base_tensor &result) const
- { result[0] = gmm::vect_norm2(args[0]->as_vector()); }
+ struct ga_instruction_diverg : public ga_instruction_val {
+ // Z(ndof,target_dim,N), coeff(Qmult,ndof) --> t(1)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: divergence");
+ size_type ndof = Z.sizes()[0];
+ if (!ndof) { gmm::clear(t.as_vector()); return 0; }
+ size_type target_dim = Z.sizes()[1];
+ size_type N = Z.sizes()[2];
+ size_type Qmult = qdim / target_dim;
+ GA_DEBUG_ASSERT(Qmult*target_dim == N && (Qmult == 1 || target_dim == 1),
+ "Dimensions mismatch for divergence operator");
+ GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*Qmult,
+ "Wrong size for coeff vector");
- // Derivative : u/|u|
- void derivative(const arg_list &args, size_type,
- base_tensor &result) const {
- scalar_type no = gmm::vect_norm2(args[0]->as_vector());
- if (no == scalar_type(0))
- gmm::clear(result.as_vector());
- else
- gmm::copy(gmm::scaled(args[0]->as_vector(), scalar_type(1)/no),
- result.as_vector());
+ t[0] = scalar_type(0);
+ base_tensor::const_iterator it = Z.begin();
+ if (Qmult == 1)
+ for (size_type k = 0; k < N; ++k) {
+ if (k) it += (N*ndof + 1);
+ for (size_type j = 0; j < ndof; ++j) {
+ if (j) ++it;
+ t[0] += coeff[j] * (*it);
+ }
+ }
+ else // if (target_dim() == 1)
+ for (size_type k = 0; k < N; ++k) {
+ if (k) ++it;
+ for (size_type j = 0; j < ndof; ++j) {
+ if (j) ++it;
+ t[0] += coeff[j*N+k] * (*it);
+ }
+ }
+ return 0;
}
- // Second derivative : (|u|^2 Id - u x u)/|u|^3
- void second_derivative(const arg_list &args, size_type, size_type,
- base_tensor &result) const {
- const base_tensor &t = *args[0];
- size_type N = t.size();
- scalar_type no = gmm::vect_norm2(t.as_vector());
- scalar_type no3 = no*no*no;
+ ga_instruction_diverg(base_tensor &tt, const base_tensor &Z_,
+ const base_vector &co, size_type q)
+ : ga_instruction_val(tt, Z_, co, q)
+ {}
+ };
- if (no < 1E-25) no = 1E-25; // In order to avoid infinite values
+ struct ga_instruction_copy_val_base : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &Z;
+ size_type qdim;
+ // Z(ndof,target_dim) --> t(Qmult*ndof,Qmult*target_dim)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: value of test functions");
+ if (qdim == 1) {
+ std::copy(Z.begin(), Z.end(), t.begin());
+ } else {
+ size_type target_dim = Z.sizes()[1];
+ size_type Qmult = qdim / target_dim;
+ if (Qmult == 1) {
+ std::copy(Z.begin(), Z.end(), t.begin());
+ } else {
+ if (target_dim == 1) {
+ size_type ndof = Z.sizes()[0];
+ GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
+ "Wrong size for base vector");
+ std::fill(t.begin(), t.end(), scalar_type(0));
+ auto itZ = Z.begin();
+ size_type s = t.sizes()[0], sss = s+1;
- for (size_type i = 0; i < N; ++i)
- for (size_type j = 0; j < N; ++j) {
- result[j*N+i] = - t[i]*t[j] / no3;
- if (i == j) result[j*N+i] += scalar_type(1)/no;
- }
- }
- };
+ // Performs t(i*Qmult+j, k*Qmult + j) = Z(i,k);
+ auto it = t.begin();
+ for (size_type i = 0; i < ndof; ++i, ++itZ) {
+ if (i) it += Qmult;
+ auto it2 = it;
+ *it2 = *itZ;
+ for (size_type j = 1; j < Qmult; ++j) { it2 += sss; *it2 = *itZ;
}
+ }
+ } else {
+ size_type ndof = Z.sizes()[0];
+ GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
+ "Wrong size for base vector");
+ std::fill(t.begin(), t.end(), scalar_type(0));
+ auto itZ = Z.begin();
+ size_type s = t.sizes()[0], ss = s * Qmult, sss = s+1;
- // Norm_sqr Operator
- struct norm_sqr_operator : public ga_nonlinear_operator {
- bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
- if (args.size() != 1 || args[0]->sizes().size() > 2) return false;
- ga_init_scalar(sizes);
- return true;
- }
-
- void value(const arg_list &args, base_tensor &result) const
- { result[0] = gmm::vect_norm2_sqr(args[0]->as_vector()); }
-
- // Derivative : 2*u
- void derivative(const arg_list &args, size_type,
- base_tensor &result) const {
- gmm::copy(gmm::scaled(args[0]->as_vector(), scalar_type(2)),
- result.as_vector());
- }
-
- // Second derivative : Id
- void second_derivative(const arg_list &args, size_type, size_type,
- base_tensor &result) const {
- const base_tensor &t = *args[0];
- size_type N = t.size();
- gmm::clear(result.as_vector());
- for (size_type i = 0; i < N; ++i)
- result[i*N+i] = scalar_type(2);
- }
- };
-
- // Det Operator
- struct det_operator : public ga_nonlinear_operator {
- bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
- if (args.size() != 1 || args[0]->sizes().size() != 2
- || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
- ga_init_scalar(sizes);
- return true;
- }
-
- void value(const arg_list &args, base_tensor &result) const {
- size_type N = args[0]->sizes()[0];
- // base_matrix M(N, N);
- // gmm::copy(args[0]->as_vector(), M.as_vector());
- // result[0] = gmm::lu_det(M);
- result[0] = bgeot::lu_det(&(*(args[0]->begin())), N);
- }
-
- // Derivative : det(M)M^{-T}
- void derivative(const arg_list &args, size_type,
- base_tensor &result) const {
- size_type N = args[0]->sizes()[0];
- if (N) {
- __mat_aux1().base_resize(N, N);
- gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
- scalar_type det = bgeot::lu_inverse(__mat_aux1());
- if (det == scalar_type(0))
- gmm::clear(result.as_vector());
- else {
- auto it = result.begin();
- auto ita = __mat_aux1().begin();
- for (size_type j = 0; j < N; ++j, ++ita) {
- auto itaa = ita;
- *it = (*itaa) * det; ++it;
- for (size_type i = 1; i < N; ++i, ++it)
- { itaa += N; *it = (*itaa) * det; }
+ // Performs t(i*Qmult+j, k*Qmult + j) = Z(i,k);
+ for (size_type k = 0; k < target_dim; ++k) {
+ auto it = t.begin() + (ss * k);
+ for (size_type i = 0; i < ndof; ++i, ++itZ) {
+ if (i) it += Qmult;
+ auto it2 = it;
+ *it2 = *itZ;
+ for (size_type j = 1; j < Qmult; ++j)
+ { it2 += sss; *it2 = *itZ; }
+ }
+ }
}
- GA_DEBUG_ASSERT(it == result.end(), "Internal error");
}
}
+ return 0;
}
- // Second derivative : det(M)(address@hidden - M^{-T}_{jk}M^{-T}_{li})
- void second_derivative(const arg_list &args, size_type, size_type,
- base_tensor &result) const {
- size_type N = args[0]->sizes()[0];
- __mat_aux1().base_resize(N, N);
- gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
- scalar_type det = bgeot::lu_inverse(__mat_aux1());
- if (det == scalar_type(0))
- gmm::clear(result.as_vector());
- else {
- auto it = result.begin();
- auto ita = __mat_aux1().begin(), ita_l = ita;
- for (size_type l = 0; l < N; ++l, ++ita_l) {
- auto ita_lk = ita_l, ita_jk = ita;
- for (size_type k = 0; k < N; ++k, ita_lk += N, ita_jk += N) {
- auto ita_j = ita;
- for (size_type j = 0; j < N; ++j, ++ita_j, ++ita_jk) {
- auto ita_ji = ita_j, ita_li = ita_l;
- for (size_type i = 0; i < N; ++i, ++it, ita_ji += N, ita_li += N)
- *it = ((*ita_ji) * (*ita_lk) - (*ita_jk) * (*ita_li)) * det;
+ ga_instruction_copy_val_base(base_tensor &tt, const base_tensor &Z_,
+ size_type q) : t(tt), Z(Z_), qdim(q) {}
+ };
+
+ struct ga_instruction_copy_grad_base : public ga_instruction_copy_val_base {
+ // Z(ndof,target_dim,N) --> t(Qmult*ndof,Qmult*target_dim,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: gradient of test functions");
+ if (qdim == 1) {
+ std::copy(Z.begin(), Z.end(), t.begin());
+ } else {
+ size_type target_dim = Z.sizes()[1];
+ size_type Qmult = qdim / target_dim;
+ if (Qmult == 1) {
+ std::copy(Z.begin(), Z.end(), t.begin());
+ } else {
+ if (target_dim == 1) {
+ size_type ndof = Z.sizes()[0];
+ size_type N = Z.sizes()[2];
+ GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
+ "Wrong size for gradient vector");
+ std::fill(t.begin(), t.end(), scalar_type(0));
+ base_tensor::const_iterator itZ = Z.begin();
+ size_type s = t.sizes()[0], sss = s+1, ssss = s*target_dim*Qmult;
+
+ // Performs t(i*Qmult+j, k*Qmult + j, l) = Z(i,k,l);
+ for (size_type l = 0; l < N; ++l) {
+ base_tensor::iterator it = t.begin() + (ssss*l);
+ for (size_type i = 0; i < ndof; ++i, ++itZ) {
+ if (i) it += Qmult;
+ base_tensor::iterator it2 = it;
+ *it2 = *itZ;
+ for (size_type j = 1; j < Qmult; ++j) { it2+=sss; *it2=*itZ; }
+ }
}
- }
- }
- GA_DEBUG_ASSERT(it == result.end(), "Internal error");
- }
- }
- };
-
- // Inverse Operator (for square matrices)
- struct inverse_operator : public ga_nonlinear_operator {
- bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
- if (args.size() != 1 || args[0]->sizes().size() != 2
- || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
- ga_init_square_matrix(sizes, args[0]->sizes()[0]);
- return true;
- }
-
- // Value : M^{-1}
- void value(const arg_list &args, base_tensor &result) const {
- size_type N = args[0]->sizes()[0];
- __mat_aux1().base_resize(N, N);
- gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
- bgeot::lu_inverse(__mat_aux1());
- gmm::copy(__mat_aux1().as_vector(), result.as_vector());
- }
-
- // Derivative : -M^{-1}{ik}M^{-1}{lj} (comes from H -> M^{-1}HM^{-1})
- void derivative(const arg_list &args, size_type,
- base_tensor &result) const { // to be verified
- size_type N = args[0]->sizes()[0];
- __mat_aux1().base_resize(N, N);
- gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
- bgeot::lu_inverse(__mat_aux1());
- auto it = result.begin();
- auto ita = __mat_aux1().begin(), ita_l = ita;
- for (size_type l = 0; l < N; ++l, ++ita_l) {
- auto ita_k = ita;
- for (size_type k = 0; k < N; ++k, ita_k += N) {
- auto ita_lj = ita_l;
- for (size_type j = 0; j < N; ++j, ++ita_lj) {
- auto ita_ik = ita_k;
- for (size_type i = 0; i < N; ++i, ++it, ++ita_ik)
- *it = -(*ita_ik) * (*ita_lj);
+ } else {
+ size_type ndof = Z.sizes()[0];
+ size_type N = Z.sizes()[2];
+ GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
+ "Wrong size for gradient vector");
+ std::fill(t.begin(), t.end(), scalar_type(0));
+ base_tensor::const_iterator itZ = Z.begin();
+ size_type s = t.sizes()[0], ss = s * Qmult, sss = s+1;
+ size_type ssss = ss*target_dim;
+
+ // Performs t(i*Qmult+j, k*Qmult + j, l) = Z(i,k,l);
+ for (size_type l = 0; l < N; ++l)
+ for (size_type k = 0; k < target_dim; ++k) {
+ base_tensor::iterator it = t.begin() + (ss * k + ssss*l);
+ for (size_type i = 0; i < ndof; ++i, ++itZ) {
+ if (i) it += Qmult;
+ base_tensor::iterator it2 = it;
+ *it2 = *itZ;
+ for (size_type j = 1; j < Qmult; ++j) { it2+=sss; *it2=*itZ;
}
+ }
+ }
}
}
}
- GA_DEBUG_ASSERT(it == result.end(), "Internal error");
- }
-
- // Second derivative :
- // M^{-1}{ik}M^{-1}{lm}M^{-1}{nj} + M^{-1}{im}M^{-1}{mk}M^{-1}{lj}
- // comes from (H,K) -> M^{-1}HM^{-1}KM^{-1} + M^{-1}KM^{-1}HM^{-1}
- void second_derivative(const arg_list &args, size_type, size_type,
- base_tensor &result) const { // to be verified
- size_type N = args[0]->sizes()[0];
- __mat_aux1().base_resize(N, N);
- gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
- bgeot::lu_inverse(__mat_aux1());
- base_tensor::iterator it = result.begin();
- for (size_type n = 0; n < N; ++n)
- for (size_type m = 0; m < N; ++m)
- for (size_type l = 0; l < N; ++l)
- for (size_type k = 0; k < N; ++k)
- for (size_type j = 0; j < N; ++j)
- for (size_type i = 0; i < N; ++i, ++it)
- *it = __mat_aux1()(i,k)*__mat_aux1()(l,m)*__mat_aux1()(n,j)
- + __mat_aux1()(i,m)*__mat_aux1()(m,k)*__mat_aux1()(l,j);
- GA_DEBUG_ASSERT(it == result.end(), "Internal error");
+ return 0;
}
- };
-
- //=========================================================================
- // Initialization of predefined functions and operators.
- //=========================================================================
+ ga_instruction_copy_grad_base(base_tensor &tt, const base_tensor &Z_,
+ size_type q)
+ : ga_instruction_copy_val_base(tt,Z_,q) {}
+ };
- bool init_predef_functions() {
-
- // Predefined functions
- ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
-
- // Power functions and their derivatives
- PREDEF_FUNCTIONS["sqrt"] = ga_predef_function(sqrt, 1, "DER_PDFUNC_SQRT");
- PREDEF_FUNCTIONS["sqr"] = ga_predef_function(ga_sqr, 2, "2*t");
- PREDEF_FUNCTIONS["pow"] = ga_predef_function(pow, 1, "DER_PDFUNC1_POW",
- "DER_PDFUNC2_POW");
-
- PREDEF_FUNCTIONS["DER_PDFUNC_SQRT"] =
- ga_predef_function(ga_der_sqrt, 2, "-0.25/(t*sqrt(t))");
- PREDEF_FUNCTIONS["DER_PDFUNC1_POW"] =
- ga_predef_function(ga_der_t_pow, 2, "u*(u-1)*pow(t,u-2)",
- "pow(t,u-1)*(u*log(t)+1)");
- PREDEF_FUNCTIONS["DER_PDFUNC2_POW"] =
- ga_predef_function(ga_der_u_pow, 2, "pow(t,u-1)*(u*log(t)+1)",
- "pow(t,u)*sqr(log(t))");
-
- // Hyperbolic functions
- PREDEF_FUNCTIONS["exp"] = ga_predef_function(exp, 1, "exp");
- PREDEF_FUNCTIONS["log"] = ga_predef_function(log, 1, "DER_PDFUNC_LOG");
- PREDEF_FUNCTIONS["log10"] =
- ga_predef_function(log10, 1, "DER_PDFUNC_LOG10");
- PREDEF_FUNCTIONS["sinh"] = ga_predef_function(sinh, 1, "cosh");
- PREDEF_FUNCTIONS["cosh"] = ga_predef_function(cosh, 1, "sinh");
- PREDEF_FUNCTIONS["tanh"] = ga_predef_function(tanh, 1, "DER_PDFUNC_TANH");
- PREDEF_FUNCTIONS["asinh"] =
- ga_predef_function(asinh, 1, "DER_PDFUNC_ASINH");
- PREDEF_FUNCTIONS["acosh"] =
- ga_predef_function(acosh, 1, "DER_PDFUNC_ACOSH");
- PREDEF_FUNCTIONS["atanh"] =
- ga_predef_function(atanh, 1, "DER_PDFUNC_ATANH");
-
-
- PREDEF_FUNCTIONS["DER_PDFUNC_LOG"] =
- ga_predef_function(ga_der_log, 2, "-1/sqr(t)");
- PREDEF_FUNCTIONS["DER_PDFUNC_LOG10"] =
- ga_predef_function(ga_der_log10, 2, "-1/(sqr(t)*log(10))");
- PREDEF_FUNCTIONS["DER_PDFUNC_TANH"] =
- ga_predef_function(ga_der_tanh, 2, "2*tanh(t)*(sqr(tanh(t))-1)");
- PREDEF_FUNCTIONS["DER_PDFUNC_ASINH"] =
- ga_predef_function(ga_der_asinh, 2, "-t/(pow(t*t+1,1.5))");
- PREDEF_FUNCTIONS["DER_PDFUNC_ACOSH"] =
- ga_predef_function(ga_der_acosh, 2, "-t/(pow(t*t-1,1.5))");
- PREDEF_FUNCTIONS["DER_PDFUNC_ATANH"] =
- ga_predef_function(ga_der_atanh, 2, "2*t/sqr(1-t*t)");
-
-
- // Trigonometric functions
- PREDEF_FUNCTIONS["sin"] = ga_predef_function(sin, 1, "cos");
- PREDEF_FUNCTIONS["cos"] = ga_predef_function(cos, 1, "DER_PDFUNC_COS");
- PREDEF_FUNCTIONS["tan"] = ga_predef_function(tan, 1, "DER_PDFUNC_TAN");
- PREDEF_FUNCTIONS["asin"] = ga_predef_function(asin, 1, "DER_PDFUNC_ASIN");
- PREDEF_FUNCTIONS["acos"] = ga_predef_function(acos, 1, "DER_PDFUNC_ACOS");
- PREDEF_FUNCTIONS["atan"] = ga_predef_function(atan, 1, "DER_PDFUNC_ATAN");
- PREDEF_FUNCTIONS["atan2"] = ga_predef_function(atan2,1,"DER_PDFUNC1_ATAN2",
-
"DER_PDFUNC2_ATAN2");
- PREDEF_FUNCTIONS["sinc"] = ga_predef_function(ga_sinc, 1,
- "DER_PDFUNC_SINC");
- PREDEF_FUNCTIONS["DER_PDFUNC_SINC"] =ga_predef_function(ga_der_sinc, 1,
-
"DER2_PDFUNC_SINC");
- PREDEF_FUNCTIONS["DER2_PDFUNC_SINC"] = ga_predef_function(ga_der2_sinc);
-
-
- PREDEF_FUNCTIONS["DER_PDFUNC_COS"] =
- ga_predef_function(ga_der_cos, 2, "-cos(t)");
- PREDEF_FUNCTIONS["DER_PDFUNC_TAN"] =
- ga_predef_function(ga_der_tan, 2, "2*tan(t)/sqr(cos(t))");
- // PREDEF_FUNCTIONS["DER_PDFUNC_TAN"] =
- // ga_predef_function(ga_der_tan, 2, "2*tan(t)*(1+sqr(tan(t)))");
- PREDEF_FUNCTIONS["DER_PDFUNC_ASIN"] =
- ga_predef_function(ga_der_asin, 2, "t/(pow(1-t*t,1.5))");
- PREDEF_FUNCTIONS["DER_PDFUNC_ACOS"] =
- ga_predef_function(ga_der_acos, 2, "-t/(pow(1-t*t,1.5))");
- PREDEF_FUNCTIONS["DER_PDFUNC_ATAN"] =
- ga_predef_function(ga_der_atan, 2, "-2*t/sqr(1+t*t)");
- PREDEF_FUNCTIONS["DER_PDFUNC1_ATAN2"] =
- ga_predef_function(ga_der_t_atan2, 2, "-2*t*u/sqr(sqr(u)+sqr(t))",
- "(sqrt(t)-sqr(u))/sqr(sqr(u)+sqr(t))");
- PREDEF_FUNCTIONS["DER_PDFUNC2_ATAN2"] =
- ga_predef_function(ga_der_u_atan2, 2,
- "(sqrt(t)-sqr(u))/sqr(sqr(u)+sqr(t))",
- "2*t*u/sqr(sqr(u)+sqr(t))");
-
-
- // Error functions
- PREDEF_FUNCTIONS["erf"]
- = ga_predef_function(erf, 1, "DER_PDFUNC_ERF");
- PREDEF_FUNCTIONS["erfc"]
- = ga_predef_function(erfc, 1, "DER_PDFUNC_ERFC");
-
- PREDEF_FUNCTIONS["DER_PDFUNC_ERF"] =
- ga_predef_function(ga_der_erf, 2, "exp(-t*t)*2/sqrt(pi)");
- PREDEF_FUNCTIONS["DER_PDFUNC_ERFC"] =
- ga_predef_function(ga_der_erfc, 2, "-exp(-t*t)*2/sqrt(pi)");
-
-
-
- // Miscellaneous functions
- PREDEF_FUNCTIONS["Heaviside"] = ga_predef_function(ga_Heaviside); //
ga_predef_function(ga_Heaviside, 2, "(0)");
- PREDEF_FUNCTIONS["sign"] = ga_predef_function(ga_sign);
- PREDEF_FUNCTIONS["abs"] = ga_predef_function(ga_abs, 1, "sign");
- PREDEF_FUNCTIONS["pos_part"]
- = ga_predef_function(ga_pos_part, 1, "Heaviside");
- PREDEF_FUNCTIONS["half_sqr_pos_part"]
- = ga_predef_function(ga_half_sqr_pos_part, 1, "pos_part");
- PREDEF_FUNCTIONS["neg_part"]
- = ga_predef_function(ga_neg_part, 1, "DER_PDFUNC_NEG_PART");
- PREDEF_FUNCTIONS["half_sqr_neg_part"]
- = ga_predef_function(ga_half_sqr_neg_part, 2, "-neg_part(t)");
- PREDEF_FUNCTIONS["reg_pos_part"]
- = ga_predef_function(ga_reg_pos_part, 1, "DER_REG_POS_PART", "");
- PREDEF_FUNCTIONS["DER_REG_POS_PART"]
- = ga_predef_function(ga_der_reg_pos_part, 1, "DER2_REG_POS_PART", "");
- PREDEF_FUNCTIONS["DER_REG_POS_PART"]
- = ga_predef_function(ga_der2_reg_pos_part);
-
- PREDEF_FUNCTIONS["max"]
- = ga_predef_function(ga_max, 1, "DER_PDFUNC1_MAX", "DER_PDFUNC2_MAX");
- PREDEF_FUNCTIONS["min"]
- = ga_predef_function(ga_min, 1, "DER_PDFUNC2_MAX", "DER_PDFUNC1_MAX");
-
- PREDEF_FUNCTIONS["DER_PDFUNC_NEG_PART"]
- = ga_predef_function(ga_der_neg_part, 2, "-Heaviside(-t)");
- PREDEF_FUNCTIONS["DER_PDFUNC1_MAX"] = ga_predef_function(ga_der_t_max);
- PREDEF_FUNCTIONS["DER_PDFUNC2_MAX"] = ga_predef_function(ga_der_u_max);
-
-
- // Predefined special functions
-
- SPEC_FUNCTIONS.insert("pi");
- SPEC_FUNCTIONS.insert("meshdim");
- SPEC_FUNCTIONS.insert("timestep");
- SPEC_FUNCTIONS.insert("qdim");
- SPEC_FUNCTIONS.insert("qdims");
- SPEC_FUNCTIONS.insert("Id");
-
- // Predefined operators
- ga_predef_operator_tab &PREDEF_OPERATORS
- = dal::singleton<ga_predef_operator_tab>::instance();
-
- PREDEF_OPERATORS.add_method("Norm", std::make_shared<norm_operator>());
- PREDEF_OPERATORS.add_method("Norm_sqr",
- std::make_shared<norm_sqr_operator>());
- PREDEF_OPERATORS.add_method("Det", std::make_shared<det_operator>());
- PREDEF_OPERATORS.add_method("Inv", std::make_shared<inverse_operator>());
- return true;
- }
-
- static bool predef_functions_initialized = init_predef_functions();
-
- bool ga_function_exists(const std::string &name) {
- const ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
- return PREDEF_FUNCTIONS.find(name) != PREDEF_FUNCTIONS.end();
- }
+ struct ga_instruction_copy_vect_val_base : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &Z;
+ size_type qdim;
+ // Z(ndof) --> t(qdim*ndof,qdim*target_dim)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: vectorized value of test functions");
+ size_type ndof = Z.sizes()[0];
+ GA_DEBUG_ASSERT(t.size() == Z.size() * qdim * qdim,
+ "Wrong size for base vector");
+ // std::fill(t.begin(), t.end(), scalar_type(0)); // Factorized
+ auto itZ = Z.begin();
+ size_type s = t.sizes()[0], sss = s+1;
- void ga_define_function(const std::string &name, size_type nbargs,
- const std::string &expr, const std::string &der1,
- const std::string &der2) {
- auto guard = omp_guard{};
-
- auto &PREDEF_FUNCTIONS =
dal::singleton<ga_predef_function_tab>::instance(0);
- if(PREDEF_FUNCTIONS.find(name) != PREDEF_FUNCTIONS.end()) return;
- GMM_ASSERT1(nbargs >= 1 && nbargs <= 2, "Generic assembly only allows "
- "the definition of scalar function with one or two arguments");
- { // Only for syntax analysis
- base_vector t(1);
- ga_workspace workspace;
- workspace.add_fixed_size_variable("t", gmm::sub_interval(0,1), t);
- if (nbargs == 2)
- workspace.add_fixed_size_variable("u", gmm::sub_interval(0,1), t);
- workspace.add_function_expression(expr);
- }
-
- PREDEF_FUNCTIONS[name] = ga_predef_function(expr);
- ga_predef_function &F = PREDEF_FUNCTIONS[name];
- F.gis = std::make_unique<instruction_set>();
- for (size_type thread = 0; thread < num_threads(); ++thread)
- {
- F.workspace(thread).add_fixed_size_variable("t", gmm::sub_interval(0,1),
- F.t(thread));
- if (nbargs == 2)
- F.workspace(thread).add_fixed_size_variable("u",
gmm::sub_interval(0,1),
- F.u(thread));
- F.workspace(thread).add_function_expression(expr);
- ga_compile_function(F.workspace(thread), (*F.gis)(thread), true);
- }
- F.nbargs_ = nbargs;
- if (nbargs == 1) {
- if (der1.size()) { F.derivative1_ = der1; F.dtype_ = 2; }
- } else {
- if (der1.size() && der2.size()) {
- F.derivative1_ = der1; F.derivative2_ = der2; F.dtype_ = 2;
+ // Performs t(i*qdim+j, k*qdim + j) = Z(i,k);
+ auto it = t.begin();
+ for (size_type i = 0; i < ndof; ++i, ++itZ) {
+ if (i) it += qdim;
+ auto it2 = it;
+ *it2 = *itZ;
+ for (size_type j = 1; j < qdim; ++j) { it2 += sss; *it2 = *itZ; }
}
+ return 0;
}
- }
- void ga_define_function(const std::string &name, pscalar_func_onearg f,
- const std::string &der) {
- ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
- PREDEF_FUNCTIONS[name] = ga_predef_function(f, 1, der);
- ga_predef_function &F = PREDEF_FUNCTIONS[name];
- if (der.size() == 0) F.dtype_ = 0;
- else if (!(ga_function_exists(der))) F.dtype_ = 2;
- }
+ ga_instruction_copy_vect_val_base(base_tensor &tt, const base_tensor &Z_,
+ size_type q) : t(tt), Z(Z_), qdim(q) {}
+ };
- void ga_define_function(const std::string &name, pscalar_func_twoargs f,
- const std::string &der1, const std::string &der2) {
- ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
- PREDEF_FUNCTIONS[name] = ga_predef_function(f, 1, der1, der2);
- ga_predef_function &F = PREDEF_FUNCTIONS[name];
- if (der1.size() == 0 || der2.size() == 0)
- F.dtype_ = 0;
- else if (!(ga_function_exists(der1)) || !(ga_function_exists(der2)))
- F.dtype_ = 2;
- }
+ struct ga_instruction_copy_vect_grad_base
+ : public ga_instruction_copy_vect_val_base {
+ // Z(ndof,N) --> t(qdim*ndof,qdim,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: vectorized gradient of test functions");
+ size_type ndof = Z.sizes()[0];
+ size_type N = Z.sizes()[2];
+ GA_DEBUG_ASSERT(t.size() == Z.size() * qdim * qdim,
+ "Wrong size for gradient vector");
+ // std::fill(t.begin(), t.end(), scalar_type(0)); // Factorized
+ base_tensor::const_iterator itZ = Z.begin();
+ size_type s = t.sizes()[0], sss = s+1, ssss = s*qdim;
- void ga_undefine_function(const std::string &name) {
- ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
- ga_predef_function_tab::iterator it = PREDEF_FUNCTIONS.find(name);
- if (it != PREDEF_FUNCTIONS.end()) {
- PREDEF_FUNCTIONS.erase(name);
- std::string name0 = "DER_PDFUNC_" + name;
- ga_undefine_function(name0);
- std::string name1 = "DER_PDFUNC1_" + name;
- ga_undefine_function(name1);
- std::string name2 = "DER_PDFUNC2_" + name;
- ga_undefine_function(name2);
+ // Performs t(i*qdim+j, k*qdim + j, l) = Z(i,k,l);
+ for (size_type l = 0; l < N; ++l) {
+ base_tensor::iterator it = t.begin() + (ssss*l);
+ for (size_type i = 0; i < ndof; ++i, ++itZ) {
+ if (i) it += qdim;
+ base_tensor::iterator it2 = it;
+ *it2 = *itZ;
+ for (size_type j = 1; j < qdim; ++j) { it2+=sss; *it2=*itZ; }
+ }
+ }
+ return 0;
}
- }
-
- //=========================================================================
- // Instructions for compilation: basic optimized operations on tensors
- //=========================================================================
-
+ ga_instruction_copy_vect_grad_base(base_tensor &tt, const base_tensor &Z_,
+ size_type q)
+ : ga_instruction_copy_vect_val_base(tt,Z_,q) {}
+ };
- struct ga_instruction_extract_local_im_data : public ga_instruction {
- base_tensor &t;
- const im_data &imd;
- papprox_integration &pai;
- const base_vector &U;
- const fem_interpolation_context &ctx;
- size_type qdim, cv_old;
+ struct ga_instruction_copy_hess_base : public ga_instruction_copy_val_base {
+ // Z(ndof,target_dim,N*N) --> t(Qmult*ndof,Qmult*target_dim,N,N)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: extract local im data");
- size_type cv = ctx.convex_num();
- if (cv != cv_old) {
- cv_old = cv;
- GMM_ASSERT1(imd.linked_mesh_im().int_method_of_element(cv)
- ->approx_method() == pai, "Im data have to be used only "
- "on their original integration method.");
+ GA_DEBUG_INFO("Instruction: Hessian of test functions");
+ size_type target_dim = Z.sizes()[1];
+ size_type Qmult = qdim / target_dim;
+ if (Qmult == 1) {
+ gmm::copy(Z.as_vector(), t.as_vector());
+ } else {
+ size_type ndof = Z.sizes()[0];
+ GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
+ "Wrong size for Hessian vector");
+ gmm::clear(t.as_vector());
+ base_tensor::const_iterator itZ = Z.begin();
+ size_type s = t.sizes()[0], ss = s * Qmult, sss = s+1;
+
+ // Performs t(i*Qmult+j, k*Qmult + j, l, m) = Z(i,k,l*N+m)
+ size_type NNdim = Z.sizes()[2]*target_dim;
+ for (size_type klm = 0; klm < NNdim; ++klm) {
+ base_tensor::iterator it = t.begin() + (ss * klm);
+ for (size_type i = 0; i < ndof; ++i, ++itZ) {
+ if (i) it += Qmult;
+ base_tensor::iterator it2 = it;
+ *it2 = *itZ;
+ for (size_type j = 1; j < Qmult; ++j) { it2 += sss; *it2 = *itZ; }
+ }
+ }
}
- size_type ipt = imd.filtered_index_of_point(cv, ctx.ii());
- GMM_ASSERT1(ipt != size_type(-1),
- "Im data with no data on the current integration point.");
- auto it = U.begin()+ipt*qdim;
- std::copy(it, it+qdim, t.begin());
return 0;
}
- ga_instruction_extract_local_im_data
- (base_tensor &t_, const im_data &imd_, const base_vector &U_,
- papprox_integration &pai_, const fem_interpolation_context &ctx_,
- size_type qdim_)
- : t(t_), imd(imd_), pai(pai_), U(U_), ctx(ctx_), qdim(qdim_),
- cv_old(-1) {}
+
+ ga_instruction_copy_hess_base(base_tensor &tt, const base_tensor &Z_,
+ size_type q)
+ : ga_instruction_copy_val_base(tt, Z_, q) {}
};
- struct ga_instruction_slice_local_dofs : public ga_instruction {
- const mesh_fem &mf;
- const base_vector &U;
- const fem_interpolation_context &ctx;
- base_vector &coeff;
- size_type qmult1, qmult2;
+ struct ga_instruction_copy_diverg_base : public ga_instruction_copy_val_base
{
+ // Z(ndof,target_dim,N) --> t(Qmult*ndof)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: Slice local dofs");
- GMM_ASSERT1(qmult1 != 0 && qmult2 != 0, "Internal error");
- slice_vector_on_basic_dof_of_element(mf, U, ctx.convex_num(),
- coeff, qmult1, qmult2);
+ GA_DEBUG_INFO("Instruction: divergence of test functions");
+ size_type ndof = Z.sizes()[0];
+ size_type target_dim = Z.sizes()[1];
+ size_type N = Z.sizes()[2];
+ size_type Qmult = qdim / target_dim;
+ GA_DEBUG_ASSERT(Qmult*target_dim == N && (Qmult == 1 || target_dim == 1),
+ "Dimensions mismatch for divergence operator");
+ GA_DEBUG_ASSERT(t.size() == ndof * Qmult,
+ "Wrong size for divergence vector");
+ gmm::clear(t.as_vector());
+ base_tensor::const_iterator itZ = Z.begin();
+ if (Qmult == 1) { // target_dim == N
+ // Performs t(i) = Trace(Z(i,:,:))
+ for (size_type l = 0; l < N; ++l) {
+ base_tensor::iterator it = t.begin();
+ if (l) itZ += target_dim*ndof+1;
+ for (size_type i = 0; i < ndof; ++i) {
+ if (i) { ++it; ++itZ; }
+ *it += *itZ;
+ }
+ }
+ } else { // Qmult == N
+ // Performs t(i*Qmult+j) = Z(i,1,j)
+ for (size_type j = 0; j < N; ++j) {
+ base_tensor::iterator it = t.begin() + j;
+ if (j) ++itZ;
+ for (size_type i = 0; i < ndof; ++i) {
+ if (i) { it += Qmult; ++itZ; }
+ *it += *itZ;
+ }
+ }
+ }
return 0;
}
- ga_instruction_slice_local_dofs(const mesh_fem &mf_, const base_vector &U_,
- const fem_interpolation_context &ctx_,
- base_vector &coeff_,
- size_type qmult1_, size_type qmult2_)
- : mf(mf_), U(U_), ctx(ctx_), coeff(coeff_),
- qmult1(qmult1_), qmult2(qmult2_) {}
+
+ ga_instruction_copy_diverg_base(base_tensor &tt, const base_tensor &Z_,
+ size_type q)
+ : ga_instruction_copy_val_base(tt, Z_, q) {}
};
- struct ga_instruction_update_pfp : public ga_instruction {
+ struct ga_instruction_elementary_transformation {
+ const base_vector &coeff_in;
+ base_vector coeff_out;
+ pelementary_transformation elemtrans;
const mesh_fem &mf;
const fem_interpolation_context &ctx;
- fem_precomp_pool &fp_pool;
- pfem_precomp &pfp;
+ base_matrix &M;
+ const mesh_fem **mf_M;
+ size_type &icv;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: Pfp update");
- if (ctx.have_pgp()) {
- size_type cv = ctx.is_convex_num_valid()
- ? ctx.convex_num() : mf.convex_index().first_true();
- pfem pf = mf.fem_of_element(cv);
- if (!pfp || pf != pfp->get_pfem() ||
- ctx.pgp()->get_ppoint_tab() != pfp->get_ppoint_tab()) {
- pfp = fp_pool(pf, ctx.pgp()->get_ppoint_tab());
- }
- } else {
- pfp = 0;
+ void do_transformation() {
+ size_type nn = gmm::vect_size(coeff_in);
+ if (M.size() == 0 || icv != ctx.convex_num() || &mf != *mf_M) {
+ M.base_resize(nn, nn);
+ *mf_M = &mf; icv = ctx.convex_num();
+ elemtrans->give_transformation(mf, icv, M);
}
- return 0;
+ coeff_out.resize(nn);
+ gmm::mult(M, coeff_in, coeff_out); // remember: coeff == coeff_out
}
- ga_instruction_update_pfp(const mesh_fem &mf_, pfem_precomp &pfp_,
- const fem_interpolation_context &ctx_,
- fem_precomp_pool &fp_pool_)
- : mf(mf_), ctx(ctx_), fp_pool(fp_pool_), pfp(pfp_) {}
+ ga_instruction_elementary_transformation
+ (const base_vector &co, pelementary_transformation e,
+ const mesh_fem &mf_, const fem_interpolation_context &ctx_,
+ base_matrix &M_, const mesh_fem **mf_M_, size_type &icv_)
+ : coeff_in(co), elemtrans(e), mf(mf_), ctx(ctx_),
+ M(M_), mf_M(mf_M_), icv(icv_) {}
+ ~ga_instruction_elementary_transformation() {};
};
- struct ga_instruction_first_ind_tensor : public ga_instruction {
- base_tensor &t;
- const fem_interpolation_context &ctx;
- size_type qdim;
- const mesh_fem *mfn, **mfg;
-
+ struct ga_instruction_elementary_transformation_val
+ : public ga_instruction_val, ga_instruction_elementary_transformation {
+ // Z(ndof,target_dim), coeff_in(Qmult,ndof) --> t(target_dim*Qmult)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: adapt first index of tensor");
- const mesh_fem &mf = *(mfg ? *mfg : mfn);
- GA_DEBUG_ASSERT(mfg ? *mfg : mfn, "Internal error");
- size_type cv_1 = ctx.is_convex_num_valid()
- ? ctx.convex_num() : mf.convex_index().first_true();
- pfem pf = mf.fem_of_element(cv_1);
- GMM_ASSERT1(pf, "An element without finite element method defined");
- size_type Qmult = qdim / pf->target_dim();
- size_type s = pf->nb_dof(cv_1) * Qmult;
- if (t.sizes()[0] != s)
- { bgeot::multi_index mi = t.sizes(); mi[0] = s; t.adjust_sizes(mi); }
- return 0;
+ GA_DEBUG_INFO("Instruction: variable value with elementary "
+ "transformation");
+ do_transformation();
+ return ga_instruction_val::exec();
}
- ga_instruction_first_ind_tensor(base_tensor &t_,
- const fem_interpolation_context &ctx_,
- size_type qdim_, const mesh_fem *mfn_,
- const mesh_fem **mfg_)
- : t(t_), ctx(ctx_), qdim(qdim_), mfn(mfn_), mfg(mfg_) {}
+ ga_instruction_elementary_transformation_val
+ (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_val(tt, Z_, coeff_out, q),
+ ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
- struct ga_instruction_second_ind_tensor
- : public ga_instruction_first_ind_tensor {
-
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: adapt second index of tensor");
- const mesh_fem &mf = *(mfg ? *mfg : mfn);
- size_type cv_1 = ctx.is_convex_num_valid()
- ? ctx.convex_num() : mf.convex_index().first_true();
- pfem pf = mf.fem_of_element(cv_1);
- GMM_ASSERT1(pf, "An element without finite element methode defined");
- size_type Qmult = qdim / pf->target_dim();
- size_type s = pf->nb_dof(cv_1) * Qmult;
- if (t.sizes()[1] != s)
- { bgeot::multi_index mi = t.sizes(); mi[1] = s; t.adjust_sizes(mi); }
- return 0;
+ struct ga_instruction_elementary_transformation_grad
+ : public ga_instruction_grad, ga_instruction_elementary_transformation {
+ // Z(ndof,target_dim,N), coeff_in(Qmult,ndof) --> t(target_dim*Qmult,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: gradient with elementary transformation");
+ do_transformation();
+ return ga_instruction_grad::exec();
}
- ga_instruction_second_ind_tensor(base_tensor &t_,
- fem_interpolation_context &ctx_,
- size_type qdim_, const mesh_fem *mfn_,
- const mesh_fem **mfg_)
- : ga_instruction_first_ind_tensor(t_, ctx_, qdim_, mfn_, mfg_) {}
-
+ ga_instruction_elementary_transformation_grad
+ (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_grad(tt, Z_, coeff_out, q),
+ ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
- struct ga_instruction_two_first_ind_tensor : public ga_instruction {
- base_tensor &t;
- const fem_interpolation_context &ctx1, &ctx2;
- size_type qdim1;
- const mesh_fem *mfn1, **mfg1;
- size_type qdim2;
- const mesh_fem *mfn2, **mfg2;
-
+ struct ga_instruction_elementary_transformation_hess
+ : public ga_instruction_hess, ga_instruction_elementary_transformation {
+ // Z(ndof,target_dim,N,N), coeff_in(Qmult,ndof) --> t(target_dim*Qmult,N,N)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: adapt two first indices of tensor");
- const mesh_fem &mf1 = *(mfg1 ? *mfg1 : mfn1);
- const mesh_fem &mf2 = *(mfg2 ? *mfg2 : mfn2);
- size_type cv_1 = ctx1.is_convex_num_valid()
- ? ctx1.convex_num() : mf1.convex_index().first_true();
- size_type cv_2 = ctx2.is_convex_num_valid()
- ? ctx2.convex_num() : mf2.convex_index().first_true();
- pfem pf1 = mf1.fem_of_element(cv_1);
- GMM_ASSERT1(pf1, "An element without finite element method defined");
- pfem pf2 = mf2.fem_of_element(cv_2);
- GMM_ASSERT1(pf2, "An element without finite element method defined");
- size_type Qmult1 = qdim1 / pf1->target_dim();
- size_type s1 = pf1->nb_dof(cv_1) * Qmult1;
- size_type Qmult2 = qdim2 / pf2->target_dim();
- size_type s2 = pf2->nb_dof(cv_2) * Qmult2;
- if (t.sizes()[0] != s1 || t.sizes()[1] != s2) {
- bgeot::multi_index mi = t.sizes();
- mi[0] = s1; mi[1] = s2;
- t.adjust_sizes(mi);
- }
- return 0;
+ GA_DEBUG_INFO("Instruction: Hessian with elementary transformation");
+ do_transformation();
+ return ga_instruction_hess::exec();
}
- ga_instruction_two_first_ind_tensor
- (base_tensor &t_, const fem_interpolation_context &ctx1_,
- const fem_interpolation_context &ctx2_,
- size_type qdim1_, const mesh_fem *mfn1_, const mesh_fem **mfg1_,
- size_type qdim2_, const mesh_fem *mfn2_, const mesh_fem **mfg2_)
- : t(t_), ctx1(ctx1_), ctx2(ctx2_), qdim1(qdim1_), mfn1(mfn1_),
- mfg1(mfg1_), qdim2(qdim2_), mfn2(mfn2_), mfg2(mfg2_) {}
+ ga_instruction_elementary_transformation_hess
+ (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_hess(tt, Z_, coeff_out, q),
+ ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
-
- struct ga_instruction_X_component : public ga_instruction {
- scalar_type &t;
- const fem_interpolation_context &ctx;
- size_type n;
-
+ struct ga_instruction_elementary_transformation_diverg
+ : public ga_instruction_diverg, ga_instruction_elementary_transformation {
+ // Z(ndof,target_dim,N), coeff_in(Qmult,ndof) --> t(1)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: X component");
- t = ctx.xreal()[n];
- return 0;
+ GA_DEBUG_INFO("Instruction: divergence with elementary transformation");
+ do_transformation();
+ return ga_instruction_diverg::exec();
}
- ga_instruction_X_component
- (scalar_type &t_, const fem_interpolation_context &ctx_, size_type n_)
- : t(t_), ctx(ctx_), n(n_) {}
+ ga_instruction_elementary_transformation_diverg
+ (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_diverg(tt, Z_, coeff_out, q),
+ ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
- struct ga_instruction_X : public ga_instruction {
- base_tensor &t;
- const fem_interpolation_context &ctx;
+ struct ga_instruction_update_group_info : public ga_instruction {
+ const ga_workspace &workspace;
+ ga_instruction_set &gis;
+ ga_instruction_set::interpolate_info &inin;
+ const std::string gname;
+ ga_instruction_set::variable_group_info &vgi;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: X");
- GA_DEBUG_ASSERT(t.size() == ctx.xreal().size(), "dimensions mismatch");
- gmm::copy(ctx.xreal(), t.as_vector());
+ GA_DEBUG_INFO("Instruction: Update group info for "+gname);
+ if (vgi.varname &&
+ &(workspace.associated_mf(*(vgi.varname))->linked_mesh())==inin.m)
+ return 0;
+ const std::string &varname
+ = inin.m ? workspace.variable_in_group(gname, *(inin.m))
+ : workspace.first_variable_of_group(gname);
+ vgi.mf = workspace.associated_mf(varname);
+ vgi.Ir = gis.var_intervals[varname];
+ vgi.In = workspace.interval_of_variable(varname);
+ vgi.alpha = workspace.factor_of_variable(varname);
+ vgi.U = gis.extended_vars[varname];
+ vgi.varname = &varname;
return 0;
}
- ga_instruction_X(base_tensor &t_, const fem_interpolation_context &ctx_)
- : t(t_), ctx(ctx_) {}
+ ga_instruction_update_group_info
+ (const ga_workspace &workspace_, ga_instruction_set &gis_,
+ ga_instruction_set::interpolate_info &inin_, const std::string &gname_,
+ ga_instruction_set::variable_group_info &vgi_) :
+ workspace(workspace_), gis(gis_), inin(inin_), gname(gname_),
+ vgi(vgi_) {}
};
- struct ga_instruction_copy_small_vect : public ga_instruction {
+ struct ga_instruction_interpolate_filter : public ga_instruction {
base_tensor &t;
- const base_small_vector &vec;
+ const ga_instruction_set::interpolate_info &inin;
+ size_type pt_type;
+ int nb;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: copy small vector");
- GMM_ASSERT1(t.size() == vec.size(), "Invalid vector size.");
- gmm::copy(vec, t.as_vector());
+ GA_DEBUG_INFO("Instruction: interpolated filter");
+ if ((pt_type == size_type(-1) && inin.pt_type) ||
+ (pt_type != size_type(-1) && inin.pt_type == pt_type)) {
+ GA_DEBUG_INFO("Instruction: interpolated filter: pass");
+ return 0;
+ }
+ else {
+ GA_DEBUG_INFO("Instruction: interpolated filter: filtered");
+ gmm::clear(t.as_vector());
+ return nb;
+ }
return 0;
}
- ga_instruction_copy_small_vect(base_tensor &t_,
- const base_small_vector &vec_)
- : t(t_), vec(vec_) {}
+
+ ga_instruction_interpolate_filter
+ (base_tensor &t_, const ga_instruction_set::interpolate_info &inin_,
+ size_type ind_, int nb_)
+ : t(t_), inin(inin_), pt_type(ind_), nb(nb_) {}
};
- struct ga_instruction_copy_Normal : public ga_instruction_copy_small_vect {
+
+ struct ga_instruction_interpolate : public ga_instruction {
+ base_tensor &t;
+ const mesh **m;
+ const mesh_fem *mfn, **mfg;
+ const base_vector *Un, **Ug;
+ fem_interpolation_context &ctx;
+ base_vector coeff;
+ size_type qdim;
+ const size_type &ipt;
+ fem_precomp_pool &fp_pool;
+ ga_instruction_set::interpolate_info &inin;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: Normal");
- GMM_ASSERT1(t.size() == vec.size(), "Invalid outward unit normal "
- "vector. Possible reasons: not on boundary or "
- "transformation failed.");
- gmm::copy(vec, t.as_vector());
+ GMM_ASSERT1(ctx.is_convex_num_valid(), "No valid element for the "
+ "transformation. Probably transformation failed");
+ const mesh_fem &mf = *(mfg ? *mfg : mfn);
+ const base_vector &U = *(Ug ? *Ug : Un);
+ GMM_ASSERT1(&(mf.linked_mesh()) == *m, "Interpolation of a variable "
+ "on another mesh than the one it is defined on");
+ slice_vector_on_basic_dof_of_element(mf, U, ctx.convex_num(), coeff);
+ pfem pf = mf.fem_of_element(ctx.convex_num());
+ GMM_ASSERT1(pf, "Undefined finite element method");
+ if (ctx.have_pgp()) {
+ if (ipt == 0)
+ inin.pfps[&mf] = fp_pool(pf, ctx.pgp()->get_ppoint_tab());
+ ctx.set_pfp(inin.pfps[&mf]);
+ } else {
+ ctx.set_pf(pf);
+ }
return 0;
}
- ga_instruction_copy_Normal(base_tensor &t_,
- const base_small_vector &Normal_)
- : ga_instruction_copy_small_vect(t_, Normal_) {}
- };
- struct ga_instruction_element_size : public ga_instruction {
- base_tensor &t;
- scalar_type &es;
+ ga_instruction_interpolate
+ (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
+ fem_interpolation_context &ctx_, size_type q, const size_type &ipt_,
+ fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
+ : t(tt), m(m_), mfn(mfn_), mfg(mfg_), Un(Un_), Ug(Ug_),
+ ctx(ctx_), qdim(q), ipt(ipt_), fp_pool(fp_pool_), inin(inin_) {}
+ };
+ struct ga_instruction_interpolate_val : public ga_instruction_interpolate {
+ // --> t(target_dim*Qmult)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: element_size");
- GMM_ASSERT1(t.size() == 1, "Invalid element size.");
- t[0] = es;
+ GA_DEBUG_INFO("Instruction: interpolated variable value");
+ ga_instruction_interpolate::exec();
+ ctx.pf()->interpolation(ctx, coeff, t.as_vector(), dim_type(qdim));
+ // cout << "interpolate " << &U << " result : " << t.as_vector() << endl;
return 0;
}
- ga_instruction_element_size(base_tensor &t_, scalar_type &es_)
- : t(t_), es(es_) {}
- };
- struct ga_instruction_element_K : public ga_instruction {
- base_tensor &t;
- const fem_interpolation_context &ctx;
+ ga_instruction_interpolate_val
+ (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
+ fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
+ fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
+ : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_,ctx_, q, ipt_,
+ fp_pool_, inin_)
+ {}
+ };
+ struct ga_instruction_interpolate_grad : public ga_instruction_interpolate {
+ // --> t(target_dim*Qmult,N)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: element_K");
- GMM_ASSERT1(t.size() == (ctx.K()).size(), "Invalid tensor size.");
- gmm::copy(ctx.K().as_vector(), t.as_vector());
+ GA_DEBUG_INFO("Instruction: interpolated variable grad");
+ ga_instruction_interpolate::exec();
+ base_matrix v(qdim, ctx.N());
+ ctx.pf()->interpolation_grad(ctx, coeff, v, dim_type(qdim));
+ gmm::copy(v.as_vector(), t.as_vector());
return 0;
}
- ga_instruction_element_K(base_tensor &t_,
- const fem_interpolation_context &ct)
- : t(t_), ctx(ct) {}
- };
- struct ga_instruction_element_B : public ga_instruction {
- base_tensor &t;
- const fem_interpolation_context &ctx;
+ ga_instruction_interpolate_grad
+ (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
+ fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
+ fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
+ : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_, ctx_, q, ipt_,
+ fp_pool_, inin_)
+ {}
+ };
+ struct ga_instruction_interpolate_hess : public ga_instruction_interpolate {
+ // --> t(target_dim*Qmult,N,N)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: element_B");
- GMM_ASSERT1(t.size() == (ctx.B()).size(), "Invalid tensor size.");
- gmm::copy(ctx.B().as_vector(), t.as_vector());
+ GA_DEBUG_INFO("Instruction: interpolated variable hessian");
+ ga_instruction_interpolate::exec();
+ base_matrix v(qdim, ctx.N()*ctx.N()); // To be optimized
+ ctx.pf()->interpolation_hess(ctx, coeff, v, dim_type(qdim));
+ gmm::copy(v.as_vector(), t.as_vector());
return 0;
}
- ga_instruction_element_B(base_tensor &t_,
- const fem_interpolation_context &ct)
- : t(t_), ctx(ct) {}
- };
- struct ga_instruction_val_base : public ga_instruction {
- base_tensor &t;
- fem_interpolation_context &ctx;
- const mesh_fem &mf;
- const pfem_precomp &pfp;
+ ga_instruction_interpolate_hess
+ (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
+ fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
+ fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
+ : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_, ctx_, q, ipt_,
+ fp_pool_, inin_)
+ {}
+ };
- virtual int exec() { // --> t(ndof,target_dim)
- GA_DEBUG_INFO("Instruction: compute value of base functions");
- // if (ctx.have_pgp()) ctx.set_pfp(pfp);
- // else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- // GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- // ctx.base_value(t);
- if (ctx.have_pgp()) ctx.pfp_base_value(t, pfp);
- else {
- ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- ctx.base_value(t);
- }
+ struct ga_instruction_interpolate_diverg : public ga_instruction_interpolate
{
+ // --> t(1)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: interpolated variable divergence");
+ ga_instruction_interpolate::exec();
+ ctx.pf()->interpolation_diverg(ctx, coeff, t[0]);
return 0;
}
- ga_instruction_val_base(base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, const pfem_precomp &pfp_)
- : t(tt), ctx(ct), mf(mf_), pfp(pfp_) {}
+ ga_instruction_interpolate_diverg
+ (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
+ fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
+ fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
+ : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_, ctx_, q, ipt_,
+ fp_pool_, inin_)
+ {}
};
- struct ga_instruction_xfem_plus_val_base : public ga_instruction {
- base_tensor &t;
- fem_interpolation_context &ctx;
- const mesh_fem &mf;
- pfem_precomp &pfp;
+ struct ga_instruction_interpolate_base {
+ base_tensor ZZ;
+ const mesh **m;
+ const mesh_fem *mfn, **mfg;
+ const size_type &ipt;
+ ga_instruction_set::interpolate_info &inin;
+ fem_precomp_pool &fp_pool;
- virtual int exec() { // --> t(ndof,target_dim)
- GA_DEBUG_INFO("Instruction: compute value of base functions");
- if (ctx.have_pgp()) ctx.set_pfp(pfp);
- else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- int old_xfem_side = ctx.xfem_side();
- ctx.set_xfem_side(1);
- ctx.base_value(t);
- ctx.set_xfem_side(old_xfem_side);
+ virtual int exec() {
+ GMM_ASSERT1(inin.ctx.is_convex_num_valid(), "No valid element for "
+ "the transformation. Probably transformation failed");
+ const mesh_fem &mf = *(mfg ? *mfg : mfn);
+ GMM_ASSERT1(&(mf.linked_mesh()) == *m, "Interpolation of a variable "
+ "on another mesh than the one it is defined on");
+
+ pfem pf = mf.fem_of_element(inin.ctx.convex_num());
+ GMM_ASSERT1(pf, "Undefined finite element method");
+
+ if (inin.ctx.have_pgp()) {
+ if (ipt == 0)
+ inin.pfps[&mf] = fp_pool(pf, inin.ctx.pgp()->get_ppoint_tab());
+ inin.ctx.set_pfp(inin.pfps[&mf]);
+ } else {
+ inin.ctx.set_pf(pf);
+ }
return 0;
}
- ga_instruction_xfem_plus_val_base(base_tensor &tt,
- fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : t(tt), ctx(ct), mf(mf_), pfp(pfp_) {}
+ ga_instruction_interpolate_base
+ (const mesh **m_, const mesh_fem *mfn_, const mesh_fem **mfg_,
+ const size_type &ipt_, ga_instruction_set::interpolate_info &inin_,
+ fem_precomp_pool &fp_pool_)
+ : m(m_), mfn(mfn_), mfg(mfg_), ipt(ipt_), inin(inin_),
+ fp_pool(fp_pool_) {}
};
- struct ga_instruction_xfem_minus_val_base : public ga_instruction {
- base_tensor &t;
- fem_interpolation_context &ctx;
- const mesh_fem &mf;
- pfem_precomp &pfp;
-
- virtual int exec() { // --> t(ndof,target_dim)
- GA_DEBUG_INFO("Instruction: compute value of base functions");
- if (ctx.have_pgp()) ctx.set_pfp(pfp);
- else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- int old_xfem_side = ctx.xfem_side();
- ctx.set_xfem_side(-1);
- ctx.base_value(t);
- ctx.set_xfem_side(old_xfem_side);
- return 0;
+ struct ga_instruction_interpolate_val_base
+ : public ga_instruction_copy_val_base, ga_instruction_interpolate_base {
+ // ctx --> Z(ndof,target_dim) --> t(Qmult*ndof,Qmult*target_dim)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: interpolated base value");
+ ga_instruction_interpolate_base::exec();
+ inin.ctx.pf()->real_base_value(inin.ctx, ZZ); // remember Z == ZZ
+ return ga_instruction_copy_val_base::exec();
}
- ga_instruction_xfem_minus_val_base
- (base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : t(tt), ctx(ct), mf(mf_), pfp(pfp_) {}
+ ga_instruction_interpolate_val_base
+ (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const size_type &ipt_, size_type q,
+ ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
+ : ga_instruction_copy_val_base(t_, ZZ, q),
+ ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
+ inin_, fp_pool_) {}
};
- struct ga_instruction_grad_base : public ga_instruction_val_base {
-
- virtual int exec() { // --> t(ndof,target_dim,N)
- GA_DEBUG_INFO("Instruction: compute gradient of base functions");
- // if (ctx.have_pgp()) ctx.set_pfp(pfp);
- // else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- // GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- // ctx.grad_base_value(t);
- if (ctx.have_pgp()) ctx.pfp_grad_base_value(t, pfp);
- else {
- ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- ctx.grad_base_value(t);
- }
- return 0;
+ struct ga_instruction_interpolate_grad_base
+ : public ga_instruction_copy_grad_base, ga_instruction_interpolate_base {
+ // ctx --> Z(ndof,target_dim,N) --> t(Qmult*ndof,Qmult*target_dim,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: interpolated base grad");
+ ga_instruction_interpolate_base::exec();
+ inin.ctx.pf()->real_grad_base_value(inin.ctx, ZZ); // remember Z == ZZ
+ return ga_instruction_copy_grad_base::exec();
}
- ga_instruction_grad_base(base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : ga_instruction_val_base(tt, ct, mf_, pfp_)
- {}
+ ga_instruction_interpolate_grad_base
+ (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const size_type &ipt_, size_type q,
+ ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
+ : ga_instruction_copy_grad_base(t_, ZZ, q),
+ ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
+ inin_, fp_pool_) {}
};
- struct ga_instruction_xfem_plus_grad_base : public ga_instruction_val_base {
-
- virtual int exec() { // --> t(ndof,target_dim,N)
- GA_DEBUG_INFO("Instruction: compute gradient of base functions");
- if (ctx.have_pgp()) ctx.set_pfp(pfp);
- else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- int old_xfem_side = ctx.xfem_side();
- ctx.set_xfem_side(1);
- ctx.grad_base_value(t);
- ctx.set_xfem_side(old_xfem_side);
- return 0;
+ struct ga_instruction_interpolate_hess_base
+ : public ga_instruction_copy_hess_base, ga_instruction_interpolate_base {
+ // ctx --> Z(ndof,target_dim,N*N) --> t(Qmult*ndof,Qmult*target_dim,N,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: interpolated base hessian");
+ ga_instruction_interpolate_base::exec();
+ inin.ctx.pf()->real_hess_base_value(inin.ctx, ZZ); // remember Z == ZZ
+ return ga_instruction_copy_hess_base::exec();
}
- ga_instruction_xfem_plus_grad_base
- (base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : ga_instruction_val_base(tt, ct, mf_, pfp_)
- {}
+ ga_instruction_interpolate_hess_base
+ (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const size_type &ipt_, size_type q,
+ ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
+ : ga_instruction_copy_hess_base(t_, ZZ, q),
+ ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
+ inin_, fp_pool_) {}
};
- struct ga_instruction_xfem_minus_grad_base : public ga_instruction_val_base {
-
- virtual int exec() { // --> t(ndof,target_dim,N)
- GA_DEBUG_INFO("Instruction: compute gradient of base functions");
- if (ctx.have_pgp()) ctx.set_pfp(pfp);
- else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- int old_xfem_side = ctx.xfem_side();
- ctx.set_xfem_side(-1);
- ctx.grad_base_value(t);
- ctx.set_xfem_side(old_xfem_side);
- return 0;
+ struct ga_instruction_interpolate_diverg_base
+ : public ga_instruction_copy_diverg_base, ga_instruction_interpolate_base {
+ // ctx --> Z(ndof,target_dim,N*N) --> t(Qmult*ndof)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: interpolated base divergence");
+ ga_instruction_interpolate_base::exec();
+ inin.ctx.pf()->real_grad_base_value(inin.ctx, ZZ); // remember Z == ZZ
+ return ga_instruction_copy_diverg_base::exec();
}
- ga_instruction_xfem_minus_grad_base
- (base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : ga_instruction_val_base(tt, ct, mf_, pfp_)
- {}
+ ga_instruction_interpolate_diverg_base
+ (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
+ const mesh_fem **mfg_, const size_type &ipt_, size_type q,
+ ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
+ : ga_instruction_copy_diverg_base(t_, ZZ, q),
+ ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
+ inin_, fp_pool_) {}
};
- struct ga_instruction_hess_base : public ga_instruction_val_base {
-
- virtual int exec() { // --> t(ndof,target_dim,N*N)
- GA_DEBUG_INFO("Instruction: compute Hessian of base functions");
- if (ctx.have_pgp()) ctx.set_pfp(pfp);
- else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- ctx.hess_base_value(t);
- return 0;
+ struct ga_instruction_elementary_transformation_base {
+ base_tensor t_in;
+ base_tensor &t_out;
+ pelementary_transformation elemtrans;
+ const mesh_fem &mf;
+ const fem_interpolation_context &ctx;
+ base_matrix &M;
+ const mesh_fem **mf_M;
+ size_type &icv;
+
+ void do_transformation(size_type n) {
+ if (M.size() == 0 || icv != ctx.convex_num() || &mf != *mf_M) {
+ M.base_resize(n, n);
+ *mf_M = &mf; icv = ctx.convex_num();
+ elemtrans->give_transformation(mf, icv, M);
+ }
+ t_out.mat_reduction(t_in, M, 0);
}
- ga_instruction_hess_base(base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : ga_instruction_val_base(tt, ct, mf_, pfp_)
- {}
+ ga_instruction_elementary_transformation_base
+ (base_tensor &t_, pelementary_transformation e, const mesh_fem &mf_,
+ const fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : t_out(t_), elemtrans(e), mf(mf_), ctx(ctx_),
+ M(M_), mf_M(mf_M_), icv(icv_) {}
};
- struct ga_instruction_xfem_plus_hess_base : public ga_instruction_val_base {
-
- virtual int exec() { // --> t(ndof,target_dim,N*N)
- GA_DEBUG_INFO("Instruction: compute Hessian of base functions");
- if (ctx.have_pgp()) ctx.set_pfp(pfp);
- else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- int old_xfem_side = ctx.xfem_side();
- ctx.set_xfem_side(1);
- ctx.hess_base_value(t);
- ctx.set_xfem_side(old_xfem_side);
+ struct ga_instruction_elementary_transformation_val_base
+ : public ga_instruction_copy_val_base,
+ ga_instruction_elementary_transformation_base {
+ // Z(ndof,target_dim) --> t_in --> t_out(Qmult*ndof,Qmult*target_dim)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: value of test functions with elementary "
+ "transformation");
+ size_type ndof = Z.sizes()[0];
+ size_type Qmult = qdim / Z.sizes()[1];
+ t_in.adjust_sizes(t_out.sizes());
+ ga_instruction_copy_val_base::exec();
+ do_transformation(ndof*Qmult);
return 0;
}
- ga_instruction_xfem_plus_hess_base
- (base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : ga_instruction_val_base(tt, ct, mf_, pfp_)
- {}
+ ga_instruction_elementary_transformation_val_base
+ (base_tensor &t_, const base_tensor &Z_, size_type q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_copy_val_base(t_in, Z_, q),
+ ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
- struct ga_instruction_xfem_minus_hess_base : public ga_instruction_val_base {
-
- virtual int exec() { // --> t(ndof,target_dim,N*N)
- GA_DEBUG_INFO("Instruction: compute Hessian of base functions");
- if (ctx.have_pgp()) ctx.set_pfp(pfp);
- else ctx.set_pf(mf.fem_of_element(ctx.convex_num()));
- GMM_ASSERT1(ctx.pf(), "Undefined finite element method");
- int old_xfem_side = ctx.xfem_side();
- ctx.set_xfem_side(-1);
- ctx.hess_base_value(t);
- ctx.set_xfem_side(old_xfem_side);
+ struct ga_instruction_elementary_transformation_grad_base
+ : public ga_instruction_copy_grad_base,
+ ga_instruction_elementary_transformation_base {
+ // Z(ndof,target_dim,N) --> t_in --> t_out(Qmult*ndof,Qmult*target_dim,N)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: gradient of test functions with elementary "
+ "transformation");
+ size_type ndof = Z.sizes()[0];
+ size_type Qmult = qdim / Z.sizes()[1];
+ t_in.adjust_sizes(t_out.sizes());
+ ga_instruction_copy_grad_base::exec();
+ do_transformation(ndof*Qmult);
return 0;
}
- ga_instruction_xfem_minus_hess_base
- (base_tensor &tt, fem_interpolation_context &ct,
- const mesh_fem &mf_, pfem_precomp &pfp_)
- : ga_instruction_val_base(tt, ct, mf_, pfp_)
- {}
+ ga_instruction_elementary_transformation_grad_base
+ (base_tensor &t_, const base_tensor &Z_, size_type q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_copy_grad_base(t_in, Z_, q),
+ ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
- struct ga_instruction_val : public ga_instruction {
- scalar_type &a;
- base_tensor &t;
- const base_tensor &Z;
- const base_vector &coeff;
- size_type qdim;
- // Z(ndof,target_dim), coeff(Qmult,ndof) --> t(target_dim*Qmult)
+ struct ga_instruction_elementary_transformation_hess_base
+ : public ga_instruction_copy_hess_base,
+ ga_instruction_elementary_transformation_base {
+ // Z(ndof,target_dim,N*N) --> t_out(Qmult*ndof,Qmult*target_dim,N,N)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: variable value");
+ GA_DEBUG_INFO("Instruction: Hessian of test functions with elementary "
+ "transformation");
size_type ndof = Z.sizes()[0];
- if (!ndof) { gmm::clear(t.as_vector()); return 0; }
- GA_DEBUG_ASSERT(t.size() == qdim, "dimensions mismatch");
-
- if (qdim == 1) {
- GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof,
- "Wrong size for coeff vector");
- auto itc = coeff.begin(); auto itZ = Z.begin();
- a = (*itc++) * (*itZ++);
- while (itc != coeff.end()) a += (*itc++) * (*itZ++);
- } else {
- size_type target_dim = Z.sizes()[1];
- if (target_dim == 1) {
- GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*qdim,
- "Wrong size for coeff vector");
- auto itc = coeff.begin(); auto itZ = Z.begin();
- for (auto it = t.begin(); it != t.end(); ++it)
- *it = (*itc++) * (*itZ);
- ++itZ;
- for (size_type j = 1; j < ndof; ++j, ++itZ) {
- for (auto it = t.begin(); it != t.end(); ++it)
- *it += (*itc++) * (*itZ);
- }
- } else {
- size_type Qmult = qdim / target_dim;
- GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*Qmult,
- "Wrong size for coeff vector");
-
- gmm::clear(t.as_vector());
- auto itc = coeff.begin();
- for (size_type j = 0; j < ndof; ++j) {
- auto it = t.begin();
- for (size_type q = 0; q < Qmult; ++q, ++itc) {
- for (size_type r = 0; r < target_dim; ++r)
- *it++ += (*itc) * Z[j + r*ndof];
- }
- }
- }
- }
+ size_type Qmult = qdim / Z.sizes()[1];
+ t_in.adjust_sizes(t_out.sizes());
+ ga_instruction_copy_hess_base::exec();
+ do_transformation(ndof*Qmult);
return 0;
}
- ga_instruction_val(base_tensor &tt, const base_tensor &Z_,
- const base_vector &co, size_type q)
- : a(tt[0]), t(tt), Z(Z_), coeff(co), qdim(q) {}
+ ga_instruction_elementary_transformation_hess_base
+ (base_tensor &t_, const base_tensor &Z_, size_type q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_copy_hess_base(t_in, Z_, q),
+ ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
- struct ga_instruction_grad : public ga_instruction_val {
- // Z(ndof,target_dim,N), coeff(Qmult,ndof) --> t(target_dim*Qmult,N)
+ struct ga_instruction_elementary_transformation_diverg_base
+ : public ga_instruction_copy_diverg_base,
+ ga_instruction_elementary_transformation_base {
+ // Z(ndof,target_dim,N) --> t_out(Qmult*ndof)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: gradient");
+ GA_DEBUG_INFO("Instruction: divergence of test functions with elementary
"
+ "transformation");
size_type ndof = Z.sizes()[0];
- if (!ndof) { gmm::clear(t.as_vector()); return 0; }
- size_type N = Z.sizes()[2];
- if (qdim == 1) {
- GA_DEBUG_ASSERT(t.size() == N, "dimensions mismatch");
- GA_DEBUG_ASSERT(coeff.size() == ndof, "Wrong size for coeff vector");
- auto itZ = Z.begin();
- for (auto it = t.begin(); it != t.end(); ++it) {
- auto itc = coeff.begin();
- *it = (*itc++) * (*itZ++);
- while (itc != coeff.end()) *it += (*itc++) * (*itZ++);
- }
- } else {
- size_type target_dim = Z.sizes()[1];
- if (target_dim == 1) {
- GA_DEBUG_ASSERT(t.size() == N*qdim, "dimensions mismatch");
- GA_DEBUG_ASSERT(coeff.size() == ndof*qdim,
- "Wrong size for coeff vector");
- for (size_type q = 0; q < qdim; ++q) {
- auto itZ = Z.begin(); auto it = t.begin() + q;
- for (size_type k = 0; k < N; ++k) {
- if (k) it += qdim;
- auto itc = coeff.begin() + q;
- *it = (*itc) * (*itZ++);
- for (size_type j = 1; j < ndof; ++j)
- { itc += qdim; *it += (*itc) * (*itZ++); }
- }
- }
- } else {
- size_type Qmult = qdim / target_dim;
- GA_DEBUG_ASSERT(t.size() == N*qdim, "dimensions mismatch");
- GA_DEBUG_ASSERT(coeff.size() == ndof*Qmult,
- "Wrong size for coeff vector");
- gmm::clear(t.as_vector());
- for (size_type q = 0; q < Qmult; ++q) {
- auto itZ = Z.begin();
- for (size_type k = 0; k < N; ++k)
- for (size_type r = 0; r < target_dim; ++r)
- for (size_type j = 0; j < ndof; ++j)
- t[r + q*target_dim + k*qdim] += coeff[j*Qmult+q] * (*itZ++);
- }
- }
- }
+ size_type Qmult = qdim / Z.sizes()[1];
+ t_in.adjust_sizes(t_out.sizes());
+ ga_instruction_copy_diverg_base::exec();
+ do_transformation(ndof*Qmult);
return 0;
}
- ga_instruction_grad(base_tensor &tt, const base_tensor &Z_,
- const base_vector &co, size_type q)
- : ga_instruction_val(tt, Z_, co, q)
- {}
-
+ ga_instruction_elementary_transformation_diverg_base
+ (base_tensor &t_, const base_tensor &Z_, size_type q,
+ pelementary_transformation e, const mesh_fem &mf_,
+ fem_interpolation_context &ctx_, base_matrix &M_,
+ const mesh_fem **mf_M_, size_type &icv_)
+ : ga_instruction_copy_diverg_base(t_in, Z_, q),
+ ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
+ mf_M_, icv_) {}
};
- struct ga_instruction_hess : public ga_instruction_val {
- // Z(ndof,target_dim,N*N), coeff(Qmult,ndof) --> t(target_dim*Qmult,N,N)
+
+ struct ga_instruction_add : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: Hessian");
- size_type ndof = Z.sizes()[0];
- if (!ndof) { gmm::clear(t.as_vector()); return 0; }
- size_type NN = gmm::sqr(t.sizes().back());
- GA_DEBUG_ASSERT(NN == Z.sizes()[2], "Internal error");
- if (qdim == 1) {
- GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof,
- "Wrong size for coeff vector");
- auto it = Z.begin(); auto itt = t.begin();
- for (size_type kl = 0; kl < NN; ++kl, ++itt) {
- *itt = scalar_type(0);
- for (auto itc = coeff.begin(); itc != coeff.end(); ++itc, ++it)
- *itt += (*itc) * (*it);
- }
- GMM_ASSERT1(itt == t.end(), "dimensions mismatch");
- } else {
- size_type target_dim = Z.sizes()[1];
- if (target_dim == 1) {
- GA_DEBUG_ASSERT(t.size() == NN*qdim, "dimensions mismatch");
- GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*qdim,
- "Wrong size for coeff vector");
- gmm::clear(t.as_vector());
- for (size_type q = 0; q < qdim; ++q) {
- base_tensor::const_iterator it = Z.begin();
- for (size_type kl = 0; kl < NN; ++kl)
- for (size_type j = 0; j < ndof; ++j, ++it)
- t[q + kl*qdim] += coeff[j*qdim+q] * (*it);
- }
- } else {
- size_type Qmult = qdim / target_dim;
- GA_DEBUG_ASSERT(t.size() == NN*qdim, "dimensions mismatch");
- GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*Qmult,
- "Wrong size for coeff vector");
- gmm::clear(t.as_vector());
- for (size_type q = 0; q < Qmult; ++q) {
- base_tensor::const_iterator it = Z.begin();
- for (size_type kl = 0; kl < NN; ++kl)
- for (size_type r = 0; r < target_dim; ++r)
- for (size_type j = 0; j < ndof; ++j, ++it)
- t[r + q*target_dim + kl*qdim] += coeff[j*Qmult+q] * (*it);
- }
- }
- }
+ GA_DEBUG_INFO("Instruction: addition");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(),
+ "internal error " << t.size() << " != " << tc1.size());
+ GA_DEBUG_ASSERT(t.size() == tc2.size(),
+ "internal error " << t.size() << " != " << tc2.size());
+ gmm::add(tc1.as_vector(), tc2.as_vector(), t.as_vector());
return 0;
}
-
- ga_instruction_hess(base_tensor &tt, const base_tensor &Z_,
- const base_vector &co, size_type q)
- : ga_instruction_val(tt, Z_, co, q)
- {}
+ ga_instruction_add(base_tensor &t_,
+ const base_tensor &tc1_, const base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_diverg : public ga_instruction_val {
- // Z(ndof,target_dim,N), coeff(Qmult,ndof) --> t(1)
+ struct ga_instruction_add_to : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: divergence");
- size_type ndof = Z.sizes()[0];
- if (!ndof) { gmm::clear(t.as_vector()); return 0; }
- size_type target_dim = Z.sizes()[1];
- size_type N = Z.sizes()[2];
- size_type Qmult = qdim / target_dim;
- GA_DEBUG_ASSERT(Qmult*target_dim == N && (Qmult == 1 || target_dim == 1),
- "Dimensions mismatch for divergence operator");
- GA_DEBUG_ASSERT(gmm::vect_size(coeff) == ndof*Qmult,
- "Wrong size for coeff vector");
-
- t[0] = scalar_type(0);
- base_tensor::const_iterator it = Z.begin();
- if (Qmult == 1)
- for (size_type k = 0; k < N; ++k) {
- if (k) it += (N*ndof + 1);
- for (size_type j = 0; j < ndof; ++j) {
- if (j) ++it;
- t[0] += coeff[j] * (*it);
- }
- }
- else // if (target_dim() == 1)
- for (size_type k = 0; k < N; ++k) {
- if (k) ++it;
- for (size_type j = 0; j < ndof; ++j) {
- if (j) ++it;
- t[0] += coeff[j*N+k] * (*it);
- }
- }
+ GA_DEBUG_INFO("Instruction: addition");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "internal error " << t.size()
+ << " incompatible with " << tc1.size());
+ gmm::add(tc1.as_vector(), t.as_vector());
return 0;
}
-
- ga_instruction_diverg(base_tensor &tt, const base_tensor &Z_,
- const base_vector &co, size_type q)
- : ga_instruction_val(tt, Z_, co, q)
- {}
+ ga_instruction_add_to(base_tensor &t_, const base_tensor &tc1_)
+ : t(t_), tc1(tc1_) {}
};
- struct ga_instruction_copy_val_base : public ga_instruction {
+ struct ga_instruction_sub : public ga_instruction {
base_tensor &t;
- const base_tensor &Z;
- size_type qdim;
- // Z(ndof,target_dim) --> t(Qmult*ndof,Qmult*target_dim)
+ const base_tensor &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: value of test functions");
- if (qdim == 1) {
- std::copy(Z.begin(), Z.end(), t.begin());
- } else {
- size_type target_dim = Z.sizes()[1];
- size_type Qmult = qdim / target_dim;
- if (Qmult == 1) {
- std::copy(Z.begin(), Z.end(), t.begin());
- } else {
- if (target_dim == 1) {
- size_type ndof = Z.sizes()[0];
- GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
- "Wrong size for base vector");
- std::fill(t.begin(), t.end(), scalar_type(0));
- auto itZ = Z.begin();
- size_type s = t.sizes()[0], sss = s+1;
-
- // Performs t(i*Qmult+j, k*Qmult + j) = Z(i,k);
- auto it = t.begin();
- for (size_type i = 0; i < ndof; ++i, ++itZ) {
- if (i) it += Qmult;
- auto it2 = it;
- *it2 = *itZ;
- for (size_type j = 1; j < Qmult; ++j) { it2 += sss; *it2 = *itZ;
}
- }
- } else {
- size_type ndof = Z.sizes()[0];
- GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
- "Wrong size for base vector");
- std::fill(t.begin(), t.end(), scalar_type(0));
- auto itZ = Z.begin();
- size_type s = t.sizes()[0], ss = s * Qmult, sss = s+1;
-
- // Performs t(i*Qmult+j, k*Qmult + j) = Z(i,k);
- for (size_type k = 0; k < target_dim; ++k) {
- auto it = t.begin() + (ss * k);
- for (size_type i = 0; i < ndof; ++i, ++itZ) {
- if (i) it += Qmult;
- auto it2 = it;
- *it2 = *itZ;
- for (size_type j = 1; j < Qmult; ++j)
- { it2 += sss; *it2 = *itZ; }
- }
- }
- }
- }
- }
+ GA_DEBUG_INFO("Instruction: subtraction");
+ GA_DEBUG_ASSERT(t.size() == tc1.size() && t.size() == tc2.size(),
+ "internal error");
+ gmm::add(tc1.as_vector(), gmm::scaled(tc2.as_vector(), scalar_type(-1)),
+ t.as_vector());
return 0;
}
-
- ga_instruction_copy_val_base(base_tensor &tt, const base_tensor &Z_,
- size_type q) : t(tt), Z(Z_), qdim(q) {}
+ ga_instruction_sub(base_tensor &t_,
+ const base_tensor &tc1_, const base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_copy_grad_base : public ga_instruction_copy_val_base {
- // Z(ndof,target_dim,N) --> t(Qmult*ndof,Qmult*target_dim,N)
+ struct ga_instruction_opposite : public ga_instruction {
+ base_tensor &t;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: gradient of test functions");
- if (qdim == 1) {
- std::copy(Z.begin(), Z.end(), t.begin());
- } else {
- size_type target_dim = Z.sizes()[1];
- size_type Qmult = qdim / target_dim;
- if (Qmult == 1) {
- std::copy(Z.begin(), Z.end(), t.begin());
- } else {
- if (target_dim == 1) {
- size_type ndof = Z.sizes()[0];
- size_type N = Z.sizes()[2];
- GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
- "Wrong size for gradient vector");
- std::fill(t.begin(), t.end(), scalar_type(0));
- base_tensor::const_iterator itZ = Z.begin();
- size_type s = t.sizes()[0], sss = s+1, ssss = s*target_dim*Qmult;
-
- // Performs t(i*Qmult+j, k*Qmult + j, l) = Z(i,k,l);
- for (size_type l = 0; l < N; ++l) {
- base_tensor::iterator it = t.begin() + (ssss*l);
- for (size_type i = 0; i < ndof; ++i, ++itZ) {
- if (i) it += Qmult;
- base_tensor::iterator it2 = it;
- *it2 = *itZ;
- for (size_type j = 1; j < Qmult; ++j) { it2+=sss; *it2=*itZ; }
- }
- }
- } else {
- size_type ndof = Z.sizes()[0];
- size_type N = Z.sizes()[2];
- GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
- "Wrong size for gradient vector");
- std::fill(t.begin(), t.end(), scalar_type(0));
- base_tensor::const_iterator itZ = Z.begin();
- size_type s = t.sizes()[0], ss = s * Qmult, sss = s+1;
- size_type ssss = ss*target_dim;
-
- // Performs t(i*Qmult+j, k*Qmult + j, l) = Z(i,k,l);
- for (size_type l = 0; l < N; ++l)
- for (size_type k = 0; k < target_dim; ++k) {
- base_tensor::iterator it = t.begin() + (ss * k + ssss*l);
- for (size_type i = 0; i < ndof; ++i, ++itZ) {
- if (i) it += Qmult;
- base_tensor::iterator it2 = it;
- *it2 = *itZ;
- for (size_type j = 1; j < Qmult; ++j) { it2+=sss; *it2=*itZ;
}
- }
- }
- }
- }
- }
+ GA_DEBUG_INFO("Instruction: multiplication with -1");
+ gmm::scale(t.as_vector(), scalar_type(-1));
return 0;
}
-
- ga_instruction_copy_grad_base(base_tensor &tt, const base_tensor &Z_,
- size_type q)
- : ga_instruction_copy_val_base(tt,Z_,q) {}
+ ga_instruction_opposite(base_tensor &t_) : t(t_) {}
};
- struct ga_instruction_copy_vect_val_base : public ga_instruction {
+ struct ga_instruction_print_tensor : public ga_instruction {
base_tensor &t;
- const base_tensor &Z;
- size_type qdim;
- // Z(ndof) --> t(qdim*ndof,qdim*target_dim)
+ pga_tree_node pnode;
+ const fem_interpolation_context &ctx;
+ size_type &nbpt, &ipt;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: vectorized value of test functions");
-
- size_type ndof = Z.sizes()[0];
- GA_DEBUG_ASSERT(t.size() == Z.size() * qdim * qdim,
- "Wrong size for base vector");
- // std::fill(t.begin(), t.end(), scalar_type(0)); // Factorized
- auto itZ = Z.begin();
- size_type s = t.sizes()[0], sss = s+1;
-
- // Performs t(i*qdim+j, k*qdim + j) = Z(i,k);
- auto it = t.begin();
- for (size_type i = 0; i < ndof; ++i, ++itZ) {
- if (i) it += qdim;
- auto it2 = it;
- *it2 = *itZ;
- for (size_type j = 1; j < qdim; ++j) { it2 += sss; *it2 = *itZ; }
- }
+ GA_DEBUG_INFO("Instruction: tensor print");
+ cout << "Print term "; ga_print_node(pnode, cout);
+ cout << " on Gauss point " << ipt << "/" << nbpt << " of element "
+ << ctx.convex_num() << ": " << t << endl;
return 0;
}
-
- ga_instruction_copy_vect_val_base(base_tensor &tt, const base_tensor &Z_,
- size_type q) : t(tt), Z(Z_), qdim(q) {}
+ ga_instruction_print_tensor(base_tensor &t_, pga_tree_node pnode_,
+ const fem_interpolation_context &ctx_,
+ size_type &nbpt_, size_type &ipt_)
+ : t(t_), pnode(pnode_), ctx(ctx_), nbpt(nbpt_), ipt(ipt_) {}
};
- struct ga_instruction_copy_vect_grad_base
- : public ga_instruction_copy_vect_val_base {
- // Z(ndof,N) --> t(qdim*ndof,qdim,N)
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: vectorized gradient of test functions");
- size_type ndof = Z.sizes()[0];
- size_type N = Z.sizes()[2];
- GA_DEBUG_ASSERT(t.size() == Z.size() * qdim * qdim,
- "Wrong size for gradient vector");
- // std::fill(t.begin(), t.end(), scalar_type(0)); // Factorized
- base_tensor::const_iterator itZ = Z.begin();
- size_type s = t.sizes()[0], sss = s+1, ssss = s*qdim;
-
- // Performs t(i*qdim+j, k*qdim + j, l) = Z(i,k,l);
- for (size_type l = 0; l < N; ++l) {
- base_tensor::iterator it = t.begin() + (ssss*l);
- for (size_type i = 0; i < ndof; ++i, ++itZ) {
- if (i) it += qdim;
- base_tensor::iterator it2 = it;
- *it2 = *itZ;
- for (size_type j = 1; j < qdim; ++j) { it2+=sss; *it2=*itZ; }
- }
- }
+ struct ga_instruction_copy_tensor : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: tensor copy");
+ std::copy(tc1.begin(), tc1.end(), t.begin());
+ // gmm::copy(tc1.as_vector(), t.as_vector());
return 0;
}
+ ga_instruction_copy_tensor(base_tensor &t_, const base_tensor &tc1_)
+ : t(t_), tc1(tc1_) {}
+ };
- ga_instruction_copy_vect_grad_base(base_tensor &tt, const base_tensor &Z_,
- size_type q)
- : ga_instruction_copy_vect_val_base(tt,Z_,q) {}
+ struct ga_instruction_clear_tensor : public ga_instruction {
+ base_tensor &t;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: clear tensor");
+ std::fill(t.begin(), t.end(), scalar_type(0));
+ return 0;
+ }
+ ga_instruction_clear_tensor(base_tensor &t_) : t(t_) {}
};
- struct ga_instruction_copy_hess_base : public ga_instruction_copy_val_base {
- // Z(ndof,target_dim,N*N) --> t(Qmult*ndof,Qmult*target_dim,N,N)
+ struct ga_instruction_copy_tensor_possibly_void : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: Hessian of test functions");
- size_type target_dim = Z.sizes()[1];
- size_type Qmult = qdim / target_dim;
- if (Qmult == 1) {
- gmm::copy(Z.as_vector(), t.as_vector());
- } else {
- size_type ndof = Z.sizes()[0];
- GA_DEBUG_ASSERT(t.size() == Z.size() * Qmult * Qmult,
- "Wrong size for Hessian vector");
+ GA_DEBUG_INFO("Instruction: tensor copy possibly void");
+ if (tc1.size())
+ gmm::copy(tc1.as_vector(), t.as_vector());
+ else
gmm::clear(t.as_vector());
- base_tensor::const_iterator itZ = Z.begin();
- size_type s = t.sizes()[0], ss = s * Qmult, sss = s+1;
+ return 0;
+ }
+ ga_instruction_copy_tensor_possibly_void(base_tensor &t_,
+ const base_tensor &tc1_)
+ : t(t_), tc1(tc1_) {}
+ };
- // Performs t(i*Qmult+j, k*Qmult + j, l, m) = Z(i,k,l*N+m)
- size_type NNdim = Z.sizes()[2]*target_dim;
- for (size_type klm = 0; klm < NNdim; ++klm) {
- base_tensor::iterator it = t.begin() + (ss * klm);
- for (size_type i = 0; i < ndof; ++i, ++itZ) {
- if (i) it += Qmult;
- base_tensor::iterator it2 = it;
- *it2 = *itZ;
- for (size_type j = 1; j < Qmult; ++j) { it2 += sss; *it2 = *itZ; }
- }
- }
- }
+ struct ga_instruction_copy_scalar : public ga_instruction {
+ scalar_type &t; const scalar_type &t1;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: scalar copy");
+ t = t1;
return 0;
}
+ ga_instruction_copy_scalar(scalar_type &t_, const scalar_type &t1_)
+ : t(t_), t1(t1_) {}
+ };
- ga_instruction_copy_hess_base(base_tensor &tt, const base_tensor &Z_,
- size_type q)
- : ga_instruction_copy_val_base(tt, Z_, q) {}
+ struct ga_instruction_copy_vect : public ga_instruction {
+ base_vector &t;
+ const base_vector &t1;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: fixed size tensor copy");
+ gmm::copy(t1, t);
+ return 0;
+ }
+ ga_instruction_copy_vect(base_vector &t_, const base_vector &t1_)
+ : t(t_), t1(t1_) {}
};
- struct ga_instruction_copy_diverg_base : public ga_instruction_copy_val_base
{
- // Z(ndof,target_dim,N) --> t(Qmult*ndof)
+ struct ga_instruction_trace : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
+ size_type n;
+ // tc1(:,:,...,n,n) --> t(:,:,...)
virtual int exec() {
- GA_DEBUG_INFO("Instruction: divergence of test functions");
- size_type ndof = Z.sizes()[0];
- size_type target_dim = Z.sizes()[1];
- size_type N = Z.sizes()[2];
- size_type Qmult = qdim / target_dim;
- GA_DEBUG_ASSERT(Qmult*target_dim == N && (Qmult == 1 || target_dim == 1),
- "Dimensions mismatch for divergence operator");
- GA_DEBUG_ASSERT(t.size() == ndof * Qmult,
- "Wrong size for divergence vector");
- gmm::clear(t.as_vector());
- base_tensor::const_iterator itZ = Z.begin();
- if (Qmult == 1) { // target_dim == N
- // Performs t(i) = Trace(Z(i,:,:))
- for (size_type l = 0; l < N; ++l) {
- base_tensor::iterator it = t.begin();
- if (l) itZ += target_dim*ndof+1;
- for (size_type i = 0; i < ndof; ++i) {
- if (i) { ++it; ++itZ; }
- *it += *itZ;
- }
- }
- } else { // Qmult == N
- // Performs t(i*Qmult+j) = Z(i,1,j)
- for (size_type j = 0; j < N; ++j) {
- base_tensor::iterator it = t.begin() + j;
- if (j) ++itZ;
- for (size_type i = 0; i < ndof; ++i) {
- if (i) { it += Qmult; ++itZ; }
- *it += *itZ;
- }
- }
+ GA_DEBUG_INFO("Instruction: Trace");
+ GA_DEBUG_ASSERT(t.size()*n*n == tc1.size(), "Wrong sizes");
+ size_type s = t.size() * (n+1);
+ auto it = t.begin();
+ auto it1 = tc1.begin();
+ for (; it != t.end(); ++it, ++it1) {
+ auto it2 = it1;
+ *it = *it2;
+ for (size_type i = 1; i < n; ++i) { it2 += s; *it += *it2; }
}
return 0;
}
- ga_instruction_copy_diverg_base(base_tensor &tt, const base_tensor &Z_,
- size_type q)
- : ga_instruction_copy_val_base(tt, Z_, q) {}
+ ga_instruction_trace(base_tensor &t_, const base_tensor &tc1_, size_type
n_)
+ : t(t_), tc1(tc1_), n(n_) {}
};
- struct ga_instruction_elementary_transformation {
- const base_vector &coeff_in;
- base_vector coeff_out;
- pelementary_transformation elemtrans;
- const mesh_fem &mf;
- const fem_interpolation_context &ctx;
- base_matrix &M;
- const mesh_fem **mf_M;
- size_type &icv;
+ struct ga_instruction_deviator : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
+ size_type n;
+ // tc1(:,:,...,n,n) --> t(:,:,...,n,n)
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: Deviator");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- void do_transformation() {
- size_type nn = gmm::vect_size(coeff_in);
- if (M.size() == 0 || icv != ctx.convex_num() || &mf != *mf_M) {
- M.base_resize(nn, nn);
- *mf_M = &mf; icv = ctx.convex_num();
- elemtrans->give_transformation(mf, icv, M);
+ gmm::copy(tc1.as_vector(), t.as_vector());
+
+ size_type nb = t.size()/(n*n);
+ size_type s = nb * (n+1), j = 0;
+ base_tensor::iterator it = t.begin();
+ base_tensor::const_iterator it1 = tc1.begin();
+ for (; j < nb; ++it, ++it1, ++j) {
+ scalar_type tr(0);
+ base_tensor::const_iterator it2 = it1;
+ tr += *it2;
+ for (size_type i = 1; i < n; ++i) { it2 += s; tr += *it2; }
+ tr /= scalar_type(n);
+
+ base_tensor::iterator it3 = it;
+ *it3 -= tr;
+ for (size_type i = 1; i < n; ++i) { it3 += s; *it3 -= tr; }
}
- coeff_out.resize(nn);
- gmm::mult(M, coeff_in, coeff_out); // remember: coeff == coeff_out
+ return 0;
}
- ga_instruction_elementary_transformation
- (const base_vector &co, pelementary_transformation e,
- const mesh_fem &mf_, const fem_interpolation_context &ctx_,
- base_matrix &M_, const mesh_fem **mf_M_, size_type &icv_)
- : coeff_in(co), elemtrans(e), mf(mf_), ctx(ctx_),
- M(M_), mf_M(mf_M_), icv(icv_) {}
- ~ga_instruction_elementary_transformation() {};
+ ga_instruction_deviator(base_tensor &t_, const base_tensor &tc1_,
+ size_type n_)
+ : t(t_), tc1(tc1_), n(n_) {}
};
- struct ga_instruction_elementary_transformation_val
- : public ga_instruction_val, ga_instruction_elementary_transformation {
- // Z(ndof,target_dim), coeff_in(Qmult,ndof) --> t(target_dim*Qmult)
+ struct ga_instruction_transpose : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: variable value with elementary "
- "transformation");
- do_transformation();
- return ga_instruction_val::exec();
+ GA_DEBUG_INFO("Instruction: transpose");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ size_type order = t.sizes().size();
+ size_type s1 = t.sizes()[order-2], s2 = t.sizes()[order-1];
+ size_type s = t.size() / (s1*s2);
+ for (size_type i = 0; i < s1; ++i)
+ for (size_type j = 0; j < s2; ++j) {
+ base_tensor::iterator it = t.begin() + s*(i + s1*j);
+ base_tensor::const_iterator it1 = tc1.begin() + s*(j + s2*i);
+ for (size_type k = 0; k < s; ++k) *it++ = *it1++;
+ }
+ return 0;
}
-
- ga_instruction_elementary_transformation_val
- (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_val(tt, Z_, coeff_out, q),
- ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ ga_instruction_transpose(base_tensor &t_, const base_tensor &tc1_)
+ : t(t_), tc1(tc1_) {}
};
- struct ga_instruction_elementary_transformation_grad
- : public ga_instruction_grad, ga_instruction_elementary_transformation {
- // Z(ndof,target_dim,N), coeff_in(Qmult,ndof) --> t(target_dim*Qmult,N)
+ struct ga_instruction_transpose_test : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: gradient with elementary transformation");
- do_transformation();
- return ga_instruction_grad::exec();
- }
+ GA_DEBUG_INFO("Instruction: copy tensor and transpose test functions");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ GA_DEBUG_ASSERT(t.sizes().size() >= 2, "Wrong sizes");
- ga_instruction_elementary_transformation_grad
- (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_grad(tt, Z_, coeff_out, q),
- ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ size_type s1 = t.sizes()[0], s2 = t.sizes()[1], s3 = s1*s2;
+ size_type s = t.size() / s3;
+ base_tensor::iterator it = t.begin();
+ for (size_type k = 0; k < s; ++k)
+ for (size_type j = 0; j < s2; ++j)
+ for (size_type i = 0; i < s1; ++i, ++it)
+ *it = tc1[j+s2*i+k*s3];
+ return 0;
+ }
+ ga_instruction_transpose_test(base_tensor &t_, const base_tensor &tc1_)
+ : t(t_), tc1(tc1_) {}
};
- struct ga_instruction_elementary_transformation_hess
- : public ga_instruction_hess, ga_instruction_elementary_transformation {
- // Z(ndof,target_dim,N,N), coeff_in(Qmult,ndof) --> t(target_dim*Qmult,N,N)
+ struct ga_instruction_sym : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: Hessian with elementary transformation");
- do_transformation();
- return ga_instruction_hess::exec();
+ GA_DEBUG_INFO("Instruction: symmetric part");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ size_type order = t.sizes().size();
+ size_type s1 = t.sizes()[order-2], s2 = t.sizes()[order-1];
+ size_type s = t.size() / (s1*s2);
+ for (size_type i = 0; i < s1; ++i)
+ for (size_type j = 0; j < s2; ++j) {
+ base_tensor::iterator it = t.begin() + s*(i + s1*j);
+ base_tensor::const_iterator it1 = tc1.begin() + s*(i + s1*j),
+ it1T = tc1.begin() + s*(j + s2*i);
+ for (size_type k = 0; k < s; ++k) *it++ = 0.5*(*it1++ + *it1T++);
+ }
+ return 0;
}
-
- ga_instruction_elementary_transformation_hess
- (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_hess(tt, Z_, coeff_out, q),
- ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ ga_instruction_sym(base_tensor &t_, const base_tensor &tc1_)
+ : t(t_), tc1(tc1_) {}
};
- struct ga_instruction_elementary_transformation_diverg
- : public ga_instruction_diverg, ga_instruction_elementary_transformation {
- // Z(ndof,target_dim,N), coeff_in(Qmult,ndof) --> t(1)
+ struct ga_instruction_skew : public ga_instruction {
+ base_tensor &t;
+ const base_tensor &tc1;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: divergence with elementary transformation");
- do_transformation();
- return ga_instruction_diverg::exec();
+ GA_DEBUG_INFO("Instruction: skew-symmetric part");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ size_type order = t.sizes().size();
+ size_type s1 = t.sizes()[order-2], s2 = t.sizes()[order-1];
+ size_type s = t.size() / (s1*s2);
+ for (size_type i = 0; i < s1; ++i)
+ for (size_type j = 0; j < s2; ++j) {
+ base_tensor::iterator it = t.begin() + s*(i + s1*j);
+ base_tensor::const_iterator it1 = tc1.begin() + s*(i + s1*j),
+ it1T = tc1.begin() + s*(j + s2*i);
+ for (size_type k = 0; k < s; ++k) *it++ = 0.5*(*it1++ - *it1T++);
+ }
+ return 0;
}
-
- ga_instruction_elementary_transformation_diverg
- (base_tensor &tt, const base_tensor &Z_, const base_vector &co, size_type
q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_diverg(tt, Z_, coeff_out, q),
- ga_instruction_elementary_transformation(co, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ ga_instruction_skew(base_tensor &t_, const base_tensor &tc1_)
+ : t(t_), tc1(tc1_) {}
};
- struct ga_instruction_update_group_info : public ga_instruction {
- const ga_workspace &workspace;
- ga_instruction_set &gis;
- ga_instruction_set::interpolate_info &inin;
- const std::string gname;
- ga_instruction_set::variable_group_info &vgi;
-
+ struct ga_instruction_scalar_add : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c, &d;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: Update group info for "+gname);
- if (vgi.varname &&
- &(workspace.associated_mf(*(vgi.varname))->linked_mesh())==inin.m)
- return 0;
- const std::string &varname
- = inin.m ? workspace.variable_in_group(gname, *(inin.m))
- : workspace.first_variable_of_group(gname);
- vgi.mf = workspace.associated_mf(varname);
- vgi.Ir = gis.var_intervals[varname];
- vgi.In = workspace.interval_of_variable(varname);
- vgi.alpha = workspace.factor_of_variable(varname);
- vgi.U = gis.extended_vars[varname];
- vgi.varname = &varname;
+ GA_DEBUG_INFO("Instruction: scalar addition");
+ t = c + d;
return 0;
}
-
- ga_instruction_update_group_info
- (const ga_workspace &workspace_, ga_instruction_set &gis_,
- ga_instruction_set::interpolate_info &inin_, const std::string &gname_,
- ga_instruction_set::variable_group_info &vgi_) :
- workspace(workspace_), gis(gis_), inin(inin_), gname(gname_),
- vgi(vgi_) {}
+ ga_instruction_scalar_add(scalar_type &t_, const scalar_type &c_,
+ const scalar_type &d_)
+ : t(t_), c(c_), d(d_) {}
};
- struct ga_instruction_interpolate_filter : public ga_instruction {
- base_tensor &t;
- const ga_instruction_set::interpolate_info &inin;
- size_type pt_type;
- int nb;
-
+ struct ga_instruction_scalar_sub : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c, &d;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated filter");
- if ((pt_type == size_type(-1) && inin.pt_type) ||
- (pt_type != size_type(-1) && inin.pt_type == pt_type)) {
- GA_DEBUG_INFO("Instruction: interpolated filter: pass");
- return 0;
- }
- else {
- GA_DEBUG_INFO("Instruction: interpolated filter: filtered");
- gmm::clear(t.as_vector());
- return nb;
- }
+ GA_DEBUG_INFO("Instruction: scalar subtraction");
+ t = c - d;
return 0;
}
-
- ga_instruction_interpolate_filter
- (base_tensor &t_, const ga_instruction_set::interpolate_info &inin_,
- size_type ind_, int nb_)
- : t(t_), inin(inin_), pt_type(ind_), nb(nb_) {}
+ ga_instruction_scalar_sub(scalar_type &t_, const scalar_type &c_,
+ const scalar_type &d_)
+ : t(t_), c(c_), d(d_) {}
};
-
- struct ga_instruction_interpolate : public ga_instruction {
- base_tensor &t;
- const mesh **m;
- const mesh_fem *mfn, **mfg;
- const base_vector *Un, **Ug;
- fem_interpolation_context &ctx;
- base_vector coeff;
- size_type qdim;
- const size_type &ipt;
- fem_precomp_pool &fp_pool;
- ga_instruction_set::interpolate_info &inin;
-
+ struct ga_instruction_scalar_scalar_mult : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c, &d;
virtual int exec() {
- GMM_ASSERT1(ctx.is_convex_num_valid(), "No valid element for the "
- "transformation. Probably transformation failed");
- const mesh_fem &mf = *(mfg ? *mfg : mfn);
- const base_vector &U = *(Ug ? *Ug : Un);
- GMM_ASSERT1(&(mf.linked_mesh()) == *m, "Interpolation of a variable "
- "on another mesh than the one it is defined on");
- slice_vector_on_basic_dof_of_element(mf, U, ctx.convex_num(), coeff);
- pfem pf = mf.fem_of_element(ctx.convex_num());
- GMM_ASSERT1(pf, "Undefined finite element method");
- if (ctx.have_pgp()) {
- if (ipt == 0)
- inin.pfps[&mf] = fp_pool(pf, ctx.pgp()->get_ppoint_tab());
- ctx.set_pfp(inin.pfps[&mf]);
- } else {
- ctx.set_pf(pf);
- }
+ GA_DEBUG_INFO("Instruction: scalar multiplication");
+ t = c * d;
return 0;
}
-
- ga_instruction_interpolate
- (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
- fem_interpolation_context &ctx_, size_type q, const size_type &ipt_,
- fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
- : t(tt), m(m_), mfn(mfn_), mfg(mfg_), Un(Un_), Ug(Ug_),
- ctx(ctx_), qdim(q), ipt(ipt_), fp_pool(fp_pool_), inin(inin_) {}
+ ga_instruction_scalar_scalar_mult(scalar_type &t_, const scalar_type &c_,
+ const scalar_type &d_)
+ : t(t_), c(c_), d(d_) {}
};
- struct ga_instruction_interpolate_val : public ga_instruction_interpolate {
- // --> t(target_dim*Qmult)
+ struct ga_instruction_scalar_scalar_div : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c, &d;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated variable value");
- ga_instruction_interpolate::exec();
- ctx.pf()->interpolation(ctx, coeff, t.as_vector(), dim_type(qdim));
- // cout << "interpolate " << &U << " result : " << t.as_vector() << endl;
+ GA_DEBUG_INFO("Instruction: scalar division");
+ t = c / d;
return 0;
}
-
- ga_instruction_interpolate_val
- (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
- fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
- fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
- : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_,ctx_, q, ipt_,
- fp_pool_, inin_)
- {}
+ ga_instruction_scalar_scalar_div(scalar_type &t_, const scalar_type &c_,
+ const scalar_type &d_)
+ : t(t_), c(c_), d(d_) {}
};
- struct ga_instruction_interpolate_grad : public ga_instruction_interpolate {
- // --> t(target_dim*Qmult,N)
+ struct ga_instruction_scalar_mult : public ga_instruction {
+ base_tensor &t, &tc1;
+ const scalar_type &c;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated variable grad");
- ga_instruction_interpolate::exec();
- base_matrix v(qdim, ctx.N());
- ctx.pf()->interpolation_grad(ctx, coeff, v, dim_type(qdim));
- gmm::copy(v.as_vector(), t.as_vector());
+ GA_DEBUG_INFO("Instruction: multiplication of a tensor by a scalar " <<
c);
+ gmm::copy(gmm::scaled(tc1.as_vector(), c), t.as_vector());
return 0;
}
-
- ga_instruction_interpolate_grad
- (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
- fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
- fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
- : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_, ctx_, q, ipt_,
- fp_pool_, inin_)
- {}
+ ga_instruction_scalar_mult(base_tensor &t_, base_tensor &tc1_,
+ const scalar_type &c_)
+ : t(t_), tc1(tc1_), c(c_) {}
};
- struct ga_instruction_interpolate_hess : public ga_instruction_interpolate {
- // --> t(target_dim*Qmult,N,N)
+ struct ga_instruction_scalar_div : public ga_instruction {
+ base_tensor &t, &tc1;
+ const scalar_type &c;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated variable hessian");
- ga_instruction_interpolate::exec();
- base_matrix v(qdim, ctx.N()*ctx.N()); // To be optimized
- ctx.pf()->interpolation_hess(ctx, coeff, v, dim_type(qdim));
- gmm::copy(v.as_vector(), t.as_vector());
+ GA_DEBUG_INFO("Instruction: division of a tensor by a scalar");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+
+ base_tensor::iterator it = t.begin(), it1 = tc1.begin();
+ for (; it != t.end(); ++it, ++it1) *it = *it1/c;
return 0;
}
+ ga_instruction_scalar_div(base_tensor &t_, base_tensor &tc1_,
+ const scalar_type &c_)
+ : t(t_), tc1(tc1_), c(c_) {}
+ };
- ga_instruction_interpolate_hess
- (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
- fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
- fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
- : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_, ctx_, q, ipt_,
- fp_pool_, inin_)
- {}
- };
-
- struct ga_instruction_interpolate_diverg : public ga_instruction_interpolate
{
- // --> t(1)
+ struct ga_instruction_dotmult : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated variable divergence");
- ga_instruction_interpolate::exec();
- ctx.pf()->interpolation_diverg(ctx, coeff, t[0]);
+ GA_DEBUG_INFO("Instruction: componentwise multiplication");
+ size_type s2 = tc2.size(), s1_1 = tc1.size() / s2;
+ GA_DEBUG_ASSERT(t.size() == s1_1*s2, "Wrong sizes");
+
+ base_tensor::iterator it = t.begin();
+ for (size_type i = 0; i < s2; ++i)
+ for (size_type m = 0; m < s1_1; ++m, ++it)
+ *it = tc1[m+s1_1*i] * tc2[i];
return 0;
}
-
- ga_instruction_interpolate_diverg
- (base_tensor &tt, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const base_vector *Un_, const base_vector **Ug_,
- fem_interpolation_context &ctx_, size_type q, size_type &ipt_,
- fem_precomp_pool &fp_pool_, ga_instruction_set::interpolate_info &inin_)
- : ga_instruction_interpolate(tt, m_, mfn_, mfg_, Un_, Ug_, ctx_, q, ipt_,
- fp_pool_, inin_)
- {}
+ ga_instruction_dotmult(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_interpolate_base {
- base_tensor ZZ;
- const mesh **m;
- const mesh_fem *mfn, **mfg;
- const size_type &ipt;
- ga_instruction_set::interpolate_info &inin;
- fem_precomp_pool &fp_pool;
-
+ struct ga_instruction_dotdiv : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GMM_ASSERT1(inin.ctx.is_convex_num_valid(), "No valid element for "
- "the transformation. Probably transformation failed");
- const mesh_fem &mf = *(mfg ? *mfg : mfn);
- GMM_ASSERT1(&(mf.linked_mesh()) == *m, "Interpolation of a variable "
- "on another mesh than the one it is defined on");
-
- pfem pf = mf.fem_of_element(inin.ctx.convex_num());
- GMM_ASSERT1(pf, "Undefined finite element method");
+ GA_DEBUG_INFO("Instruction: componentwise division");
+ size_type s2 = tc2.size(), s1_1 = tc1.size() / s2;
+ GA_DEBUG_ASSERT(t.size() == s1_1*s2, "Wrong sizes");
- if (inin.ctx.have_pgp()) {
- if (ipt == 0)
- inin.pfps[&mf] = fp_pool(pf, inin.ctx.pgp()->get_ppoint_tab());
- inin.ctx.set_pfp(inin.pfps[&mf]);
- } else {
- inin.ctx.set_pf(pf);
- }
+ base_tensor::iterator it = t.begin();
+ for (size_type i = 0; i < s2; ++i)
+ for (size_type m = 0; m < s1_1; ++m, ++it)
+ *it = tc1[m+s1_1*i] / tc2[i];
return 0;
}
-
- ga_instruction_interpolate_base
- (const mesh **m_, const mesh_fem *mfn_, const mesh_fem **mfg_,
- const size_type &ipt_, ga_instruction_set::interpolate_info &inin_,
- fem_precomp_pool &fp_pool_)
- : m(m_), mfn(mfn_), mfg(mfg_), ipt(ipt_), inin(inin_),
- fp_pool(fp_pool_) {}
+ ga_instruction_dotdiv(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_interpolate_val_base
- : public ga_instruction_copy_val_base, ga_instruction_interpolate_base {
- // ctx --> Z(ndof,target_dim) --> t(Qmult*ndof,Qmult*target_dim)
+ // Performs Ami Bni -> Cmni
+ struct ga_instruction_dotmult_spec : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated base value");
- ga_instruction_interpolate_base::exec();
- inin.ctx.pf()->real_base_value(inin.ctx, ZZ); // remember Z == ZZ
- return ga_instruction_copy_val_base::exec();
- }
-
- ga_instruction_interpolate_val_base
- (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const size_type &ipt_, size_type q,
- ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
- : ga_instruction_copy_val_base(t_, ZZ, q),
- ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
- inin_, fp_pool_) {}
- };
+ GA_DEBUG_INFO("Instruction: specific componentwise "
+ "multiplication");
+ size_type s2_1 = tc2.sizes()[0], s2_2 = tc2.size() / s2_1;
+ size_type s1_1 = tc1.size() / s2_2;
- struct ga_instruction_interpolate_grad_base
- : public ga_instruction_copy_grad_base, ga_instruction_interpolate_base {
- // ctx --> Z(ndof,target_dim,N) --> t(Qmult*ndof,Qmult*target_dim,N)
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated base grad");
- ga_instruction_interpolate_base::exec();
- inin.ctx.pf()->real_grad_base_value(inin.ctx, ZZ); // remember Z == ZZ
- return ga_instruction_copy_grad_base::exec();
+ base_tensor::iterator it = t.begin();
+ for (size_type i = 0; i < s2_2; ++i)
+ for (size_type n = 0; n < s2_1; ++n)
+ for (size_type m = 0; m < s1_1; ++m, ++it)
+ *it = tc1[m+s1_1*i] * tc2[n+s2_1*i];
+ GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
+ return 0;
}
-
- ga_instruction_interpolate_grad_base
- (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const size_type &ipt_, size_type q,
- ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
- : ga_instruction_copy_grad_base(t_, ZZ, q),
- ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
- inin_, fp_pool_) {}
+ ga_instruction_dotmult_spec(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_interpolate_hess_base
- : public ga_instruction_copy_hess_base, ga_instruction_interpolate_base {
- // ctx --> Z(ndof,target_dim,N*N) --> t(Qmult*ndof,Qmult*target_dim,N,N)
+ // Performs Amij Bjk -> Cmik. To be optimized
+ struct ga_instruction_matrix_mult : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated base hessian");
- ga_instruction_interpolate_base::exec();
- inin.ctx.pf()->real_hess_base_value(inin.ctx, ZZ); // remember Z == ZZ
- return ga_instruction_copy_hess_base::exec();
- }
+ GA_DEBUG_INFO("Instruction: matrix multiplication");
+ size_type order = tc2.sizes().size();
+ size_type s2_1 = tc2.sizes()[order-2];
+ size_type s2_2 = tc2.sizes()[order-1];
+ size_type s1 = tc1.size() / s2_1;
+ size_type s2 = tc2.size() / (s2_1*s2_2);
- ga_instruction_interpolate_hess_base
- (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const size_type &ipt_, size_type q,
- ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
- : ga_instruction_copy_hess_base(t_, ZZ, q),
- ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
- inin_, fp_pool_) {}
+ base_tensor::iterator it = t.begin();
+ for (size_type k = 0; k < s2_2; ++k)
+ for (size_type i = 0; i < s1; ++i)
+ for (size_type m = 0; m < s2; ++m, ++it) {
+ *it = scalar_type(0);
+ for (size_type j = 0; j < s2_1; ++j)
+ *it += tc1[i+j*s1] * tc2[m+j*s2+k*s2_1*s2];
+ }
+ GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
+ return 0;
+ }
+ ga_instruction_matrix_mult(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_interpolate_diverg_base
- : public ga_instruction_copy_diverg_base, ga_instruction_interpolate_base {
- // ctx --> Z(ndof,target_dim,N*N) --> t(Qmult*ndof)
+ // Performs Amij Bnjk -> Cmnik. To be optimized
+ struct ga_instruction_matrix_mult_spec : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: interpolated base divergence");
- ga_instruction_interpolate_base::exec();
- inin.ctx.pf()->real_grad_base_value(inin.ctx, ZZ); // remember Z == ZZ
- return ga_instruction_copy_diverg_base::exec();
- }
+ GA_DEBUG_INFO("Instruction: specific matrix multiplication");
+ size_type s1_1 = tc1.sizes()[0];
+ size_type s1_2 = tc1.sizes()[1];
+ // size_type s1_3 = tc1.sizes()[2];
+ size_type s2_1 = tc2.sizes()[0];
+ size_type s2_2 = tc2.sizes()[1];
+ size_type s2_3 = tc2.sizes()[2];
- ga_instruction_interpolate_diverg_base
- (base_tensor &t_, const mesh **m_, const mesh_fem *mfn_,
- const mesh_fem **mfg_, const size_type &ipt_, size_type q,
- ga_instruction_set::interpolate_info &inin_, fem_precomp_pool &fp_pool_)
- : ga_instruction_copy_diverg_base(t_, ZZ, q),
- ga_instruction_interpolate_base(m_, mfn_, mfg_, ipt_,
- inin_, fp_pool_) {}
+ base_tensor::iterator it = t.begin();
+ for (size_type k = 0; k < s2_3; ++k)
+ for (size_type i = 0; i < s1_2; ++i)
+ for (size_type n = 0; n < s2_1; ++n)
+ for (size_type m = 0; m < s1_1; ++m, ++it) {
+ *it = scalar_type(0);
+ for (size_type j = 0; j < s2_2; ++j)
+ *it += tc1[m+i*s1_1+j*s1_1*s1_2] * tc2[n+j*s2_1+k*s2_1*s2_2];
+ }
+ GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
+ return 0;
+ }
+ ga_instruction_matrix_mult_spec(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_elementary_transformation_base {
- base_tensor t_in;
- base_tensor &t_out;
- pelementary_transformation elemtrans;
- const mesh_fem &mf;
- const fem_interpolation_context &ctx;
- base_matrix &M;
- const mesh_fem **mf_M;
- size_type &icv;
+ // Performs Ani Bmi -> Cmn
+ struct ga_instruction_reduction : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type nn;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: reduction operation of size " << nn);
+#if GA_USES_BLAS
+ long m = int(tc1.size()/nn), k = int(nn), n = int(tc2.size()/nn);
+ long lda = m, ldb = n, ldc = m;
+ char T = 'T', N = 'N';
+ scalar_type alpha(1), beta(0);
+ gmm::dgemm_(&N, &T, &m, &n, &k, &alpha, &(tc1[0]), &lda, &(tc2[0]), &ldb,
+ &beta, &(t[0]), &ldc);
+#else
+ size_type s1 = tc1.size()/nn, s2 = tc2.size()/nn;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
- void do_transformation(size_type n) {
- if (M.size() == 0 || icv != ctx.convex_num() || &mf != *mf_M) {
- M.base_resize(n, n);
- *mf_M = &mf; icv = ctx.convex_num();
- elemtrans->give_transformation(mf, icv, M);
+ auto it1=tc1.begin(), it2=tc2.begin(), it2end=it2 + s2;
+ for (auto it = t.begin(); it != t.end(); ++it) {
+ auto it11 = it1, it22 = it2;
+ scalar_type a = (*it11) * (*it22);
+ for (size_type i = 1; i < nn; ++i)
+ { it11 += s1; it22 += s2; a += (*it11) * (*it22); }
+ *it = a;
+ ++it2; if (it2 == it2end) { it2 = tc2.begin(), ++it1; }
}
- t_out.mat_reduction(t_in, M, 0);
+ // auto it = t.begin(); // Unoptimized version.
+ // for (size_type i = 0; i < s1; ++i)
+ // for (size_type j = 0; j < s2; ++j, ++it) {
+ // *it = scalar_type(0);
+ // for (size_type k = 0; k < nn; ++k)
+ // *it += tc1[i+k*s1] * tc2[j+k*s2];
+ // }
+#endif
+ return 0;
}
-
- ga_instruction_elementary_transformation_base
- (base_tensor &t_, pelementary_transformation e, const mesh_fem &mf_,
- const fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : t_out(t_), elemtrans(e), mf(mf_), ctx(ctx_),
- M(M_), mf_M(mf_M_), icv(icv_) {}
+ ga_instruction_reduction(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type n_)
+ : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
};
- struct ga_instruction_elementary_transformation_val_base
- : public ga_instruction_copy_val_base,
- ga_instruction_elementary_transformation_base {
- // Z(ndof,target_dim) --> t_in --> t_out(Qmult*ndof,Qmult*target_dim)
+ // Performs Ani Bmi -> Cmn
+ struct ga_instruction_reduction_opt0_2 : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type n, q;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: value of test functions with elementary "
- "transformation");
- size_type ndof = Z.sizes()[0];
- size_type Qmult = qdim / Z.sizes()[1];
- t_in.adjust_sizes(t_out.sizes());
- ga_instruction_copy_val_base::exec();
- do_transformation(ndof*Qmult);
+ GA_DEBUG_INFO("Instruction: reduction operation of size " << n*q <<
+ " optimized for vectorized second tensor of type 2");
+ size_type nn = n*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn, s2_q = s2/q;
+ size_type s1_qq = s1*q, s2_qq = s2*q;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
+
+ auto it = t.begin(), it1 = tc1.begin();
+ for (size_type i = 0; i < s1; ++i, ++it1) {
+ auto it2 = tc2.begin();
+ for (size_type j = 0; j < s2_q; ++j) {
+ if (j) it2+=q;
+ auto itt1 = it1;
+ for (size_type l = 0; l < q; ++l, ++it) {
+ if (l) itt1 += s1;
+ auto ittt1 = itt1, ittt2 = it2;
+ *it = *ittt1 * (*ittt2);
+ for (size_type m = 1; m < n; ++m) {
+ ittt1 += s1_qq, ittt2 += s2_qq; *it += *ittt1 * (*ittt2);
+ }
+ }
+ }
+ }
+ // base_tensor u = t;
+ // ga_instruction_reduction toto(t, tc1, tc2, n*q);
+ // toto.exec();
+ // GMM_ASSERT1(gmm::vect_dist2(t.as_vector(), u.as_vector()) < 1E-9,
"Erroneous");
return 0;
}
-
- ga_instruction_elementary_transformation_val_base
- (base_tensor &t_, const base_tensor &Z_, size_type q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_copy_val_base(t_in, Z_, q),
- ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ ga_instruction_reduction_opt0_2(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type n_,
+ size_type q_)
+ : t(t_), tc1(tc1_), tc2(tc2_), n(n_), q(q_) {}
};
- struct ga_instruction_elementary_transformation_grad_base
- : public ga_instruction_copy_grad_base,
- ga_instruction_elementary_transformation_base {
- // Z(ndof,target_dim,N) --> t_in --> t_out(Qmult*ndof,Qmult*target_dim,N)
+ // Performs Ani Bmi -> Cmn
+ template <int N>
+ struct ga_instruction_reduction_opt0_2_unrolled : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type q;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: gradient of test functions with elementary "
- "transformation");
- size_type ndof = Z.sizes()[0];
- size_type Qmult = qdim / Z.sizes()[1];
- t_in.adjust_sizes(t_out.sizes());
- ga_instruction_copy_grad_base::exec();
- do_transformation(ndof*Qmult);
+ GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*q
+ << " optimized for vectorized second tensor of type 2");
+ size_type nn = N*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn, s2_q = s2/q;
+ size_type s1_qq = s1*q, s2_qq = s2*q;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
+
+ auto it = t.begin(), it1 = tc1.begin();
+ for (size_type i = 0; i < s1; ++i, ++it1) {
+ auto it2 = tc2.begin();
+ for (size_type j = 0; j < s2_q; ++j) {
+ if (j) it2+=q;
+ auto itt1 = it1;
+ for (size_type l = 0; l < q; ++l, ++it) {
+ if (l) itt1 += s1;
+ auto ittt1 = itt1, ittt2 = it2;
+ *it = *ittt1 * (*ittt2);
+ for (size_type m = 1; m < N; ++m) {
+ ittt1 += s1_qq, ittt2 += s2_qq; *it += *ittt1 * (*ittt2);
+ }
+ }
+ }
+ }
return 0;
}
-
- ga_instruction_elementary_transformation_grad_base
- (base_tensor &t_, const base_tensor &Z_, size_type q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_copy_grad_base(t_in, Z_, q),
- ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ ga_instruction_reduction_opt0_2_unrolled(base_tensor &t_, base_tensor
&tc1_,
+ base_tensor &tc2_, size_type q_)
+ : t(t_), tc1(tc1_), tc2(tc2_), q(q_) {}
};
- struct ga_instruction_elementary_transformation_hess_base
- : public ga_instruction_copy_hess_base,
- ga_instruction_elementary_transformation_base {
- // Z(ndof,target_dim,N*N) --> t_out(Qmult*ndof,Qmult*target_dim,N,N)
+ // Performs Ani Bmi -> Cmn
+ template <int N, int Q>
+ struct ga_instruction_reduction_opt0_2_dunrolled : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: Hessian of test functions with elementary "
- "transformation");
- size_type ndof = Z.sizes()[0];
- size_type Qmult = qdim / Z.sizes()[1];
- t_in.adjust_sizes(t_out.sizes());
- ga_instruction_copy_hess_base::exec();
- do_transformation(ndof*Qmult);
+ GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*Q
+ << " optimized for vectorized second tensor of type 2");
+ size_type s1 = tc1.size()/(N*Q), s2 = tc2.size()/(N*Q), s2_q = s2/Q;
+ size_type s1_qq = s1*Q, s2_qq = s2*Q;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
+
+ auto it = t.begin(), it1 = tc1.begin();
+ for (size_type i = 0; i < s1; ++i, ++it1) {
+ auto it2 = tc2.begin();
+ for (size_type j = 0; j < s2_q; ++j) {
+ if (j) it2+=Q;
+ auto itt1 = it1;
+ for (size_type l = 0; l < Q; ++l, ++it) {
+ if (l) itt1 += s1;
+ auto ittt1 = itt1, ittt2 = it2;
+ *it = *ittt1 * (*ittt2);
+ for (size_type m = 1; m < N; ++m) {
+ ittt1 += s1_qq, ittt2 += s2_qq; *it += *ittt1 * (*ittt2);
+ }
+ }
+ }
+ }
return 0;
}
-
- ga_instruction_elementary_transformation_hess_base
- (base_tensor &t_, const base_tensor &Z_, size_type q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_copy_hess_base(t_in, Z_, q),
- ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ ga_instruction_reduction_opt0_2_dunrolled
+ (base_tensor &t_, base_tensor &tc1_, base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_elementary_transformation_diverg_base
- : public ga_instruction_copy_diverg_base,
- ga_instruction_elementary_transformation_base {
- // Z(ndof,target_dim,N) --> t_out(Qmult*ndof)
+ // Performs Ani Bmi -> Cmn
+ struct ga_instruction_reduction_opt2_0 : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type n, q;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: divergence of test functions with elementary
"
- "transformation");
- size_type ndof = Z.sizes()[0];
- size_type Qmult = qdim / Z.sizes()[1];
- t_in.adjust_sizes(t_out.sizes());
- ga_instruction_copy_diverg_base::exec();
- do_transformation(ndof*Qmult);
+ GA_DEBUG_INFO("Instruction: reduction operation of size " << n*q <<
+ " optimized for vectorized second tensor of type 2");
+ size_type nn = n*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn;
+ size_type s1_q = s1/q, s1_qq = s1*q, s2_qq = s2*q;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
+
+ auto it = t.begin();
+ for (size_type i = 0; i < s1_q; ++i) {
+ auto it1 = tc1.begin() + i*q;
+ for (size_type l = 0; l < q; ++l) {
+ auto it2 = tc2.begin() + l*s2;
+ for (size_type j = 0; j < s2; ++j, ++it, ++it2) {
+ auto itt1 = it1, itt2 = it2;
+ *it = *itt1 * (*itt2);
+ for (size_type m = 1; m < n; ++m) {
+ itt1 += s1_qq, itt2 += s2_qq; *it += *itt1 * (*itt2);
+ }
+ }
+ }
+ }
return 0;
}
-
- ga_instruction_elementary_transformation_diverg_base
- (base_tensor &t_, const base_tensor &Z_, size_type q,
- pelementary_transformation e, const mesh_fem &mf_,
- fem_interpolation_context &ctx_, base_matrix &M_,
- const mesh_fem **mf_M_, size_type &icv_)
- : ga_instruction_copy_diverg_base(t_in, Z_, q),
- ga_instruction_elementary_transformation_base(t_, e, mf_, ctx_, M_,
- mf_M_, icv_) {}
+ ga_instruction_reduction_opt2_0(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type n_,
+ size_type q_)
+ : t(t_), tc1(tc1_), tc2(tc2_), n(n_), q(q_) { }
};
-
- struct ga_instruction_add : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1, &tc2;
+ // Performs Ani Bmi -> Cmn
+ template <int N>
+ struct ga_instruction_reduction_opt2_0_unrolled : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type q;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: addition");
- GA_DEBUG_ASSERT(t.size() == tc1.size(),
- "internal error " << t.size() << " != " << tc1.size());
- GA_DEBUG_ASSERT(t.size() == tc2.size(),
- "internal error " << t.size() << " != " << tc2.size());
- gmm::add(tc1.as_vector(), tc2.as_vector(), t.as_vector());
+ GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*q
+ << " optimized for vectorized second tensor of type 2");
+ size_type nn = N*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn;
+ size_type s1_q = s1/q, s1_qq = s1*q, s2_qq = s2*q;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
+
+ auto it = t.begin(), it1 = tc1.begin();
+ for (size_type i = 0; i < s1_q; ++i, it1 += q) {
+ for (size_type l = 0; l < q; ++l) {
+ auto it2 = tc2.begin() + l*s2;
+ for (size_type j = 0; j < s2; ++j, ++it, ++it2) {
+ auto itt1 = it1, itt2 = it2;
+ *it = *itt1 * (*itt2);
+ for (size_type m = 1; m < N; ++m) {
+ itt1 += s1_qq, itt2 += s2_qq; *it += *itt1 * (*itt2);
+ }
+ }
+ }
+ }
return 0;
}
- ga_instruction_add(base_tensor &t_,
- const base_tensor &tc1_, const base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
+ ga_instruction_reduction_opt2_0_unrolled(base_tensor &t_, base_tensor
&tc1_,
+ base_tensor &tc2_, size_type q_)
+ : t(t_), tc1(tc1_), tc2(tc2_), q(q_) {}
};
- struct ga_instruction_add_to : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
+ // Performs Ani Bmi -> Cmn
+ template <int N, int Q>
+ struct ga_instruction_reduction_opt2_0_dunrolled : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: addition");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "internal error " << t.size()
- << " incompatible with " << tc1.size());
- gmm::add(tc1.as_vector(), t.as_vector());
- return 0;
- }
- ga_instruction_add_to(base_tensor &t_, const base_tensor &tc1_)
- : t(t_), tc1(tc1_) {}
- };
+ GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*Q
+ << " optimized for vectorized second tensor of type 2");
+ size_type s1 = tc1.size()/(N*Q), s2 = tc2.size()/(N*Q);
+ size_type s1_q = s1/Q, s1_qq = s1*Q, s2_qq = s2*Q;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
- struct ga_instruction_sub : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: subtraction");
- GA_DEBUG_ASSERT(t.size() == tc1.size() && t.size() == tc2.size(),
- "internal error");
- gmm::add(tc1.as_vector(), gmm::scaled(tc2.as_vector(), scalar_type(-1)),
- t.as_vector());
+ auto it = t.begin(), it1 = tc1.begin();
+ for (size_type i = 0; i < s1_q; ++i, it1 += Q) {
+ for (size_type l = 0; l < Q; ++l) {
+ auto it2 = tc2.begin() + l*s2;
+ for (size_type j = 0; j < s2; ++j, ++it, ++it2) {
+ auto itt1 = it1, itt2 = it2;
+ *it = *itt1 * (*itt2);
+ for (size_type m = 1; m < N; ++m) {
+ itt1 += s1_qq, itt2 += s2_qq; *it += *itt1 * (*itt2);
+ }
+ }
+ }
+ }
return 0;
}
- ga_instruction_sub(base_tensor &t_,
- const base_tensor &tc1_, const base_tensor &tc2_)
+ ga_instruction_reduction_opt2_0_dunrolled
+ (base_tensor &t_, base_tensor &tc1_, base_tensor &tc2_)
: t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_opposite : public ga_instruction {
- base_tensor &t;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: multiplication with -1");
- gmm::scale(t.as_vector(), scalar_type(-1));
- return 0;
- }
- ga_instruction_opposite(base_tensor &t_) : t(t_) {}
- };
-
- struct ga_instruction_print_tensor : public ga_instruction {
- base_tensor &t;
- pga_tree_node pnode;
- const fem_interpolation_context &ctx;
- size_type &nbpt, &ipt;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: tensor print");
- cout << "Print term "; ga_print_node(pnode, cout);
- cout << " on Gauss point " << ipt << "/" << nbpt << " of element "
- << ctx.convex_num() << ": " << t << endl;
- return 0;
- }
- ga_instruction_print_tensor(base_tensor &t_, pga_tree_node pnode_,
- const fem_interpolation_context &ctx_,
- size_type &nbpt_, size_type &ipt_)
- : t(t_), pnode(pnode_), ctx(ctx_), nbpt(nbpt_), ipt(ipt_) {}
- };
-
- struct ga_instruction_copy_tensor : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
+ // Performs Ani Bmi -> Cmn
+ struct ga_instruction_reduction_opt0_1 : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type nn;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: tensor copy");
- std::copy(tc1.begin(), tc1.end(), t.begin());
- // gmm::copy(tc1.as_vector(), t.as_vector());
- return 0;
- }
- ga_instruction_copy_tensor(base_tensor &t_, const base_tensor &tc1_)
- : t(t_), tc1(tc1_) {}
- };
+ GA_DEBUG_INFO("Instruction: reduction operation of size " << nn <<
+ " optimized for vectorized second tensor of type 1");
+ size_type ss1=tc1.size(), s1 = ss1/nn, s2=tc2.size()/nn, s2_n=s2/nn;
- struct ga_instruction_clear_tensor : public ga_instruction {
- base_tensor &t;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: clear tensor");
- std::fill(t.begin(), t.end(), scalar_type(0));
+ auto it = t.begin(), it1 = tc1.begin();
+ for (size_type i = 0; i < s1; ++i, ++it1) {
+ auto it2 = tc2.begin();
+ for (size_type j = 0; j < s2_n; ++j) {
+ if (j) it2 += nn;
+ auto itt1 = it1;
+ *it++ = (*itt1) * (*it2);
+ for (size_type k = 1; k < nn; ++k)
+ { itt1 += s1; *it++ = (*itt1) * (*it2); }
+ }
+ }
return 0;
}
- ga_instruction_clear_tensor(base_tensor &t_) : t(t_) {}
+ ga_instruction_reduction_opt0_1(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type n_)
+ : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
};
- struct ga_instruction_copy_tensor_possibly_void : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: tensor copy possibly void");
- if (tc1.size())
- gmm::copy(tc1.as_vector(), t.as_vector());
- else
- gmm::clear(t.as_vector());
- return 0;
- }
- ga_instruction_copy_tensor_possibly_void(base_tensor &t_,
- const base_tensor &tc1_)
- : t(t_), tc1(tc1_) {}
- };
+ template<int N> inline void reduc_elem_unrolled_opt1_
+ (const base_vector::iterator &it, const base_vector::iterator &it1,
+ scalar_type a, size_type s1) {
+ it[N-1] = it1[(N-1)*s1] * a;
+ reduc_elem_unrolled_opt1_<N-1>(it, it1, a, s1);
+ }
+ template<> inline void reduc_elem_unrolled_opt1_<1>
+ (const base_vector::iterator &it, const base_vector::iterator &it1,
+ scalar_type a, size_type /* s1 */)
+ { *it = (*it1) * a; }
- struct ga_instruction_copy_scalar : public ga_instruction {
- scalar_type &t; const scalar_type &t1;
+ // Performs Ani Bmi -> Cmn
+ template <int N>
+ struct ga_instruction_reduction_opt0_1_unrolled : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: scalar copy");
- t = t1;
+ GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N
+ << " optimized for vectorized second tensor of type 1");
+ size_type s1 = tc1.size()/N, s2 = tc2.size()/N;
+ auto it = t.begin(), it1 = tc1.begin();
+ for (size_type i = 0; i < s1; ++i, ++it1) {
+ auto it2 = tc2.begin(), it2e = it2 + s2;
+ for (; it2 != it2e; it2 += N, it += N)
+ reduc_elem_unrolled_opt1_<N>(it, it1, *it2, s1);
+ }
return 0;
}
- ga_instruction_copy_scalar(scalar_type &t_, const scalar_type &t1_)
- : t(t_), t1(t1_) {}
+ ga_instruction_reduction_opt0_1_unrolled(base_tensor &t_, base_tensor
&tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_copy_vect : public ga_instruction {
- base_vector &t;
- const base_vector &t1;
+ // Performs Ani Bmi -> Cmn
+ struct ga_instruction_reduction_opt1_1 : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type nn;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: fixed size tensor copy");
- gmm::copy(t1, t);
- return 0;
- }
- ga_instruction_copy_vect(base_vector &t_, const base_vector &t1_)
- : t(t_), t1(t1_) {}
- };
+ GA_DEBUG_INFO("Instruction: reduction operation of size " << nn <<
+ " optimized for both vectorized tensor of type 1");
+ size_type s1 = tc1.size()/nn, s2 = tc2.size()/nn, s2_1 = s2+1;
+ GA_DEBUG_ASSERT(t.size() == s2*s1, "Internal error");
+ size_type ss1 = s1/nn, ss2 = s2/nn;
- struct ga_instruction_trace : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
- size_type n;
- // tc1(:,:,...,n,n) --> t(:,:,...)
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: Trace");
- GA_DEBUG_ASSERT(t.size()*n*n == tc1.size(), "Wrong sizes");
- size_type s = t.size() * (n+1);
- auto it = t.begin();
- auto it1 = tc1.begin();
- for (; it != t.end(); ++it, ++it1) {
- auto it2 = it1;
- *it = *it2;
- for (size_type i = 1; i < n; ++i) { it2 += s; *it += *it2; }
+ // std::fill(t.begin(), t.end(), scalar_type(0)); // Factorized
+ auto it2 = tc2.begin();
+ for (size_type j = 0; j < ss2; ++j) {
+ if (j) it2 += nn;
+ auto it1 = tc1.begin(), it = t.begin() + j*nn;
+ for (size_type i = 0; i < ss1; ++i) {
+ if (i) { it1 += nn, it += s2*nn; }
+ scalar_type a = (*it1) * (*it2);
+ auto itt = it;
+ *itt = a; itt += s2_1; *itt = a;
+ for (size_type k = 2; k < nn; ++k) { itt += s2_1; *itt = a; }
+ }
}
return 0;
}
-
- ga_instruction_trace(base_tensor &t_, const base_tensor &tc1_, size_type
n_)
- : t(t_), tc1(tc1_), n(n_) {}
+ ga_instruction_reduction_opt1_1(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type n_)
+ : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
};
- struct ga_instruction_deviator : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
- size_type n;
- // tc1(:,:,...,n,n) --> t(:,:,...,n,n)
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: Deviator");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- gmm::copy(tc1.as_vector(), t.as_vector());
- size_type nb = t.size()/(n*n);
- size_type s = nb * (n+1), j = 0;
- base_tensor::iterator it = t.begin();
- base_tensor::const_iterator it1 = tc1.begin();
- for (; j < nb; ++it, ++it1, ++j) {
- scalar_type tr(0);
- base_tensor::const_iterator it2 = it1;
- tr += *it2;
- for (size_type i = 1; i < n; ++i) { it2 += s; tr += *it2; }
- tr /= scalar_type(n);
+ template<int N> inline scalar_type reduc_elem_unrolled__
+ (base_tensor::iterator &it1, base_tensor::iterator &it2,
+ size_type s1, size_type s2) {
+ return (it1[(N-1)*s1])*(it2[(N-1)*s2])
+ + reduc_elem_unrolled__<N-1>(it1, it2, s1, s2);
+ }
+ template<> inline scalar_type reduc_elem_unrolled__<1>
+ (base_tensor::iterator &it1, base_tensor::iterator &it2,
+ size_type /*s1*/, size_type /*s2*/)
+ { return (*it1)*(*it2); }
- base_tensor::iterator it3 = it;
- *it3 -= tr;
- for (size_type i = 1; i < n; ++i) { it3 += s; *it3 -= tr; }
+ // Performs Ani Bmi -> Cmn. Unrolled operation.
+ template<int N> struct ga_instruction_reduction_unrolled
+ : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N);
+ size_type s1 = tc1.size()/N, s2 = tc2.size()/N;
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error, " << t.size()
+ << " != " << s1 << "*" << s2);
+ base_tensor::iterator it1=tc1.begin(), it2=tc2.begin(), it2end=it2 + s2;
+ for (base_tensor::iterator it = t.begin(); it != t.end(); ++it) {
+ *it = reduc_elem_unrolled__<N>(it1, it2, s1, s2);
+ ++it2; if (it2 == it2end) { it2 = tc2.begin(), ++it1; }
}
return 0;
}
-
- ga_instruction_deviator(base_tensor &t_, const base_tensor &tc1_,
- size_type n_)
- : t(t_), tc1(tc1_), n(n_) {}
+ ga_instruction_reduction_unrolled(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_transpose : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: transpose");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- size_type order = t.sizes().size();
- size_type s1 = t.sizes()[order-2], s2 = t.sizes()[order-1];
- size_type s = t.size() / (s1*s2);
- for (size_type i = 0; i < s1; ++i)
- for (size_type j = 0; j < s2; ++j) {
- base_tensor::iterator it = t.begin() + s*(i + s1*j);
- base_tensor::const_iterator it1 = tc1.begin() + s*(j + s2*i);
- for (size_type k = 0; k < s; ++k) *it++ = *it1++;
- }
- return 0;
- }
- ga_instruction_transpose(base_tensor &t_, const base_tensor &tc1_)
- : t(t_), tc1(tc1_) {}
- };
-
- struct ga_instruction_transpose_test : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: copy tensor and transpose test functions");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- GA_DEBUG_ASSERT(t.sizes().size() >= 2, "Wrong sizes");
-
- size_type s1 = t.sizes()[0], s2 = t.sizes()[1], s3 = s1*s2;
- size_type s = t.size() / s3;
- base_tensor::iterator it = t.begin();
- for (size_type k = 0; k < s; ++k)
- for (size_type j = 0; j < s2; ++j)
- for (size_type i = 0; i < s1; ++i, ++it)
- *it = tc1[j+s2*i+k*s3];
- return 0;
- }
- ga_instruction_transpose_test(base_tensor &t_, const base_tensor &tc1_)
- : t(t_), tc1(tc1_) {}
- };
-
- struct ga_instruction_sym : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: symmetric part");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- size_type order = t.sizes().size();
- size_type s1 = t.sizes()[order-2], s2 = t.sizes()[order-1];
- size_type s = t.size() / (s1*s2);
- for (size_type i = 0; i < s1; ++i)
- for (size_type j = 0; j < s2; ++j) {
- base_tensor::iterator it = t.begin() + s*(i + s1*j);
- base_tensor::const_iterator it1 = tc1.begin() + s*(i + s1*j),
- it1T = tc1.begin() + s*(j + s2*i);
- for (size_type k = 0; k < s; ++k) *it++ = 0.5*(*it1++ + *it1T++);
- }
- return 0;
- }
- ga_instruction_sym(base_tensor &t_, const base_tensor &tc1_)
- : t(t_), tc1(tc1_) {}
- };
-
- struct ga_instruction_skew : public ga_instruction {
- base_tensor &t;
- const base_tensor &tc1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: skew-symmetric part");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- size_type order = t.sizes().size();
- size_type s1 = t.sizes()[order-2], s2 = t.sizes()[order-1];
- size_type s = t.size() / (s1*s2);
- for (size_type i = 0; i < s1; ++i)
- for (size_type j = 0; j < s2; ++j) {
- base_tensor::iterator it = t.begin() + s*(i + s1*j);
- base_tensor::const_iterator it1 = tc1.begin() + s*(i + s1*j),
- it1T = tc1.begin() + s*(j + s2*i);
- for (size_type k = 0; k < s; ++k) *it++ = 0.5*(*it1++ - *it1T++);
- }
- return 0;
- }
- ga_instruction_skew(base_tensor &t_, const base_tensor &tc1_)
- : t(t_), tc1(tc1_) {}
- };
-
- struct ga_instruction_scalar_add : public ga_instruction {
- scalar_type &t;
- const scalar_type &c, &d;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: scalar addition");
- t = c + d;
- return 0;
- }
- ga_instruction_scalar_add(scalar_type &t_, const scalar_type &c_,
- const scalar_type &d_)
- : t(t_), c(c_), d(d_) {}
- };
+ template<int N, int S2> inline void reduc_elem_d_unrolled__
+ (base_tensor::iterator &it, base_tensor::iterator &it1,
+ base_tensor::iterator &it2, size_type s1, size_type s2) {
+ *it++ = reduc_elem_unrolled__<N>(it1, it2, s1, s2);
+ reduc_elem_d_unrolled__<N, S2-1>(it, it1, ++it2, s1, s2);
+ }
+ // A Repeated definition is following because partial specialization
+ // of functions is not allowed in C++ for the moment.
+ // The gain in assembly time is small compared to the simply unrolled version
+ template<> inline void reduc_elem_d_unrolled__<1, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<2, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<3, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<4, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<5, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<6, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<7, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<8, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<9, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<10, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<11, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<12, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<13, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<14, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<15, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
+ template<> inline void reduc_elem_d_unrolled__<16, 0>
+ (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
+ base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- struct ga_instruction_scalar_sub : public ga_instruction {
- scalar_type &t;
- const scalar_type &c, &d;
+ // Performs Ani Bmi -> Cmn. Automatically doubly unrolled operation
+ // (for uniform meshes).
+ template<int N, int S2> struct ga_ins_red_d_unrolled
+ : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: scalar subtraction");
- t = c - d;
+ GA_DEBUG_INFO("Instruction: doubly unrolled reduction operation of size "
+ << S2 << "x" << N);
+ size_type s1 = tc1.size()/N, s2 = tc2.size()/N;
+ GA_DEBUG_ASSERT(s2 == S2, "Internal error");
+ GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error, " << t.size()
+ << " != " << s1 << "*" << s2);
+ base_tensor::iterator it = t.begin(), it1 = tc1.begin();
+ for (size_type ii = 0; ii < s1; ++ii, ++it1) {
+ base_tensor::iterator it2 = tc2.begin();
+ reduc_elem_d_unrolled__<N, S2>(it, it1, it2, s1, s2);
+ }
+ GA_DEBUG_ASSERT(it == t.end(), "Internal error");
return 0;
}
- ga_instruction_scalar_sub(scalar_type &t_, const scalar_type &c_,
- const scalar_type &d_)
- : t(t_), c(c_), d(d_) {}
+ ga_ins_red_d_unrolled(base_tensor &t_, base_tensor &tc1_, base_tensor
&tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
- struct ga_instruction_scalar_scalar_mult : public ga_instruction {
- scalar_type &t;
- const scalar_type &c, &d;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: scalar multiplication");
- t = c * d;
- return 0;
- }
- ga_instruction_scalar_scalar_mult(scalar_type &t_, const scalar_type &c_,
- const scalar_type &d_)
- : t(t_), c(c_), d(d_) {}
- };
- struct ga_instruction_scalar_scalar_div : public ga_instruction {
- scalar_type &t;
- const scalar_type &c, &d;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: scalar division");
- t = c / d;
- return 0;
- }
- ga_instruction_scalar_scalar_div(scalar_type &t_, const scalar_type &c_,
- const scalar_type &d_)
- : t(t_), c(c_), d(d_) {}
- };
+ pga_instruction ga_instruction_reduction_switch
+ (assembly_tensor &t_, assembly_tensor &tc1_, assembly_tensor &tc2_,
+ size_type n, bool &to_clear) {
+ base_tensor &t = t_.tensor(), &tc1 = tc1_.tensor(), &tc2 = tc2_.tensor();
- struct ga_instruction_scalar_mult : public ga_instruction {
- base_tensor &t, &tc1;
- const scalar_type &c;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: multiplication of a tensor by a scalar " <<
c);
- gmm::copy(gmm::scaled(tc1.as_vector(), c), t.as_vector());
- return 0;
+ if (tc1_.sparsity() == 1 && tc2_.sparsity() == 1 &&
+ tc1_.qdim() == n && tc2_.qdim() == n) {
+ to_clear = true;
+ t_.set_sparsity(10, tc1_.qdim());
+ return std::make_shared<ga_instruction_reduction_opt1_1>(t, tc1, tc2, n);
}
- ga_instruction_scalar_mult(base_tensor &t_, base_tensor &tc1_,
- const scalar_type &c_)
- : t(t_), tc1(tc1_), c(c_) {}
- };
-
- struct ga_instruction_scalar_div : public ga_instruction {
- base_tensor &t, &tc1;
- const scalar_type &c;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: division of a tensor by a scalar");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- base_tensor::iterator it = t.begin(), it1 = tc1.begin();
- for (; it != t.end(); ++it, ++it1) *it = *it1/c;
- return 0;
+ if (tc2_.sparsity() == 1) {
+ switch(n) {
+ case 2:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<2>>
+ (t, tc1, tc2);
+ case 3:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<3>>
+ (t, tc1, tc2);
+ case 4:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<4>>
+ (t, tc1, tc2);
+ case 5:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<5>>
+ (t, tc1, tc2);
+ default:
+ return std::make_shared<ga_instruction_reduction_opt0_1>(t,tc1,tc2, n);
+ }
}
- ga_instruction_scalar_div(base_tensor &t_, base_tensor &tc1_,
- const scalar_type &c_)
- : t(t_), tc1(tc1_), c(c_) {}
- };
-
- struct ga_instruction_dotmult : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: componentwise multiplication");
- size_type s2 = tc2.size(), s1_1 = tc1.size() / s2;
- GA_DEBUG_ASSERT(t.size() == s1_1*s2, "Wrong sizes");
-
- base_tensor::iterator it = t.begin();
- for (size_type i = 0; i < s2; ++i)
- for (size_type m = 0; m < s1_1; ++m, ++it)
- *it = tc1[m+s1_1*i] * tc2[i];
- return 0;
- }
- ga_instruction_dotmult(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- struct ga_instruction_dotdiv : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: componentwise division");
- size_type s2 = tc2.size(), s1_1 = tc1.size() / s2;
- GA_DEBUG_ASSERT(t.size() == s1_1*s2, "Wrong sizes");
-
- base_tensor::iterator it = t.begin();
- for (size_type i = 0; i < s2; ++i)
- for (size_type m = 0; m < s1_1; ++m, ++it)
- *it = tc1[m+s1_1*i] / tc2[i];
- return 0;
- }
- ga_instruction_dotdiv(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- // Performs Ami Bni -> Cmni
- struct ga_instruction_dotmult_spec : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: specific componentwise "
- "multiplication");
- size_type s2_1 = tc2.sizes()[0], s2_2 = tc2.size() / s2_1;
- size_type s1_1 = tc1.size() / s2_2;
-
- base_tensor::iterator it = t.begin();
- for (size_type i = 0; i < s2_2; ++i)
- for (size_type n = 0; n < s2_1; ++n)
- for (size_type m = 0; m < s1_1; ++m, ++it)
- *it = tc1[m+s1_1*i] * tc2[n+s2_1*i];
- GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
- return 0;
- }
- ga_instruction_dotmult_spec(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- // Performs Amij Bjk -> Cmik. To be optimized
- struct ga_instruction_matrix_mult : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: matrix multiplication");
- size_type order = tc2.sizes().size();
- size_type s2_1 = tc2.sizes()[order-2];
- size_type s2_2 = tc2.sizes()[order-1];
- size_type s1 = tc1.size() / s2_1;
- size_type s2 = tc2.size() / (s2_1*s2_2);
-
- base_tensor::iterator it = t.begin();
- for (size_type k = 0; k < s2_2; ++k)
- for (size_type i = 0; i < s1; ++i)
- for (size_type m = 0; m < s2; ++m, ++it) {
- *it = scalar_type(0);
- for (size_type j = 0; j < s2_1; ++j)
- *it += tc1[i+j*s1] * tc2[m+j*s2+k*s2_1*s2];
- }
- GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
- return 0;
- }
- ga_instruction_matrix_mult(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- // Performs Amij Bnjk -> Cmnik. To be optimized
- struct ga_instruction_matrix_mult_spec : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: specific matrix multiplication");
- size_type s1_1 = tc1.sizes()[0];
- size_type s1_2 = tc1.sizes()[1];
- // size_type s1_3 = tc1.sizes()[2];
- size_type s2_1 = tc2.sizes()[0];
- size_type s2_2 = tc2.sizes()[1];
- size_type s2_3 = tc2.sizes()[2];
-
- base_tensor::iterator it = t.begin();
- for (size_type k = 0; k < s2_3; ++k)
- for (size_type i = 0; i < s1_2; ++i)
- for (size_type n = 0; n < s2_1; ++n)
- for (size_type m = 0; m < s1_1; ++m, ++it) {
- *it = scalar_type(0);
- for (size_type j = 0; j < s2_2; ++j)
- *it += tc1[m+i*s1_1+j*s1_1*s1_2] * tc2[n+j*s2_1+k*s2_1*s2_2];
- }
- GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
- return 0;
- }
- ga_instruction_matrix_mult_spec(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
-
- // Performs Ani Bmi -> Cmn
- struct ga_instruction_reduction : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type nn;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: reduction operation of size " << nn);
-#if GA_USES_BLAS
- long m = int(tc1.size()/nn), k = int(nn), n = int(tc2.size()/nn);
- long lda = m, ldb = n, ldc = m;
- char T = 'T', N = 'N';
- scalar_type alpha(1), beta(0);
- gmm::dgemm_(&N, &T, &m, &n, &k, &alpha, &(tc1[0]), &lda, &(tc2[0]), &ldb,
- &beta, &(t[0]), &ldc);
-#else
- size_type s1 = tc1.size()/nn, s2 = tc2.size()/nn;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
-
- auto it1=tc1.begin(), it2=tc2.begin(), it2end=it2 + s2;
- for (auto it = t.begin(); it != t.end(); ++it) {
- auto it11 = it1, it22 = it2;
- scalar_type a = (*it11) * (*it22);
- for (size_type i = 1; i < nn; ++i)
- { it11 += s1; it22 += s2; a += (*it11) * (*it22); }
- *it = a;
- ++it2; if (it2 == it2end) { it2 = tc2.begin(), ++it1; }
- }
- // auto it = t.begin(); // Unoptimized version.
- // for (size_type i = 0; i < s1; ++i)
- // for (size_type j = 0; j < s2; ++j, ++it) {
- // *it = scalar_type(0);
- // for (size_type k = 0; k < nn; ++k)
- // *it += tc1[i+k*s1] * tc2[j+k*s2];
- // }
-#endif
- return 0;
- }
- ga_instruction_reduction(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type n_)
- : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
- };
-
- // Performs Ani Bmi -> Cmn
- struct ga_instruction_reduction_opt0_2 : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type n, q;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: reduction operation of size " << n*q <<
- " optimized for vectorized second tensor of type 2");
- size_type nn = n*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn, s2_q = s2/q;
- size_type s1_qq = s1*q, s2_qq = s2*q;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
-
- auto it = t.begin(), it1 = tc1.begin();
- for (size_type i = 0; i < s1; ++i, ++it1) {
- auto it2 = tc2.begin();
- for (size_type j = 0; j < s2_q; ++j) {
- if (j) it2+=q;
- auto itt1 = it1;
- for (size_type l = 0; l < q; ++l, ++it) {
- if (l) itt1 += s1;
- auto ittt1 = itt1, ittt2 = it2;
- *it = *ittt1 * (*ittt2);
- for (size_type m = 1; m < n; ++m) {
- ittt1 += s1_qq, ittt2 += s2_qq; *it += *ittt1 * (*ittt2);
- }
- }
- }
- }
- // base_tensor u = t;
- // ga_instruction_reduction toto(t, tc1, tc2, n*q);
- // toto.exec();
- // GMM_ASSERT1(gmm::vect_dist2(t.as_vector(), u.as_vector()) < 1E-9,
"Erroneous");
- return 0;
- }
- ga_instruction_reduction_opt0_2(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type n_,
- size_type q_)
- : t(t_), tc1(tc1_), tc2(tc2_), n(n_), q(q_) {}
- };
-
- // Performs Ani Bmi -> Cmn
- template <int N>
- struct ga_instruction_reduction_opt0_2_unrolled : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type q;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*q
- << " optimized for vectorized second tensor of type 2");
- size_type nn = N*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn, s2_q = s2/q;
- size_type s1_qq = s1*q, s2_qq = s2*q;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
-
- auto it = t.begin(), it1 = tc1.begin();
- for (size_type i = 0; i < s1; ++i, ++it1) {
- auto it2 = tc2.begin();
- for (size_type j = 0; j < s2_q; ++j) {
- if (j) it2+=q;
- auto itt1 = it1;
- for (size_type l = 0; l < q; ++l, ++it) {
- if (l) itt1 += s1;
- auto ittt1 = itt1, ittt2 = it2;
- *it = *ittt1 * (*ittt2);
- for (size_type m = 1; m < N; ++m) {
- ittt1 += s1_qq, ittt2 += s2_qq; *it += *ittt1 * (*ittt2);
- }
- }
- }
- }
- return 0;
- }
- ga_instruction_reduction_opt0_2_unrolled(base_tensor &t_, base_tensor
&tc1_,
- base_tensor &tc2_, size_type q_)
- : t(t_), tc1(tc1_), tc2(tc2_), q(q_) {}
- };
-
- // Performs Ani Bmi -> Cmn
- template <int N, int Q>
- struct ga_instruction_reduction_opt0_2_dunrolled : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*Q
- << " optimized for vectorized second tensor of type 2");
- size_type s1 = tc1.size()/(N*Q), s2 = tc2.size()/(N*Q), s2_q = s2/Q;
- size_type s1_qq = s1*Q, s2_qq = s2*Q;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
-
- auto it = t.begin(), it1 = tc1.begin();
- for (size_type i = 0; i < s1; ++i, ++it1) {
- auto it2 = tc2.begin();
- for (size_type j = 0; j < s2_q; ++j) {
- if (j) it2+=Q;
- auto itt1 = it1;
- for (size_type l = 0; l < Q; ++l, ++it) {
- if (l) itt1 += s1;
- auto ittt1 = itt1, ittt2 = it2;
- *it = *ittt1 * (*ittt2);
- for (size_type m = 1; m < N; ++m) {
- ittt1 += s1_qq, ittt2 += s2_qq; *it += *ittt1 * (*ittt2);
- }
- }
- }
- }
- return 0;
- }
- ga_instruction_reduction_opt0_2_dunrolled
- (base_tensor &t_, base_tensor &tc1_, base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- // Performs Ani Bmi -> Cmn
- struct ga_instruction_reduction_opt2_0 : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type n, q;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: reduction operation of size " << n*q <<
- " optimized for vectorized second tensor of type 2");
- size_type nn = n*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn;
- size_type s1_q = s1/q, s1_qq = s1*q, s2_qq = s2*q;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
-
- auto it = t.begin();
- for (size_type i = 0; i < s1_q; ++i) {
- auto it1 = tc1.begin() + i*q;
- for (size_type l = 0; l < q; ++l) {
- auto it2 = tc2.begin() + l*s2;
- for (size_type j = 0; j < s2; ++j, ++it, ++it2) {
- auto itt1 = it1, itt2 = it2;
- *it = *itt1 * (*itt2);
- for (size_type m = 1; m < n; ++m) {
- itt1 += s1_qq, itt2 += s2_qq; *it += *itt1 * (*itt2);
- }
- }
- }
- }
- return 0;
- }
- ga_instruction_reduction_opt2_0(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type n_,
- size_type q_)
- : t(t_), tc1(tc1_), tc2(tc2_), n(n_), q(q_) { }
- };
-
- // Performs Ani Bmi -> Cmn
- template <int N>
- struct ga_instruction_reduction_opt2_0_unrolled : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type q;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*q
- << " optimized for vectorized second tensor of type 2");
- size_type nn = N*q, s1 = tc1.size()/nn, s2 = tc2.size()/nn;
- size_type s1_q = s1/q, s1_qq = s1*q, s2_qq = s2*q;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
-
- auto it = t.begin(), it1 = tc1.begin();
- for (size_type i = 0; i < s1_q; ++i, it1 += q) {
- for (size_type l = 0; l < q; ++l) {
- auto it2 = tc2.begin() + l*s2;
- for (size_type j = 0; j < s2; ++j, ++it, ++it2) {
- auto itt1 = it1, itt2 = it2;
- *it = *itt1 * (*itt2);
- for (size_type m = 1; m < N; ++m) {
- itt1 += s1_qq, itt2 += s2_qq; *it += *itt1 * (*itt2);
- }
- }
- }
- }
- return 0;
- }
- ga_instruction_reduction_opt2_0_unrolled(base_tensor &t_, base_tensor
&tc1_,
- base_tensor &tc2_, size_type q_)
- : t(t_), tc1(tc1_), tc2(tc2_), q(q_) {}
- };
-
- // Performs Ani Bmi -> Cmn
- template <int N, int Q>
- struct ga_instruction_reduction_opt2_0_dunrolled : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N*Q
- << " optimized for vectorized second tensor of type 2");
- size_type s1 = tc1.size()/(N*Q), s2 = tc2.size()/(N*Q);
- size_type s1_q = s1/Q, s1_qq = s1*Q, s2_qq = s2*Q;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error");
-
- auto it = t.begin(), it1 = tc1.begin();
- for (size_type i = 0; i < s1_q; ++i, it1 += Q) {
- for (size_type l = 0; l < Q; ++l) {
- auto it2 = tc2.begin() + l*s2;
- for (size_type j = 0; j < s2; ++j, ++it, ++it2) {
- auto itt1 = it1, itt2 = it2;
- *it = *itt1 * (*itt2);
- for (size_type m = 1; m < N; ++m) {
- itt1 += s1_qq, itt2 += s2_qq; *it += *itt1 * (*itt2);
- }
- }
- }
- }
- return 0;
- }
- ga_instruction_reduction_opt2_0_dunrolled
- (base_tensor &t_, base_tensor &tc1_, base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- // Performs Ani Bmi -> Cmn
- struct ga_instruction_reduction_opt0_1 : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type nn;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: reduction operation of size " << nn <<
- " optimized for vectorized second tensor of type 1");
- size_type ss1=tc1.size(), s1 = ss1/nn, s2=tc2.size()/nn, s2_n=s2/nn;
-
- auto it = t.begin(), it1 = tc1.begin();
- for (size_type i = 0; i < s1; ++i, ++it1) {
- auto it2 = tc2.begin();
- for (size_type j = 0; j < s2_n; ++j) {
- if (j) it2 += nn;
- auto itt1 = it1;
- *it++ = (*itt1) * (*it2);
- for (size_type k = 1; k < nn; ++k)
- { itt1 += s1; *it++ = (*itt1) * (*it2); }
- }
- }
- return 0;
- }
- ga_instruction_reduction_opt0_1(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type n_)
- : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
- };
-
- template<int N> inline void reduc_elem_unrolled_opt1_
- (const base_vector::iterator &it, const base_vector::iterator &it1,
- scalar_type a, size_type s1) {
- it[N-1] = it1[(N-1)*s1] * a;
- reduc_elem_unrolled_opt1_<N-1>(it, it1, a, s1);
- }
- template<> inline void reduc_elem_unrolled_opt1_<1>
- (const base_vector::iterator &it, const base_vector::iterator &it1,
- scalar_type a, size_type /* s1 */)
- { *it = (*it1) * a; }
-
- // Performs Ani Bmi -> Cmn
- template <int N>
- struct ga_instruction_reduction_opt0_1_unrolled : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N
- << " optimized for vectorized second tensor of type 1");
- size_type s1 = tc1.size()/N, s2 = tc2.size()/N;
- auto it = t.begin(), it1 = tc1.begin();
- for (size_type i = 0; i < s1; ++i, ++it1) {
- auto it2 = tc2.begin(), it2e = it2 + s2;
- for (; it2 != it2e; it2 += N, it += N)
- reduc_elem_unrolled_opt1_<N>(it, it1, *it2, s1);
- }
- return 0;
- }
- ga_instruction_reduction_opt0_1_unrolled(base_tensor &t_, base_tensor
&tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- // Performs Ani Bmi -> Cmn
- struct ga_instruction_reduction_opt1_1 : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type nn;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: reduction operation of size " << nn <<
- " optimized for both vectorized tensor of type 1");
- size_type s1 = tc1.size()/nn, s2 = tc2.size()/nn, s2_1 = s2+1;
- GA_DEBUG_ASSERT(t.size() == s2*s1, "Internal error");
- size_type ss1 = s1/nn, ss2 = s2/nn;
-
- // std::fill(t.begin(), t.end(), scalar_type(0)); // Factorized
- auto it2 = tc2.begin();
- for (size_type j = 0; j < ss2; ++j) {
- if (j) it2 += nn;
- auto it1 = tc1.begin(), it = t.begin() + j*nn;
- for (size_type i = 0; i < ss1; ++i) {
- if (i) { it1 += nn, it += s2*nn; }
- scalar_type a = (*it1) * (*it2);
- auto itt = it;
- *itt = a; itt += s2_1; *itt = a;
- for (size_type k = 2; k < nn; ++k) { itt += s2_1; *itt = a; }
- }
- }
- return 0;
- }
- ga_instruction_reduction_opt1_1(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type n_)
- : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
- };
-
-
-
- template<int N> inline scalar_type reduc_elem_unrolled__
- (base_tensor::iterator &it1, base_tensor::iterator &it2,
- size_type s1, size_type s2) {
- return (it1[(N-1)*s1])*(it2[(N-1)*s2])
- + reduc_elem_unrolled__<N-1>(it1, it2, s1, s2);
- }
- template<> inline scalar_type reduc_elem_unrolled__<1>
- (base_tensor::iterator &it1, base_tensor::iterator &it2,
- size_type /*s1*/, size_type /*s2*/)
- { return (*it1)*(*it2); }
-
- // Performs Ani Bmi -> Cmn. Unrolled operation.
- template<int N> struct ga_instruction_reduction_unrolled
- : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: unrolled reduction operation of size " << N);
- size_type s1 = tc1.size()/N, s2 = tc2.size()/N;
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error, " << t.size()
- << " != " << s1 << "*" << s2);
- base_tensor::iterator it1=tc1.begin(), it2=tc2.begin(), it2end=it2 + s2;
- for (base_tensor::iterator it = t.begin(); it != t.end(); ++it) {
- *it = reduc_elem_unrolled__<N>(it1, it2, s1, s2);
- ++it2; if (it2 == it2end) { it2 = tc2.begin(), ++it1; }
- }
- return 0;
- }
- ga_instruction_reduction_unrolled(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- template<int N, int S2> inline void reduc_elem_d_unrolled__
- (base_tensor::iterator &it, base_tensor::iterator &it1,
- base_tensor::iterator &it2, size_type s1, size_type s2) {
- *it++ = reduc_elem_unrolled__<N>(it1, it2, s1, s2);
- reduc_elem_d_unrolled__<N, S2-1>(it, it1, ++it2, s1, s2);
- }
- // A Repeated definition is following because partial specialization
- // of functions is not allowed in C++ for the moment.
- // The gain in assembly time is small compared to the simply unrolled version
- template<> inline void reduc_elem_d_unrolled__<1, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<2, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<3, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<4, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<5, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<6, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<7, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<8, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<9, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<10, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<11, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<12, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<13, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<14, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<15, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
- template<> inline void reduc_elem_d_unrolled__<16, 0>
- (base_tensor::iterator &/* it */, base_tensor::iterator &/* it1 */,
- base_tensor::iterator &/* it2 */, size_type /* s1 */, size_type /* s2 */) {
}
-
- // Performs Ani Bmi -> Cmn. Automatically doubly unrolled operation
- // (for uniform meshes).
- template<int N, int S2> struct ga_ins_red_d_unrolled
- : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: doubly unrolled reduction operation of size "
- << S2 << "x" << N);
- size_type s1 = tc1.size()/N, s2 = tc2.size()/N;
- GA_DEBUG_ASSERT(s2 == S2, "Internal error");
- GA_DEBUG_ASSERT(t.size() == s1*s2, "Internal error, " << t.size()
- << " != " << s1 << "*" << s2);
- base_tensor::iterator it = t.begin(), it1 = tc1.begin();
- for (size_type ii = 0; ii < s1; ++ii, ++it1) {
- base_tensor::iterator it2 = tc2.begin();
- reduc_elem_d_unrolled__<N, S2>(it, it1, it2, s1, s2);
- }
- GA_DEBUG_ASSERT(it == t.end(), "Internal error");
- return 0;
- }
- ga_ins_red_d_unrolled(base_tensor &t_, base_tensor &tc1_, base_tensor
&tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
-
- pga_instruction ga_instruction_reduction_switch
- (assembly_tensor &t_, assembly_tensor &tc1_, assembly_tensor &tc2_,
- size_type n, bool &to_clear) {
- base_tensor &t = t_.tensor(), &tc1 = tc1_.tensor(), &tc2 = tc2_.tensor();
-
- if (tc1_.sparsity() == 1 && tc2_.sparsity() == 1 &&
- tc1_.qdim() == n && tc2_.qdim() == n) {
- to_clear = true;
- t_.set_sparsity(10, tc1_.qdim());
- return std::make_shared<ga_instruction_reduction_opt1_1>(t, tc1, tc2, n);
- }
-
- if (tc2_.sparsity() == 1) {
- switch(n) {
- case 2:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<2>>
- (t, tc1, tc2);
- case 3:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<3>>
- (t, tc1, tc2);
- case 4:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<4>>
- (t, tc1, tc2);
- case 5:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<5>>
- (t, tc1, tc2);
- default:
- return std::make_shared<ga_instruction_reduction_opt0_1>(t,tc1,tc2, n);
- }
- }
- if (tc2_.sparsity() == 2) {
- size_type q2 = tc2.sizes()[1];
- size_type n2 = (tc2.sizes().size() > 2) ? tc2.sizes()[1] : 1;
- if (n2*q2 == n) {
- switch (n2) {
- case 1:
- switch (q2) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<1>>
- (t, tc1, tc2, q2);
- }
- case 2:
- switch (q2) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<2>>
- (t, tc1, tc2, q2);
- }
- case 3:
- switch (q2) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<3>>
- (t, tc1, tc2, q2);
- }
- case 4:
- return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<4>>
- (t, tc1, tc2, q2);
- case 5:
- return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<5>>
- (t, tc1, tc2, q2);
- default:
- return std::make_shared<ga_instruction_reduction_opt0_2>
- (t,tc1,tc2,n2,q2);
- }
- }
- }
- if (tc1_.sparsity() == 2) {
- size_type q1 = tc1.sizes()[1];
- size_type n1 = (tc1.sizes().size() > 2) ? tc1.sizes()[1] : 1;
- if (n1*q1 == n) {
- switch (n1) {
- case 1:
- switch (q1) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<1>>
- (t, tc1, tc2, q1);
- }
- case 2:
- switch (q1) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<2>>
- (t, tc1, tc2, q1);
- }
- case 3:
- switch (q1) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
- (t, tc1, tc2, q1);
- }
- return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
- (t, tc1, tc2, q1);
- case 4:
- return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<4>>
- (t, tc1, tc2, q1);
- case 5:
- return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<5>>
- (t, tc1, tc2, q1);
- default:
- return std::make_shared<ga_instruction_reduction_opt2_0>
- (t,tc1,tc2, n1, q1);
- }
- }
- }
-
- switch(n) {
- case 2 : return std::make_shared<ga_instruction_reduction_unrolled< 2>>
- (t, tc1, tc2);
- case 3 : return std::make_shared<ga_instruction_reduction_unrolled< 3>>
- (t, tc1, tc2);
- case 4 : return std::make_shared<ga_instruction_reduction_unrolled< 4>>
- (t, tc1, tc2);
- case 5 : return std::make_shared<ga_instruction_reduction_unrolled< 5>>
- (t, tc1, tc2);
- case 6 : return std::make_shared<ga_instruction_reduction_unrolled< 6>>
- (t, tc1, tc2);
- case 7 : return std::make_shared<ga_instruction_reduction_unrolled< 7>>
- (t, tc1, tc2);
- case 8 : return std::make_shared<ga_instruction_reduction_unrolled< 8>>
- (t, tc1, tc2);
- case 9 : return std::make_shared<ga_instruction_reduction_unrolled< 9>>
- (t, tc1, tc2);
- case 10 : return std::make_shared<ga_instruction_reduction_unrolled<10>>
- (t, tc1, tc2);
- case 11 : return std::make_shared<ga_instruction_reduction_unrolled<11>>
- (t, tc1, tc2);
- case 12 : return std::make_shared<ga_instruction_reduction_unrolled<12>>
- (t, tc1, tc2);
- case 13 : return std::make_shared<ga_instruction_reduction_unrolled<13>>
- (t, tc1, tc2);
- case 14 : return std::make_shared<ga_instruction_reduction_unrolled<14>>
- (t, tc1, tc2);
- case 15 : return std::make_shared<ga_instruction_reduction_unrolled<15>>
- (t, tc1, tc2);
- case 16 : return std::make_shared<ga_instruction_reduction_unrolled<16>>
- (t, tc1, tc2);
- default : return std::make_shared<ga_instruction_reduction>
- (t, tc1, tc2, n);
- }
- }
-
- pga_instruction ga_uniform_instruction_reduction_switch
- (assembly_tensor &t_, assembly_tensor &tc1_, assembly_tensor &tc2_,
- size_type n, bool &to_clear) {
- base_tensor &t = t_.tensor(), &tc1 = tc1_.tensor(), &tc2 = tc2_.tensor();
-
- if (tc1_.sparsity() == 1 && tc2_.sparsity() == 1 &&
- tc1_.qdim() == n && tc2_.qdim() == n) {
- to_clear = true;
- t_.set_sparsity(10, tc1_.qdim());
- return std::make_shared<ga_instruction_reduction_opt1_1>(t,tc1,tc2,n);
- }
- if (tc2_.sparsity() == 1) {
- switch(n) {
- case 2:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<2>>
- (t, tc1, tc2);
- case 3:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<3>>
- (t, tc1, tc2);
- case 4:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<4>>
- (t, tc1, tc2);
- case 5:
- return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<5>>
- (t, tc1, tc2);
- default:
- return std::make_shared<ga_instruction_reduction_opt0_1>(t,tc1,tc2, n);
- }
- }
- if (tc2_.sparsity() == 2) {
- size_type q2 = tc2.sizes()[1];
- size_type n2 = (tc2.sizes().size() > 2) ? tc2.sizes()[1] : 1;
- if (n2*q2 == n) {
- switch (n2) {
- case 1:
- switch (q2) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<1>>
- (t, tc1, tc2, q2);
- }
- case 2:
- switch (q2) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<2>>
- (t, tc1, tc2, q2);
- }
- case 3:
- switch (q2) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<3>>
- (t, tc1, tc2, q2);
- }
- case 4:
- return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<4>>
- (t, tc1, tc2, q2);
- case 5:
- return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<5>>
- (t, tc1, tc2, q2);
- default:
- return std::make_shared<ga_instruction_reduction_opt0_2>
- (t,tc1,tc2,n2,q2);
- }
- }
- }
- if (tc1_.sparsity() == 2) {
- size_type q1 = tc1.sizes()[1];
- size_type n1 = (tc1.sizes().size() > 2) ? tc1.sizes()[1] : 1;
- if (n1*q1 == n) {
- switch (n1) {
- case 1:
- switch (q1) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<1>>
- (t, tc1, tc2, q1);
- }
- case 2:
- switch (q1) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<2>>
- (t, tc1, tc2, q1);
- }
- case 3:
- switch (q1) {
- case 2:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,2>>
- (t, tc1, tc2);
- case 3:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,3>>
- (t, tc1, tc2);
- case 4:
- return
- std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,4>>
- (t, tc1, tc2);
- default :
- return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
- (t, tc1, tc2, q1);
- }
- return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
- (t, tc1, tc2, q1);
- case 4:
- return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<4>>
- (t, tc1, tc2, q1);
- case 5:
- return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<5>>
- (t, tc1, tc2, q1);
- default:
- return std::make_shared<ga_instruction_reduction_opt2_0>
- (t,tc1,tc2, n1, q1);
- }
- }
- }
-
- // Only specialized for certain values
- size_type s2 = tc2.size()/n;
- switch(s2) {
- case 1 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,1>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,1>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,1>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 2 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,2>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,2>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,2>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 3 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,3>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,3>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,3>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 4 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,4>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,4>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,4>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 5 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,5>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,5>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,5>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 6 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,6>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,6>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,6>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 7 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,7>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,7>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,7>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 8 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,8>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,8>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,8>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 9 :
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,9>>(t, tc1, tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,9>>(t, tc1, tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,9>>(t, tc1, tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- case 10:
- switch(n) {
- case 2: return std::make_shared<ga_ins_red_d_unrolled<2,10>>(t, tc1,
tc2);
- case 3: return std::make_shared<ga_ins_red_d_unrolled<3,10>>(t, tc1,
tc2);
- case 4: return std::make_shared<ga_ins_red_d_unrolled<4,10>>(t, tc1,
tc2);
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
- }
- }
-
-
- // Performs Amij Bnj -> Cmni. To be optimized.
- struct ga_instruction_spec_reduction : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type nn;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: specific reduction operation of "
- "size " << nn);
- size_type s1 = tc1.sizes()[0], s11 = tc1.size() / (s1*nn), s111 = s1*s11;
- size_type s2 = tc2.sizes()[0];
- base_tensor::iterator it = t.begin();
- for (size_type i = 0; i < s11; ++i)
- for (size_type n = 0; n < s2; ++n)
- for (size_type m = 0; m < s1; ++m, ++it) {
- *it = scalar_type(0);
- for (size_type j = 0; j < nn; ++j)
- *it += tc1[m+i*s1+j*s111] * tc2[n+j*s2];
- }
- GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
- return 0;
- }
- ga_instruction_spec_reduction(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type n_)
- : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
- };
-
- // Performs Amik Bnjk -> Cmnij. To be optimized.
- struct ga_instruction_spec2_reduction : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type nn;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: second specific reduction operation of "
- "size " << nn);
- size_type s1 = tc1.sizes()[0], s11 = tc1.size() / (s1*nn), s111 = s1*s11;
- size_type s2 = tc2.sizes()[0], s22 = tc2.size() / (s2*nn), s222 = s2*s22;
- base_tensor::iterator it = t.begin();
- for (size_type j = 0; j < s22; ++j)
- for (size_type i = 0; i < s11; ++i)
- for (size_type m = 0; m < s1; ++m)
- for (size_type n = 0; n < s2; ++n, ++it) {
- *it = scalar_type(0);
- for (size_type k = 0; k < nn; ++k)
- *it += tc1[m+i*s1+k*s111] * tc2[n+j*s2+k*s222];
- }
- GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
- return 0;
- }
- ga_instruction_spec2_reduction(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type n_)
- : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
- };
-
- // Performs Aij Bkl -> Cijkl
- struct ga_instruction_simple_tmult : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: simple tensor product");
- size_type s1 = tc1.size();
- GA_DEBUG_ASSERT(t.size() == s1 * tc2.size(), "Wrong sizes");
- base_tensor::iterator it2=tc2.begin(), it1=tc1.begin(), it1end=it1 + s1;
- for (base_tensor::iterator it = t.begin(); it != t.end(); ++it) {
- *it = *(it2) * (*it1);
- ++it1; if (it1 == it1end) { it1 = tc1.begin(), ++it2; }
- }
- return 0;
- }
- ga_instruction_simple_tmult(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- template<int S1> inline void tmult_elem_unrolled__
- (base_tensor::iterator &it, base_tensor::iterator &it1,
- base_tensor::iterator &it2) {
- *it++ = (*it1++)*(*it2);
- tmult_elem_unrolled__<S1-1>(it, it1, it2);
- }
- template<> inline void tmult_elem_unrolled__<0>
- (base_tensor::iterator &/*it*/, base_tensor::iterator &/*it1*/,
- base_tensor::iterator &/*it2*/) { }
-
- // Performs Aij Bkl -> Cijkl, partially unrolled version
- template<int S1> struct ga_instruction_simple_tmult_unrolled
- : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- size_type s2 = tc2.size();
- GA_DEBUG_INFO("Instruction: simple tensor product, unrolled with "
- << tc1.size() << " operations");
- GA_DEBUG_ASSERT(t.size() == tc1.size() * s2, "Wrong sizes");
- GA_DEBUG_ASSERT(tc1.size() == S1, "Wrong sizes");
-
- base_tensor::iterator it = t.begin(), it2 = tc2.begin();
- for (size_type ii = 0; ii < s2; ++ii, ++it2) {
- base_tensor::iterator it1 = tc1.begin();
- tmult_elem_unrolled__<S1>(it, it1, it2);
- }
- GA_DEBUG_ASSERT(it == t.end(), "Internal error");
- return 0;
- }
- ga_instruction_simple_tmult_unrolled(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
- pga_instruction ga_uniform_instruction_simple_tmult
- (base_tensor &t, base_tensor &tc1, base_tensor &tc2) {
- switch(tc1.size()) {
- case 2 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 2>>
- (t, tc1, tc2);
- case 3 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 3>>
- (t, tc1, tc2);
- case 4 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 4>>
- (t, tc1, tc2);
- case 5 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 5>>
- (t, tc1, tc2);
- case 6 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 6>>
- (t, tc1, tc2);
- case 7 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 7>>
- (t, tc1, tc2);
- case 8 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 8>>
- (t, tc1, tc2);
- case 9 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 9>>
- (t, tc1, tc2);
- case 10 : return std::make_shared<ga_instruction_simple_tmult_unrolled<10>>
- (t, tc1, tc2);
- case 11 : return std::make_shared<ga_instruction_simple_tmult_unrolled<11>>
- (t, tc1, tc2);
- case 12 : return std::make_shared<ga_instruction_simple_tmult_unrolled<12>>
- (t, tc1, tc2);
- case 13 : return std::make_shared<ga_instruction_simple_tmult_unrolled<13>>
- (t, tc1, tc2);
- case 14 : return std::make_shared<ga_instruction_simple_tmult_unrolled<14>>
- (t, tc1, tc2);
- case 15 : return std::make_shared<ga_instruction_simple_tmult_unrolled<15>>
- (t, tc1, tc2);
- case 16 : return std::make_shared<ga_instruction_simple_tmult_unrolled<16>>
- (t, tc1, tc2);
- default : return std::make_shared<ga_instruction_simple_tmult>
- (t, tc1, tc2);
- }
- }
-
-
- // Performs Ami Bnj -> Cmnij. To be optimized.
- struct ga_instruction_spec_tmult : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- size_type s1_2, s2_2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: specific tensor product");
- GA_DEBUG_ASSERT(t.size() == tc1.size() * tc2.size(), "Wrong sizes");
- size_type s1_1 = tc1.size() / s1_2;
- size_type s2_1 = tc2.size() / s2_2;
-
- base_tensor::iterator it = t.begin();
- for (size_type j = 0; j < s2_2; ++j)
- for (size_type i = 0; i < s1_2; ++i)
- for (size_type n = 0; n < s2_1; ++n)
- for (size_type m = 0; m < s1_1; ++m, ++it)
- *it = tc1[m+i*s1_1] * tc2[n+j*s2_1];
- GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
- return 0;
- }
- ga_instruction_spec_tmult(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_, size_type s1_2_,
- size_type s2_2_)
- : t(t_), tc1(tc1_), tc2(tc2_), s1_2(s1_2_), s2_2(s2_2_) {}
- };
-
- // Performs Ai Bmj -> Cmij. To be optimized.
- struct ga_instruction_spec2_tmult : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: second specific tensor product");
- GA_DEBUG_ASSERT(t.size() == tc1.size() * tc2.size(), "Wrong sizes");
- size_type s1 = tc1.size();
- size_type s2_1 = tc2.sizes()[0], s2_2 = tc2.size() / s2_1;
-
- base_tensor::iterator it = t.begin();
- for (size_type j = 0; j < s2_2; ++j)
- for (size_type i = 0; i < s1; ++i)
- for (size_type m = 0; m < s2_1; ++m, ++it)
- *it = tc1[i] * tc2[m+j*s2_1];
- GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
- return 0;
- }
- ga_instruction_spec2_tmult(base_tensor &t_, base_tensor &tc1_,
- base_tensor &tc2_)
- : t(t_), tc1(tc1_), tc2(tc2_) {}
- };
-
-
-
- struct ga_instruction_simple_c_matrix : public ga_instruction {
- base_tensor &t;
- std::vector<scalar_type *> components;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: gathering components for explicit "
- "matrix");
- GA_DEBUG_ASSERT(t.size() == components.size(), "Wrong sizes");
- for (size_type i = 0; i < components.size(); ++i)
- t[i] = *(components[i]);
- return 0;
- }
- ga_instruction_simple_c_matrix(base_tensor &t_,
- std::vector<scalar_type *> &components_)
- : t(t_), components(components_) {}
- };
-
- struct ga_instruction_c_matrix_with_tests : public ga_instruction {
- base_tensor &t;
- const std::vector<const base_tensor *> components;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: gathering components for explicit "
- "matrix with tests functions");
- size_type s = t.size() / components.size();
- GA_DEBUG_ASSERT(s, "Wrong sizes");
- base_tensor::iterator it = t.begin();
- for (size_type i = 0; i < components.size(); ++i) {
- const base_tensor &t1 = *(components[i]);
- if (t1.size() > 1) {
- GA_DEBUG_ASSERT(t1.size() == s, "Wrong sizes, " << t1.size()
- << " != " << s);
- for (size_type j = 0; j < s; ++j) *it++ = t1[j];
- } else {
- for (size_type j = 0; j < s; ++j) *it++ = t1[0];
- }
- }
- return 0;
- }
- ga_instruction_c_matrix_with_tests
- (base_tensor &t_, const std::vector<const base_tensor *> &components_)
- : t(t_), components(components_) {}
- };
-
- struct ga_instruction_eval_func_1arg_1res : public ga_instruction {
- scalar_type &t;
- const scalar_type &c;
- pscalar_func_onearg f1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a one argument "
- "predefined function on a scalar");
- t = (*f1)(c);
- return 0;
- }
- ga_instruction_eval_func_1arg_1res(scalar_type &t_, const scalar_type &c_,
- pscalar_func_onearg f1_)
- : t(t_), c(c_), f1(f1_) {}
- };
-
- struct ga_instruction_eval_func_1arg_1res_expr : public ga_instruction {
- scalar_type &t;
- const scalar_type &c;
- const ga_predef_function &F;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a one argument "
- "predefined function on a scalar");
- t = F(c);
- return 0;
- }
- ga_instruction_eval_func_1arg_1res_expr(scalar_type &t_,
- const scalar_type &c_,
- const ga_predef_function &F_)
- : t(t_), c(c_), F(F_) {}
- };
-
- struct ga_instruction_eval_func_1arg : public ga_instruction {
- base_tensor &t, &tc1;
- pscalar_func_onearg f1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a one argument "
- "predefined function on tensor");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- for (size_type i = 0; i < t.size(); ++i) t[i] = (*f1)(tc1[i]);
- return 0;
- }
- ga_instruction_eval_func_1arg(base_tensor &t_, base_tensor &c_,
- pscalar_func_onearg f1_)
- : t(t_), tc1(c_), f1(f1_) {}
- };
-
- struct ga_instruction_eval_func_1arg_expr : public ga_instruction {
- base_tensor &t, &tc1;
- const ga_predef_function &F;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a one argument "
- "predefined function on tensor");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[i]);
- return 0;
- }
- ga_instruction_eval_func_1arg_expr(base_tensor &t_, base_tensor &c_,
- const ga_predef_function &F_)
- : t(t_), tc1(c_), F(F_) {}
- };
-
- struct ga_instruction_eval_func_2arg_1res : public ga_instruction {
- scalar_type &t;
- const scalar_type &c, &d;
- pscalar_func_twoargs f2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on two scalar");
- t = (*f2)(c, d);
- return 0;
- }
- ga_instruction_eval_func_2arg_1res(scalar_type &t_, const scalar_type &c_,
- const scalar_type &d_,
- pscalar_func_twoargs f2_)
- : t(t_), c(c_), d(d_), f2(f2_) {}
- };
-
- struct ga_instruction_eval_func_2arg_1res_expr : public ga_instruction {
- scalar_type &t;
- const scalar_type &c, &d;
- const ga_predef_function &F;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on two scalar");
- t = F(c, d);
- return 0;
- }
- ga_instruction_eval_func_2arg_1res_expr(scalar_type &t_,
- const scalar_type &c_,
- const scalar_type &d_,
- const ga_predef_function &F_)
- : t(t_), c(c_), d(d_), F(F_) {}
- };
-
- struct ga_instruction_eval_func_2arg_first_scalar : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- pscalar_func_twoargs f2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on one scalar and one tensor");
- GA_DEBUG_ASSERT(t.size() == tc2.size(), "Wrong sizes");
- for (size_type i = 0; i < t.size(); ++i) t[i] = (*f2)(tc1[0], tc2[i]);
- return 0;
- }
- ga_instruction_eval_func_2arg_first_scalar
- (base_tensor &t_, base_tensor &c_, base_tensor &d_,
- pscalar_func_twoargs f2_)
- : t(t_), tc1(c_), tc2(d_), f2(f2_) {}
- };
-
- struct ga_instruction_eval_func_2arg_first_scalar_expr
- : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- const ga_predef_function &F;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on one scalar and one tensor");
- GA_DEBUG_ASSERT(t.size() == tc2.size(), "Wrong sizes");
- for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[0], tc2[i]);
- return 0;
- }
- ga_instruction_eval_func_2arg_first_scalar_expr
- (base_tensor &t_, base_tensor &c_, base_tensor &d_,
- const ga_predef_function &F_)
- : t(t_), tc1(c_), tc2(d_), F(F_) {}
- };
-
- struct ga_instruction_eval_func_2arg_second_scalar : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- pscalar_func_twoargs f2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on one tensor and one scalar");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- for (size_type i = 0; i < t.size(); ++i) t[i] = (*f2)(tc1[i], tc2[0]);
- return 0;
- }
- ga_instruction_eval_func_2arg_second_scalar(base_tensor &t_,
- base_tensor &c_,
- base_tensor &d_,
- pscalar_func_twoargs f2_)
- : t(t_), tc1(c_), tc2(d_), f2(f2_) {}
- };
-
- struct ga_instruction_eval_func_2arg_second_scalar_expr
- : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- const ga_predef_function &F;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on one tensor and one scalar");
- GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
- for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[i], tc2[0]);
- return 0;
- }
- ga_instruction_eval_func_2arg_second_scalar_expr
- (base_tensor &t_, base_tensor &c_, base_tensor &d_,
- const ga_predef_function &F_)
- : t(t_), tc1(c_), tc2(d_), F(F_) {}
- };
-
- struct ga_instruction_eval_func_2arg : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- pscalar_func_twoargs f2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on two tensors");
- GA_DEBUG_ASSERT(t.size() == tc1.size() && t.size() == tc2.size(),
- "Wrong sizes");
-
- for (size_type i = 0; i < t.size(); ++i) t[i] = (*f2)(tc1[i], tc2[i]);
- return 0;
- }
- ga_instruction_eval_func_2arg(base_tensor &t_, base_tensor &c_,
- base_tensor &d_, pscalar_func_twoargs f2_)
- : t(t_), tc1(c_), tc2(d_), f2(f2_) {}
- };
-
- struct ga_instruction_eval_func_2arg_expr : public ga_instruction {
- base_tensor &t, &tc1, &tc2;
- const ga_predef_function &F;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
- "predefined function on two tensors");
- GA_DEBUG_ASSERT(t.size() == tc1.size() && t.size() == tc2.size(),
- "Wrong sizes");
-
- for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[i], tc2[i]);
- return 0;
- }
- ga_instruction_eval_func_2arg_expr(base_tensor &t_, base_tensor &c_,
- base_tensor &d_,
- const ga_predef_function &F_)
- : t(t_), tc1(c_), tc2(d_), F(F_) {}
- };
-
- struct ga_instruction_eval_OP : public ga_instruction {
- base_tensor &t;
- const ga_nonlinear_operator &OP;
- ga_nonlinear_operator::arg_list args;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: operator evaluation");
- OP.value(args, t);
- return 0;
- }
- ga_instruction_eval_OP(base_tensor &t_, const ga_nonlinear_operator &OP_,
- ga_nonlinear_operator::arg_list &args_)
- : t(t_), OP(OP_), args(args_) {}
- };
-
- struct ga_instruction_eval_derivative_OP : public ga_instruction {
- base_tensor &t;
- const ga_nonlinear_operator &OP;
- ga_nonlinear_operator::arg_list args;
- size_type der1;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: operator derivative evaluation");
- OP.derivative(args, der1, t);
- return 0;
- }
- ga_instruction_eval_derivative_OP(base_tensor &t_,
- const ga_nonlinear_operator &OP_,
- ga_nonlinear_operator::arg_list &args_,
- size_type der1_)
- : t(t_), OP(OP_), args(args_), der1(der1_) {}
- };
-
- struct ga_instruction_eval_second_derivative_OP : public ga_instruction {
- base_tensor &t;
- const ga_nonlinear_operator &OP;
- ga_nonlinear_operator::arg_list args;
- size_type der1, der2;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: operator second derivative evaluation");
- OP.second_derivative(args, der1, der2, t);
- return 0;
- }
- ga_instruction_eval_second_derivative_OP
- (base_tensor &t_, const ga_nonlinear_operator &OP_,
- ga_nonlinear_operator::arg_list &args_, size_type der1_, size_type der2_)
- : t(t_), OP(OP_), args(args_), der1(der1_), der2(der2_) {}
- };
-
- struct ga_instruction_tensor_slice : public ga_instruction {
- base_tensor &t, &tc1;
- bgeot::multi_index mi, indices;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: tensor slice");
- size_type order = t.sizes().size();
- for (bgeot::multi_index mi3(order); !mi3.finished(t.sizes());
- mi3.incrementation(t.sizes())) {
- for (size_type j = 0; j < order; ++j)
- mi[indices[j]] = mi3[j];
- t(mi3) = tc1(mi);
- }
- return 0;
- }
- ga_instruction_tensor_slice(base_tensor &t_, base_tensor &tc1_,
- bgeot::multi_index &mi_,
- bgeot::multi_index &indices_)
- : t(t_), tc1(tc1_), mi(mi_), indices(indices_) {}
- };
-
- struct ga_instruction_transformation_call : public ga_instruction {
- const ga_workspace &workspace;
- ga_instruction_set::interpolate_info &inin;
- pinterpolate_transformation trans;
- fem_interpolation_context &ctx;
- const base_small_vector &Normal;
- const mesh &m;
- bool compute_der;
-
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: call interpolate transformation");
- base_node P_ref;
- size_type cv;
- short_type face_num;
- gmm::clear(inin.Normal);
- inin.pt_type = trans->transform(workspace, m, ctx, Normal, &(inin.m), cv,
- face_num, P_ref, inin.Normal,
- inin.derivatives, compute_der);
- if (inin.pt_type) {
- if (cv != size_type(-1)) {
- inin.m->points_of_convex(cv, inin.G);
- inin.ctx.change((inin.m)->trans_of_convex(cv),
- 0, P_ref, inin.G, cv, face_num);
- inin.has_ctx = true;
- if (face_num != short_type(-1)) {
- inin.Normal = bgeot::compute_normal(inin.ctx, face_num);
- gmm::scale(inin.Normal, 1.0/gmm::vect_norm2(inin.Normal));
- } else
- inin.Normal.resize(0);
- inin.pt_y = inin.ctx.xreal();
- } else {
- inin.ctx.invalid_convex_num();
- inin.pt_y = P_ref;
- inin.has_ctx = false;
- }
- } else {
- inin.ctx.invalid_convex_num();
- inin.Normal.resize(0);
- inin.pt_y.resize(0);
- inin.has_ctx = false;
- }
- GA_DEBUG_INFO("Instruction: end of call interpolate transformation");
- return 0;
- }
- ga_instruction_transformation_call
- (const ga_workspace &w, ga_instruction_set::interpolate_info &i,
- pinterpolate_transformation t, fem_interpolation_context &ctxx,
- const base_small_vector &No, const mesh &mm, bool compute_der_)
- : workspace(w), inin(i), trans(t), ctx(ctxx), Normal(No), m(mm),
- compute_der(compute_der_) {}
- };
-
- struct ga_instruction_neighbour_transformation_call : public ga_instruction {
- const ga_workspace &workspace;
- ga_instruction_set::interpolate_info &inin;
- pinterpolate_transformation trans;
- fem_interpolation_context &ctx;
- base_small_vector &Normal;
- const mesh &m;
- size_type &ipt;
- papprox_integration &pai;
- bgeot::geotrans_precomp_pool &gp_pool;
- std::map<gauss_pt_corresp, bgeot::pstored_point_tab> &neighbour_corresp;
-
- virtual int exec() {
- bool cancel_optimization = false;
- GA_DEBUG_INFO("Instruction: call interpolate transformation");
- if (ipt == 0) {
- if (!(ctx.have_pgp()) || !pai || pai->is_built_on_the_fly()
- || cancel_optimization) {
- inin.ctx.invalid_convex_num();
- } else {
- // Test if the situation has already been encountered
- size_type cv = ctx.convex_num();
- short_type f = ctx.face_num();
- auto adj_face = m.adjacent_face(cv, f);
- if (adj_face.cv == size_type(-1)) {
- inin.ctx.invalid_convex_num();
- } else {
- gauss_pt_corresp gpc;
- gpc.pgt1 = m.trans_of_convex(cv);
- gpc.pgt2 = m.trans_of_convex(adj_face.cv);
- gpc.pai = pai;
- auto inds_pt1 = m.ind_points_of_face_of_convex(cv, f);
- auto inds_pt2 = m.ind_points_of_face_of_convex(adj_face.cv,
- adj_face.f);
- auto str1 = gpc.pgt1->structure();
- auto str2 = gpc.pgt2->structure();
- size_type nbptf1 = str1->nb_points_of_face(f);
- size_type nbptf2 = str2->nb_points_of_face(adj_face.f);
- gpc.nodes.resize(nbptf1*2);
- for (size_type i = 0; i < nbptf1; ++i) {
- gpc.nodes[2*i] = str1->ind_points_of_face(f)[i];
- bool found = false;
- for (size_type j = 0; j < nbptf2; ++j) {
- if (inds_pt2[j] == inds_pt1[i]) {
- gpc.nodes[2*i+1] = str2->ind_points_of_face(adj_face.f)[j];
- found = true;
- break;
- }
- }
- GMM_ASSERT1(found, "Internal error");
- }
- bgeot::pstored_point_tab pspt = 0;
- auto itm = neighbour_corresp.find(gpc);
- if (itm != neighbour_corresp.end()) {
- pspt = itm->second;
- } else {
- size_type nbpt = pai->nb_points_on_face(f);
- bgeot::geotrans_inv_convex gic;
- gic.init(m.points_of_convex(adj_face.cv), gpc.pgt2);
- size_type first_ind = pai->ind_first_point_on_face(f);
- const bgeot::stored_point_tab
- &spt = *(pai->pintegration_points());
- base_matrix G;
- m.points_of_convex(cv, G);
- fem_interpolation_context ctx_x(gpc.pgt1, 0, spt[0], G, cv, f);
- std::vector<base_node> P_ref(nbpt);
-
- for (size_type i = 0; i < nbpt; ++i) {
- ctx_x.set_xref(spt[first_ind+i]);
- bool converged = true;
- bool is_in = gic.invert(ctx_x.xreal(),
P_ref[i],converged,1E-4);
- GMM_ASSERT1(is_in && converged,"Geometric transformation "
- "inversion has failed in neighbour
transformation");
- }
- pspt = store_point_tab(P_ref);
- neighbour_corresp[gpc] = pspt;
- }
- m.points_of_convex(adj_face.cv, inin.G);
- bgeot::pgeotrans_precomp pgp = gp_pool(gpc.pgt2, pspt);
- inin.ctx.change(pgp, 0, 0, inin.G, adj_face.cv, adj_face.f);
- }
- }
- }
-
- if (inin.ctx.have_pgp()) {
- inin.ctx.set_ii(ipt);
- inin.pt_type = 1;
- inin.has_ctx = true;
- inin.pt_y = inin.ctx.xreal();
- inin.Normal = bgeot::compute_normal(inin.ctx, inin.ctx.face_num());
- gmm::scale(inin.Normal, 1.0/gmm::vect_norm2(inin.Normal));
- inin.m = &m;
- } else {
- base_node P_ref;
- size_type cv;
- short_type face_num;
- gmm::clear(inin.Normal);
- inin.pt_type = trans->transform(workspace, m, ctx, Normal, &(inin.m),
- cv, face_num, P_ref, inin.Normal,
- inin.derivatives, false);
- if (inin.pt_type) {
- if (cv != size_type(-1)) {
- inin.m->points_of_convex(cv, inin.G);
- inin.ctx.change((inin.m)->trans_of_convex(cv),
- 0, P_ref, inin.G, cv, face_num);
- inin.has_ctx = true;
- if (face_num != short_type(-1)) {
- inin.Normal = bgeot::compute_normal(inin.ctx, face_num);
- gmm::scale(inin.Normal, 1.0/gmm::vect_norm2(inin.Normal));
- } else
- inin.Normal.resize(0);
- inin.pt_y = inin.ctx.xreal();
- } else {
- inin.ctx.invalid_convex_num();
- inin.pt_y = P_ref;
- inin.has_ctx = false;
- }
- } else {
- inin.ctx.invalid_convex_num();
- inin.Normal.resize(0);
- inin.pt_y.resize(0);
- inin.has_ctx = false;
- }
- }
- GA_DEBUG_INFO("Instruction: end of call interpolate transformation");
- return 0;
- }
- ga_instruction_neighbour_transformation_call
- (const ga_workspace &w, ga_instruction_set::interpolate_info &i,
- pinterpolate_transformation t, fem_interpolation_context &ctxx,
- base_small_vector &No, const mesh &mm, size_type &ipt_,
- papprox_integration &pai_, bgeot::geotrans_precomp_pool &gp_pool_,
- std::map<gauss_pt_corresp, bgeot::pstored_point_tab> &neighbour_corresp_)
- : workspace(w), inin(i), trans(t), ctx(ctxx), Normal(No), m(mm),
- ipt(ipt_), pai(pai_), gp_pool(gp_pool_),
- neighbour_corresp(neighbour_corresp_) {}
- };
-
-
- struct ga_instruction_scalar_assembly : public ga_instruction {
- base_tensor &t;
- scalar_type &E, &coeff;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: scalar term assembly");
- E += t[0] * coeff;
- return 0;
- }
- ga_instruction_scalar_assembly(base_tensor &t_, scalar_type &E_,
- scalar_type &coeff_)
- : t(t_), E(E_), coeff(coeff_) {}
- };
-
- struct ga_instruction_fem_vector_assembly : public ga_instruction {
- base_tensor &t;
- base_vector &Vr, &Vn;
- const fem_interpolation_context &ctx;
- const gmm::sub_interval &Ir, &In;
- const mesh_fem *mfn, **mfg;
- scalar_type &coeff;
- const size_type &nbpt, &ipt;
- base_vector elem;
- bool interpolate;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: vector term assembly for fem variable");
- if (ipt == 0 || interpolate) {
- elem.resize(t.size());
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- size_type nd = ((t.size()) >> 2);
- for (size_type i = 0; i < nd; ++i) {
- *it++ = (*itt++) * coeff; *it++ = (*itt++) * coeff;
- *it++ = (*itt++) * coeff; *it++ = (*itt++) * coeff;
- }
- for (; it != ite;) *it++ = (*itt++) * coeff;
- // gmm::copy(gmm::scaled(t.as_vector(), coeff), elem);
- } else {
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- size_type nd = ((t.size()) >> 2);
- for (size_type i = 0; i < nd; ++i) {
- *it++ += (*itt++) * coeff; *it++ += (*itt++) * coeff;
- *it++ += (*itt++) * coeff; *it++ += (*itt++) * coeff;
- }
- for (; it != ite;) *it++ += (*itt++) * coeff;
- // gmm::add(gmm::scaled(t.as_vector(), coeff), elem);
- }
- if (ipt == nbpt-1 || interpolate) {
- const mesh_fem &mf = *(mfg ? *mfg : mfn);
- GMM_ASSERT1(mfg ? *mfg : mfn, "Internal error");
- const gmm::sub_interval &I = mf.is_reduced() ? Ir : In;
- base_vector &V = mf.is_reduced() ? Vr : Vn;
- if (!(ctx.is_convex_num_valid())) return 0;
- size_type cv_1 = ctx.convex_num();
- // size_type cv_1 = ctx.is_convex_num_valid()
- // ? ctx.convex_num() : mf.convex_index().first_true();
- GA_DEBUG_ASSERT(V.size() >= I.first() + mf.nb_basic_dof(),
- "Bad assembly vector size");
- auto &ct = mf.ind_scalar_basic_dof_of_element(cv_1);
- size_type qmult = mf.get_qdim();
- if (qmult > 1) qmult /= mf.fem_of_element(cv_1)->target_dim();
- size_type ifirst = I.first();
- auto ite = elem.begin();
- for (auto itc = ct.begin(); itc != ct.end(); ++itc)
- for (size_type q = 0; q < qmult; ++q)
- V[ifirst+(*itc)+q] += *ite++;
- GMM_ASSERT1(ite == elem.end(), "Internal error");
- }
- return 0;
- }
- ga_instruction_fem_vector_assembly
- (base_tensor &t_, base_vector &Vr_, base_vector &Vn_,
- const fem_interpolation_context &ctx_,
- const gmm::sub_interval &Ir_, const gmm::sub_interval &In_,
- const mesh_fem *mfn_, const mesh_fem **mfg_,
- scalar_type &coeff_,
- const size_type &nbpt_, const size_type &ipt_, bool interpolate_)
- : t(t_), Vr(Vr_), Vn(Vn_), ctx(ctx_), Ir(Ir_), In(In_), mfn(mfn_),
- mfg(mfg_), coeff(coeff_), nbpt(nbpt_), ipt(ipt_),
- interpolate(interpolate_) {}
- };
-
- struct ga_instruction_vector_assembly : public ga_instruction {
- base_tensor &t;
- base_vector &V;
- const gmm::sub_interval &I;
- scalar_type &coeff;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: vector term assembly for "
- "fixed size variable");
- gmm::add(gmm::scaled(t.as_vector(), coeff), gmm::sub_vector(V, I));
- return 0;
- }
- ga_instruction_vector_assembly(base_tensor &t_, base_vector &V_,
- const gmm::sub_interval &I_,
- scalar_type &coeff_)
- : t(t_), V(V_), I(I_), coeff(coeff_) {}
- };
-
- struct ga_instruction_assignment : public ga_instruction {
- base_tensor &t;
- base_vector &V;
- const fem_interpolation_context &ctx;
- const im_data *imd;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: Assignement to im_data");
- imd->set_tensor(V, ctx.convex_num(), ctx.ii(), t);
- return 0;
- }
- ga_instruction_assignment(base_tensor &t_, base_vector &V_,
- const fem_interpolation_context &ctx_,
- const im_data *imd_)
- : t(t_), V(V_), ctx(ctx_), imd(imd_) {}
- };
-
- template <class MAT>
- inline void add_elem_matrix_
- (MAT &K, const std::vector<size_type> &dofs1,
- const std::vector<size_type> &dofs2, std::vector<size_type> &/*dofs1_sort*/,
- base_vector &elem, scalar_type threshold, size_type /* N */) {
- base_vector::const_iterator it = elem.cbegin();
- for (const size_type &dof2 : dofs2)
- for (const size_type &dof1 : dofs1) {
- if (gmm::abs(*it) > threshold)
- K(dof1, dof2) += *it;
- ++it;
- }
- }
-
- // static const std::vector<size_type> *the_indto_sort;
- // int compare_my_indices(const void *a, const void *b) {
- // size_type aa = *((const size_type *)(a));
- // size_type bb = *((const size_type *)(b));
- // return int((*the_indto_sort)[aa]) - int((*the_indto_sort)[bb]);
- // }
-
- inline void add_elem_matrix_
- (gmm::col_matrix<gmm::rsvector<scalar_type>> &K,
- const std::vector<size_type> &dofs1, const std::vector<size_type> &dofs2,
- std::vector<size_type> &dofs1_sort,
- base_vector &elem, scalar_type threshold, size_type N) {
- size_type maxest = (N+1) * std::max(dofs1.size(), dofs2.size());
- size_type s1 = dofs1.size(), s2 = dofs2.size();
- gmm::elt_rsvector_<scalar_type> ev;
-
- dofs1_sort.resize(s1);
- for (size_type i = 0; i < s1; ++i) { // insertion sort
- size_type j = i, k = j-1;
- while (j > 0 && dofs1[i] < dofs1[dofs1_sort[k]])
- { dofs1_sort[j] = dofs1_sort[k]; j--; k--; }
- dofs1_sort[j] = i;
- }
-
- // dofs1_sort.resize(s1); // test with qsort: not faster in the tested
cases
- // for (size_type i = 0; i < s1; ++i) dofs1_sort[i] = i;
- // the_indto_sort = &dofs1;
- // qsort(&(dofs1_sort[0]), s1, sizeof(size_type), compare_my_indices);
-
- base_vector::const_iterator it = elem.cbegin();
- for (size_type j = 0; j < s2; ++j) { // Iteration on columns
- if (j) it += s1;
- std::vector<gmm::elt_rsvector_<scalar_type>> &col = K[dofs2[j]];
- size_type nb = col.size();
-
- if (nb == 0) {
- col.reserve(maxest);
- for (size_type i = 0; i < s1; ++i) {
- size_type k = dofs1_sort[i]; ev.e = *(it+k);
- if (gmm::abs(ev.e) > threshold) { ev.c=dofs1[k]; col.push_back(ev); }
- }
- } else { // column merge
- size_type ind = 0;
- for (size_type i = 0; i < s1; ++i) {
- size_type k = dofs1_sort[i]; ev.e = *(it+k);
- if (gmm::abs(ev.e) > threshold) {
- ev.c = dofs1[k];
-
- size_type count = nb - ind, step, l;
- while (count > 0) {
- step = count / 2; l = ind + step;
- if (col[l].c < ev.c) { ind = ++l; count -= step + 1; }
- else count = step;
- }
-
- auto itc = col.begin() + ind;
- if (ind != nb && itc->c == ev.c) itc->e += ev.e;
- else {
- if (nb - ind > 1100)
- GMM_WARNING2("Inefficient addition of element in rsvector with
"
- << col.size() - ind << " non-zero entries");
- col.push_back(ev);
- if (ind != nb) {
- itc = col.begin() + ind;
- auto ite = col.end(); --ite; auto itee = ite;
- for (; ite != itc; --ite) { --itee; *ite = *itee; }
- *itc = ev;
- }
- ++nb;
- }
- ++ind;
+ if (tc2_.sparsity() == 2) {
+ size_type q2 = tc2.sizes()[1];
+ size_type n2 = (tc2.sizes().size() > 2) ? tc2.sizes()[1] : 1;
+ if (n2*q2 == n) {
+ switch (n2) {
+ case 1:
+ switch (q2) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<1>>
+ (t, tc1, tc2, q2);
}
- }
- }
- }
- }
-
-
- template <class MAT = model_real_sparse_matrix>
- struct ga_instruction_matrix_assembly : public ga_instruction {
- const base_tensor &t;
- MAT &Kr, &Kn;
- const fem_interpolation_context &ctx1, &ctx2;
- const gmm::sub_interval &Ir1, &Ir2;
- const gmm::sub_interval &In1, &In2;
- const mesh_fem *mfn1, *mfn2;
- const mesh_fem **mfg1, **mfg2;
- const scalar_type &coeff, &alpha1, &alpha2;
- const size_type &nbpt, &ipt;
- base_vector elem;
- bool interpolate;
- std::vector<size_type> dofs1, dofs2, dofs1_sort;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: matrix term assembly");
- if (ipt == 0 || interpolate) {
- elem.resize(t.size());
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- scalar_type e = coeff*alpha1*alpha2;
- size_type nd = ((t.size()) >> 2);
- for (size_type i = 0; i < nd; ++i) {
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- }
- for (; it != ite;) *it++ = (*itt++) * e;
- // gmm::copy(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
- } else {
- // Faster than a daxpy blas call on my config
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- scalar_type e = coeff*alpha1*alpha2;
- size_type nd = ((t.size()) >> 2);
- for (size_type i = 0; i < nd; ++i) {
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
- }
- for (; it != ite;) *it++ += (*itt++) * e;
- // gmm::add(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
- }
- if (ipt == nbpt-1 || interpolate) {
- const mesh_fem *pmf1 = mfg1 ? *mfg1 : mfn1;
- const mesh_fem *pmf2 = mfg2 ? *mfg2 : mfn2;
- bool reduced = (pmf1 && pmf1->is_reduced())
- || (pmf2 && pmf2->is_reduced());
- MAT &K = reduced ? Kr : Kn;
- const gmm::sub_interval &I1 = reduced ? Ir1 : In1;
- const gmm::sub_interval &I2 = reduced ? Ir2 : In2;
- GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
-
- scalar_type ninf = gmm::vect_norminf(elem);
- if (ninf == scalar_type(0)) return 0;
-
- size_type s1 = t.sizes()[0], s2 = t.sizes()[1];
- size_type cv1 = pmf1 ? ctx1.convex_num() : s1;
- size_type cv2 = pmf2 ? ctx2.convex_num() : s2;
- size_type N = 1;
-
- dofs1.assign(s1, I1.first());
- if (pmf1) {
- if (!(ctx1.is_convex_num_valid())) return 0;
- N = ctx1.N();
- auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
- size_type qmult1 = pmf1->get_qdim();
- if (qmult1 > 1) qmult1 /= pmf1->fem_of_element(cv1)->target_dim();
- auto itd = dofs1.begin();
- if (qmult1 == 1) {
- for (auto itt = ct1.begin(); itt != ct1.end(); ++itt)
- *itd++ += *itt;
- } else {
- for (auto itt = ct1.begin(); itt != ct1.end(); ++itt)
- for (size_type q = 0; q < qmult1; ++q)
- *itd++ += *itt + q;
+ case 2:
+ switch (q2) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<2>>
+ (t, tc1, tc2, q2);
}
- } else
- for (size_type i=0; i < s1; ++i) dofs1[i] += i;
-
- if (pmf1 == pmf2 && cv1 == cv2) {
- if (I1.first() == I2.first()) {
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf*1E-14, N);
- } else {
- dofs2.resize(dofs1.size());
- for (size_type i = 0; i < dofs1.size(); ++i)
- dofs2[i] = dofs1[i] + I2.first() - I1.first();
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ case 3:
+ switch (q2) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<3>>
+ (t, tc1, tc2, q2);
}
- } else {
- dofs2.assign(s2, I2.first());
- if (pmf2) {
- if (!(ctx2.is_convex_num_valid())) return 0;
- N = std::max(N, ctx2.N());
- auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
- size_type qmult2 = pmf2->get_qdim();
- if (qmult2 > 1) qmult2 /= pmf2->fem_of_element(cv2)->target_dim();
- auto itd = dofs2.begin();
- if (qmult2 == 1) {
- for (auto itt = ct2.begin(); itt != ct2.end(); ++itt)
- *itd++ += *itt;
- } else {
- for (auto itt = ct2.begin(); itt != ct2.end(); ++itt)
- for (size_type q = 0; q < qmult2; ++q)
- *itd++ += *itt + q;
- }
- } else
- for (size_type i=0; i < s2; ++i) dofs2[i] += i;
-
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ case 4:
+ return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<4>>
+ (t, tc1, tc2, q2);
+ case 5:
+ return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<5>>
+ (t, tc1, tc2, q2);
+ default:
+ return std::make_shared<ga_instruction_reduction_opt0_2>
+ (t,tc1,tc2,n2,q2);
}
}
- return 0;
}
- ga_instruction_matrix_assembly
- (const base_tensor &t_, MAT &Kr_, MAT &Kn_,
- const fem_interpolation_context &ctx1_,
- const fem_interpolation_context &ctx2_,
- const gmm::sub_interval &Ir1_, const gmm::sub_interval &In1_,
- const gmm::sub_interval &Ir2_, const gmm::sub_interval &In2_,
- const mesh_fem *mfn1_, const mesh_fem **mfg1_,
- const mesh_fem *mfn2_, const mesh_fem **mfg2_,
- const scalar_type &coeff_,
- const scalar_type &alpha2_, const scalar_type &alpha1_,
- const size_type &nbpt_, const size_type &ipt_, bool interpolate_)
- : t(t_), Kr(Kr_), Kn(Kn_), ctx1(ctx1_), ctx2(ctx2_),
- Ir1(Ir1_), Ir2(Ir2_), In1(In1_), In2(In2_),
- mfn1(mfn1_), mfn2(mfn2_), mfg1(mfg1_), mfg2(mfg2_),
- coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
- nbpt(nbpt_), ipt(ipt_), interpolate(interpolate_),
- dofs1(0), dofs2(0) {}
- };
-
- template <class MAT = model_real_sparse_matrix>
- struct ga_instruction_matrix_assembly_standard_scalar: public ga_instruction
{
- const base_tensor &t;
- MAT &K;
- const fem_interpolation_context &ctx1, &ctx2;
- const gmm::sub_interval &I1, &I2;
- const mesh_fem *pmf1, *pmf2;
- const scalar_type &coeff, &alpha1, &alpha2;
- const size_type &nbpt, &ipt;
- base_vector elem;
- std::vector<size_type> dofs1, dofs2, dofs1_sort;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
- "scalar fems");
- if (ipt == 0) {
- elem.resize(t.size());
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- scalar_type e = coeff*alpha1*alpha2;
- size_type nd = ((t.size()) >> 2);
- for (size_type i = 0; i < nd; ++i) {
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- }
- for (; it != ite;) *it++ = (*itt++) * e;
- // gmm::copy(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
- } else {
- // Faster than a daxpy blas call on my config
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- scalar_type e = coeff*alpha1*alpha2;
- size_type nd = ((t.size()) >> 2);
- for (size_type i = 0; i < nd; ++i) {
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ if (tc1_.sparsity() == 2) {
+ size_type q1 = tc1.sizes()[1];
+ size_type n1 = (tc1.sizes().size() > 2) ? tc1.sizes()[1] : 1;
+ if (n1*q1 == n) {
+ switch (n1) {
+ case 1:
+ switch (q1) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<1>>
+ (t, tc1, tc2, q1);
+ }
+ case 2:
+ switch (q1) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<2>>
+ (t, tc1, tc2, q1);
+ }
+ case 3:
+ switch (q1) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
+ (t, tc1, tc2, q1);
+ }
+ return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
+ (t, tc1, tc2, q1);
+ case 4:
+ return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<4>>
+ (t, tc1, tc2, q1);
+ case 5:
+ return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<5>>
+ (t, tc1, tc2, q1);
+ default:
+ return std::make_shared<ga_instruction_reduction_opt2_0>
+ (t,tc1,tc2, n1, q1);
}
- for (; it != ite;) *it++ += (*itt++) * e;
- // gmm::add(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
}
- if (ipt == nbpt-1) {
- GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
+ }
- scalar_type ninf = gmm::vect_norminf(elem);
- if (ninf == scalar_type(0)) return 0;
+ switch(n) {
+ case 2 : return std::make_shared<ga_instruction_reduction_unrolled< 2>>
+ (t, tc1, tc2);
+ case 3 : return std::make_shared<ga_instruction_reduction_unrolled< 3>>
+ (t, tc1, tc2);
+ case 4 : return std::make_shared<ga_instruction_reduction_unrolled< 4>>
+ (t, tc1, tc2);
+ case 5 : return std::make_shared<ga_instruction_reduction_unrolled< 5>>
+ (t, tc1, tc2);
+ case 6 : return std::make_shared<ga_instruction_reduction_unrolled< 6>>
+ (t, tc1, tc2);
+ case 7 : return std::make_shared<ga_instruction_reduction_unrolled< 7>>
+ (t, tc1, tc2);
+ case 8 : return std::make_shared<ga_instruction_reduction_unrolled< 8>>
+ (t, tc1, tc2);
+ case 9 : return std::make_shared<ga_instruction_reduction_unrolled< 9>>
+ (t, tc1, tc2);
+ case 10 : return std::make_shared<ga_instruction_reduction_unrolled<10>>
+ (t, tc1, tc2);
+ case 11 : return std::make_shared<ga_instruction_reduction_unrolled<11>>
+ (t, tc1, tc2);
+ case 12 : return std::make_shared<ga_instruction_reduction_unrolled<12>>
+ (t, tc1, tc2);
+ case 13 : return std::make_shared<ga_instruction_reduction_unrolled<13>>
+ (t, tc1, tc2);
+ case 14 : return std::make_shared<ga_instruction_reduction_unrolled<14>>
+ (t, tc1, tc2);
+ case 15 : return std::make_shared<ga_instruction_reduction_unrolled<15>>
+ (t, tc1, tc2);
+ case 16 : return std::make_shared<ga_instruction_reduction_unrolled<16>>
+ (t, tc1, tc2);
+ default : return std::make_shared<ga_instruction_reduction>
+ (t, tc1, tc2, n);
+ }
+ }
- size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num(), N=ctx1.N();
- if (cv1 == size_type(-1)) return 0;
- auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
- GA_DEBUG_ASSERT(ct1.size() == t.sizes()[0], "Internal error");
- dofs1.resize(ct1.size());
- for (size_type i = 0; i < ct1.size(); ++i)
- dofs1[i] = ct1[i] + I1.first();
+ pga_instruction ga_uniform_instruction_reduction_switch
+ (assembly_tensor &t_, assembly_tensor &tc1_, assembly_tensor &tc2_,
+ size_type n, bool &to_clear) {
+ base_tensor &t = t_.tensor(), &tc1 = tc1_.tensor(), &tc2 = tc2_.tensor();
- if (pmf2 == pmf1 && cv1 == cv2) {
- if (I1.first() == I2.first()) {
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf*1E-14, N);
- } else {
- dofs2.resize(dofs1.size());
- for (size_type i = 0; i < dofs1.size(); ++i)
- dofs2[i] = dofs1[i] + I2.first() - I1.first();
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ if (tc1_.sparsity() == 1 && tc2_.sparsity() == 1 &&
+ tc1_.qdim() == n && tc2_.qdim() == n) {
+ to_clear = true;
+ t_.set_sparsity(10, tc1_.qdim());
+ return std::make_shared<ga_instruction_reduction_opt1_1>(t,tc1,tc2,n);
+ }
+ if (tc2_.sparsity() == 1) {
+ switch(n) {
+ case 2:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<2>>
+ (t, tc1, tc2);
+ case 3:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<3>>
+ (t, tc1, tc2);
+ case 4:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<4>>
+ (t, tc1, tc2);
+ case 5:
+ return std::make_shared<ga_instruction_reduction_opt0_1_unrolled<5>>
+ (t, tc1, tc2);
+ default:
+ return std::make_shared<ga_instruction_reduction_opt0_1>(t,tc1,tc2, n);
+ }
+ }
+ if (tc2_.sparsity() == 2) {
+ size_type q2 = tc2.sizes()[1];
+ size_type n2 = (tc2.sizes().size() > 2) ? tc2.sizes()[1] : 1;
+ if (n2*q2 == n) {
+ switch (n2) {
+ case 1:
+ switch (q2) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<1,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<1>>
+ (t, tc1, tc2, q2);
}
- } else {
- if (cv2 == size_type(-1)) return 0;
- auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
- GA_DEBUG_ASSERT(ct2.size() == t.sizes()[1], "Internal error");
- dofs2.resize(ct2.size());
- for (size_type i = 0; i < ct2.size(); ++i)
- dofs2[i] = ct2[i] + I2.first();
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ case 2:
+ switch (q2) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<2,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<2>>
+ (t, tc1, tc2, q2);
+ }
+ case 3:
+ switch (q2) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt0_2_dunrolled<3,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt0_2_unrolled<3>>
+ (t, tc1, tc2, q2);
+ }
+ case 4:
+ return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<4>>
+ (t, tc1, tc2, q2);
+ case 5:
+ return std::make_shared<ga_instruction_reduction_opt0_2_unrolled<5>>
+ (t, tc1, tc2, q2);
+ default:
+ return std::make_shared<ga_instruction_reduction_opt0_2>
+ (t,tc1,tc2,n2,q2);
+ }
+ }
+ }
+ if (tc1_.sparsity() == 2) {
+ size_type q1 = tc1.sizes()[1];
+ size_type n1 = (tc1.sizes().size() > 2) ? tc1.sizes()[1] : 1;
+ if (n1*q1 == n) {
+ switch (n1) {
+ case 1:
+ switch (q1) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<1,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<1>>
+ (t, tc1, tc2, q1);
+ }
+ case 2:
+ switch (q1) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<2,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<2>>
+ (t, tc1, tc2, q1);
+ }
+ case 3:
+ switch (q1) {
+ case 2:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,2>>
+ (t, tc1, tc2);
+ case 3:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,3>>
+ (t, tc1, tc2);
+ case 4:
+ return
+ std::make_shared<ga_instruction_reduction_opt2_0_dunrolled<3,4>>
+ (t, tc1, tc2);
+ default :
+ return
std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
+ (t, tc1, tc2, q1);
+ }
+ return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<3>>
+ (t, tc1, tc2, q1);
+ case 4:
+ return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<4>>
+ (t, tc1, tc2, q1);
+ case 5:
+ return std::make_shared<ga_instruction_reduction_opt2_0_unrolled<5>>
+ (t, tc1, tc2, q1);
+ default:
+ return std::make_shared<ga_instruction_reduction_opt2_0>
+ (t,tc1,tc2, n1, q1);
}
}
- return 0;
}
- ga_instruction_matrix_assembly_standard_scalar
- (const base_tensor &t_, MAT &Kn_,
- const fem_interpolation_context &ctx1_,
- const fem_interpolation_context &ctx2_,
- const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
- const mesh_fem *mfn1_, const mesh_fem *mfn2_,
- const scalar_type &coeff_, const scalar_type &alpha2_,
- const scalar_type &alpha1_,
- const size_type &nbpt_, const size_type &ipt_)
- : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
- I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
- coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
- nbpt(nbpt_), ipt(ipt_) {}
- };
- template <class MAT = model_real_sparse_matrix>
- struct ga_instruction_matrix_assembly_standard_vector: public ga_instruction
{
- const base_tensor &t;
- MAT &K;
- const fem_interpolation_context &ctx1, &ctx2;
- const gmm::sub_interval &I1, &I2;
- const mesh_fem *pmf1, *pmf2;
- const scalar_type &coeff, &alpha1, &alpha2;
- const size_type &nbpt, &ipt;
- mutable base_vector elem;
- mutable std::vector<size_type> dofs1, dofs2, dofs1_sort;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
- "vector fems");
- if (ipt == 0) {
- elem.resize(t.size());
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- scalar_type e = coeff*alpha1*alpha2;
- size_type nd = ((t.size()) >> 3);
- for (size_type i = 0; i < nd; ++i) {
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- *it++ = (*itt++) * e; *it++ = (*itt++) * e;
- }
- for (; it != ite;) *it++ = (*itt++) * e;
- // gmm::copy(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
- } else {
- // (Far) faster than a daxpy blas call on my config.
- auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
- scalar_type e = coeff*alpha1*alpha2;
- size_type nd = ((t.size()) >> 3);
- for (size_type i = 0; i < nd; ++i) {
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
- *it++ += (*itt++) * e; *it++ += (*itt++) * e;
- }
- for (; it != ite;) *it++ += (*itt++) * e;
- // gmm::add(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
+ // Only specialized for certain values
+ size_type s2 = tc2.size()/n;
+ switch(s2) {
+ case 1 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,1>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,1>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,1>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
}
- if (ipt == nbpt-1) {
- GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
-
- scalar_type ninf = gmm::vect_norminf(elem);
- if (ninf == scalar_type(0)) return 0;
- size_type s1 = t.sizes()[0], s2 = t.sizes()[1], N = ctx1.N();
-
- size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num();
- if (cv1 == size_type(-1)) return 0;
- auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
- size_type qmult1 = pmf1->get_qdim();
- if (qmult1 > 1) qmult1 /= pmf1->fem_of_element(cv1)->target_dim();
- dofs1.assign(s1, I1.first());
- auto itd = dofs1.begin();
- for (auto itt = ct1.begin(); itt != ct1.end(); ++itt)
- for (size_type q = 0; q < qmult1; ++q)
- *itd++ += *itt + q;
-
- if (pmf2 == pmf1 && cv1 == cv2) {
- if (I1.first() == I2.first()) {
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf*1E-14, N);
- } else {
- dofs2.resize(dofs1.size());
- for (size_type i = 0; i < dofs1.size(); ++i)
- dofs2[i] = dofs1[i] + I2.first() - I1.first();
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
- }
- } else {
- if (cv2 == size_type(-1)) return 0;
- auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
- size_type qmult2 = pmf2->get_qdim();
- if (qmult2 > 1) qmult2 /= pmf2->fem_of_element(cv2)->target_dim();
- dofs2.assign(s2, I2.first());
- itd = dofs2.begin();
- for (auto itt = ct2.begin(); itt != ct2.end(); ++itt)
- for (size_type q = 0; q < qmult2; ++q)
- *itd++ += *itt + q;
-
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
- }
+ case 2 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,2>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,2>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,2>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
}
- return 0;
- }
- ga_instruction_matrix_assembly_standard_vector
- (const base_tensor &t_, MAT &Kn_,
- const fem_interpolation_context &ctx1_,
- const fem_interpolation_context &ctx2_,
- const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
- const mesh_fem *mfn1_, const mesh_fem *mfn2_,
- const scalar_type &coeff_, const scalar_type &alpha2_,
- const scalar_type &alpha1_, const size_type &nbpt_,
- const size_type &ipt_)
- : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
- I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
- coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
- nbpt(nbpt_), ipt(ipt_), dofs1(0), dofs2(0) {}
- };
-
- struct ga_instruction_matrix_assembly_standard_vector_opt10_2
- : public ga_instruction {
- const base_tensor &t;
- model_real_sparse_matrix &K;
- const fem_interpolation_context &ctx1, &ctx2;
- const gmm::sub_interval &I1, &I2;
- const mesh_fem *pmf1, *pmf2;
- const scalar_type &coeff, &alpha1, &alpha2;
- const size_type &nbpt, &ipt;
- mutable base_vector elem;
- mutable std::vector<size_type> dofs1, dofs2, dofs1_sort;
- virtual int exec() {
- GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
- "vector fems optimized for format 10 qdim 2");
- size_type s1 = t.sizes()[0], s2 = t.sizes()[1], s1_q = 2*s1;
- size_type ss1 = s1/2, ss2 = s2/2;
- scalar_type e = coeff*alpha1*alpha2;
- if (ipt == 0) {
- elem.resize(ss1*ss2);
- auto itel = elem.begin();
- for (size_type j = 0; j < ss2; ++j) {
- auto it = t.begin() + j*s1_q;
- for (size_type i = 0; i < ss1; ++i, it += 2)
- *itel++ = (*it) * e;
- }
- } else {
- auto itel = elem.begin();
- for (size_type j = 0; j < ss2; ++j) {
- auto it = t.begin() + j*s1_q;
- for (size_type i = 0; i < ss1; ++i, it += 2)
- *itel++ += (*it) * e;
- }
+ case 3 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,3>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,3>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,3>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
}
- if (ipt == nbpt-1) {
- GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
+ case 4 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,4>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,4>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,4>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ case 5 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,5>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,5>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,5>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ case 6 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,6>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,6>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,6>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ case 7 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,7>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,7>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,7>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ case 8 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,8>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,8>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,8>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ case 9 :
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,9>>(t, tc1, tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,9>>(t, tc1, tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,9>>(t, tc1, tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ case 10:
+ switch(n) {
+ case 2: return std::make_shared<ga_ins_red_d_unrolled<2,10>>(t, tc1,
tc2);
+ case 3: return std::make_shared<ga_ins_red_d_unrolled<3,10>>(t, tc1,
tc2);
+ case 4: return std::make_shared<ga_ins_red_d_unrolled<4,10>>(t, tc1,
tc2);
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ default: return ga_instruction_reduction_switch(t_,tc1_,tc2_,n,to_clear);
+ }
+ }
- scalar_type ninf = gmm::vect_norminf(elem) * 1E-14;
- if (ninf == scalar_type(0)) return 0;
- size_type N = ctx1.N();
- size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num();
- size_type i1 = I1.first(), i2 = I2.first();
- if (cv1 == size_type(-1)) return 0;
- auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
- dofs1.resize(ss1);
- for (size_type i = 0; i < ss1; ++i) dofs1[i] = i1 + ct1[i];
- if (pmf2 == pmf1 && cv1 == cv2) {
- if (i1 == i2) {
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
- } else {
- dofs2.resize(ss2);
- for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct1[i];
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ // Performs Amij Bnj -> Cmni. To be optimized.
+ struct ga_instruction_spec_reduction : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type nn;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: specific reduction operation of "
+ "size " << nn);
+ size_type s1 = tc1.sizes()[0], s11 = tc1.size() / (s1*nn), s111 = s1*s11;
+ size_type s2 = tc2.sizes()[0];
+ base_tensor::iterator it = t.begin();
+ for (size_type i = 0; i < s11; ++i)
+ for (size_type n = 0; n < s2; ++n)
+ for (size_type m = 0; m < s1; ++m, ++it) {
+ *it = scalar_type(0);
+ for (size_type j = 0; j < nn; ++j)
+ *it += tc1[m+i*s1+j*s111] * tc2[n+j*s2];
}
- } else {
- if (cv2 == size_type(-1)) return 0;
- auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
- dofs2.resize(ss2);
- for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct2[i];
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- }
- }
+ GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
return 0;
}
- ga_instruction_matrix_assembly_standard_vector_opt10_2
- (const base_tensor &t_, model_real_sparse_matrix &Kn_,
- const fem_interpolation_context &ctx1_,
- const fem_interpolation_context &ctx2_,
- const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
- const mesh_fem *mfn1_, const mesh_fem *mfn2_,
- const scalar_type &coeff_, const scalar_type &alpha2_,
- const scalar_type &alpha1_, const size_type &nbpt_,
- const size_type &ipt_)
- : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
- I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
- coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
- nbpt(nbpt_), ipt(ipt_), dofs1(0), dofs2(0) {}
+ ga_instruction_spec_reduction(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type n_)
+ : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
};
- struct ga_instruction_matrix_assembly_standard_vector_opt10_3
- : public ga_instruction {
- const base_tensor &t;
- model_real_sparse_matrix &K;
- const fem_interpolation_context &ctx1, &ctx2;
- const gmm::sub_interval &I1, &I2;
- const mesh_fem *pmf1, *pmf2;
- const scalar_type &coeff, &alpha1, &alpha2;
- const size_type &nbpt, &ipt;
- mutable base_vector elem;
- mutable std::vector<size_type> dofs1, dofs2, dofs1_sort;
+ // Performs Amik Bnjk -> Cmnij. To be optimized.
+ struct ga_instruction_spec2_reduction : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type nn;
virtual int exec() {
- GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
- "vector fems optimized for format 10 qdim 3");
- size_type s1 = t.sizes()[0], s2 = t.sizes()[1], s1_q = 3*s1;
- size_type ss1 = s1/3, ss2 = s2/3;
- scalar_type e = coeff*alpha1*alpha2;
- if (ipt == 0) {
- elem.resize(ss1*ss2);
- auto itel = elem.begin();
- for (size_type j = 0; j < ss2; ++j) {
- auto it = t.begin() + j*s1_q;
- for (size_type i = 0; i < ss1; ++i, it += 3)
- *itel++ = (*it) * e;
- }
- } else {
- auto itel = elem.begin();
- for (size_type j = 0; j < ss2; ++j) {
- auto it = t.begin() + j*s1_q;
- for (size_type i = 0; i < ss1; ++i, it += 3)
- *itel++ += (*it) * e;
- }
- }
- if (ipt == nbpt-1) {
- GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
-
- scalar_type ninf = gmm::vect_norminf(elem)*1E-14;
- if (ninf == scalar_type(0)) return 0;
- size_type N = ctx1.N();
- size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num();
- size_type i1 = I1.first(), i2 = I2.first();
- if (cv1 == size_type(-1)) return 0;
- auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
- dofs1.resize(ss1);
- for (size_type i = 0; i < ss1; ++i) dofs1[i] = i1 + ct1[i];
+ GA_DEBUG_INFO("Instruction: second specific reduction operation of "
+ "size " << nn);
+ size_type s1 = tc1.sizes()[0], s11 = tc1.size() / (s1*nn), s111 = s1*s11;
+ size_type s2 = tc2.sizes()[0], s22 = tc2.size() / (s2*nn), s222 = s2*s22;
+ base_tensor::iterator it = t.begin();
+ for (size_type j = 0; j < s22; ++j)
+ for (size_type i = 0; i < s11; ++i)
+ for (size_type m = 0; m < s1; ++m)
+ for (size_type n = 0; n < s2; ++n, ++it) {
+ *it = scalar_type(0);
+ for (size_type k = 0; k < nn; ++k)
+ *it += tc1[m+i*s1+k*s111] * tc2[n+j*s2+k*s222];
+ }
+ GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
+ return 0;
+ }
+ ga_instruction_spec2_reduction(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type n_)
+ : t(t_), tc1(tc1_), tc2(tc2_), nn(n_) {}
+ };
- if (pmf2 == pmf1 && cv1 == cv2) {
- if (i1 == i2) {
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
- } else {
- dofs2.resize(ss2);
- for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct1[i];
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- }
- } else {
- if (cv2 == size_type(-1)) return 0;
- auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
- dofs2.resize(ss2);
- for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct2[i];
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
- for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
- add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
- }
+ // Performs Aij Bkl -> Cijkl
+ struct ga_instruction_simple_tmult : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: simple tensor product");
+ size_type s1 = tc1.size();
+ GA_DEBUG_ASSERT(t.size() == s1 * tc2.size(), "Wrong sizes");
+ base_tensor::iterator it2=tc2.begin(), it1=tc1.begin(), it1end=it1 + s1;
+ for (base_tensor::iterator it = t.begin(); it != t.end(); ++it) {
+ *it = *(it2) * (*it1);
+ ++it1; if (it1 == it1end) { it1 = tc1.begin(), ++it2; }
}
return 0;
}
- ga_instruction_matrix_assembly_standard_vector_opt10_3
- (const base_tensor &t_, model_real_sparse_matrix &Kn_,
- const fem_interpolation_context &ctx1_,
- const fem_interpolation_context &ctx2_,
- const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
- const mesh_fem *mfn1_, const mesh_fem *mfn2_,
- const scalar_type &coeff_, const scalar_type &alpha2_,
- const scalar_type &alpha1_, const size_type &nbpt_,
- const size_type &ipt_)
- : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
- I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
- coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
- nbpt(nbpt_), ipt(ipt_), dofs1(0), dofs2(0) {}
+ ga_instruction_simple_tmult(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
};
-
-
-
- //=========================================================================
- // Structure dealing with user defined environment : constant, variables,
- // functions, operators.
- //=========================================================================
-
- void ga_workspace::init() {
- // allocate own storage for K an V to be used unless/until external
- // storage is provided with set_assembled_matrix/vector
- K = std::make_shared<model_real_sparse_matrix>(2,2);
- V = std::make_shared<base_vector>(2);
- // add default transformations
- add_interpolate_transformation
- ("neighbour_elt", interpolate_transformation_neighbour_instance());
- }
-
- // variables and variable groups
- void ga_workspace::add_fem_variable
- (const std::string &name, const mesh_fem &mf,
- const gmm::sub_interval &I, const model_real_plain_vector &VV) {
- variables[name] = var_description(true, true, &mf, I, &VV, 0, 1);
- }
-
- void ga_workspace::add_fixed_size_variable
- (const std::string &name,
- const gmm::sub_interval &I, const model_real_plain_vector &VV) {
- variables[name] = var_description(true, false, 0, I, &VV, 0,
- dim_type(gmm::vect_size(VV)));
- }
-
- void ga_workspace::add_fem_constant
- (const std::string &name, const mesh_fem &mf,
- const model_real_plain_vector &VV) {
- GMM_ASSERT1(mf.nb_dof(), "The provided mesh_fem of variable" << name
- << "has zero degrees of freedom.");
- size_type Q = gmm::vect_size(VV)/mf.nb_dof();
- if (Q == 0) Q = size_type(1);
- variables[name] = var_description(false, true, &mf,
- gmm::sub_interval(), &VV, 0, Q);
- }
-
- void ga_workspace::add_fixed_size_constant
- (const std::string &name, const model_real_plain_vector &VV) {
- variables[name] = var_description(false, false, 0,
- gmm::sub_interval(), &VV, 0,
- gmm::vect_size(VV));
- }
-
- void ga_workspace::add_im_data(const std::string &name, const im_data &imd,
- const model_real_plain_vector &VV) {
- variables[name] = var_description
- (false, false, 0, gmm::sub_interval(), &VV, &imd,
- gmm::vect_size(VV)/(imd.nb_filtered_index() * imd.nb_tensor_elem()));
- }
-
-
- bool ga_workspace::variable_exists(const std::string &name) const {
- return (md && md->variable_exists(name)) ||
- (parent_workspace && parent_workspace->variable_exists(name)) ||
- (variables.find(name) != variables.end());
- }
-
- bool ga_workspace::variable_group_exists(const std::string &name) const {
- return (variable_groups.find(name) != variable_groups.end()) ||
- (md && md->variable_group_exists(name)) ||
- (parent_workspace && parent_workspace->variable_group_exists(name));
- }
-
- const std::vector<std::string>&
- ga_workspace::variable_group(const std::string &group_name) const {
- std::map<std::string, std::vector<std::string> >::const_iterator
- it = variable_groups.find(group_name);
- if (it != variable_groups.end())
- return (variable_groups.find(group_name))->second;
- if (md && md->variable_group_exists(group_name))
- return md->variable_group(group_name);
- if (parent_workspace &&
- parent_workspace->variable_group_exists(group_name))
- return parent_workspace->variable_group(group_name);
- GMM_ASSERT1(false, "Undefined variable group " << group_name);
- }
-
- const std::string&
- ga_workspace::first_variable_of_group(const std::string &name) const {
- const std::vector<std::string> &t = variable_group(name);
- GMM_ASSERT1(t.size(), "Variable group " << name << " is empty");
- return t[0];
+ template<int S1> inline void tmult_elem_unrolled__
+ (base_tensor::iterator &it, base_tensor::iterator &it1,
+ base_tensor::iterator &it2) {
+ *it++ = (*it1++)*(*it2);
+ tmult_elem_unrolled__<S1-1>(it, it1, it2);
}
+ template<> inline void tmult_elem_unrolled__<0>
+ (base_tensor::iterator &/*it*/, base_tensor::iterator &/*it1*/,
+ base_tensor::iterator &/*it2*/) { }
- bool ga_workspace::is_constant(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end()) return !(it->second.is_variable);
- if (variable_group_exists(name))
- return is_constant(first_variable_of_group(name));
- if (md && md->variable_exists(name)) {
- if (enable_all_md_variables) return md->is_true_data(name);
- return md->is_data(name);
+ // Performs Aij Bkl -> Cijkl, partially unrolled version
+ template<int S1> struct ga_instruction_simple_tmult_unrolled
+ : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ virtual int exec() {
+ size_type s2 = tc2.size();
+ GA_DEBUG_INFO("Instruction: simple tensor product, unrolled with "
+ << tc1.size() << " operations");
+ GA_DEBUG_ASSERT(t.size() == tc1.size() * s2, "Wrong sizes");
+ GA_DEBUG_ASSERT(tc1.size() == S1, "Wrong sizes");
+
+ base_tensor::iterator it = t.begin(), it2 = tc2.begin();
+ for (size_type ii = 0; ii < s2; ++ii, ++it2) {
+ base_tensor::iterator it1 = tc1.begin();
+ tmult_elem_unrolled__<S1>(it, it1, it2);
+ }
+ GA_DEBUG_ASSERT(it == t.end(), "Internal error");
+ return 0;
}
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->is_constant(name);
- GMM_ASSERT1(false, "Undefined variable " << name);
- }
+ ga_instruction_simple_tmult_unrolled(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
+ };
- bool ga_workspace::is_disabled_variable(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end()) return false;
- if (variable_group_exists(name))
- return is_disabled_variable(first_variable_of_group(name));
- if (md && md->variable_exists(name)) {
- if (enable_all_md_variables) return false;
- return md->is_disabled_variable(name);
+ pga_instruction ga_uniform_instruction_simple_tmult
+ (base_tensor &t, base_tensor &tc1, base_tensor &tc2) {
+ switch(tc1.size()) {
+ case 2 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 2>>
+ (t, tc1, tc2);
+ case 3 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 3>>
+ (t, tc1, tc2);
+ case 4 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 4>>
+ (t, tc1, tc2);
+ case 5 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 5>>
+ (t, tc1, tc2);
+ case 6 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 6>>
+ (t, tc1, tc2);
+ case 7 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 7>>
+ (t, tc1, tc2);
+ case 8 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 8>>
+ (t, tc1, tc2);
+ case 9 : return std::make_shared<ga_instruction_simple_tmult_unrolled< 9>>
+ (t, tc1, tc2);
+ case 10 : return std::make_shared<ga_instruction_simple_tmult_unrolled<10>>
+ (t, tc1, tc2);
+ case 11 : return std::make_shared<ga_instruction_simple_tmult_unrolled<11>>
+ (t, tc1, tc2);
+ case 12 : return std::make_shared<ga_instruction_simple_tmult_unrolled<12>>
+ (t, tc1, tc2);
+ case 13 : return std::make_shared<ga_instruction_simple_tmult_unrolled<13>>
+ (t, tc1, tc2);
+ case 14 : return std::make_shared<ga_instruction_simple_tmult_unrolled<14>>
+ (t, tc1, tc2);
+ case 15 : return std::make_shared<ga_instruction_simple_tmult_unrolled<15>>
+ (t, tc1, tc2);
+ case 16 : return std::make_shared<ga_instruction_simple_tmult_unrolled<16>>
+ (t, tc1, tc2);
+ default : return std::make_shared<ga_instruction_simple_tmult>
+ (t, tc1, tc2);
}
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->is_disabled_variable(name);
- GMM_ASSERT1(false, "Undefined variable " << name);
}
- const scalar_type &
- ga_workspace::factor_of_variable(const std::string &name) const {
- static const scalar_type one(1);
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end()) return one;
- if (variable_group_exists(name))
- return one;
- if (md && md->variable_exists(name)) return md->factor_of_variable(name);
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->factor_of_variable(name);
- GMM_ASSERT1(false, "Undefined variable " << name);
- }
- const gmm::sub_interval &
- ga_workspace::interval_of_disabled_variable(const std::string &name) const {
- std::map<std::string, gmm::sub_interval>::const_iterator
- it1 = int_disabled_variables.find(name);
- if (it1 != int_disabled_variables.end()) return it1->second;
- if (md->is_affine_dependent_variable(name))
- return interval_of_disabled_variable(md->org_variable(name));
+ // Performs Ami Bnj -> Cmnij. To be optimized.
+ struct ga_instruction_spec_tmult : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ size_type s1_2, s2_2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: specific tensor product");
+ GA_DEBUG_ASSERT(t.size() == tc1.size() * tc2.size(), "Wrong sizes");
+ size_type s1_1 = tc1.size() / s1_2;
+ size_type s2_1 = tc2.size() / s2_2;
- size_type first = md->nb_dof();
- for (const std::pair<std::string, gmm::sub_interval> &p
- : int_disabled_variables)
- first = std::max(first, p.second.last());
+ base_tensor::iterator it = t.begin();
+ for (size_type j = 0; j < s2_2; ++j)
+ for (size_type i = 0; i < s1_2; ++i)
+ for (size_type n = 0; n < s2_1; ++n)
+ for (size_type m = 0; m < s1_1; ++m, ++it)
+ *it = tc1[m+i*s1_1] * tc2[n+j*s2_1];
+ GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
+ return 0;
+ }
+ ga_instruction_spec_tmult(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_, size_type s1_2_,
+ size_type s2_2_)
+ : t(t_), tc1(tc1_), tc2(tc2_), s1_2(s1_2_), s2_2(s2_2_) {}
+ };
- int_disabled_variables[name]
- = gmm::sub_interval(first, gmm::vect_size(value(name)));
- return int_disabled_variables[name];
- }
+ // Performs Ai Bmj -> Cmij. To be optimized.
+ struct ga_instruction_spec2_tmult : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: second specific tensor product");
+ GA_DEBUG_ASSERT(t.size() == tc1.size() * tc2.size(), "Wrong sizes");
+ size_type s1 = tc1.size();
+ size_type s2_1 = tc2.sizes()[0], s2_2 = tc2.size() / s2_1;
- const gmm::sub_interval &
- ga_workspace::interval_of_variable(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end()) return it->second.I;
- if (md && md->variable_exists(name)) {
- if (enable_all_md_variables && md->is_disabled_variable(name))
- return interval_of_disabled_variable(name);
- return md->interval_of_variable(name);
+ base_tensor::iterator it = t.begin();
+ for (size_type j = 0; j < s2_2; ++j)
+ for (size_type i = 0; i < s1; ++i)
+ for (size_type m = 0; m < s2_1; ++m, ++it)
+ *it = tc1[i] * tc2[m+j*s2_1];
+ GA_DEBUG_ASSERT(it == t.end(), "Wrong sizes");
+ return 0;
}
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->interval_of_variable(name);
- GMM_ASSERT1(false, "Undefined variable " << name);
- }
+ ga_instruction_spec2_tmult(base_tensor &t_, base_tensor &tc1_,
+ base_tensor &tc2_)
+ : t(t_), tc1(tc1_), tc2(tc2_) {}
+ };
- const mesh_fem *
- ga_workspace::associated_mf(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end())
- return it->second.is_fem_dofs ? it->second.mf : 0;
- if (md && md->variable_exists(name))
- return md->pmesh_fem_of_variable(name);
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->associated_mf(name);
- if (variable_group_exists(name))
- return associated_mf(first_variable_of_group(name));
- GMM_ASSERT1(false, "Undefined variable or group " << name);
- }
- const im_data *
- ga_workspace::associated_im_data(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end()) return it->second.imd;
- if (md && md->variable_exists(name))
- return md->pim_data_of_variable(name);
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->associated_im_data(name);
- if (variable_group_exists(name)) return 0;
- GMM_ASSERT1(false, "Undefined variable " << name);
- }
- size_type ga_workspace::qdim(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end()) {
- const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
- const im_data *imd = it->second.imd;
- size_type n = it->second.qdim();
- if (mf) {
- return n * mf->get_qdim();
- } else if (imd) {
- return n * imd->tensor_size().total_size();
- }
- return n;
+ struct ga_instruction_simple_c_matrix : public ga_instruction {
+ base_tensor &t;
+ std::vector<scalar_type *> components;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: gathering components for explicit "
+ "matrix");
+ GA_DEBUG_ASSERT(t.size() == components.size(), "Wrong sizes");
+ for (size_type i = 0; i < components.size(); ++i)
+ t[i] = *(components[i]);
+ return 0;
}
- if (md && md->variable_exists(name))
- return md->qdim_of_variable(name);
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->qdim(name);
- if (variable_group_exists(name))
- return qdim(first_variable_of_group(name));
- GMM_ASSERT1(false, "Undefined variable or group " << name);
- }
+ ga_instruction_simple_c_matrix(base_tensor &t_,
+ std::vector<scalar_type *> &components_)
+ : t(t_), components(components_) {}
+ };
- bgeot::multi_index
- ga_workspace::qdims(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end()) {
- const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
- const im_data *imd = it->second.imd;
- size_type n = it->second.qdim();
- if (mf) {
- bgeot::multi_index mi = mf->get_qdims();
- if (n > 1 || it->second.qdims.size() > 1) {
- size_type i = 0;
- if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
- for (; i < it->second.qdims.size(); ++i)
- mi.push_back(it->second.qdims[i]);
- }
- return mi;
- } else if (imd) {
- bgeot::multi_index mi = imd->tensor_size();
- size_type q = n / imd->nb_filtered_index();
- GMM_ASSERT1(q % imd->nb_tensor_elem() == 0,
- "Invalid mesh im data vector");
- if (n > 1 || it->second.qdims.size() > 1) {
- size_type i = 0;
- if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
- for (; i < it->second.qdims.size(); ++i)
- mi.push_back(it->second.qdims[i]);
+ struct ga_instruction_c_matrix_with_tests : public ga_instruction {
+ base_tensor &t;
+ const std::vector<const base_tensor *> components;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: gathering components for explicit "
+ "matrix with tests functions");
+ size_type s = t.size() / components.size();
+ GA_DEBUG_ASSERT(s, "Wrong sizes");
+ base_tensor::iterator it = t.begin();
+ for (size_type i = 0; i < components.size(); ++i) {
+ const base_tensor &t1 = *(components[i]);
+ if (t1.size() > 1) {
+ GA_DEBUG_ASSERT(t1.size() == s, "Wrong sizes, " << t1.size()
+ << " != " << s);
+ for (size_type j = 0; j < s; ++j) *it++ = t1[j];
+ } else {
+ for (size_type j = 0; j < s; ++j) *it++ = t1[0];
}
- return mi;
}
- return it->second.qdims;
+ return 0;
}
- if (md && md->variable_exists(name))
- return md->qdims_of_variable(name);
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->qdims(name);
- if (variable_group_exists(name))
- return qdims(first_variable_of_group(name));
- GMM_ASSERT1(false, "Undefined variable or group " << name);
- }
+ ga_instruction_c_matrix_with_tests
+ (base_tensor &t_, const std::vector<const base_tensor *> &components_)
+ : t(t_), components(components_) {}
+ };
- const model_real_plain_vector &
- ga_workspace::value(const std::string &name) const {
- VAR_SET::const_iterator it = variables.find(name);
- if (it != variables.end())
- return *(it->second.V);
- if (md && md->variable_exists(name))
- return md->real_variable(name);
- if (parent_workspace && parent_workspace->variable_exists(name))
- return parent_workspace->value(name);
- if (variable_group_exists(name))
- return value(first_variable_of_group(name));
- GMM_ASSERT1(false, "Undefined variable or group " << name);
- }
+ struct ga_instruction_eval_func_1arg_1res : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c;
+ pscalar_func_onearg f1;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a one argument "
+ "predefined function on a scalar");
+ t = (*f1)(c);
+ return 0;
+ }
+ ga_instruction_eval_func_1arg_1res(scalar_type &t_, const scalar_type &c_,
+ pscalar_func_onearg f1_)
+ : t(t_), c(c_), f1(f1_) {}
+ };
- scalar_type ga_workspace::get_time_step() const {
- if (md) return md->get_time_step();
- if (parent_workspace) return parent_workspace->get_time_step();
- GMM_ASSERT1(false, "No time step defined here");
- }
+ struct ga_instruction_eval_func_1arg_1res_expr : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c;
+ const ga_predef_function &F;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a one argument "
+ "predefined function on a scalar");
+ t = F(c);
+ return 0;
+ }
+ ga_instruction_eval_func_1arg_1res_expr(scalar_type &t_,
+ const scalar_type &c_,
+ const ga_predef_function &F_)
+ : t(t_), c(c_), F(F_) {}
+ };
+ struct ga_instruction_eval_func_1arg : public ga_instruction {
+ base_tensor &t, &tc1;
+ pscalar_func_onearg f1;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a one argument "
+ "predefined function on tensor");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ for (size_type i = 0; i < t.size(); ++i) t[i] = (*f1)(tc1[i]);
+ return 0;
+ }
+ ga_instruction_eval_func_1arg(base_tensor &t_, base_tensor &c_,
+ pscalar_func_onearg f1_)
+ : t(t_), tc1(c_), f1(f1_) {}
+ };
- // Macros
- bool ga_workspace::macro_exists(const std::string &name) const {
- if (macros.find(name) != macros.end()) return true;
- if (md && md->macro_exists(name)) return true;
- if (parent_workspace &&
- parent_workspace->macro_exists(name)) return true;
- return false;
- }
+ struct ga_instruction_eval_func_1arg_expr : public ga_instruction {
+ base_tensor &t, &tc1;
+ const ga_predef_function &F;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a one argument "
+ "predefined function on tensor");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[i]);
+ return 0;
+ }
+ ga_instruction_eval_func_1arg_expr(base_tensor &t_, base_tensor &c_,
+ const ga_predef_function &F_)
+ : t(t_), tc1(c_), F(F_) {}
+ };
- const std::string&
- ga_workspace::get_macro(const std::string &name) const {
- std::map<std::string, std::string>::const_iterator it=macros.find(name);
- if (it != macros.end()) return it->second;
- if (md && md->macro_exists(name)) return md->get_macro(name);
- if (parent_workspace &&
- parent_workspace->macro_exists(name))
- return parent_workspace->get_macro(name);
- GMM_ASSERT1(false, "Undefined macro");
- }
+ struct ga_instruction_eval_func_2arg_1res : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c, &d;
+ pscalar_func_twoargs f2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on two scalar");
+ t = (*f2)(c, d);
+ return 0;
+ }
+ ga_instruction_eval_func_2arg_1res(scalar_type &t_, const scalar_type &c_,
+ const scalar_type &d_,
+ pscalar_func_twoargs f2_)
+ : t(t_), c(c_), d(d_), f2(f2_) {}
+ };
- ga_tree &
- ga_workspace::macro_tree(const std::string &name, size_type meshdim,
- size_type ref_elt_dim, bool ignore_X) const {
- GMM_ASSERT1(macro_exists(name), "Undefined macro");
- auto it = macro_trees.find(name);
- bool to_be_analyzed = false;
- m_tree *mt = 0;
+ struct ga_instruction_eval_func_2arg_1res_expr : public ga_instruction {
+ scalar_type &t;
+ const scalar_type &c, &d;
+ const ga_predef_function &F;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on two scalar");
+ t = F(c, d);
+ return 0;
+ }
+ ga_instruction_eval_func_2arg_1res_expr(scalar_type &t_,
+ const scalar_type &c_,
+ const scalar_type &d_,
+ const ga_predef_function &F_)
+ : t(t_), c(c_), d(d_), F(F_) {}
+ };
- if (it == macro_trees.end()) {
- mt = &(macro_trees[name]);
- to_be_analyzed = true;
- } else {
- mt = &(it->second);
- GMM_ASSERT1(mt->ptree, "Recursive definition of macro " << name);
- if (mt->meshdim != meshdim || mt->ignore_X != ignore_X) {
- to_be_analyzed = true;
- delete mt->ptree; mt->ptree = 0;
- }
+ struct ga_instruction_eval_func_2arg_first_scalar : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ pscalar_func_twoargs f2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on one scalar and one tensor");
+ GA_DEBUG_ASSERT(t.size() == tc2.size(), "Wrong sizes");
+ for (size_type i = 0; i < t.size(); ++i) t[i] = (*f2)(tc1[0], tc2[i]);
+ return 0;
}
- if (to_be_analyzed) {
- ga_tree tree;
- ga_read_string(get_macro(name), tree);
- ga_semantic_analysis(get_macro(name), tree, *this, meshdim, ref_elt_dim,
- false, ignore_X, 3);
- GMM_ASSERT1(tree.root, "Invalid macro");
- mt->ptree = new ga_tree(tree);
- mt->meshdim = meshdim;
- mt->ignore_X = ignore_X;
+ ga_instruction_eval_func_2arg_first_scalar
+ (base_tensor &t_, base_tensor &c_, base_tensor &d_,
+ pscalar_func_twoargs f2_)
+ : t(t_), tc1(c_), tc2(d_), f2(f2_) {}
+ };
+
+ struct ga_instruction_eval_func_2arg_first_scalar_expr
+ : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ const ga_predef_function &F;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on one scalar and one tensor");
+ GA_DEBUG_ASSERT(t.size() == tc2.size(), "Wrong sizes");
+ for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[0], tc2[i]);
+ return 0;
}
- return *(mt->ptree);
- }
+ ga_instruction_eval_func_2arg_first_scalar_expr
+ (base_tensor &t_, base_tensor &c_, base_tensor &d_,
+ const ga_predef_function &F_)
+ : t(t_), tc1(c_), tc2(d_), F(F_) {}
+ };
- void ga_workspace::add_interpolate_transformation
- (const std::string &name, pinterpolate_transformation ptrans) {
- if (transformations.find(name) != transformations.end())
- GMM_ASSERT1(name.compare("neighbour_elt"), "neighbour_elt is a "
- "reserved interpolate transformation name");
- transformations[name] = ptrans;
- }
+ struct ga_instruction_eval_func_2arg_second_scalar : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ pscalar_func_twoargs f2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on one tensor and one scalar");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ for (size_type i = 0; i < t.size(); ++i) t[i] = (*f2)(tc1[i], tc2[0]);
+ return 0;
+ }
+ ga_instruction_eval_func_2arg_second_scalar(base_tensor &t_,
+ base_tensor &c_,
+ base_tensor &d_,
+ pscalar_func_twoargs f2_)
+ : t(t_), tc1(c_), tc2(d_), f2(f2_) {}
+ };
- bool ga_workspace::interpolate_transformation_exists
- (const std::string &name) const {
- return (md && md->interpolate_transformation_exists(name)) ||
- (parent_workspace &&
- parent_workspace->interpolate_transformation_exists(name)) ||
- (transformations.find(name) != transformations.end());
- }
+ struct ga_instruction_eval_func_2arg_second_scalar_expr
+ : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ const ga_predef_function &F;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on one tensor and one scalar");
+ GA_DEBUG_ASSERT(t.size() == tc1.size(), "Wrong sizes");
+ for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[i], tc2[0]);
+ return 0;
+ }
+ ga_instruction_eval_func_2arg_second_scalar_expr
+ (base_tensor &t_, base_tensor &c_, base_tensor &d_,
+ const ga_predef_function &F_)
+ : t(t_), tc1(c_), tc2(d_), F(F_) {}
+ };
+
+ struct ga_instruction_eval_func_2arg : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ pscalar_func_twoargs f2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on two tensors");
+ GA_DEBUG_ASSERT(t.size() == tc1.size() && t.size() == tc2.size(),
+ "Wrong sizes");
- pinterpolate_transformation
- ga_workspace::interpolate_transformation(const std::string &name) const {
- std::map<std::string, pinterpolate_transformation>::const_iterator
- it = transformations.find(name);
- if (it != transformations.end()) return it->second;
- if (md && md->interpolate_transformation_exists(name))
- return md->interpolate_transformation(name);
- if (parent_workspace &&
- parent_workspace->interpolate_transformation_exists(name))
- return parent_workspace->interpolate_transformation(name);
- GMM_ASSERT1(false, "Inexistent transformation " << name);
- }
+ for (size_type i = 0; i < t.size(); ++i) t[i] = (*f2)(tc1[i], tc2[i]);
+ return 0;
+ }
+ ga_instruction_eval_func_2arg(base_tensor &t_, base_tensor &c_,
+ base_tensor &d_, pscalar_func_twoargs f2_)
+ : t(t_), tc1(c_), tc2(d_), f2(f2_) {}
+ };
- bool ga_workspace::elementary_transformation_exists
- (const std::string &name) const {
- return (md && md->elementary_transformation_exists(name)) ||
- (parent_workspace &&
- parent_workspace->elementary_transformation_exists(name)) ||
- (elem_transformations.find(name) != elem_transformations.end());
- }
+ struct ga_instruction_eval_func_2arg_expr : public ga_instruction {
+ base_tensor &t, &tc1, &tc2;
+ const ga_predef_function &F;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: evaluation of a two arguments "
+ "predefined function on two tensors");
+ GA_DEBUG_ASSERT(t.size() == tc1.size() && t.size() == tc2.size(),
+ "Wrong sizes");
- pelementary_transformation
- ga_workspace::elementary_transformation(const std::string &name) const {
- std::map<std::string, pelementary_transformation>::const_iterator
- it = elem_transformations.find(name);
- if (it != elem_transformations.end()) return it->second;
- if (md && md->elementary_transformation_exists(name))
- return md->elementary_transformation(name);
- if (parent_workspace &&
- parent_workspace->elementary_transformation_exists(name))
- return parent_workspace->elementary_transformation(name);
- GMM_ASSERT1(false, "Inexistent elementary transformation " << name);
- }
+ for (size_type i = 0; i < t.size(); ++i) t[i] = F(tc1[i], tc2[i]);
+ return 0;
+ }
+ ga_instruction_eval_func_2arg_expr(base_tensor &t_, base_tensor &c_,
+ base_tensor &d_,
+ const ga_predef_function &F_)
+ : t(t_), tc1(c_), tc2(d_), F(F_) {}
+ };
- const mesh_region &
- ga_workspace::register_region(const mesh &m, const mesh_region ®ion) {
- if (&m == &dummy_mesh())
- return dummy_mesh_region();
+ struct ga_instruction_eval_OP : public ga_instruction {
+ base_tensor &t;
+ const ga_nonlinear_operator &OP;
+ ga_nonlinear_operator::arg_list args;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: operator evaluation");
+ OP.value(args, t);
+ return 0;
+ }
+ ga_instruction_eval_OP(base_tensor &t_, const ga_nonlinear_operator &OP_,
+ ga_nonlinear_operator::arg_list &args_)
+ : t(t_), OP(OP_), args(args_) {}
+ };
- std::list<mesh_region> &lmr = registred_mesh_regions[&m];
- for (const mesh_region &rg : lmr)
- if (rg.compare(m, region, m)) return rg;
- lmr.push_back(region);
- return lmr.back();
- }
+ struct ga_instruction_eval_derivative_OP : public ga_instruction {
+ base_tensor &t;
+ const ga_nonlinear_operator &OP;
+ ga_nonlinear_operator::arg_list args;
+ size_type der1;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: operator derivative evaluation");
+ OP.derivative(args, der1, t);
+ return 0;
+ }
+ ga_instruction_eval_derivative_OP(base_tensor &t_,
+ const ga_nonlinear_operator &OP_,
+ ga_nonlinear_operator::arg_list &args_,
+ size_type der1_)
+ : t(t_), OP(OP_), args(args_), der1(der1_) {}
+ };
+
+ struct ga_instruction_eval_second_derivative_OP : public ga_instruction {
+ base_tensor &t;
+ const ga_nonlinear_operator &OP;
+ ga_nonlinear_operator::arg_list args;
+ size_type der1, der2;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: operator second derivative evaluation");
+ OP.second_derivative(args, der1, der2, t);
+ return 0;
+ }
+ ga_instruction_eval_second_derivative_OP
+ (base_tensor &t_, const ga_nonlinear_operator &OP_,
+ ga_nonlinear_operator::arg_list &args_, size_type der1_, size_type der2_)
+ : t(t_), OP(OP_), args(args_), der1(der1_), der2(der2_) {}
+ };
+ struct ga_instruction_tensor_slice : public ga_instruction {
+ base_tensor &t, &tc1;
+ bgeot::multi_index mi, indices;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: tensor slice");
+ size_type order = t.sizes().size();
+ for (bgeot::multi_index mi3(order); !mi3.finished(t.sizes());
+ mi3.incrementation(t.sizes())) {
+ for (size_type j = 0; j < order; ++j)
+ mi[indices[j]] = mi3[j];
+ t(mi3) = tc1(mi);
+ }
+ return 0;
+ }
+ ga_instruction_tensor_slice(base_tensor &t_, base_tensor &tc1_,
+ bgeot::multi_index &mi_,
+ bgeot::multi_index &indices_)
+ : t(t_), tc1(tc1_), mi(mi_), indices(indices_) {}
+ };
+ struct ga_instruction_transformation_call : public ga_instruction {
+ const ga_workspace &workspace;
+ ga_instruction_set::interpolate_info &inin;
+ pinterpolate_transformation trans;
+ fem_interpolation_context &ctx;
+ const base_small_vector &Normal;
+ const mesh &m;
+ bool compute_der;
- static bool ga_extract_variables(const pga_tree_node pnode,
- const ga_workspace &workspace,
- const mesh &m,
- std::set<var_trans_pair> &vars,
- bool ignore_data) {
- bool expand_groups = !ignore_data;
- bool found_var = false;
- if (pnode->node_type == GA_NODE_VAL ||
- pnode->node_type == GA_NODE_GRAD ||
- pnode->node_type == GA_NODE_HESS ||
- pnode->node_type == GA_NODE_DIVERG ||
- pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
- pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
- pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
- pnode->node_type == GA_NODE_INTERPOLATE_DIVERG ||
- pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
- pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
- pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
- pnode->node_type == GA_NODE_ELEMENTARY_DIVERG ||
- pnode->node_type == GA_NODE_XFEM_PLUS_VAL ||
- pnode->node_type == GA_NODE_XFEM_PLUS_GRAD ||
- pnode->node_type == GA_NODE_XFEM_PLUS_HESS ||
- pnode->node_type == GA_NODE_XFEM_PLUS_DIVERG ||
- pnode->node_type == GA_NODE_XFEM_MINUS_VAL ||
- pnode->node_type == GA_NODE_XFEM_MINUS_GRAD ||
- pnode->node_type == GA_NODE_XFEM_MINUS_HESS ||
- pnode->node_type == GA_NODE_XFEM_MINUS_DIVERG) {
- bool group = workspace.variable_group_exists(pnode->name);
- bool iscte = (!group) && workspace.is_constant(pnode->name);
- if (!iscte) found_var = true;
- if (!ignore_data || !iscte) {
- if (group && expand_groups) {
- for (const std::string &t : workspace.variable_group(pnode->name))
- vars.insert(var_trans_pair(t, pnode->interpolate_name));
- } else
- vars.insert(var_trans_pair(pnode->name, pnode->interpolate_name));
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: call interpolate transformation");
+ base_node P_ref;
+ size_type cv;
+ short_type face_num;
+ gmm::clear(inin.Normal);
+ inin.pt_type = trans->transform(workspace, m, ctx, Normal, &(inin.m), cv,
+ face_num, P_ref, inin.Normal,
+ inin.derivatives, compute_der);
+ if (inin.pt_type) {
+ if (cv != size_type(-1)) {
+ inin.m->points_of_convex(cv, inin.G);
+ inin.ctx.change((inin.m)->trans_of_convex(cv),
+ 0, P_ref, inin.G, cv, face_num);
+ inin.has_ctx = true;
+ if (face_num != short_type(-1)) {
+ inin.Normal = bgeot::compute_normal(inin.ctx, face_num);
+ gmm::scale(inin.Normal, 1.0/gmm::vect_norm2(inin.Normal));
+ } else
+ inin.Normal.resize(0);
+ inin.pt_y = inin.ctx.xreal();
+ } else {
+ inin.ctx.invalid_convex_num();
+ inin.pt_y = P_ref;
+ inin.has_ctx = false;
+ }
+ } else {
+ inin.ctx.invalid_convex_num();
+ inin.Normal.resize(0);
+ inin.pt_y.resize(0);
+ inin.has_ctx = false;
}
+ GA_DEBUG_INFO("Instruction: end of call interpolate transformation");
+ return 0;
}
- if (pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
- pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
- pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
- pnode->node_type == GA_NODE_INTERPOLATE_DIVERG ||
- pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST ||
- pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST ||
- pnode->node_type == GA_NODE_INTERPOLATE_HESS_TEST ||
- pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST ||
- pnode->node_type == GA_NODE_INTERPOLATE_X ||
- pnode->node_type == GA_NODE_INTERPOLATE_NORMAL) {
- workspace.interpolate_transformation(pnode->interpolate_name)
- ->extract_variables(workspace, vars, ignore_data, m,
- pnode->interpolate_name);
- }
- for (auto&& child : pnode->children)
- found_var = ga_extract_variables(child, workspace, m,
- vars, ignore_data)
- || found_var;
- return found_var;
- }
+ ga_instruction_transformation_call
+ (const ga_workspace &w, ga_instruction_set::interpolate_info &i,
+ pinterpolate_transformation t, fem_interpolation_context &ctxx,
+ const base_small_vector &No, const mesh &mm, bool compute_der_)
+ : workspace(w), inin(i), trans(t), ctx(ctxx), Normal(No), m(mm),
+ compute_der(compute_der_) {}
+ };
- static size_type ref_elt_dim_of_mesh(const mesh &m) {
- if (m.convex_index().card())
- return m.trans_of_convex(m.convex_index().first())->dim();
- else
- return size_type(0);
- }
+ struct ga_instruction_neighbour_transformation_call : public ga_instruction {
+ const ga_workspace &workspace;
+ ga_instruction_set::interpolate_info &inin;
+ pinterpolate_transformation trans;
+ fem_interpolation_context &ctx;
+ base_small_vector &Normal;
+ const mesh &m;
+ size_type &ipt;
+ papprox_integration &pai;
+ bgeot::geotrans_precomp_pool &gp_pool;
+ std::map<gauss_pt_corresp, bgeot::pstored_point_tab> &neighbour_corresp;
- void ga_workspace::add_tree(ga_tree &tree, const mesh &m,
- const mesh_im &mim, const mesh_region &rg,
- const std::string &expr,
- size_type add_derivative_order,
- bool function_expr, size_type for_interpolation,
- const std::string varname_interpolation) {
- if (tree.root) {
+ virtual int exec() {
+ bool cancel_optimization = false;
+ GA_DEBUG_INFO("Instruction: call interpolate transformation");
+ if (ipt == 0) {
+ if (!(ctx.have_pgp()) || !pai || pai->is_built_on_the_fly()
+ || cancel_optimization) {
+ inin.ctx.invalid_convex_num();
+ } else {
+ // Test if the situation has already been encountered
+ size_type cv = ctx.convex_num();
+ short_type f = ctx.face_num();
+ auto adj_face = m.adjacent_face(cv, f);
+ if (adj_face.cv == size_type(-1)) {
+ inin.ctx.invalid_convex_num();
+ } else {
+ gauss_pt_corresp gpc;
+ gpc.pgt1 = m.trans_of_convex(cv);
+ gpc.pgt2 = m.trans_of_convex(adj_face.cv);
+ gpc.pai = pai;
+ auto inds_pt1 = m.ind_points_of_face_of_convex(cv, f);
+ auto inds_pt2 = m.ind_points_of_face_of_convex(adj_face.cv,
+ adj_face.f);
+ auto str1 = gpc.pgt1->structure();
+ auto str2 = gpc.pgt2->structure();
+ size_type nbptf1 = str1->nb_points_of_face(f);
+ size_type nbptf2 = str2->nb_points_of_face(adj_face.f);
+ gpc.nodes.resize(nbptf1*2);
+ for (size_type i = 0; i < nbptf1; ++i) {
+ gpc.nodes[2*i] = str1->ind_points_of_face(f)[i];
+ bool found = false;
+ for (size_type j = 0; j < nbptf2; ++j) {
+ if (inds_pt2[j] == inds_pt1[i]) {
+ gpc.nodes[2*i+1] = str2->ind_points_of_face(adj_face.f)[j];
+ found = true;
+ break;
+ }
+ }
+ GMM_ASSERT1(found, "Internal error");
+ }
+ bgeot::pstored_point_tab pspt = 0;
+ auto itm = neighbour_corresp.find(gpc);
+ if (itm != neighbour_corresp.end()) {
+ pspt = itm->second;
+ } else {
+ size_type nbpt = pai->nb_points_on_face(f);
+ bgeot::geotrans_inv_convex gic;
+ gic.init(m.points_of_convex(adj_face.cv), gpc.pgt2);
+ size_type first_ind = pai->ind_first_point_on_face(f);
+ const bgeot::stored_point_tab
+ &spt = *(pai->pintegration_points());
+ base_matrix G;
+ m.points_of_convex(cv, G);
+ fem_interpolation_context ctx_x(gpc.pgt1, 0, spt[0], G, cv, f);
+ std::vector<base_node> P_ref(nbpt);
- // Eliminate the term if it corresponds to disabled variables
- if ((tree.root->test_function_type >= 1 &&
- is_disabled_variable(tree.root->name_test1)) ||
- (tree.root->test_function_type >= 2 &&
- is_disabled_variable(tree.root->name_test2))) {
- // cout<<"disabling term "; ga_print_node(tree.root, cout);
cout<<endl;
- return;
+ for (size_type i = 0; i < nbpt; ++i) {
+ ctx_x.set_xref(spt[first_ind+i]);
+ bool converged = true;
+ bool is_in = gic.invert(ctx_x.xreal(),
P_ref[i],converged,1E-4);
+ GMM_ASSERT1(is_in && converged,"Geometric transformation "
+ "inversion has failed in neighbour
transformation");
+ }
+ pspt = store_point_tab(P_ref);
+ neighbour_corresp[gpc] = pspt;
+ }
+ m.points_of_convex(adj_face.cv, inin.G);
+ bgeot::pgeotrans_precomp pgp = gp_pool(gpc.pgt2, pspt);
+ inin.ctx.change(pgp, 0, 0, inin.G, adj_face.cv, adj_face.f);
+ }
+ }
}
- // cout << "add tree with tests functions of " << tree.root->name_test1
- // << " and " << tree.root->name_test2 << endl;
- // ga_print_node(tree.root, cout); cout << endl;
- bool remain = true;
- size_type order = 0, ind_tree = 0;
- if (for_interpolation)
- order = size_type(-1) - add_derivative_order;
- else {
- switch(tree.root->test_function_type) {
- case 0: order = 0; break;
- case 1: order = 1; break;
- case 3: order = 2; break;
- default: GMM_ASSERT1(false, "Inconsistent term "
- << tree.root->test_function_type);
+ if (inin.ctx.have_pgp()) {
+ inin.ctx.set_ii(ipt);
+ inin.pt_type = 1;
+ inin.has_ctx = true;
+ inin.pt_y = inin.ctx.xreal();
+ inin.Normal = bgeot::compute_normal(inin.ctx, inin.ctx.face_num());
+ gmm::scale(inin.Normal, 1.0/gmm::vect_norm2(inin.Normal));
+ inin.m = &m;
+ } else {
+ base_node P_ref;
+ size_type cv;
+ short_type face_num;
+ gmm::clear(inin.Normal);
+ inin.pt_type = trans->transform(workspace, m, ctx, Normal, &(inin.m),
+ cv, face_num, P_ref, inin.Normal,
+ inin.derivatives, false);
+ if (inin.pt_type) {
+ if (cv != size_type(-1)) {
+ inin.m->points_of_convex(cv, inin.G);
+ inin.ctx.change((inin.m)->trans_of_convex(cv),
+ 0, P_ref, inin.G, cv, face_num);
+ inin.has_ctx = true;
+ if (face_num != short_type(-1)) {
+ inin.Normal = bgeot::compute_normal(inin.ctx, face_num);
+ gmm::scale(inin.Normal, 1.0/gmm::vect_norm2(inin.Normal));
+ } else
+ inin.Normal.resize(0);
+ inin.pt_y = inin.ctx.xreal();
+ } else {
+ inin.ctx.invalid_convex_num();
+ inin.pt_y = P_ref;
+ inin.has_ctx = false;
+ }
+ } else {
+ inin.ctx.invalid_convex_num();
+ inin.Normal.resize(0);
+ inin.pt_y.resize(0);
+ inin.has_ctx = false;
}
}
+ GA_DEBUG_INFO("Instruction: end of call interpolate transformation");
+ return 0;
+ }
+ ga_instruction_neighbour_transformation_call
+ (const ga_workspace &w, ga_instruction_set::interpolate_info &i,
+ pinterpolate_transformation t, fem_interpolation_context &ctxx,
+ base_small_vector &No, const mesh &mm, size_type &ipt_,
+ papprox_integration &pai_, bgeot::geotrans_precomp_pool &gp_pool_,
+ std::map<gauss_pt_corresp, bgeot::pstored_point_tab> &neighbour_corresp_)
+ : workspace(w), inin(i), trans(t), ctx(ctxx), Normal(No), m(mm),
+ ipt(ipt_), pai(pai_), gp_pool(gp_pool_),
+ neighbour_corresp(neighbour_corresp_) {}
+ };
- bool found = false;
- for (size_type i = 0; i < trees.size(); ++i) {
- if (trees[i].mim == &mim && trees[i].m == &m &&
- trees[i].order == order &&
- trees[i].name_test1.compare(tree.root->name_test1) == 0 &&
- trees[i].interpolate_name_test1.compare
- (tree.root->interpolate_name_test1) == 0 &&
- trees[i].name_test2.compare(tree.root->name_test2) == 0 &&
- trees[i].interpolate_name_test2.compare
- (tree.root->interpolate_name_test2) == 0 &&
- trees[i].rg == &rg && trees[i].interpolation == for_interpolation
&&
- trees[i].varname_interpolation.compare(varname_interpolation)==0) {
- ga_tree &ftree = *(trees[i].ptree);
- ftree.insert_node(ftree.root, GA_NODE_OP);
- ftree.root->op_type = GA_PLUS;
- ftree.root->children.resize(2, nullptr);
- ftree.copy_node(tree.root, ftree.root, ftree.root->children[1]);
- ga_semantic_analysis("", ftree, *this, m.dim(),
- ref_elt_dim_of_mesh(m), false, function_expr);
- found = true;
- break;
+ struct ga_instruction_scalar_assembly : public ga_instruction {
+ base_tensor &t;
+ scalar_type &E, &coeff;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: scalar term assembly");
+ E += t[0] * coeff;
+ return 0;
+ }
+ ga_instruction_scalar_assembly(base_tensor &t_, scalar_type &E_,
+ scalar_type &coeff_)
+ : t(t_), E(E_), coeff(coeff_) {}
+ };
+
+ struct ga_instruction_fem_vector_assembly : public ga_instruction {
+ base_tensor &t;
+ base_vector &Vr, &Vn;
+ const fem_interpolation_context &ctx;
+ const gmm::sub_interval &Ir, &In;
+ const mesh_fem *mfn, **mfg;
+ scalar_type &coeff;
+ const size_type &nbpt, &ipt;
+ base_vector elem;
+ bool interpolate;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: vector term assembly for fem variable");
+ if (ipt == 0 || interpolate) {
+ elem.resize(t.size());
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ size_type nd = ((t.size()) >> 2);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ = (*itt++) * coeff; *it++ = (*itt++) * coeff;
+ *it++ = (*itt++) * coeff; *it++ = (*itt++) * coeff;
+ }
+ for (; it != ite;) *it++ = (*itt++) * coeff;
+ // gmm::copy(gmm::scaled(t.as_vector(), coeff), elem);
+ } else {
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ size_type nd = ((t.size()) >> 2);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ += (*itt++) * coeff; *it++ += (*itt++) * coeff;
+ *it++ += (*itt++) * coeff; *it++ += (*itt++) * coeff;
}
+ for (; it != ite;) *it++ += (*itt++) * coeff;
+ // gmm::add(gmm::scaled(t.as_vector(), coeff), elem);
+ }
+ if (ipt == nbpt-1 || interpolate) {
+ const mesh_fem &mf = *(mfg ? *mfg : mfn);
+ GMM_ASSERT1(mfg ? *mfg : mfn, "Internal error");
+ const gmm::sub_interval &I = mf.is_reduced() ? Ir : In;
+ base_vector &V = mf.is_reduced() ? Vr : Vn;
+ if (!(ctx.is_convex_num_valid())) return 0;
+ size_type cv_1 = ctx.convex_num();
+ // size_type cv_1 = ctx.is_convex_num_valid()
+ // ? ctx.convex_num() : mf.convex_index().first_true();
+ GA_DEBUG_ASSERT(V.size() >= I.first() + mf.nb_basic_dof(),
+ "Bad assembly vector size");
+ auto &ct = mf.ind_scalar_basic_dof_of_element(cv_1);
+ size_type qmult = mf.get_qdim();
+ if (qmult > 1) qmult /= mf.fem_of_element(cv_1)->target_dim();
+ size_type ifirst = I.first();
+ auto ite = elem.begin();
+ for (auto itc = ct.begin(); itc != ct.end(); ++itc)
+ for (size_type q = 0; q < qmult; ++q)
+ V[ifirst+(*itc)+q] += *ite++;
+ GMM_ASSERT1(ite == elem.end(), "Internal error");
}
+ return 0;
+ }
+ ga_instruction_fem_vector_assembly
+ (base_tensor &t_, base_vector &Vr_, base_vector &Vn_,
+ const fem_interpolation_context &ctx_,
+ const gmm::sub_interval &Ir_, const gmm::sub_interval &In_,
+ const mesh_fem *mfn_, const mesh_fem **mfg_,
+ scalar_type &coeff_,
+ const size_type &nbpt_, const size_type &ipt_, bool interpolate_)
+ : t(t_), Vr(Vr_), Vn(Vn_), ctx(ctx_), Ir(Ir_), In(In_), mfn(mfn_),
+ mfg(mfg_), coeff(coeff_), nbpt(nbpt_), ipt(ipt_),
+ interpolate(interpolate_) {}
+ };
- if (!found) {
- ind_tree = trees.size(); remain = false;
- trees.push_back(tree_description());
- trees.back().mim = &mim; trees.back().m = &m;
- trees.back().rg = &rg;
- trees.back().ptree = new ga_tree;
- trees.back().ptree->swap(tree);
- pga_tree_node root = trees.back().ptree->root;
- trees.back().name_test1 = root->name_test1;
- trees.back().name_test2 = root->name_test2;
- trees.back().interpolate_name_test1 = root->interpolate_name_test1;
- trees.back().interpolate_name_test2 = root->interpolate_name_test2;
- trees.back().order = order;
- trees.back().interpolation = for_interpolation;
- trees.back().varname_interpolation = varname_interpolation;
- }
+ struct ga_instruction_vector_assembly : public ga_instruction {
+ base_tensor &t;
+ base_vector &V;
+ const gmm::sub_interval &I;
+ scalar_type &coeff;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: vector term assembly for "
+ "fixed size variable");
+ gmm::add(gmm::scaled(t.as_vector(), coeff), gmm::sub_vector(V, I));
+ return 0;
+ }
+ ga_instruction_vector_assembly(base_tensor &t_, base_vector &V_,
+ const gmm::sub_interval &I_,
+ scalar_type &coeff_)
+ : t(t_), V(V_), I(I_), coeff(coeff_) {}
+ };
- if (for_interpolation == 0 && order < add_derivative_order) {
- std::set<var_trans_pair> expr_variables;
- ga_extract_variables((remain ? tree : *(trees[ind_tree].ptree)).root,
- *this, m, expr_variables, true);
- for (const var_trans_pair &var : expr_variables) {
- if (!(is_constant(var.varname))) {
- ga_tree dtree = (remain ? tree : *(trees[ind_tree].ptree));
- // cout << "Derivation with respect to " << var.first << " : "
- // << var.second << " of " << ga_tree_to_string(dtree) << endl;
- GA_TIC;
- ga_derivative(dtree, *this, m, var.varname, var.transname,
1+order);
- // cout << "Result : " << ga_tree_to_string(dtree) << endl;
- GA_TOCTIC("Derivative time");
- ga_semantic_analysis(expr, dtree, *this, m.dim(),
- ref_elt_dim_of_mesh(m), false, function_expr);
- GA_TOCTIC("Analysis after Derivative time");
- // cout << "after analysis " << ga_tree_to_string(dtree) << endl;
- add_tree(dtree, m, mim, rg, expr, add_derivative_order,
- function_expr, for_interpolation, varname_interpolation);
- }
- }
+ struct ga_instruction_assignment : public ga_instruction {
+ base_tensor &t;
+ base_vector &V;
+ const fem_interpolation_context &ctx;
+ const im_data *imd;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: Assignement to im_data");
+ imd->set_tensor(V, ctx.convex_num(), ctx.ii(), t);
+ return 0;
+ }
+ ga_instruction_assignment(base_tensor &t_, base_vector &V_,
+ const fem_interpolation_context &ctx_,
+ const im_data *imd_)
+ : t(t_), V(V_), ctx(ctx_), imd(imd_) {}
+ };
+
+ template <class MAT>
+ inline void add_elem_matrix_
+ (MAT &K, const std::vector<size_type> &dofs1,
+ const std::vector<size_type> &dofs2, std::vector<size_type> &/*dofs1_sort*/,
+ base_vector &elem, scalar_type threshold, size_type /* N */) {
+ base_vector::const_iterator it = elem.cbegin();
+ for (const size_type &dof2 : dofs2)
+ for (const size_type &dof1 : dofs1) {
+ if (gmm::abs(*it) > threshold)
+ K(dof1, dof2) += *it;
+ ++it;
}
- }
}
- ga_workspace::m_tree::~m_tree() { if (ptree) delete ptree; }
- ga_workspace::m_tree::m_tree(const m_tree& o)
- : ptree(o.ptree), meshdim(o.meshdim), ignore_X(o.ignore_X)
- { if (o.ptree) ptree = new ga_tree(*(o.ptree)); }
- ga_workspace::m_tree &ga_workspace::m_tree::operator =(const m_tree& o) {
- if (ptree) delete ptree;
- ptree = o.ptree; meshdim = o.meshdim; ignore_X = o.ignore_X;
- if (o.ptree) ptree = new ga_tree(*(o.ptree));
- return *this;
- }
+ // static const std::vector<size_type> *the_indto_sort;
+ // int compare_my_indices(const void *a, const void *b) {
+ // size_type aa = *((const size_type *)(a));
+ // size_type bb = *((const size_type *)(b));
+ // return int((*the_indto_sort)[aa]) - int((*the_indto_sort)[bb]);
+ // }
- size_type ga_workspace::add_expression(const std::string &expr,
- const mesh_im &mim,
- const mesh_region &rg_,
- size_type add_derivative_order) {
- const mesh_region &rg = register_region(mim.linked_mesh(), rg_);
- // cout << "adding expression " << expr << endl;
- GA_TIC;
- size_type max_order = 0;
- std::vector<ga_tree> ltrees(1);
- ga_read_string(expr, ltrees[0]);
- // cout << "read : " << ga_tree_to_string(ltrees[0]) << endl;
- ga_semantic_analysis(expr, ltrees[0], *this, mim.linked_mesh().dim(),
- ref_elt_dim_of_mesh(mim.linked_mesh()),
- false, false, 1);
- // cout << "analysed : " << ga_tree_to_string(ltrees[0]) << endl;
- GA_TOC("First analysis time");
- if (ltrees[0].root) {
- if (test1.size() > 1 || test2.size() > 1) {
- size_type ntest2 = std::max(size_type(1), test2.size());
- size_type nb_ltrees = test1.size()*ntest2;
- ltrees.resize(nb_ltrees);
- for (size_type i = 1; i < nb_ltrees; ++i) ltrees[i] = ltrees[0];
- std::set<var_trans_pair>::iterator it1 = test1.begin();
- for (size_type i = 0; i < test1.size(); ++i, ++it1) {
- std::set<var_trans_pair>::iterator it2 = test2.begin();
- for (size_type j = 0; j < ntest2; ++j) {
- selected_test1 = *it1;
- if (test2.size()) selected_test2 = *it2++;
- // cout << "analysis with " << selected_test1.first << endl;
- ga_semantic_analysis(expr, ltrees[i*ntest2+j], *this,
- mim.linked_mesh().dim(),
- ref_elt_dim_of_mesh(mim.linked_mesh()),
- false, false, 2);
- // cout <<"split: "<< ga_tree_to_string(ltrees[i*ntest2+j]) <<
endl;
- }
- }
- }
+ inline void add_elem_matrix_
+ (gmm::col_matrix<gmm::rsvector<scalar_type>> &K,
+ const std::vector<size_type> &dofs1, const std::vector<size_type> &dofs2,
+ std::vector<size_type> &dofs1_sort,
+ base_vector &elem, scalar_type threshold, size_type N) {
+ size_type maxest = (N+1) * std::max(dofs1.size(), dofs2.size());
+ size_type s1 = dofs1.size(), s2 = dofs2.size();
+ gmm::elt_rsvector_<scalar_type> ev;
- for (size_type i = 0; i < ltrees.size(); ++i) {
- if (ltrees[i].root) {
- // cout << "adding tree " << ga_tree_to_string(ltrees[i]) << endl;
- max_order = std::max(ltrees[i].root->nb_test_functions(), max_order);
- add_tree(ltrees[i], mim.linked_mesh(), mim, rg, expr,
- add_derivative_order, true, 0, "");
- }
- }
+ dofs1_sort.resize(s1);
+ for (size_type i = 0; i < s1; ++i) { // insertion sort
+ size_type j = i, k = j-1;
+ while (j > 0 && dofs1[i] < dofs1[dofs1_sort[k]])
+ { dofs1_sort[j] = dofs1_sort[k]; j--; k--; }
+ dofs1_sort[j] = i;
}
- GA_TOC("Time for add expression");
- return max_order;
- }
- void ga_workspace::add_function_expression(const std::string &expr) {
- ga_tree tree;
- ga_read_string(expr, tree);
- ga_semantic_analysis(expr, tree, *this, 1, 1, false, true);
- if (tree.root) {
- // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
- // "Invalid function expression");
- add_tree(tree, dummy_mesh(), dummy_mesh_im(), dummy_mesh_region(),
- expr, 0, true, 0, "");
- }
- }
+ // dofs1_sort.resize(s1); // test with qsort: not faster in the tested
cases
+ // for (size_type i = 0; i < s1; ++i) dofs1_sort[i] = i;
+ // the_indto_sort = &dofs1;
+ // qsort(&(dofs1_sort[0]), s1, sizeof(size_type), compare_my_indices);
- void ga_workspace::add_interpolation_expression(const std::string &expr,
- const mesh &m,
- const mesh_region &rg_) {
- const mesh_region &rg = register_region(m, rg_);
- ga_tree tree;
- ga_read_string(expr, tree);
- ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
- false, false);
- if (tree.root) {
- // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
- // "Invalid expression containing test functions");
- add_tree(tree, m, dummy_mesh_im(), rg, expr, 0, false, 1, "");
- }
- }
+ base_vector::const_iterator it = elem.cbegin();
+ for (size_type j = 0; j < s2; ++j) { // Iteration on columns
+ if (j) it += s1;
+ std::vector<gmm::elt_rsvector_<scalar_type>> &col = K[dofs2[j]];
+ size_type nb = col.size();
- void ga_workspace::add_interpolation_expression(const std::string &expr,
- const mesh_im &mim,
- const mesh_region &rg_) {
- const mesh &m = mim.linked_mesh();
- const mesh_region &rg = register_region(m, rg_);
- ga_tree tree;
- ga_read_string(expr, tree);
- ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
- false, false);
- if (tree.root) {
- GMM_ASSERT1(tree.root->nb_test_functions() == 0,
- "Invalid expression containing test functions");
- add_tree(tree, m, mim, rg, expr, 0, false, 1, "");
- }
- }
+ if (nb == 0) {
+ col.reserve(maxest);
+ for (size_type i = 0; i < s1; ++i) {
+ size_type k = dofs1_sort[i]; ev.e = *(it+k);
+ if (gmm::abs(ev.e) > threshold) { ev.c=dofs1[k]; col.push_back(ev); }
+ }
+ } else { // column merge
+ size_type ind = 0;
+ for (size_type i = 0; i < s1; ++i) {
+ size_type k = dofs1_sort[i]; ev.e = *(it+k);
+ if (gmm::abs(ev.e) > threshold) {
+ ev.c = dofs1[k];
- void ga_workspace::add_assignment_expression
- (const std::string &varname, const std::string &expr, const mesh_region &rg_,
- size_type order, bool before) {
- const im_data *imd = associated_im_data(varname);
- GMM_ASSERT1(imd != 0, "Only applicable to im_data");
- const mesh_im &mim = imd->linked_mesh_im();
- const mesh &m = mim.linked_mesh();
- const mesh_region &rg = register_region(m, rg_);
- ga_tree tree;
- ga_read_string(expr, tree);
- ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
- false, false);
- if (tree.root) {
- GMM_ASSERT1(tree.root->nb_test_functions() == 0,
- "Invalid expression containing test functions");
- add_tree(tree, m, mim, rg, expr, order+1, false, (before ? 1 : 2),
- varname);
+ size_type count = nb - ind, step, l;
+ while (count > 0) {
+ step = count / 2; l = ind + step;
+ if (col[l].c < ev.c) { ind = ++l; count -= step + 1; }
+ else count = step;
+ }
+
+ auto itc = col.begin() + ind;
+ if (ind != nb && itc->c == ev.c) itc->e += ev.e;
+ else {
+ if (nb - ind > 1100)
+ GMM_WARNING2("Inefficient addition of element in rsvector with
"
+ << col.size() - ind << " non-zero entries");
+ col.push_back(ev);
+ if (ind != nb) {
+ itc = col.begin() + ind;
+ auto ite = col.end(); --ite; auto itee = ite;
+ for (; ite != itc; --ite) { --itee; *ite = *itee; }
+ *itc = ev;
+ }
+ ++nb;
+ }
+ ++ind;
+ }
+ }
+ }
}
}
- size_type ga_workspace::nb_trees() const { return trees.size(); }
- ga_workspace::tree_description &ga_workspace::tree_info(size_type i)
- { return trees[i]; }
+ template <class MAT = model_real_sparse_matrix>
+ struct ga_instruction_matrix_assembly : public ga_instruction {
+ const base_tensor &t;
+ MAT &Kr, &Kn;
+ const fem_interpolation_context &ctx1, &ctx2;
+ const gmm::sub_interval &Ir1, &Ir2;
+ const gmm::sub_interval &In1, &In2;
+ const mesh_fem *mfn1, *mfn2;
+ const mesh_fem **mfg1, **mfg2;
+ const scalar_type &coeff, &alpha1, &alpha2;
+ const size_type &nbpt, &ipt;
+ base_vector elem;
+ bool interpolate;
+ std::vector<size_type> dofs1, dofs2, dofs1_sort;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: matrix term assembly");
+ if (ipt == 0 || interpolate) {
+ elem.resize(t.size());
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ scalar_type e = coeff*alpha1*alpha2;
+ size_type nd = ((t.size()) >> 2);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ }
+ for (; it != ite;) *it++ = (*itt++) * e;
+ // gmm::copy(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
+ } else {
+ // Faster than a daxpy blas call on my config
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ scalar_type e = coeff*alpha1*alpha2;
+ size_type nd = ((t.size()) >> 2);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ }
+ for (; it != ite;) *it++ += (*itt++) * e;
+ // gmm::add(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
+ }
+ if (ipt == nbpt-1 || interpolate) {
+ const mesh_fem *pmf1 = mfg1 ? *mfg1 : mfn1;
+ const mesh_fem *pmf2 = mfg2 ? *mfg2 : mfn2;
+ bool reduced = (pmf1 && pmf1->is_reduced())
+ || (pmf2 && pmf2->is_reduced());
+ MAT &K = reduced ? Kr : Kn;
+ const gmm::sub_interval &I1 = reduced ? Ir1 : In1;
+ const gmm::sub_interval &I2 = reduced ? Ir2 : In2;
+ GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
- bool ga_workspace::used_variables(std::vector<std::string> &vl,
- std::vector<std::string> &vl_test1,
- std::vector<std::string> &vl_test2,
- std::vector<std::string> &dl,
- size_type order) {
- bool islin = true;
- std::set<var_trans_pair> vll, dll;
- for (size_type i = 0; i < vl.size(); ++i)
- vll.insert(var_trans_pair(vl[i], ""));
- for (size_type i = 0; i < dl.size(); ++i)
- dll.insert(var_trans_pair(dl[i], ""));
+ scalar_type ninf = gmm::vect_norminf(elem);
+ if (ninf == scalar_type(0)) return 0;
- for (size_type i = 0; i < trees.size(); ++i) {
- ga_workspace::tree_description &td = trees[i];
- std::set<var_trans_pair> dllaux;
- bool fv = ga_extract_variables(td.ptree->root, *this, *(td.m),
- dllaux, false);
+ size_type s1 = t.sizes()[0], s2 = t.sizes()[1];
+ size_type cv1 = pmf1 ? ctx1.convex_num() : s1;
+ size_type cv2 = pmf2 ? ctx2.convex_num() : s2;
+ size_type N = 1;
- if (td.order == order) {
- for (std::set<var_trans_pair>::iterator it = dllaux.begin();
- it!=dllaux.end(); ++it)
- dll.insert(*it);
- }
- switch (td.order) {
- case 0: break;
- case 1:
- if (td.order == order) {
- if (variable_group_exists(td.name_test1)) {
- for (const std::string &t : variable_group(td.name_test1))
- vll.insert(var_trans_pair(t, td.interpolate_name_test1));
- } else {
- vll.insert(var_trans_pair(td.name_test1,
- td.interpolate_name_test1));
- }
- bool found = false;
- for (const std::string &t : vl_test1)
- if (td.name_test1.compare(t) == 0)
- found = true;
- if (!found)
- vl_test1.push_back(td.name_test1);
- }
- break;
- case 2:
- if (td.order == order) {
- if (variable_group_exists(td.name_test1)) {
- for (const std::string &t : variable_group(td.name_test1))
- vll.insert(var_trans_pair(t, td.interpolate_name_test1));
+ dofs1.assign(s1, I1.first());
+ if (pmf1) {
+ if (!(ctx1.is_convex_num_valid())) return 0;
+ N = ctx1.N();
+ auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
+ size_type qmult1 = pmf1->get_qdim();
+ if (qmult1 > 1) qmult1 /= pmf1->fem_of_element(cv1)->target_dim();
+ auto itd = dofs1.begin();
+ if (qmult1 == 1) {
+ for (auto itt = ct1.begin(); itt != ct1.end(); ++itt)
+ *itd++ += *itt;
} else {
- vll.insert(var_trans_pair(td.name_test1,
- td.interpolate_name_test1));
+ for (auto itt = ct1.begin(); itt != ct1.end(); ++itt)
+ for (size_type q = 0; q < qmult1; ++q)
+ *itd++ += *itt + q;
}
- if (variable_group_exists(td.name_test2)) {
- for (const std::string &t : variable_group(td.name_test2))
- vll.insert(var_trans_pair(t, td.interpolate_name_test2));
+ } else
+ for (size_type i=0; i < s1; ++i) dofs1[i] += i;
+
+ if (pmf1 == pmf2 && cv1 == cv2) {
+ if (I1.first() == I2.first()) {
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf*1E-14, N);
} else {
- vll.insert(var_trans_pair(td.name_test2,
- td.interpolate_name_test2));
- }
- bool found = false;
- for (size_type j = 0; j < vl_test1.size(); ++j)
- if ((td.name_test1.compare(vl_test1[j]) == 0) &&
- (td.name_test2.compare(vl_test2[j]) == 0))
- found = true;
- if (!found) {
- vl_test1.push_back(td.name_test1);
- vl_test2.push_back(td.name_test2);
+ dofs2.resize(dofs1.size());
+ for (size_type i = 0; i < dofs1.size(); ++i)
+ dofs2[i] = dofs1[i] + I2.first() - I1.first();
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
}
+ } else {
+ dofs2.assign(s2, I2.first());
+ if (pmf2) {
+ if (!(ctx2.is_convex_num_valid())) return 0;
+ N = std::max(N, ctx2.N());
+ auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
+ size_type qmult2 = pmf2->get_qdim();
+ if (qmult2 > 1) qmult2 /= pmf2->fem_of_element(cv2)->target_dim();
+ auto itd = dofs2.begin();
+ if (qmult2 == 1) {
+ for (auto itt = ct2.begin(); itt != ct2.end(); ++itt)
+ *itd++ += *itt;
+ } else {
+ for (auto itt = ct2.begin(); itt != ct2.end(); ++itt)
+ for (size_type q = 0; q < qmult2; ++q)
+ *itd++ += *itt + q;
+ }
+ } else
+ for (size_type i=0; i < s2; ++i) dofs2[i] += i;
+
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
}
- if (fv) islin = false;
- break;
}
+ return 0;
}
- vl.clear();
- for (const auto &var : vll)
- if (vl.size() == 0 || var.varname.compare(vl.back()))
- vl.push_back(var.varname);
- dl.clear();
- for (const auto &var : dll)
- if (dl.size() == 0 || var.varname.compare(dl.back()))
- dl.push_back(var.varname);
+ ga_instruction_matrix_assembly
+ (const base_tensor &t_, MAT &Kr_, MAT &Kn_,
+ const fem_interpolation_context &ctx1_,
+ const fem_interpolation_context &ctx2_,
+ const gmm::sub_interval &Ir1_, const gmm::sub_interval &In1_,
+ const gmm::sub_interval &Ir2_, const gmm::sub_interval &In2_,
+ const mesh_fem *mfn1_, const mesh_fem **mfg1_,
+ const mesh_fem *mfn2_, const mesh_fem **mfg2_,
+ const scalar_type &coeff_,
+ const scalar_type &alpha2_, const scalar_type &alpha1_,
+ const size_type &nbpt_, const size_type &ipt_, bool interpolate_)
+ : t(t_), Kr(Kr_), Kn(Kn_), ctx1(ctx1_), ctx2(ctx2_),
+ Ir1(Ir1_), Ir2(Ir2_), In1(In1_), In2(In2_),
+ mfn1(mfn1_), mfn2(mfn2_), mfg1(mfg1_), mfg2(mfg2_),
+ coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
+ nbpt(nbpt_), ipt(ipt_), interpolate(interpolate_),
+ dofs1(0), dofs2(0) {}
+ };
- return islin;
- }
+ template <class MAT = model_real_sparse_matrix>
+ struct ga_instruction_matrix_assembly_standard_scalar: public ga_instruction
{
+ const base_tensor &t;
+ MAT &K;
+ const fem_interpolation_context &ctx1, &ctx2;
+ const gmm::sub_interval &I1, &I2;
+ const mesh_fem *pmf1, *pmf2;
+ const scalar_type &coeff, &alpha1, &alpha2;
+ const size_type &nbpt, &ipt;
+ base_vector elem;
+ std::vector<size_type> dofs1, dofs2, dofs1_sort;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
+ "scalar fems");
+ if (ipt == 0) {
+ elem.resize(t.size());
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ scalar_type e = coeff*alpha1*alpha2;
+ size_type nd = ((t.size()) >> 2);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ }
+ for (; it != ite;) *it++ = (*itt++) * e;
+ // gmm::copy(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
+ } else {
+ // Faster than a daxpy blas call on my config
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ scalar_type e = coeff*alpha1*alpha2;
+ size_type nd = ((t.size()) >> 2);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ }
+ for (; it != ite;) *it++ += (*itt++) * e;
+ // gmm::add(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
+ }
+ if (ipt == nbpt-1) {
+ GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
- void ga_workspace::define_variable_group(const std::string &group_name,
- const std::vector<std::string> &nl)
{
- GMM_ASSERT1(!(variable_exists(group_name)), "The name of a group of "
- "variables cannot be the same as a variable name");
+ scalar_type ninf = gmm::vect_norminf(elem);
+ if (ninf == scalar_type(0)) return 0;
- std::set<const mesh *> ms;
- bool is_data_ = false;
- for (size_type i = 0; i < nl.size(); ++i) {
- if (i == 0)
- is_data_ = is_constant(nl[i]);
- else {
- GMM_ASSERT1(is_data_ == is_constant(nl[i]),
- "It is not possible to mix variables and data in a group");
+ size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num(), N=ctx1.N();
+ if (cv1 == size_type(-1)) return 0;
+ auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
+ GA_DEBUG_ASSERT(ct1.size() == t.sizes()[0], "Internal error");
+ dofs1.resize(ct1.size());
+ for (size_type i = 0; i < ct1.size(); ++i)
+ dofs1[i] = ct1[i] + I1.first();
+
+ if (pmf2 == pmf1 && cv1 == cv2) {
+ if (I1.first() == I2.first()) {
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf*1E-14, N);
+ } else {
+ dofs2.resize(dofs1.size());
+ for (size_type i = 0; i < dofs1.size(); ++i)
+ dofs2[i] = dofs1[i] + I2.first() - I1.first();
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ }
+ } else {
+ if (cv2 == size_type(-1)) return 0;
+ auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
+ GA_DEBUG_ASSERT(ct2.size() == t.sizes()[1], "Internal error");
+ dofs2.resize(ct2.size());
+ for (size_type i = 0; i < ct2.size(); ++i)
+ dofs2[i] = ct2[i] + I2.first();
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ }
+ }
+ return 0;
+ }
+ ga_instruction_matrix_assembly_standard_scalar
+ (const base_tensor &t_, MAT &Kn_,
+ const fem_interpolation_context &ctx1_,
+ const fem_interpolation_context &ctx2_,
+ const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
+ const mesh_fem *mfn1_, const mesh_fem *mfn2_,
+ const scalar_type &coeff_, const scalar_type &alpha2_,
+ const scalar_type &alpha1_,
+ const size_type &nbpt_, const size_type &ipt_)
+ : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
+ I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
+ coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
+ nbpt(nbpt_), ipt(ipt_) {}
+ };
+
+ template <class MAT = model_real_sparse_matrix>
+ struct ga_instruction_matrix_assembly_standard_vector: public ga_instruction
{
+ const base_tensor &t;
+ MAT &K;
+ const fem_interpolation_context &ctx1, &ctx2;
+ const gmm::sub_interval &I1, &I2;
+ const mesh_fem *pmf1, *pmf2;
+ const scalar_type &coeff, &alpha1, &alpha2;
+ const size_type &nbpt, &ipt;
+ mutable base_vector elem;
+ mutable std::vector<size_type> dofs1, dofs2, dofs1_sort;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
+ "vector fems");
+ if (ipt == 0) {
+ elem.resize(t.size());
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ scalar_type e = coeff*alpha1*alpha2;
+ size_type nd = ((t.size()) >> 3);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ *it++ = (*itt++) * e; *it++ = (*itt++) * e;
+ }
+ for (; it != ite;) *it++ = (*itt++) * e;
+ // gmm::copy(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
+ } else {
+ // (Far) faster than a daxpy blas call on my config.
+ auto itt = t.begin(); auto it = elem.begin(), ite = elem.end();
+ scalar_type e = coeff*alpha1*alpha2;
+ size_type nd = ((t.size()) >> 3);
+ for (size_type i = 0; i < nd; ++i) {
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ *it++ += (*itt++) * e; *it++ += (*itt++) * e;
+ }
+ for (; it != ite;) *it++ += (*itt++) * e;
+ // gmm::add(gmm::scaled(t.as_vector(), coeff*alpha1*alpha2), elem);
}
- GMM_ASSERT1(variable_exists(nl[i]),
- "All variables in a group have to exist in the model");
- const mesh_fem *mf = associated_mf(nl[i]);
- GMM_ASSERT1(mf, "Variables in a group should be fem variables");
- GMM_ASSERT1(ms.find(&(mf->linked_mesh())) == ms.end(),
- "Two variables in a group cannot share the same mesh");
- ms.insert(&(mf->linked_mesh()));
- }
- variable_groups[group_name] = nl;
- }
-
-
- const std::string &ga_workspace::variable_in_group
- (const std::string &group_name, const mesh &m) const {
- if (variable_group_exists(group_name)) {
- for (const std::string &t : variable_group(group_name))
- if (&(associated_mf(t)->linked_mesh()) == &m)
- return t;
- GMM_ASSERT1(false, "No variable in this group for the given mesh");
- } else
- return group_name;
- }
+ if (ipt == nbpt-1) {
+ GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
+ scalar_type ninf = gmm::vect_norminf(elem);
+ if (ninf == scalar_type(0)) return 0;
+ size_type s1 = t.sizes()[0], s2 = t.sizes()[1], N = ctx1.N();
- void ga_workspace::assembly(size_type order) {
- size_type ndof;
- const ga_workspace *w = this;
- while (w->parent_workspace) w = w->parent_workspace;
- if (w->md) ndof = w->md->nb_dof(); // To eventually call actualize_sizes()
+ size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num();
+ if (cv1 == size_type(-1)) return 0;
+ auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
+ size_type qmult1 = pmf1->get_qdim();
+ if (qmult1 > 1) qmult1 /= pmf1->fem_of_element(cv1)->target_dim();
+ dofs1.assign(s1, I1.first());
+ auto itd = dofs1.begin();
+ for (auto itt = ct1.begin(); itt != ct1.end(); ++itt)
+ for (size_type q = 0; q < qmult1; ++q)
+ *itd++ += *itt + q;
- GA_TIC;
- ga_instruction_set gis;
- ga_compile(*this, gis, order);
- ndof = gis.nb_dof;
- size_type max_dof = gis.max_dof;
- GA_TOCTIC("Compile time");
+ if (pmf2 == pmf1 && cv1 == cv2) {
+ if (I1.first() == I2.first()) {
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf*1E-14, N);
+ } else {
+ dofs2.resize(dofs1.size());
+ for (size_type i = 0; i < dofs1.size(); ++i)
+ dofs2[i] = dofs1[i] + I2.first() - I1.first();
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ }
+ } else {
+ if (cv2 == size_type(-1)) return 0;
+ auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
+ size_type qmult2 = pmf2->get_qdim();
+ if (qmult2 > 1) qmult2 /= pmf2->fem_of_element(cv2)->target_dim();
+ dofs2.assign(s2, I2.first());
+ itd = dofs2.begin();
+ for (auto itt = ct2.begin(); itt != ct2.end(); ++itt)
+ for (size_type q = 0; q < qmult2; ++q)
+ *itd++ += *itt + q;
- if (order == 2) {
- if (K.use_count()) {
- gmm::clear(*K);
- gmm::resize(*K, max_dof, max_dof);
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf*1E-14, N);
+ }
}
- gmm::clear(unreduced_K);
- gmm::resize(unreduced_K, ndof, ndof);
+ return 0;
}
- if (order == 1) {
- if (V.use_count()) {
- gmm::clear(*V);
- gmm::resize(*V, max_dof);
+ ga_instruction_matrix_assembly_standard_vector
+ (const base_tensor &t_, MAT &Kn_,
+ const fem_interpolation_context &ctx1_,
+ const fem_interpolation_context &ctx2_,
+ const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
+ const mesh_fem *mfn1_, const mesh_fem *mfn2_,
+ const scalar_type &coeff_, const scalar_type &alpha2_,
+ const scalar_type &alpha1_, const size_type &nbpt_,
+ const size_type &ipt_)
+ : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
+ I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
+ coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
+ nbpt(nbpt_), ipt(ipt_), dofs1(0), dofs2(0) {}
+ };
+
+ struct ga_instruction_matrix_assembly_standard_vector_opt10_2
+ : public ga_instruction {
+ const base_tensor &t;
+ model_real_sparse_matrix &K;
+ const fem_interpolation_context &ctx1, &ctx2;
+ const gmm::sub_interval &I1, &I2;
+ const mesh_fem *pmf1, *pmf2;
+ const scalar_type &coeff, &alpha1, &alpha2;
+ const size_type &nbpt, &ipt;
+ mutable base_vector elem;
+ mutable std::vector<size_type> dofs1, dofs2, dofs1_sort;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
+ "vector fems optimized for format 10 qdim 2");
+ size_type s1 = t.sizes()[0], s2 = t.sizes()[1], s1_q = 2*s1;
+ size_type ss1 = s1/2, ss2 = s2/2;
+ scalar_type e = coeff*alpha1*alpha2;
+ if (ipt == 0) {
+ elem.resize(ss1*ss2);
+ auto itel = elem.begin();
+ for (size_type j = 0; j < ss2; ++j) {
+ auto it = t.begin() + j*s1_q;
+ for (size_type i = 0; i < ss1; ++i, it += 2)
+ *itel++ = (*it) * e;
+ }
+ } else {
+ auto itel = elem.begin();
+ for (size_type j = 0; j < ss2; ++j) {
+ auto it = t.begin() + j*s1_q;
+ for (size_type i = 0; i < ss1; ++i, it += 2)
+ *itel++ += (*it) * e;
+ }
}
- gmm::clear(unreduced_V);
- gmm::resize(unreduced_V, ndof);
- }
- E = 0;
- GA_TOCTIC("Init time");
+ if (ipt == nbpt-1) {
+ GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
- ga_exec(gis, *this);
- GA_TOCTIC("Exec time");
+ scalar_type ninf = gmm::vect_norminf(elem) * 1E-14;
+ if (ninf == scalar_type(0)) return 0;
+ size_type N = ctx1.N();
+ size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num();
+ size_type i1 = I1.first(), i2 = I2.first();
+ if (cv1 == size_type(-1)) return 0;
+ auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
+ dofs1.resize(ss1);
+ for (size_type i = 0; i < ss1; ++i) dofs1[i] = i1 + ct1[i];
- if (order == 1) {
- MPI_SUM_VECTOR(assembled_vector());
- MPI_SUM_VECTOR(unreduced_V);
- } else if (order == 0) {
- assembled_potential() = MPI_SUM_SCALAR(assembled_potential());
+ if (pmf2 == pmf1 && cv1 == cv2) {
+ if (i1 == i2) {
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
+ } else {
+ dofs2.resize(ss2);
+ for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct1[i];
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ }
+ } else {
+ if (cv2 == size_type(-1)) return 0;
+ auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
+ dofs2.resize(ss2);
+ for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct2[i];
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ }
+ }
+ return 0;
}
+ ga_instruction_matrix_assembly_standard_vector_opt10_2
+ (const base_tensor &t_, model_real_sparse_matrix &Kn_,
+ const fem_interpolation_context &ctx1_,
+ const fem_interpolation_context &ctx2_,
+ const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
+ const mesh_fem *mfn1_, const mesh_fem *mfn2_,
+ const scalar_type &coeff_, const scalar_type &alpha2_,
+ const scalar_type &alpha1_, const size_type &nbpt_,
+ const size_type &ipt_)
+ : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
+ I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
+ coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
+ nbpt(nbpt_), ipt(ipt_), dofs1(0), dofs2(0) {}
+ };
- // Deal with reduced fems.
- if (order > 0) {
- std::set<std::string> vars_vec_done;
- std::set<std::pair<std::string, std::string> > vars_mat_done;
- for (ga_tree &tree : gis.trees) {
- if (tree.root) {
- if (order == 1) {
- const std::string &name = tree.root->name_test1;
- const std::vector<std::string> vnames_(1,name);
- const std::vector<std::string> &vnames
- = variable_group_exists(name) ? variable_group(name)
- : vnames_;
- for (const std::string &vname : vnames) {
- const mesh_fem *mf = associated_mf(vname);
- if (mf && mf->is_reduced() &&
- vars_vec_done.find(vname) == vars_vec_done.end()) {
- gmm::mult_add(gmm::transposed(mf->extension_matrix()),
- gmm::sub_vector(unreduced_V,
- gis.var_intervals[vname]),
- gmm::sub_vector(*V,
- interval_of_variable(vname)));
- vars_vec_done.insert(vname);
- }
- }
+ struct ga_instruction_matrix_assembly_standard_vector_opt10_3
+ : public ga_instruction {
+ const base_tensor &t;
+ model_real_sparse_matrix &K;
+ const fem_interpolation_context &ctx1, &ctx2;
+ const gmm::sub_interval &I1, &I2;
+ const mesh_fem *pmf1, *pmf2;
+ const scalar_type &coeff, &alpha1, &alpha2;
+ const size_type &nbpt, &ipt;
+ mutable base_vector elem;
+ mutable std::vector<size_type> dofs1, dofs2, dofs1_sort;
+ virtual int exec() {
+ GA_DEBUG_INFO("Instruction: matrix term assembly for standard "
+ "vector fems optimized for format 10 qdim 3");
+ size_type s1 = t.sizes()[0], s2 = t.sizes()[1], s1_q = 3*s1;
+ size_type ss1 = s1/3, ss2 = s2/3;
+ scalar_type e = coeff*alpha1*alpha2;
+ if (ipt == 0) {
+ elem.resize(ss1*ss2);
+ auto itel = elem.begin();
+ for (size_type j = 0; j < ss2; ++j) {
+ auto it = t.begin() + j*s1_q;
+ for (size_type i = 0; i < ss1; ++i, it += 3)
+ *itel++ = (*it) * e;
+ }
+ } else {
+ auto itel = elem.begin();
+ for (size_type j = 0; j < ss2; ++j) {
+ auto it = t.begin() + j*s1_q;
+ for (size_type i = 0; i < ss1; ++i, it += 3)
+ *itel++ += (*it) * e;
+ }
+ }
+ if (ipt == nbpt-1) {
+ GA_DEBUG_ASSERT(I1.size() && I2.size(), "Internal error");
+
+ scalar_type ninf = gmm::vect_norminf(elem)*1E-14;
+ if (ninf == scalar_type(0)) return 0;
+ size_type N = ctx1.N();
+ size_type cv1 = ctx1.convex_num(), cv2 = ctx2.convex_num();
+ size_type i1 = I1.first(), i2 = I2.first();
+ if (cv1 == size_type(-1)) return 0;
+ auto &ct1 = pmf1->ind_scalar_basic_dof_of_element(cv1);
+ dofs1.resize(ss1);
+ for (size_type i = 0; i < ss1; ++i) dofs1[i] = i1 + ct1[i];
+
+ if (pmf2 == pmf1 && cv1 == cv2) {
+ if (i1 == i2) {
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ add_elem_matrix_(K, dofs1, dofs1, dofs1_sort, elem, ninf, N);
} else {
- std::string &name1 = tree.root->name_test1;
- std::string &name2 = tree.root->name_test2;
- const std::vector<std::string> vnames1_(1,name1),
- vnames2_(2,name2);
- const std::vector<std::string> &vnames1
- = variable_group_exists(name1) ? variable_group(name1)
- : vnames1_;
- const std::vector<std::string> &vnames2
- = variable_group_exists(name2) ? variable_group(name2)
- : vnames2_;
- for (const std::string &vname1 : vnames1) {
- for (const std::string &vname2 : vnames2) {
- const mesh_fem *mf1 = associated_mf(vname1);
- const mesh_fem *mf2 = associated_mf(vname2);
- if (((mf1 && mf1->is_reduced())
- || (mf2 && mf2->is_reduced()))) {
- std::pair<std::string, std::string> p(vname1, vname2);
- if (vars_mat_done.find(p) == vars_mat_done.end()) {
- gmm::sub_interval uI1 = gis.var_intervals[vname1];
- gmm::sub_interval uI2 = gis.var_intervals[vname2];
- gmm::sub_interval I1 = interval_of_variable(vname1);
- gmm::sub_interval I2 = interval_of_variable(vname2);
- if ((mf1 && mf1->is_reduced()) &&
- (mf2 && mf2->is_reduced())) {
- model_real_sparse_matrix aux(I1.size(), uI2.size());
- model_real_row_sparse_matrix M(I1.size(), I2.size());
- gmm::mult(gmm::transposed(mf1->extension_matrix()),
- gmm::sub_matrix(unreduced_K, uI1, uI2), aux);
- gmm::mult(aux, mf2->extension_matrix(), M);
- gmm::add(M, gmm::sub_matrix(*K, I1, I2));
- } else if (mf1 && mf1->is_reduced()) {
- model_real_sparse_matrix M(I1.size(), I2.size());
- gmm::mult(gmm::transposed(mf1->extension_matrix()),
- gmm::sub_matrix(unreduced_K, uI1, uI2), M);
- gmm::add(M, gmm::sub_matrix(*K, I1, I2));
- } else {
- model_real_row_sparse_matrix M(I1.size(), I2.size());
- gmm::mult(gmm::sub_matrix(unreduced_K, uI1, uI2),
- mf2->extension_matrix(), M);
- gmm::add(M, gmm::sub_matrix(*K, I1, I2));
- }
- vars_mat_done.insert(p);
- }
- }
- }
- }
+ dofs2.resize(ss2);
+ for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct1[i];
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
}
+ } else {
+ if (cv2 == size_type(-1)) return 0;
+ auto &ct2 = pmf2->ind_scalar_basic_dof_of_element(cv2);
+ dofs2.resize(ss2);
+ for (size_type i = 0; i < ss2; ++i) dofs2[i] = i2 + ct2[i];
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
+ for (size_type i = 0; i < ss1; ++i) (dofs1[i])++;
+ for (size_type i = 0; i < ss2; ++i) (dofs2[i])++;
+ add_elem_matrix_(K, dofs1, dofs2, dofs1_sort, elem, ninf, N);
}
}
+ return 0;
}
- }
-
- void ga_workspace::clear_expressions() {
- trees.clear();
- macro_trees.clear();
- }
+ ga_instruction_matrix_assembly_standard_vector_opt10_3
+ (const base_tensor &t_, model_real_sparse_matrix &Kn_,
+ const fem_interpolation_context &ctx1_,
+ const fem_interpolation_context &ctx2_,
+ const gmm::sub_interval &In1_, const gmm::sub_interval &In2_,
+ const mesh_fem *mfn1_, const mesh_fem *mfn2_,
+ const scalar_type &coeff_, const scalar_type &alpha2_,
+ const scalar_type &alpha1_, const size_type &nbpt_,
+ const size_type &ipt_)
+ : t(t_), K(Kn_), ctx1(ctx1_), ctx2(ctx2_),
+ I1(In1_), I2(In2_), pmf1(mfn1_), pmf2(mfn2_),
+ coeff(coeff_), alpha1(alpha1_), alpha2(alpha2_),
+ nbpt(nbpt_), ipt(ipt_), dofs1(0), dofs2(0) {}
+ };
- void ga_workspace::print(std::ostream &str) {
- for (size_type i = 0; i < trees.size(); ++i)
- if (trees[i].ptree->root) {
- cout << "Expression tree " << i << " of order " <<
- trees[i].ptree->root->nb_test_functions() << " :" << endl;
- ga_print_node(trees[i].ptree->root, str);
- cout << endl;
- }
- }
- void ga_workspace::tree_description::copy(const tree_description& td) {
- order = td.order;
- interpolation = td.interpolation;
- varname_interpolation = td.varname_interpolation;
- name_test1 = td.name_test1;
- name_test2 = td.name_test2;
- interpolate_name_test1 = td.interpolate_name_test1;
- interpolate_name_test2 = td.interpolate_name_test2;
- mim = td.mim;
- m = td.m;
- rg = td.rg;
- ptree = 0;
- if (td.ptree) ptree = new ga_tree(*(td.ptree));
- }
- ga_workspace::tree_description &ga_workspace::tree_description::operator =
- (const ga_workspace::tree_description& td)
- { if (ptree) delete ptree; ptree = 0; copy(td); return *this; }
- ga_workspace::tree_description::~tree_description()
- { if (ptree) delete ptree; ptree = 0; }
//=========================================================================
- // Some hash code functions for node identification
+ // Structure dealing with user defined environment : constant, variables,
+ // functions, operators.
//=========================================================================
- static scalar_type ga_hash_code(const std::string &s) {
- scalar_type c(0);
- for (size_type i = 0; i < s.size(); ++i)
- c += sin(M_E+scalar_type(s[i]))+M_PI*M_E*scalar_type(i+1);
- return c;
+ void ga_workspace::init() {
+ // allocate own storage for K an V to be used unless/until external
+ // storage is provided with set_assembled_matrix/vector
+ K = std::make_shared<model_real_sparse_matrix>(2,2);
+ V = std::make_shared<base_vector>(2);
+ // add default transformations
+ add_interpolate_transformation
+ ("neighbour_elt", interpolate_transformation_neighbour_instance());
}
- static scalar_type ga_hash_code(const base_tensor &t) {
- scalar_type c(0);
- for (size_type i = 0; i < t.size(); ++i)
- c += sin(M_E+t[i]+M_E*M_E*scalar_type(i+1))+scalar_type(i+1)*M_PI;
- return c;
+ // variables and variable groups
+ void ga_workspace::add_fem_variable
+ (const std::string &name, const mesh_fem &mf,
+ const gmm::sub_interval &I, const model_real_plain_vector &VV) {
+ variables[name] = var_description(true, true, &mf, I, &VV, 0, 1);
}
- static scalar_type ga_hash_code(GA_NODE_TYPE e) {
- return cos(M_E + scalar_type((e == GA_NODE_ZERO) ? GA_NODE_CONSTANT : e));
+ void ga_workspace::add_fixed_size_variable
+ (const std::string &name,
+ const gmm::sub_interval &I, const model_real_plain_vector &VV) {
+ variables[name] = var_description(true, false, 0, I, &VV, 0,
+ dim_type(gmm::vect_size(VV)));
}
- static scalar_type ga_hash_code(const pga_tree_node pnode) {
- scalar_type c = ga_hash_code(pnode->node_type);
-
- switch (pnode->node_type) {
- case GA_NODE_CONSTANT: case GA_NODE_ZERO:
- c += ga_hash_code(pnode->tensor());
- if (pnode->test_function_type & 1)
- c += 34.731 * ga_hash_code(pnode->name_test1);
- if (pnode->test_function_type & 2)
- c += 34.731 * ga_hash_code(pnode->name_test2);
- break;
-
- case GA_NODE_OP: c += scalar_type(pnode->op_type)*M_E*M_PI*M_PI; break;
- case GA_NODE_X: c += scalar_type(pnode->nbc1) + M_E*M_PI; break;
- case GA_NODE_VAL: case GA_NODE_GRAD:
- case GA_NODE_HESS: case GA_NODE_DIVERG:
- case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST:
- case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST:
- c += ga_hash_code(pnode->name); break;
-
- case GA_NODE_INTERPOLATE_FILTER:
- c += 1.73*ga_hash_code(pnode->interpolate_name)
- + 2.486*double(pnode->nbc1 + 1);
- break;
- case GA_NODE_INTERPOLATE_DERIVATIVE:
- c += 2.321*ga_hash_code(pnode->interpolate_name_der);
- // No break. The hash code is completed with the next item
- case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
- case GA_NODE_INTERPOLATE_VAL_TEST: case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_HESS_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
- c += 1.33*(1.22+ga_hash_code(pnode->name))
- + 1.66*ga_hash_code(pnode->interpolate_name);
- break;
- case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
- case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
- c += 1.33*(1.22+ga_hash_code(pnode->name))
- + 2.63*ga_hash_code(pnode->elementary_name);
- break;
- case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
- case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
- case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
- case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
- case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
- c += 1.33*(1.22+ga_hash_code(pnode->name));
- break;
- case GA_NODE_INTERPOLATE_X: case GA_NODE_INTERPOLATE_NORMAL:
- c += M_PI*1.33*ga_hash_code(pnode->interpolate_name);
- break;
- case GA_NODE_PREDEF_FUNC: case GA_NODE_SPEC_FUNC: case GA_NODE_OPERATOR:
- c += ga_hash_code(pnode->name)
- + tanh(scalar_type(pnode->der1)/M_PI + scalar_type(pnode->der2)*M_PI);
- break;
- default: break;
- }
- return c;
+ void ga_workspace::add_fem_constant
+ (const std::string &name, const mesh_fem &mf,
+ const model_real_plain_vector &VV) {
+ GMM_ASSERT1(mf.nb_dof(), "The provided mesh_fem of variable" << name
+ << "has zero degrees of freedom.");
+ size_type Q = gmm::vect_size(VV)/mf.nb_dof();
+ if (Q == 0) Q = size_type(1);
+ variables[name] = var_description(false, true, &mf,
+ gmm::sub_interval(), &VV, 0, Q);
}
+ void ga_workspace::add_fixed_size_constant
+ (const std::string &name, const model_real_plain_vector &VV) {
+ variables[name] = var_description(false, false, 0,
+ gmm::sub_interval(), &VV, 0,
+ gmm::vect_size(VV));
+ }
+ void ga_workspace::add_im_data(const std::string &name, const im_data &imd,
+ const model_real_plain_vector &VV) {
+ variables[name] = var_description
+ (false, false, 0, gmm::sub_interval(), &VV, &imd,
+ gmm::vect_size(VV)/(imd.nb_filtered_index() * imd.nb_tensor_elem()));
+ }
- // 0 : ok
- // 1 : function or operator name or "X"
- // 2 : reserved prefix Grad, Hess, Div, Test and Test2
- // 3 : reserved prefix Dot and Previous
- int ga_check_name_validity(const std::string &name) {
-
- if (!(name.compare("X")) ||
- !(name.compare("Normal")) ||
- !(name.compare("Reshape")))
- return 1;
-
-
- if (name.compare(0, 11, "Derivative_") == 0)
- return 2;
-
- ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
- ga_predef_operator_tab &PREDEF_OPERATORS
- = dal::singleton<ga_predef_operator_tab>::instance(0);
- ga_predef_function_tab::const_iterator it=PREDEF_FUNCTIONS.find(name);
- if (it != PREDEF_FUNCTIONS.end())
- return 1;
-
- if (SPEC_FUNCTIONS.find(name) != SPEC_FUNCTIONS.end())
- return 1;
-
- if (PREDEF_OPERATORS.tab.find(name) != PREDEF_OPERATORS.tab.end())
- return 1;
-
- if (name.size() >= 5 && name.compare(0, 5, "Grad_") == 0)
- return 2;
-
- if (name.size() >= 5 && name.compare(0, 5, "Hess_") == 0)
- return 2;
-
- if (name.size() >= 4 && name.compare(0, 4, "Div_") == 0)
- return 2;
-
- if (name.size() >= 6 && name.compare(0, 6, "Test2_") == 0)
- return 2;
-
- if (name.size() >= 5 && name.compare(0, 5, "Test_") == 0)
- return 2;
+ bool ga_workspace::variable_exists(const std::string &name) const {
+ return (md && md->variable_exists(name)) ||
+ (parent_workspace && parent_workspace->variable_exists(name)) ||
+ (variables.find(name) != variables.end());
+ }
-// if (name.size() >= 4 && name.compare(0, 4, "Dot_") == 0)
-// return 3;
-// if (name.size() >= 5 && name.compare(0, 5, "Dot2_") == 0)
-// return 3;
+ bool ga_workspace::variable_group_exists(const std::string &name) const {
+ return (variable_groups.find(name) != variable_groups.end()) ||
+ (md && md->variable_group_exists(name)) ||
+ (parent_workspace && parent_workspace->variable_group_exists(name));
+ }
-// if (name.size() >= 9 && name.compare(0, 9, "Previous_") == 0)
-// return 3;
-// if (name.size() >= 10 && name.compare(0, 10, "Previous2_") == 0)
-// return 3;
-// if (name.size() >= 12 && name.compare(0, 12, "Previous1_2_") == 0)
-// return 3;
+ const std::vector<std::string>&
+ ga_workspace::variable_group(const std::string &group_name) const {
+ std::map<std::string, std::vector<std::string> >::const_iterator
+ it = variable_groups.find(group_name);
+ if (it != variable_groups.end())
+ return (variable_groups.find(group_name))->second;
+ if (md && md->variable_group_exists(group_name))
+ return md->variable_group(group_name);
+ if (parent_workspace &&
+ parent_workspace->variable_group_exists(group_name))
+ return parent_workspace->variable_group(group_name);
+ GMM_ASSERT1(false, "Undefined variable group " << group_name);
+ }
+ const std::string&
+ ga_workspace::first_variable_of_group(const std::string &name) const {
+ const std::vector<std::string> &t = variable_group(name);
+ GMM_ASSERT1(t.size(), "Variable group " << name << " is empty");
+ return t[0];
+ }
- return 0;
+ bool ga_workspace::is_constant(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end()) return !(it->second.is_variable);
+ if (variable_group_exists(name))
+ return is_constant(first_variable_of_group(name));
+ if (md && md->variable_exists(name)) {
+ if (enable_all_md_variables) return md->is_true_data(name);
+ return md->is_data(name);
+ }
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->is_constant(name);
+ GMM_ASSERT1(false, "Undefined variable " << name);
}
-
- //=========================================================================
- // Semantic analysis, tree simplification and tree enrichment
- // - Control tensor sizes for operations, operator or function call
- // - Compute all constant operations (i.e. non element dependent)
- // - Build a ready to use tree for derivation/compilation
- //=========================================================================
- // option = 0 : strict analysis,
- // 1 : do not complain about incompatible test functions but
- // store them,
- // 2 : cut incompatible test function branches with respect to the
- // one in workspace.selected_pair
- // 3 : do not complain about incompatible test functions neither
- // store them,
- static void ga_semantic_analysis(const std::string &expr, ga_tree &tree,
- const ga_workspace &workspace,
- size_type meshdim,
- size_type ref_elt_dim,
- bool eval_fixed_size,
- bool ignore_X, int option) {
- GMM_ASSERT1(predef_functions_initialized &&
- predef_operators_nonlinear_elasticity_initialized &&
- predef_operators_plasticity_initialized &&
- predef_operators_contact_initialized, "Internal error");
- if (!(tree.root)) return;
- if (option == 1) { workspace.test1.clear(); workspace.test2.clear(); }
- // cout << "semantic analysis of " << ga_tree_to_string(tree) << endl;
- ga_node_analysis(expr, tree, workspace, tree.root, meshdim, ref_elt_dim,
- eval_fixed_size, ignore_X, option);
- if (tree.root && option == 2) {
- if (((tree.root->test_function_type & 1) &&
- (tree.root->name_test1.compare(workspace.selected_test1.varname)
- || tree.root->interpolate_name_test1.compare
- (workspace.selected_test1.transname)))
- ||
- ((tree.root->test_function_type & 2) &&
- (tree.root->name_test2.compare(workspace.selected_test2.varname)
- || tree.root->interpolate_name_test2.compare
- (workspace.selected_test2.transname))))
- tree.clear();
- }
- // cout << "semantic analysis done " << endl;
- ga_valid_operand(expr, tree.root);
+ bool ga_workspace::is_disabled_variable(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end()) return false;
+ if (variable_group_exists(name))
+ return is_disabled_variable(first_variable_of_group(name));
+ if (md && md->variable_exists(name)) {
+ if (enable_all_md_variables) return false;
+ return md->is_disabled_variable(name);
+ }
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->is_disabled_variable(name);
+ GMM_ASSERT1(false, "Undefined variable " << name);
}
- static void ga_node_analysis(const std::string &expr, ga_tree &tree,
- const ga_workspace &workspace,
- pga_tree_node pnode, size_type meshdim,
- size_type ref_elt_dim, bool eval_fixed_size,
- bool ignore_X, int option) {
- bool all_cte = true, all_sc = true;
- pnode->symmetric_op = false;
-
- for (size_type i = 0; i < pnode->children.size(); ++i) {
- ga_node_analysis(expr, tree, workspace, pnode->children[i], meshdim,
- ref_elt_dim, eval_fixed_size, ignore_X, option);
- all_cte = all_cte && (pnode->children[i]->node_type == GA_NODE_CONSTANT);
- all_sc = all_sc && (pnode->children[i]->tensor_proper_size() == 1);
- GMM_ASSERT1(pnode->children[i]->test_function_type != size_type(-1),
- "internal error on child " << i);
- if (pnode->node_type != GA_NODE_PARAMS)
- ga_valid_operand(expr, pnode->children[i]);
- }
+ const scalar_type &
+ ga_workspace::factor_of_variable(const std::string &name) const {
+ static const scalar_type one(1);
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end()) return one;
+ if (variable_group_exists(name))
+ return one;
+ if (md && md->variable_exists(name)) return md->factor_of_variable(name);
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->factor_of_variable(name);
+ GMM_ASSERT1(false, "Undefined variable " << name);
+ }
- size_type nbch = pnode->children.size();
- pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
- pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
- bgeot::multi_index mi;
- const bgeot::multi_index &size0 = child0 ? child0->t.sizes() : mi;
- const bgeot::multi_index &size1 = child1 ? child1->t.sizes() : mi;
- size_type dim0 = child0 ? child0->tensor_order() : 0;
- size_type dim1 = child1 ? child1->tensor_order() : 0;
+ const gmm::sub_interval &
+ ga_workspace::interval_of_disabled_variable(const std::string &name) const {
+ std::map<std::string, gmm::sub_interval>::const_iterator
+ it1 = int_disabled_variables.find(name);
+ if (it1 != int_disabled_variables.end()) return it1->second;
+ if (md->is_affine_dependent_variable(name))
+ return interval_of_disabled_variable(md->org_variable(name));
- // cout << "child1 = " << child1 << endl;
- // cout << "child0 = " << child0 << endl;
- // cout << "nbch = " << nbch << endl;
- // cout<<"begin analysis of node "; ga_print_node(pnode, cout); cout<<endl;
+ size_type first = md->nb_dof();
+ for (const std::pair<std::string, gmm::sub_interval> &p
+ : int_disabled_variables)
+ first = std::max(first, p.second.last());
- const ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
- const ga_predef_operator_tab &PREDEF_OPERATORS
- = dal::singleton<ga_predef_operator_tab>::instance(0);
+ int_disabled_variables[name]
+ = gmm::sub_interval(first, gmm::vect_size(value(name)));
+ return int_disabled_variables[name];
+ }
- switch (pnode->node_type) {
- case GA_NODE_PREDEF_FUNC: case GA_NODE_OPERATOR: case GA_NODE_SPEC_FUNC :
- case GA_NODE_CONSTANT: case GA_NODE_X: case GA_NODE_ELT_SIZE:
- case GA_NODE_ELT_K: case GA_NODE_ELT_B:
- case GA_NODE_NORMAL: case GA_NODE_RESHAPE:
- case GA_NODE_INTERPOLATE_X: case GA_NODE_INTERPOLATE_NORMAL:
- pnode->test_function_type = 0; break;
-
- case GA_NODE_ALLINDICES: pnode->test_function_type = 0; break;
- case GA_NODE_VAL:
- if (eval_fixed_size && !(workspace.associated_mf(pnode->name))
- && !(workspace.associated_im_data(pnode->name))) {
- gmm::copy(workspace.value(pnode->name), pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_CONSTANT;
- }
- break;
+ const gmm::sub_interval &
+ ga_workspace::interval_of_variable(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end()) return it->second.I;
+ if (md && md->variable_exists(name)) {
+ if (enable_all_md_variables && md->is_disabled_variable(name))
+ return interval_of_disabled_variable(name);
+ return md->interval_of_variable(name);
+ }
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->interval_of_variable(name);
+ GMM_ASSERT1(false, "Undefined variable " << name);
+ }
- case GA_NODE_ZERO: case GA_NODE_GRAD:
- case GA_NODE_HESS: case GA_NODE_DIVERG:
- case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
- case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
- break;
+ const mesh_fem *
+ ga_workspace::associated_mf(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end())
+ return it->second.is_fem_dofs ? it->second.mf : 0;
+ if (md && md->variable_exists(name))
+ return md->pmesh_fem_of_variable(name);
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->associated_mf(name);
+ if (variable_group_exists(name))
+ return associated_mf(first_variable_of_group(name));
+ GMM_ASSERT1(false, "Undefined variable or group " << name);
+ }
- case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST:
- case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST:
- case GA_NODE_INTERPOLATE_VAL_TEST: case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_HESS_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
- case GA_NODE_INTERPOLATE_DERIVATIVE:
- case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
- case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
- case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
- case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
- case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
- case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
- {
- const mesh_fem *mf = workspace.associated_mf(pnode->name);
- size_type t_type = pnode->test_function_type;
- if (t_type == 1) {
- pnode->name_test1 = pnode->name;
- pnode->interpolate_name_test1 = pnode->interpolate_name;
- pnode->interpolate_name_test2 = pnode->name_test2 = "";
- pnode->qdim1 = (mf ? workspace.qdim(pnode->name)
- : gmm::vect_size(workspace.value(pnode->name)));
- if (option == 1)
- workspace.test1.insert
- (var_trans_pair(pnode->name_test1,
- pnode->interpolate_name_test1));
- if (!(pnode->qdim1))
- ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
- } else {
- pnode->interpolate_name_test1 = pnode->name_test1 = "";
- pnode->name_test2 = pnode->name;
- pnode->interpolate_name_test2 = pnode->interpolate_name;
- pnode->qdim2 = (mf ? workspace.qdim(pnode->name)
- : gmm::vect_size(workspace.value(pnode->name)));
- if (option == 1)
- workspace.test2.insert
- (var_trans_pair(pnode->name_test2,
- pnode->interpolate_name_test2));
- if (!(pnode->qdim2))
- ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
- }
- if (!mf) {
- size_type n = workspace.qdim(pnode->name);
- if (!n)
- ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
- if (n == 1) {
- pnode->init_vector_tensor(1);
- pnode->tensor()[0] = scalar_type(1);
- pnode->test_function_type = t_type;
- } else {
- pnode->init_matrix_tensor(n,n);
- pnode->test_function_type = t_type;
- for (size_type i = 0; i < n; ++i)
- for (size_type j = 0; j < n; ++j)
- pnode->tensor()(i,j) = (i==j) ? scalar_type(1) :
scalar_type(0);
- }
- }
- }
- break;
+ const im_data *
+ ga_workspace::associated_im_data(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end()) return it->second.imd;
+ if (md && md->variable_exists(name))
+ return md->pim_data_of_variable(name);
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->associated_im_data(name);
+ if (variable_group_exists(name)) return 0;
+ GMM_ASSERT1(false, "Undefined variable " << name);
+ }
- case GA_NODE_INTERPOLATE:
- if (pnode->name.compare("X") == 0) {
- pnode->node_type = GA_NODE_INTERPOLATE_X;
- pnode->init_vector_tensor(meshdim);
- break;
- }
- if (pnode->name.compare("Normal") == 0) {
- pnode->node_type = GA_NODE_INTERPOLATE_NORMAL;
- pnode->init_vector_tensor(meshdim);
- break;
+ size_type ga_workspace::qdim(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end()) {
+ const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
+ const im_data *imd = it->second.imd;
+ size_type n = it->second.qdim();
+ if (mf) {
+ return n * mf->get_qdim();
+ } else if (imd) {
+ return n * imd->tensor_size().total_size();
}
- // else continue with what follows
- case GA_NODE_ELEMENTARY: // and ... case GA_NODE_INTERPOLATE:
- case GA_NODE_XFEM_PLUS:
- case GA_NODE_XFEM_MINUS:
- {
- int ndt = ((pnode->node_type == GA_NODE_INTERPOLATE) ? 1 : 0)
- + ((pnode->node_type == GA_NODE_ELEMENTARY) ? 2 : 0)
- + ((pnode->node_type == GA_NODE_XFEM_PLUS) ? 3 : 0)
- + ((pnode->node_type == GA_NODE_XFEM_MINUS) ? 4 : 0);
- std::string op__name =
- (pnode->node_type == GA_NODE_INTERPOLATE) ? "Interpolation" : ""
- + (pnode->node_type == GA_NODE_ELEMENTARY) ?
- "Elementary transformation" : ""
- + (pnode->node_type == GA_NODE_XFEM_PLUS) ? "Xfem_plus" : ""
- + (pnode->node_type == GA_NODE_XFEM_MINUS) ? "Xfem_minus" : "";
-
- std::string name = pnode->name;
- size_type prefix_id = ga_parse_prefix_operator(name);
- size_type test = ga_parse_prefix_test(name);
- pnode->name = name;
-
- // Group must be tested and it should be a fem variable
- if (!(workspace.variable_or_group_exists(name)))
- ga_throw_error(expr, pnode->pos,
- "Unknown variable or group of variables");
-
- const mesh_fem *mf = workspace.associated_mf(name);
- if (!mf)
- ga_throw_error(expr, pnode->pos, op__name
- << " can only apply to finite element
variables/data");
-
- size_type q = workspace.qdim(name), n = mf->linked_mesh().dim();
- if (!q) ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable");
-
- bgeot::multi_index mii = workspace.qdims(name);
- if (mii.size() > 6)
- ga_throw_error(expr, pnode->pos,
- "Tensor with too many dimensions. Limited to 6");
-
- if (test == 1) {
- pnode->name_test1 = name;
- pnode->interpolate_name_test1 = pnode->interpolate_name;
- if (option == 1)
- workspace.test1.insert
- (var_trans_pair(pnode->name_test1,
- pnode->interpolate_name_test1));
- pnode->qdim1 = workspace.qdim(name);
- if (!(pnode->qdim1))
- ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable");
- } else if (test == 2) {
- pnode->name_test2 = name;
- pnode->interpolate_name_test2 = pnode->interpolate_name;
- if (option == 1)
- workspace.test2.insert
- (var_trans_pair(pnode->name_test2,
- pnode->interpolate_name_test2));
- pnode->qdim2 = workspace.qdim(name);
- if (!(pnode->qdim2))
- ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable");
- }
+ return n;
+ }
+ if (md && md->variable_exists(name))
+ return md->qdim_of_variable(name);
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->qdim(name);
+ if (variable_group_exists(name))
+ return qdim(first_variable_of_group(name));
+ GMM_ASSERT1(false, "Undefined variable or group " << name);
+ }
- switch (prefix_id) {
- case 0: // value
- if (!test) {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_VAL; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_VAL; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_VAL; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_VAL; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- } else {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_VAL_TEST; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_VAL_TEST; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_VAL_TEST; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_VAL_TEST; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- if (q == 1 && mii.size() <= 1) {
- mii.resize(1);
- mii[0] = 2;
- } else
- mii.insert(mii.begin(), 2);
- }
- break;
- case 1: // grad
- if (!test) {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_GRAD; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_GRAD; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_GRAD; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_GRAD; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- if (n > 1) {
- if (q == 1 && mii.size() == 1) mii[0] = n;
- else mii.push_back(n);
- }
- } else {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_GRAD_TEST; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_GRAD_TEST; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_GRAD_TEST; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_GRAD_TEST; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- if (q == 1 && mii.size() <= 1) {
- mii.resize(1);
- mii[0] = 2;
- } else
- mii.insert(mii.begin(), 2);
- if (n > 1) mii.push_back(n);
- }
- break;
- case 2: // Hessian
- if (!test) {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_HESS; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_HESS; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_HESS; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_HESS; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- if (n > 1) {
- if (q == 1 && mii.size() == 1) { mii[0] = n; mii.push_back(n); }
- else { mii.push_back(n); mii.push_back(n); }
- }
- } else {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_HESS_TEST; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_HESS_TEST; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_HESS_TEST; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_HESS_TEST; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- if (q == 1 && mii.size() <= 1) {
- mii.resize(1);
- mii[0] = 2;
- } else
- mii.insert(mii.begin(), 2);
- if (n > 1) { mii.push_back(n); mii.push_back(n); }
- }
- break;
- case 3: // divergence
- if (q != n)
- ga_throw_error(expr, pnode->pos,
- "Divergence operator requires fem qdim ("
- << q << ") to be equal to dim (" << n << ")");
- if (!test) {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_DIVERG; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_DIVERG; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_DIVERG; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_DIVERG; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- mii.resize(1);
- mii[0] = 1;
- } else {
- switch (ndt) {
- case 1: pnode->node_type = GA_NODE_INTERPOLATE_DIVERG_TEST; break;
- case 2: pnode->node_type = GA_NODE_ELEMENTARY_DIVERG_TEST; break;
- case 3: pnode->node_type = GA_NODE_XFEM_PLUS_DIVERG_TEST; break;
- case 4: pnode->node_type = GA_NODE_XFEM_MINUS_DIVERG_TEST; break;
- default: GMM_ASSERT1(false, "internal error");
- }
- mii.resize(1);
- mii[0] = 2;
- }
- break;
- }
- pnode->t.adjust_sizes(mii);
- pnode->test_function_type = test;
-
- if (ndt == 1) {
- if (!(workspace.interpolate_transformation_exists
- (pnode->interpolate_name))) {
- ga_throw_error(expr, pnode->pos,
- "Unknown interpolate transformation");
- }
- } else if (ndt == 2) {
- if (!(workspace.elementary_transformation_exists
- (pnode->elementary_name))) {
- ga_throw_error(expr, pnode->pos,
- "Unknown elementary transformation");
- }
+ bgeot::multi_index
+ ga_workspace::qdims(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end()) {
+ const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
+ const im_data *imd = it->second.imd;
+ size_type n = it->second.qdim();
+ if (mf) {
+ bgeot::multi_index mi = mf->get_qdims();
+ if (n > 1 || it->second.qdims.size() > 1) {
+ size_type i = 0;
+ if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
+ for (; i < it->second.qdims.size(); ++i)
+ mi.push_back(it->second.qdims[i]);
}
- }
- break;
-
- case GA_NODE_INTERPOLATE_FILTER:
- {
- if (pnode->children.size() == 2) {
- bool valid = (child1->node_type == GA_NODE_CONSTANT);
- int n = valid ? int(round(child1->tensor()[0])) : -1;
- if (n < 0 || n > 100 || child1->tensor_order() > 0)
- ga_throw_error(expr, pnode->pos, "The third argument of "
- "Interpolate_filter should be a (small) "
- "non-negative integer.");
- pnode->nbc1 = size_type(n);
- tree.clear_node(child1);
+ return mi;
+ } else if (imd) {
+ bgeot::multi_index mi = imd->tensor_size();
+ size_type q = n / imd->nb_filtered_index();
+ GMM_ASSERT1(q % imd->nb_tensor_elem() == 0,
+ "Invalid mesh im data vector");
+ if (n > 1 || it->second.qdims.size() > 1) {
+ size_type i = 0;
+ if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
+ for (; i < it->second.qdims.size(); ++i)
+ mi.push_back(it->second.qdims[i]);
}
- if (!(workspace.interpolate_transformation_exists
- (pnode->interpolate_name)))
- ga_throw_error(expr, pnode->pos,
- "Unknown interpolate transformation");
- pnode->t = child0->t;
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
+ return mi;
}
- break;
-
-
- case GA_NODE_OP:
- switch(pnode->op_type) {
-
- case GA_PLUS: case GA_MINUS:
- {
- if (pnode->op_type == GA_PLUS) pnode->symmetric_op = true;
- size_type c_size = std::min(size0.size(), size1.size());
- bool compatible = true;
-
- size_type f_ind = 0;
- if (child0->test_function_type &&
- child1->test_function_type == child0->test_function_type)
- f_ind = (child0->test_function_type == 3) ? 2:1;
-
- for (size_type i = f_ind; i < c_size; ++i)
- if (size0[i] != size1[i]) compatible = false;
- for (size_type i = c_size; i < size0.size(); ++i)
- if (size0[i] != 1) compatible = false;
- for (size_type i = c_size; i < size1.size(); ++i)
- if (size1[i] != 1) compatible = false;
-
- if (!compatible)
- ga_throw_error(expr, pnode->pos, "Addition or subtraction of "
- "expressions of different sizes: "
- << size0 << " != " << size1);
- if (child0->test_function_type || child1->test_function_type) {
- switch (option) {
- case 0: case 2:
- if (child0->name_test1.compare(child1->name_test1) ||
- child0->name_test2.compare(child1->name_test2) ||
- child0->interpolate_name_test1.compare
- (child1->interpolate_name_test1) ||
- child0->interpolate_name_test2.compare
- (child1->interpolate_name_test2))
- compatible = false;
- break;
- case 1: case 3: break;
- default: GMM_ASSERT1(false, "Unknown option");
- }
- }
-
- if (child0->test_function_type != child1->test_function_type ||
- (!compatible && option != 2))
- ga_throw_error(expr, pnode->pos, "Addition or subtraction of "
- "incompatible test functions");
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- pnode->tensor() = pnode->children[0]->tensor();
- if (pnode->op_type == GA_MINUS)
- pnode->tensor() -= pnode->children[1]->tensor();
- else
- pnode->tensor() += pnode->children[1]->tensor();
- tree.clear_children(pnode);
- } else {
- pnode->t = child0->t;
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
-
- // simplification if one of the two operands is constant and zero
- if (child0->tensor_is_zero()) {
- if (pnode->op_type == GA_MINUS) {
- pnode->op_type = GA_UNARY_MINUS;
- tree.clear_node(child0);
- } else {
- tree.replace_node_by_child(pnode, 1);
- pnode = child1;
- }
- } else if (child1->tensor_is_zero()) {
- tree.replace_node_by_child(pnode, 0);
- pnode = child0;
- } else if (option == 2 && !compatible) {
- bool child0_compatible = true, child1_compatible = true;
- if (pnode->test_function_type & 1) {
- if
(child0->name_test1.compare(workspace.selected_test1.varname)
- || child0->interpolate_name_test1.compare
- (workspace.selected_test1.transname))
- child0_compatible = false;
- if
(child1->name_test1.compare(workspace.selected_test1.varname)
- || child1->interpolate_name_test1.compare
- (workspace.selected_test1.transname))
- child1_compatible = false;
- }
- if (pnode->test_function_type & 2) {
- if
(child0->name_test2.compare(workspace.selected_test2.varname)
- || child0->interpolate_name_test2.compare
- (workspace.selected_test2.transname))
- child0_compatible = false;
- if
(child1->name_test2.compare(workspace.selected_test2.varname)
- || child1->interpolate_name_test1.compare
- (workspace.selected_test2.transname))
- child1_compatible = false;
- }
- if (child0_compatible) {
- tree.replace_node_by_child(pnode, 0);
- pnode = child0;
- } else if (child1_compatible) {
- if (pnode->op_type == GA_MINUS) {
- pnode->op_type = GA_UNARY_MINUS;
- pnode->t = child1->t;
- pnode->test_function_type = child1->test_function_type;
- pnode->name_test1 = child1->name_test1;
- pnode->name_test2 = child1->name_test2;
- pnode->interpolate_name_test1=child1->interpolate_name_test1;
- pnode->interpolate_name_test2=child1->interpolate_name_test2;
- pnode->qdim1 = child1->qdim1;
- pnode->qdim2 = child1->qdim2;
- tree.clear_node(child0);
- } else {
- tree.replace_node_by_child(pnode, 1);
- pnode = child1;
- }
- }
- }
- }
- }
- break;
-
- case GA_DOTMULT: case GA_DOTDIV:
- {
- if (pnode->op_type == GA_DOTMULT) pnode->symmetric_op = true;
- bool compatible = true;
- if (child0->tensor_proper_size() != child1->tensor_proper_size())
- compatible = false;
-
- if (child0->tensor_proper_size() != 1) {
- if (child0->tensor_order() != child1->tensor_order())
- compatible = false;
-
- for (size_type i = 0; i < child0->tensor_order(); ++i)
- if (child0->tensor_proper_size(i)!=child1->tensor_proper_size(i))
- compatible = false;
- }
-
- if (!compatible)
- ga_throw_error(expr, pnode->pos,
- "Arguments of different sizes for .* or ./");
-
- if (pnode->op_type == GA_DOTDIV && child1->test_function_type)
- ga_throw_error(expr, pnode->pos,
- "Division by test functions is not allowed");
-
- pnode->mult_test(child0, child1, expr);
- mi = pnode->t.sizes();
- for (size_type i = 0; i < child0->tensor_order(); ++i)
- mi.push_back(child0->tensor_proper_size(i));
- pnode->t.adjust_sizes(mi);
-
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- if (pnode->op_type == GA_DOTMULT) {
- for (size_type i = 0; i < child0->tensor().size(); ++i)
- pnode->tensor()[i] = child0->tensor()[i] * child1->tensor()[i];
- } else {
- for (size_type i = 0; i < child0->tensor().size(); ++i) {
- if (child1->tensor()[i] == scalar_type(0))
- ga_throw_error(expr, pnode->pos, "Division by zero.");
- pnode->tensor()[i] = child0->tensor()[i] / child1->tensor()[i];
- }
- }
- tree.clear_children(pnode);
- } else {
- if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
- gmm::clear(pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- }
- if (child1->tensor_is_zero() && pnode->op_type == GA_DOTDIV)
- ga_throw_error(expr, pnode->pos, "Division by zero.");
- }
- }
- break;
+ return it->second.qdims;
+ }
+ if (md && md->variable_exists(name))
+ return md->qdims_of_variable(name);
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->qdims(name);
+ if (variable_group_exists(name))
+ return qdims(first_variable_of_group(name));
+ GMM_ASSERT1(false, "Undefined variable or group " << name);
+ }
- case GA_UNARY_MINUS:
- pnode->t = child0->t;
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- gmm::scale(pnode->tensor().as_vector(), scalar_type(-1));
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_ZERO) {
- tree.replace_node_by_child(pnode, 0);
- pnode = child0;
- }
- break;
+ const model_real_plain_vector &
+ ga_workspace::value(const std::string &name) const {
+ VAR_SET::const_iterator it = variables.find(name);
+ if (it != variables.end())
+ return *(it->second.V);
+ if (md && md->variable_exists(name))
+ return md->real_variable(name);
+ if (parent_workspace && parent_workspace->variable_exists(name))
+ return parent_workspace->value(name);
+ if (variable_group_exists(name))
+ return value(first_variable_of_group(name));
+ GMM_ASSERT1(false, "Undefined variable or group " << name);
+ }
- case GA_QUOTE:
- if (dim0 > 2)
- ga_throw_error(expr, pnode->pos, "Transpose operator is for "
- "vectors or matrices only.");
- mi = size0;
- if (child0->tensor_proper_size() == 1)
- { tree.replace_node_by_child(pnode, 0); pnode = child0; break; }
- else if (dim0 == 2) std::swap(mi.back(), mi[size0.size()-2]);
- else { size_type N = mi.back(); mi.back() = 1; mi.push_back(N); }
-
- pnode->t.adjust_sizes(mi);
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- if (dim0 == 2) {
- for (size_type i = 0; i < mi.back(); ++i)
- for (size_type j = 0; j < mi[size0.size()-2]; ++j)
- pnode->tensor()(j, i) = child0->tensor()(i,j);
- } else if (dim0 == 1) {
- for (size_type i = 0; i < mi.back(); ++i)
- pnode->tensor()(0, i) = child0->tensor()[i];
- }
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_ZERO) {
- pnode->node_type = GA_NODE_ZERO;
- gmm::clear(pnode->tensor().as_vector());
- tree.clear_children(pnode);
- }
- break;
+ scalar_type ga_workspace::get_time_step() const {
+ if (md) return md->get_time_step();
+ if (parent_workspace) return parent_workspace->get_time_step();
+ GMM_ASSERT1(false, "No time step defined here");
+ }
- case GA_SYM: case GA_SKEW:
- if (child0->tensor_proper_size() != 1 &&
- (dim0 != 2 || size0.back() != size0[size0.size()-2]))
- ga_throw_error(expr, pnode->pos, "Sym and Skew operators are for "
- "square matrices only.");
- mi = size0;
- if (child0->tensor_proper_size() == 1) {
- if (pnode->op_type == GA_SYM)
- { tree.replace_node_by_child(pnode, 0); pnode = child0; break; }
- else {
- pnode->node_type = GA_NODE_ZERO;
- gmm::clear(pnode->tensor().as_vector());
- tree.clear_children(pnode);
- break;
- }
- }
- pnode->t.adjust_sizes(mi);
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- for (size_type i = 0; i < mi.back(); ++i)
- for (size_type j = 0; j < mi.back(); ++j)
- if (pnode->op_type == GA_SYM)
- pnode->tensor()(j, i) = 0.5*(child0->tensor()(j,i)
- + child0->tensor()(i,j));
- else
- pnode->tensor()(j, i) = 0.5*(child0->tensor()(j,i)
- - child0->tensor()(i,j));
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_ZERO) {
- pnode->node_type = GA_NODE_ZERO;
- gmm::clear(pnode->tensor().as_vector());
- tree.clear_children(pnode);
- }
- break;
+ // Macros
+ bool ga_workspace::macro_exists(const std::string &name) const {
+ if (macros.find(name) != macros.end()) return true;
+ if (md && md->macro_exists(name)) return true;
+ if (parent_workspace &&
+ parent_workspace->macro_exists(name)) return true;
+ return false;
+ }
- case GA_TRACE:
- {
- mi = size0;
- size_type N = (child0->tensor_proper_size() == 1) ? 1 : mi.back();
-
- if (child0->tensor_proper_size() == 1)
- { tree.replace_node_by_child(pnode, 0); pnode = child0; break; }
-
- if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
- (dim0 == 2 && mi[mi.size()-2] != N))
- ga_throw_error(expr, pnode->pos,
- "Trace operator is for square matrices only.");
-
- if (dim0 == 2) { mi.pop_back(); mi.pop_back(); }
- pnode->t.adjust_sizes(mi);
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- if (dim0 == 2) {
- pnode->tensor()[0] = scalar_type(0);
- for (size_type i = 0; i < N; ++i)
- pnode->tensor()[0] += child0->tensor()(i,i);
- } else {
- pnode->tensor()[0] += child0->tensor()[0];
- }
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_ZERO) {
- pnode->node_type = GA_NODE_ZERO;
- gmm::clear(pnode->tensor().as_vector());
- tree.clear_children(pnode);
- }
- }
- break;
+ const std::string&
+ ga_workspace::get_macro(const std::string &name) const {
+ std::map<std::string, std::string>::const_iterator it=macros.find(name);
+ if (it != macros.end()) return it->second;
+ if (md && md->macro_exists(name)) return md->get_macro(name);
+ if (parent_workspace &&
+ parent_workspace->macro_exists(name))
+ return parent_workspace->get_macro(name);
+ GMM_ASSERT1(false, "Undefined macro");
+ }
- case GA_DEVIATOR:
- {
- mi = size0;
- size_type N = (child0->tensor_proper_size() == 1) ? 1 : mi.back();
+ ga_tree &
+ ga_workspace::macro_tree(const std::string &name, size_type meshdim,
+ size_type ref_elt_dim, bool ignore_X) const {
+ GMM_ASSERT1(macro_exists(name), "Undefined macro");
+ auto it = macro_trees.find(name);
+ bool to_be_analyzed = false;
+ m_tree *mt = 0;
- if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
- (dim0 == 2 && mi[mi.size()-2] != N))
- ga_throw_error(expr, pnode->pos,
- "Deviator operator is for square matrices only.");
+ if (it == macro_trees.end()) {
+ mt = &(macro_trees[name]);
+ to_be_analyzed = true;
+ } else {
+ mt = &(it->second);
+ GMM_ASSERT1(mt->ptree, "Recursive definition of macro " << name);
+ if (mt->meshdim != meshdim || mt->ignore_X != ignore_X) {
+ to_be_analyzed = true;
+ delete mt->ptree; mt->ptree = 0;
+ }
+ }
+ if (to_be_analyzed) {
+ ga_tree tree;
+ ga_read_string(get_macro(name), tree);
+ ga_semantic_analysis(get_macro(name), tree, *this, meshdim, ref_elt_dim,
+ false, ignore_X, 3);
+ GMM_ASSERT1(tree.root, "Invalid macro");
+ mt->ptree = new ga_tree(tree);
+ mt->meshdim = meshdim;
+ mt->ignore_X = ignore_X;
+ }
+ return *(mt->ptree);
+ }
- if (child0->tensor_proper_size() == 1) {
- pnode->node_type = GA_NODE_ZERO;
- gmm::clear(pnode->tensor().as_vector());
- tree.clear_children(pnode);
- break;
- }
+ void ga_workspace::add_interpolate_transformation
+ (const std::string &name, pinterpolate_transformation ptrans) {
+ if (transformations.find(name) != transformations.end())
+ GMM_ASSERT1(name.compare("neighbour_elt"), "neighbour_elt is a "
+ "reserved interpolate transformation name");
+ transformations[name] = ptrans;
+ }
- pnode->t.adjust_sizes(mi);
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- if (dim0 == 2) {
- scalar_type tr(0);
- gmm::copy(child0->tensor().as_vector(),
- pnode->tensor().as_vector());
- for (size_type i = 0; i < N; ++i)
- tr += child0->tensor()(i,i);
- for (size_type i = 0; i < N; ++i)
- pnode->tensor()(i,i) -= tr / scalar_type(N);
- } else {
- pnode->tensor()[0] = scalar_type(0);
- }
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_ZERO) {
- pnode->node_type = GA_NODE_ZERO;
- gmm::clear(pnode->tensor().as_vector());
- tree.clear_children(pnode);
- }
- }
- break;
+ bool ga_workspace::interpolate_transformation_exists
+ (const std::string &name) const {
+ return (md && md->interpolate_transformation_exists(name)) ||
+ (parent_workspace &&
+ parent_workspace->interpolate_transformation_exists(name)) ||
+ (transformations.find(name) != transformations.end());
+ }
- case GA_PRINT:
- {
- pnode->t = child0->t;
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- cout << "Print constant term "; ga_print_node(child0, cout);
- cout << ": " << pnode->tensor() << endl;
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_ZERO) {
- pnode->node_type = GA_NODE_ZERO;
- gmm::clear(pnode->tensor().as_vector());
- cout << "Print zero term "; ga_print_node(child0, cout);
- cout << ": " << pnode->tensor() << endl;
- tree.clear_children(pnode);
- }
- }
- break;
+ pinterpolate_transformation
+ ga_workspace::interpolate_transformation(const std::string &name) const {
+ std::map<std::string, pinterpolate_transformation>::const_iterator
+ it = transformations.find(name);
+ if (it != transformations.end()) return it->second;
+ if (md && md->interpolate_transformation_exists(name))
+ return md->interpolate_transformation(name);
+ if (parent_workspace &&
+ parent_workspace->interpolate_transformation_exists(name))
+ return parent_workspace->interpolate_transformation(name);
+ GMM_ASSERT1(false, "Inexistent transformation " << name);
+ }
- case GA_DOT:
- if (dim1 > 1)
- ga_throw_error(expr, pnode->pos, "The second argument of the dot "
- "product has to be a vector.")
- else {
- size_type s0 = dim0 == 0 ? 1 : size0.back();
- size_type s1 = dim1 == 0 ? 1 : size1.back();
- if (s0 != s1) ga_throw_error(expr, pnode->pos, "Dot product "
- "of expressions of different sizes ("
- << s0 << " != " << s1 << ").");
- if (child0->tensor_order() <= 1) pnode->symmetric_op = true;
- pnode->mult_test(child0, child1, expr);
- if (dim0 > 1) {
- mi = pnode->t.sizes();
- for (size_type i = 1; i < dim0; ++i)
- mi.push_back(child0->tensor_proper_size(i-1));
- pnode->t.adjust_sizes(mi);
- }
+ bool ga_workspace::elementary_transformation_exists
+ (const std::string &name) const {
+ return (md && md->elementary_transformation_exists(name)) ||
+ (parent_workspace &&
+ parent_workspace->elementary_transformation_exists(name)) ||
+ (elem_transformations.find(name) != elem_transformations.end());
+ }
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- gmm::clear(pnode->tensor().as_vector());
- size_type k = 0;
- for (size_type i = 0, j = 0; i < child0->tensor().size(); ++i) {
- pnode->tensor()[j] += child0->tensor()[i] * child1->tensor()[k];
- ++j; if (j == pnode->tensor().size()) { j = 0; ++k; }
- }
- GMM_ASSERT1(k == child1->tensor().size(), "Internal error");
- tree.clear_children(pnode);
- } else {
- if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
- gmm::clear(pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- }
- }
- }
- break;
+ pelementary_transformation
+ ga_workspace::elementary_transformation(const std::string &name) const {
+ std::map<std::string, pelementary_transformation>::const_iterator
+ it = elem_transformations.find(name);
+ if (it != elem_transformations.end()) return it->second;
+ if (md && md->elementary_transformation_exists(name))
+ return md->elementary_transformation(name);
+ if (parent_workspace &&
+ parent_workspace->elementary_transformation_exists(name))
+ return parent_workspace->elementary_transformation(name);
+ GMM_ASSERT1(false, "Inexistent elementary transformation " << name);
+ }
- case GA_COLON:
- if (dim1 > 2)
- ga_throw_error(expr, pnode->pos,
- "Frobenius product acts only on matrices.")
- else {
- size_type s00 = (dim0 == 0) ? 1
- : (dim0 == 1 ? size0.back() : size0[size0.size()-2]);
- size_type s01 = (dim0 >= 2) ? size0.back() : 1;
- size_type s10 = (dim1 == 0) ? 1
- : (dim1 == 1 ? size1.back() : size1[size1.size()-2]);
- size_type s11 = (dim1 >= 2) ? size1.back() : 1;
- if (s00 != s10 || s01 != s11)
- ga_throw_error(expr, pnode->pos, "Frobenius product "
- "of expressions of different sizes ("
- << s00 << "," << s01 << " != " << s10 << ","
- << s11 << ").");
- if (child0->tensor_order() <= 2) pnode->symmetric_op = true;
- pnode->mult_test(child0, child1, expr);
- if (dim0 > 2) {
- mi = pnode->t.sizes();
- for (size_type i = 2; i < dim0; ++i)
- mi.push_back(child0->tensor_proper_size(i-2));
- pnode->t.adjust_sizes(mi);
- }
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- gmm::clear(pnode->tensor().as_vector());
- size_type k = 0;
- for (size_type i = 0, j = 0; i < child0->tensor().size(); ++i) {
- pnode->tensor()[j] += child0->tensor()[i] * child1->tensor()[k];
- ++j; if (j == pnode->tensor().size()) { j = 0; ++k; }
- }
- GMM_ASSERT1(k == child1->tensor().size(), "Internal error");
- tree.clear_children(pnode);
- } else {
- if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
- gmm::clear(pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- }
- }
- }
- break;
+ const mesh_region &
+ ga_workspace::register_region(const mesh &m, const mesh_region ®ion) {
+ if (&m == &dummy_mesh())
+ return dummy_mesh_region();
- case GA_TMULT:
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- if (child0->tensor().size() == 1 && child1->tensor().size() == 1) {
- pnode->init_scalar_tensor
- (child0->tensor()[0] * child1->tensor()[0]);
- } else if (child0->tensor().size() == 1) {
- pnode->t = child1->t;
- gmm::scale(pnode->tensor().as_vector(),
- scalar_type(child0->tensor()[0]));
- } else if (child1->tensor().size() == 1) {
- pnode->t = child0->t;
- gmm::scale(pnode->tensor().as_vector(),
- scalar_type(child1->tensor()[0]));
- } else {
- if (dim0+dim1 > 6)
- ga_throw_error(expr, pnode->pos, "Unauthorized "
- "tensor multiplication.");
- for (size_type i = 0; i < dim0; ++i)
- mi.push_back(child0->tensor().size(i));
- for (size_type i = 0; i < dim1; ++i)
- mi.push_back(child1->tensor().size(i));
- pnode->t.adjust_sizes(mi);
- size_type n0 = child0->tensor().size();
- size_type n1 = child1->tensor().size();
- for (size_type i = 0; i < n0; ++i)
- for (size_type j = 0; j < n1; ++j)
-
pnode->tensor()[i+j*n0]=child0->tensor()[i]*child1->tensor()[j];
- }
- tree.clear_children(pnode);
- } else {
- pnode->mult_test(child0, child1, expr);
- mi = pnode->t.sizes();
- if (child0->tensor_proper_size() != 1
- || child1->tensor_proper_size() != 1) {
- if (child0->tensor_proper_size() == 1) {
- for (size_type i = 0; i < dim1; ++i)
- mi.push_back(child1->tensor_proper_size(i));
- } else if (child1->tensor().size() == 1) {
- for (size_type i = 0; i < dim0; ++i)
- mi.push_back(child0->tensor_proper_size(i));
- } else {
- if (dim0+dim1 > 6)
- ga_throw_error(expr, pnode->pos, "Unauthorized "
- "tensor multiplication.");
- for (size_type i = 0; i < dim0; ++i)
- mi.push_back(child0->tensor_proper_size(i));
- for (size_type i = 0; i < dim1; ++i)
- mi.push_back(child1->tensor_proper_size(i));
- }
- pnode->t.adjust_sizes(mi);
- }
- if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
- gmm::clear(pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- }
- }
- break;
+ std::list<mesh_region> &lmr = registred_mesh_regions[&m];
+ for (const mesh_region &rg : lmr)
+ if (rg.compare(m, region, m)) return rg;
+ lmr.push_back(region);
+ return lmr.back();
+ }
- case GA_MULT:
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- if (child0->tensor_proper_size() == 1 &&
- child1->tensor_proper_size() == 1) {
- pnode->init_scalar_tensor(child0->tensor()[0]*child1->tensor()[0]);
- } else if (child0->tensor_proper_size() == 1) {
- pnode->t = child1->t;
- gmm::scale(pnode->tensor().as_vector(), child0->tensor()[0]);
- } else if (child1->tensor_proper_size() == 1) {
- pnode->t = child0->t;
- gmm::scale(pnode->tensor().as_vector(), child1->tensor()[0]);
- } else if (dim0 == 2 && dim1 == 1) {
- size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
- if (n != child1->tensor().size(0))
- ga_throw_error(expr, pnode->pos,
- "Incompatible sizes in matrix-vector "
- "multiplication (" << n << " != "
- << child1->tensor().size(0) << ").");
- pnode->init_vector_tensor(m);
- gmm::clear(pnode->tensor().as_vector());
- for (size_type i = 0; i < m; ++i)
- for (size_type j = 0; j < n; ++j)
- pnode->tensor()[i] +=
child0->tensor()(i,j)*child1->tensor()[j];
- } else if (dim0 == 2 && dim1 == 2) {
- size_type m = child0->tensor().size(0);
- size_type n = child0->tensor().size(1);
- size_type p = child1->tensor().size(1);
- if (n != child1->tensor().size(0))
- ga_throw_error(expr, pnode->pos,
- "Incompatible sizes in matrix-matrix "
- "multiplication (" << n << " != "
- << child1->tensor().size(0) << ").");
- pnode->init_matrix_tensor(m,p);
- gmm::clear(pnode->tensor().as_vector());
- for (size_type i = 0; i < m; ++i)
- for (size_type j = 0; j < n; ++j)
- for (size_type k = 0; k < p; ++k)
- pnode->tensor()(i,k) += child0->tensor()(i,j)
- * child1->tensor()(j,k);
- }
- else if (dim0 == 4 && dim1 == 2) {
- size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
- size_type o=child0->tensor().size(2), p=child0->tensor().size(3);
- if (o != child1->tensor().size(0) || p != child1->tensor().size(1))
- ga_throw_error(expr, pnode->pos,
- "Incompatible sizes in tensor-matrix "
- "multiplication (" << o << "," << p << " != "
- << child1->tensor().size(0) << ","
- << child1->tensor().size(1) << ").");
- pnode->init_matrix_tensor(m,n);
- gmm::clear(pnode->tensor().as_vector());
- for (size_type i = 0; i < m; ++i)
- for (size_type j = 0; j < n; ++j)
- for (size_type k = 0; k < o; ++k)
- for (size_type l = 0; l < p; ++l)
- pnode->tensor()(i,j) += child0->tensor()(i,j,k,l)
- * child1->tensor()(k,l);
- } else ga_throw_error(expr, pnode->pos,
- "Unauthorized multiplication.");
- tree.clear_children(pnode);
- } else {
- pnode->mult_test(child0, child1, expr);
- mi = pnode->t.sizes();
-
- if (child0->tensor_proper_size() == 1 &&
- child1->tensor_proper_size() == 1) {
- pnode->symmetric_op = true;
- } else if (child0->tensor_proper_size() == 1) {
- pnode->symmetric_op = true;
- for (size_type i = 0; i < dim1; ++i)
- mi.push_back(child1->tensor_proper_size(i));
- } else if (child1->tensor_proper_size() == 1) {
- pnode->symmetric_op = true;
- for (size_type i = 0; i < dim0; ++i)
- mi.push_back(child0->tensor_proper_size(i));
- } else if (child0->tensor_order() == 2 &&
- child1->tensor_order() == 1) {
- size_type m = child0->tensor_proper_size(0);
- size_type n = child0->tensor_proper_size(1);
- mi.push_back(m);
- if (n != child1->tensor_proper_size(0))
- ga_throw_error(expr, pnode->pos,
- "Incompatible sizes in matrix-vector "
- "multiplication (" << n << " != "
- << child1->tensor_proper_size(0) << ").");
- } else if (child0->tensor_order() == 2 &&
- child1->tensor_order() == 2) {
- size_type m = child0->tensor_proper_size(0);
- size_type n = child0->tensor_proper_size(1);
- size_type p = child1->tensor_proper_size(1);
- mi.push_back(m); mi.push_back(p);
- if (n != child1->tensor_proper_size(0))
- ga_throw_error(expr, pnode->pos,
- "Incompatible sizes in matrix-matrix "
- "multiplication (" << n << " != "
- << child1->tensor_proper_size(0) << ").");
- }
- else if (pnode->children[0]->tensor_order() == 4 &&
- pnode->children[1]->tensor_order() == 2) {
- size_type m = child0->tensor_proper_size(0);
- size_type n = child0->tensor_proper_size(1);
- size_type o = child0->tensor_proper_size(2);
- size_type p = child0->tensor_proper_size(3);
- mi.push_back(m); mi.push_back(n);
- if (o != child1->tensor_proper_size(0) ||
- p != child1->tensor_proper_size(1))
- ga_throw_error(expr, pnode->pos,
- "Incompatible sizes in tensor-matrix "
- "multiplication (" << o << "," << p << " != "
- << child1->tensor_proper_size(0) << ","
- << child1->tensor_proper_size(1) << ").");
- } else ga_throw_error(expr, pnode->pos,
- "Unauthorized multiplication.");
- pnode->t.adjust_sizes(mi);
- // Simplifications
- if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
- gmm::clear(pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_CONSTANT &&
- child0->tensor().size() == 1 &&
- child0->tensor()[0] == scalar_type(1)) {
- tree.replace_node_by_child(pnode, 1);
- pnode = child1;
- } else if (child1->node_type == GA_NODE_CONSTANT &&
- child1->tensor().size() == 1 &&
- child1->tensor()[0] == scalar_type(1)) {
- tree.replace_node_by_child(pnode, 0);
- pnode = child0;
- }
- }
- break;
- case GA_DIV:
- if (child1->tensor_proper_size() > 1)
- ga_throw_error(expr, pnode->pos,
- "Only the division by a scalar is allowed. "
- "Got a size of " << child1->tensor_proper_size());
- if (child1->test_function_type)
- ga_throw_error(expr, pnode->pos,
- "Division by test functions is not allowed.");
- if (child1->node_type == GA_NODE_CONSTANT &&
- child1->tensor()[0] == scalar_type(0))
- ga_throw_error(expr, pnode->children[1]->pos, "Division by zero");
-
- pnode->t = child0->t;
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
-
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->t = pnode->children[0]->t;
- pnode->test_function_type = 0;
- gmm::scale(pnode->tensor().as_vector(),
- scalar_type(1) / pnode->children[1]->tensor()[0]);
- tree.clear_children(pnode);
- } else if (child0->tensor_is_zero()) {
- gmm::clear(pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- } else if (child1->node_type == GA_NODE_CONSTANT &&
- child1->tensor().size() == 1 &&
- child1->tensor()[0] == scalar_type(1)) {
- tree.replace_node_by_child(pnode, 0);
- pnode = child0;
- }
- break;
+ void ga_workspace::add_tree(ga_tree &tree, const mesh &m,
+ const mesh_im &mim, const mesh_region &rg,
+ const std::string &expr,
+ size_type add_derivative_order,
+ bool function_expr, size_type for_interpolation,
+ const std::string varname_interpolation) {
+ if (tree.root) {
- default:GMM_ASSERT1(false, "Unexpected operation. Internal error.");
+ // Eliminate the term if it corresponds to disabled variables
+ if ((tree.root->test_function_type >= 1 &&
+ is_disabled_variable(tree.root->name_test1)) ||
+ (tree.root->test_function_type >= 2 &&
+ is_disabled_variable(tree.root->name_test2))) {
+ // cout<<"disabling term "; ga_print_node(tree.root, cout);
cout<<endl;
+ return;
}
- break;
-
- case GA_NODE_C_MATRIX:
- {
- if (!all_sc) {
- ga_throw_error(expr, pnode->pos, "Constant vector/matrix/tensor "
- "components should be scalar valued.");
- }
+ // cout << "add tree with tests functions of " << tree.root->name_test1
+ // << " and " << tree.root->name_test2 << endl;
+ // ga_print_node(tree.root, cout); cout << endl;
+ bool remain = true;
+ size_type order = 0, ind_tree = 0;
- size_type nbc1 = pnode->nbc1, nbc2 = pnode->nbc2, nbc3 = pnode->nbc3;
- size_type nbl = pnode->children.size() / (nbc1*nbc2*nbc3);
- if (all_cte) pnode->node_type = GA_NODE_CONSTANT;
- pnode->test_function_type = 0;
- for (size_type i = 0; i < pnode->children.size(); ++i) {
- if (pnode->children[i]->test_function_type) {
- if (pnode->test_function_type == 0) {
- pnode->test_function_type=pnode->children[i]->test_function_type;
- pnode->name_test1 = pnode->children[i]->name_test1;
- pnode->name_test2 = pnode->children[i]->name_test2;
- pnode->interpolate_name_test1
- = pnode->children[i]->interpolate_name_test1;
- pnode->interpolate_name_test2
- = pnode->children[i]->interpolate_name_test2;
- pnode->qdim1 = pnode->children[i]->qdim1;
- pnode->qdim2 = pnode->children[i]->qdim2;
- } else {
- if (pnode->test_function_type !=
- pnode->children[i]->test_function_type ||
- pnode->name_test1.compare(pnode->children[i]->name_test1) ||
- pnode->name_test2.compare(pnode->children[i]->name_test2) ||
- pnode->interpolate_name_test1.compare
- (pnode->children[i]->interpolate_name_test1) ||
- pnode->interpolate_name_test2.compare
- (pnode->children[i]->interpolate_name_test2))
- ga_throw_error(expr, pnode->pos, "Inconsistent use of test "
- "function in constant matrix.");
- }
- }
- }
- mi.resize(0);
- if (pnode->test_function_type) mi.push_back(2);
- if (pnode->test_function_type >= 3) mi.push_back(2);
- if (nbc1 == 1 && nbc2 == 1 && nbc3 == 1 && nbl == 1) {
- pnode->t.adjust_sizes(mi);
- if (all_cte) pnode->tensor()[0] = child0->tensor()[0];
- } else {
- mi.push_back(nbl);
- if (nbc3 != 1) mi.push_back(nbc3);
- if (nbc2 != 1) mi.push_back(nbc2);
- if (nbc1 != 1) mi.push_back(nbc1);
- pnode->t.adjust_sizes(mi);
- if (all_cte) {
- size_type n = 0;
- if (nbc1 == 1 && nbc2 == 1 && nbc3 == 1)
- for (size_type i = 0; i < nbl; ++i)
- pnode->tensor()[i] = pnode->children[i]->tensor()[0];
- else if (nbc2 == 1 && nbc3 == 1) // TODO: verify order
- for (size_type i = 0; i < nbl; ++i)
- for (size_type j = 0; j < nbc1; ++j)
- pnode->tensor()(i,j) = pnode->children[n++]->tensor()[0];
- else if (nbc3 == 1) // TODO: verify order
- for (size_type i = 0; i < nbl; ++i)
- for (size_type j = 0; j < nbc2; ++j)
- for (size_type k = 0; k < nbc1; ++k)
- pnode->tensor()(i,j,k) = pnode->children[n++]->tensor()[0];
- else // TODO: verify order
- for (size_type i = 0; i < nbl; ++i)
- for (size_type j = 0; j < nbc3; ++j)
- for (size_type k = 0; k < nbc2; ++k)
- for (size_type l = 0; l < nbc1; ++l)
- pnode->tensor()(i,j,k,l)
- = pnode->children[n++]->tensor()[0];
- }
+ if (for_interpolation)
+ order = size_type(-1) - add_derivative_order;
+ else {
+ switch(tree.root->test_function_type) {
+ case 0: order = 0; break;
+ case 1: order = 1; break;
+ case 3: order = 2; break;
+ default: GMM_ASSERT1(false, "Inconsistent term "
+ << tree.root->test_function_type);
}
- if (all_cte) tree.clear_children(pnode);
}
- break;
-
- case GA_NODE_NAME:
- {
- std::string name = pnode->name;
-
- if (!ignore_X && !(name.compare("X"))) {
- pnode->node_type = GA_NODE_X;
- pnode->nbc1 = 0;
- pnode->init_vector_tensor(meshdim);
- break;
- }
- if (!(name.compare("element_size"))) {
- pnode->node_type = GA_NODE_ELT_SIZE;
- pnode->init_scalar_tensor(0);
- break;
- }
- if (!(name.compare("element_K"))) {
- pnode->node_type = GA_NODE_ELT_K;
- if (ref_elt_dim == 1)
- pnode->init_vector_tensor(meshdim);
- else
- pnode->init_matrix_tensor(meshdim, ref_elt_dim);
- break;
- }
- if (!(name.compare("element_B"))) {
- pnode->node_type = GA_NODE_ELT_B;
- pnode->init_matrix_tensor(ref_elt_dim, meshdim);
- break;
- }
- if (!(name.compare("Normal"))) {
- pnode->node_type = GA_NODE_NORMAL;
- pnode->init_vector_tensor(meshdim);
- break;
- }
- if (!(name.compare("Reshape"))) {
- pnode->node_type = GA_NODE_RESHAPE;
- pnode->init_vector_tensor(meshdim);
- break;
- }
+ bool found = false;
+ for (size_type i = 0; i < trees.size(); ++i) {
+ if (trees[i].mim == &mim && trees[i].m == &m &&
+ trees[i].order == order &&
+ trees[i].name_test1.compare(tree.root->name_test1) == 0 &&
+ trees[i].interpolate_name_test1.compare
+ (tree.root->interpolate_name_test1) == 0 &&
+ trees[i].name_test2.compare(tree.root->name_test2) == 0 &&
+ trees[i].interpolate_name_test2.compare
+ (tree.root->interpolate_name_test2) == 0 &&
+ trees[i].rg == &rg && trees[i].interpolation == for_interpolation
&&
+ trees[i].varname_interpolation.compare(varname_interpolation)==0) {
+ ga_tree &ftree = *(trees[i].ptree);
- if (name.compare(0, 11, "Derivative_") == 0) {
- name = name.substr(11);
- bool valid = true;
- pnode->der1 = 1; pnode->der2 = 0;
- char *p;
- size_type d = strtol(name.c_str(), &p, 10);
- size_type s = p - name.c_str();
- if (s > 0) {
- pnode->der1 = d;
- if (name[s] != '_') valid = false; else
- name = name.substr(s+1);
- }
- d = strtol(name.c_str(), &p, 10);
- s = p - name.c_str();
- if (s > 0) {
- pnode->der2 = d;
- if (name[s] != '_') valid = false; else
- name = name.substr(s+1);
- }
- if (!valid || pnode->der1 == 0)
- ga_throw_error(expr, pnode->pos, "Invalid derivative format");
+ ftree.insert_node(ftree.root, GA_NODE_OP);
+ ftree.root->op_type = GA_PLUS;
+ ftree.root->children.resize(2, nullptr);
+ ftree.copy_node(tree.root, ftree.root, ftree.root->children[1]);
+ ga_semantic_analysis("", ftree, *this, m.dim(),
+ ref_elt_dim_of_mesh(m), false, function_expr);
+ found = true;
+ break;
}
+ }
- ga_predef_function_tab::const_iterator it=PREDEF_FUNCTIONS.find(name);
- if (it != PREDEF_FUNCTIONS.end()) {
- // Predefined function found
- pnode->node_type = GA_NODE_PREDEF_FUNC;
- pnode->name = name;
- pnode->test_function_type = 0;
- if (pnode->der1) {
- if (pnode->der1 > it->second.nbargs()
- || pnode->der2 > it->second.nbargs())
- ga_throw_error(expr, pnode->pos, "Invalid derivative.");
- const ga_predef_function &F = it->second;
- if ((F.ftype() == 0 || F.dtype() == 2) && !(pnode->der2)) {
- pnode->name = ((pnode->der1 == 1) ?
- F.derivative1() : F.derivative2());
- pnode->der1 = pnode->der2 = 0;
- }
- }
- } else if (SPEC_FUNCTIONS.find(name) != SPEC_FUNCTIONS.end()) {
- // Special function found
- if (pnode->der1)
- ga_throw_error(expr, pnode->pos, "Special functions do not "
- "support derivatives.");
- pnode->node_type = GA_NODE_SPEC_FUNC;
- pnode->name = name;
- pnode->test_function_type = 0;
- if (!name.compare("pi")) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->init_scalar_tensor(M_PI);
- } else if (!name.compare("meshdim")) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->init_scalar_tensor(scalar_type(meshdim));
- } else if (!name.compare("timestep")) {
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->init_scalar_tensor(scalar_type(workspace.get_time_step()));
- }
- } else if (PREDEF_OPERATORS.tab.find(name)
- != PREDEF_OPERATORS.tab.end()) {
- // Nonlinear operator found
- pnode->node_type = GA_NODE_OPERATOR;
- pnode->name = name;
- pnode->test_function_type = 0;
- } else if (workspace.macro_exists(name)) {
- GMM_ASSERT1(pnode->der1 == 0 && pnode->der2 == 0,
- "Derivativation of a macro is not allowed");
- ga_tree &ma_tree
- = workspace.macro_tree(name, meshdim, ref_elt_dim, ignore_X);
- pga_tree_node pnode_old = pnode;
- pnode = nullptr;
- tree.copy_node(ma_tree.root, pnode_old->parent, pnode);
- if (pnode_old->parent)
- pnode_old->parent->replace_child(pnode_old, pnode);
- else
- tree.root = pnode;
- GMM_ASSERT1(pnode_old->children.empty(), "Internal error");
- delete pnode_old;
- ga_node_analysis(expr, tree, workspace, pnode, meshdim,
- ref_elt_dim, eval_fixed_size, ignore_X, option);
- } else {
- // Search for a variable name with optional gradient, Hessian,
- // divergence or test functions
-
- size_type prefix_id = ga_parse_prefix_operator(name);
- size_type test = ga_parse_prefix_test(name);
-
- if (!(workspace.variable_exists(name)))
- ga_throw_error(expr, pnode->pos, "Unknown variable, function, "
- "operator or data " + name);
-
- if (pnode->der1)
- ga_throw_error(expr, pnode->pos, "Derivative is for functions or "
- "operators, not for variables. Use Grad instead.");
- pnode->name = name;
-
- const mesh_fem *mf = workspace.associated_mf(name);
- const im_data *imd = workspace.associated_im_data(name);
-
- if (test && workspace.is_constant(name) &&
- !(workspace.is_disabled_variable(name)))
- ga_throw_error(expr, pnode->pos, "Test functions of constants "
- "are not allowed.");
- if (test == 1) {
- pnode->name_test1 = name;
- pnode->interpolate_name_test1 = "";
- if (option == 1)
- workspace.test1.insert
- (var_trans_pair(pnode->name_test1,
- pnode->interpolate_name_test1));
- pnode->qdim1 = mf ? workspace.qdim(name)
- : gmm::vect_size(workspace.value(name));
- if (!(pnode->qdim1))
- ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable");
- } else if (test == 2) {
- pnode->name_test2 = name;
- pnode->interpolate_name_test2 = "";
- if (option == 1)
- workspace.test2.insert
- (var_trans_pair(pnode->name_test2,
- pnode->interpolate_name_test2));
- pnode->qdim2 = mf ? workspace.qdim(name)
- : gmm::vect_size(workspace.value(name));
- if (!(pnode->qdim2))
- ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable");
- }
-
- if (!mf && (test || !imd)) {
- if (prefix_id)
- ga_throw_error(expr, pnode->pos, "Gradient, Hessian or
Divergence"
- " cannot be evaluated for fixed size data.");
- if (test)
- pnode->node_type = GA_NODE_VAL_TEST;
- else if (eval_fixed_size)
- pnode->node_type = GA_NODE_CONSTANT;
- else
- pnode->node_type = GA_NODE_VAL;
+ if (!found) {
+ ind_tree = trees.size(); remain = false;
+ trees.push_back(tree_description());
+ trees.back().mim = &mim; trees.back().m = &m;
+ trees.back().rg = &rg;
+ trees.back().ptree = new ga_tree;
+ trees.back().ptree->swap(tree);
+ pga_tree_node root = trees.back().ptree->root;
+ trees.back().name_test1 = root->name_test1;
+ trees.back().name_test2 = root->name_test2;
+ trees.back().interpolate_name_test1 = root->interpolate_name_test1;
+ trees.back().interpolate_name_test2 = root->interpolate_name_test2;
+ trees.back().order = order;
+ trees.back().interpolation = for_interpolation;
+ trees.back().varname_interpolation = varname_interpolation;
+ }
- size_type n = gmm::vect_size(workspace.value(name));
- if (n == 1) {
- if (test) {
- pnode->init_vector_tensor(1);
- pnode->tensor()[0]=scalar_type(1);
- }
- else pnode->init_scalar_tensor(workspace.value(name)[0]);
- } else {
- if (test) {
- pnode->init_matrix_tensor(n,n);
- for (size_type i = 0; i < n; ++i)
- for (size_type j = 0; j < n; ++j)
- pnode->tensor()(i,j)
- = ((i == j) ? scalar_type(1) : scalar_type(0));
- } else {
- pnode->t.adjust_sizes(workspace.qdims(name));
- gmm::copy(workspace.value(name), pnode->tensor().as_vector());
- }
- }
- } else if (!test && imd) {
- if (prefix_id)
- ga_throw_error(expr, pnode->pos, "Gradient, Hessian or
Divergence"
- " cannot be evaluated for im data.");
- pnode->node_type = GA_NODE_VAL;
- pnode->t.adjust_sizes(workspace.qdims(name));
- } else {
- size_type q = workspace.qdim(name);
- size_type n = mf->linked_mesh().dim();
- bgeot::multi_index mii = workspace.qdims(name);
-
- if (!q) ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable " << name);
- if (mii.size() > 6)
- ga_throw_error(expr, pnode->pos,
- "Tensor with too much dimensions. Limited to 6");
-
- switch (prefix_id) {
- case 0: // value
- pnode->node_type = test ? GA_NODE_VAL_TEST : GA_NODE_VAL;
- // For Test nodes a first dimension of size equal to 2 has to be
- // prepended by convention (to be adapted later)
- if (test && q == 1 && mii.size() <= 1) {
- mii.resize(1);
- mii[0] = 2;
- } else if (test) {
- mii.insert(mii.begin(), 2);
- pnode->t.adjust_sizes(mii);
- }
- break;
- case 1: // grad
- pnode->node_type = test ? GA_NODE_GRAD_TEST : GA_NODE_GRAD;
- if (test) {
- if (q == 1 && mii.size() <= 1) {
- mii.resize(1);
- mii[0] = 2;
- } else
- mii.insert(mii.begin(), 2);
- }
- if (n > 1) {
- if (mii.size() == 1 && mii[0] == 1) mii[0] = n;
- else mii.push_back(n);
- }
- break;
- case 2: // Hessian
- pnode->node_type = test ? GA_NODE_HESS_TEST : GA_NODE_HESS;
- if (test) {
- if (q == 1 && mii.size() <= 1) {
- mii.resize(1);
- mii[0] = 2;
- } else
- mii.insert(mii.begin(), 2);
- }
- if (n > 1) {
- if (mii.size() == 1 && mii[0] == 1) mii[0] = n;
- else mii.push_back(n);
- mii.push_back(n);
- }
- break;
- case 3: // divergence
- pnode->node_type = test ? GA_NODE_DIVERG_TEST : GA_NODE_DIVERG;
- if (q != n)
- ga_throw_error(expr, pnode->pos,
- "Divergence operator can only be applied to"
- "Fields with qdim (" << q << ") equal to dim ("
- << n << ")");
- mii.resize(1);
- mii[0] = test ? 2 : 1;
- break;
- }
- pnode->t.adjust_sizes(mii);
+ if (for_interpolation == 0 && order < add_derivative_order) {
+ std::set<var_trans_pair> expr_variables;
+ ga_extract_variables((remain ? tree : *(trees[ind_tree].ptree)).root,
+ *this, m, expr_variables, true);
+ for (const var_trans_pair &var : expr_variables) {
+ if (!(is_constant(var.varname))) {
+ ga_tree dtree = (remain ? tree : *(trees[ind_tree].ptree));
+ // cout << "Derivation with respect to " << var.first << " : "
+ // << var.second << " of " << ga_tree_to_string(dtree) << endl;
+ GA_TIC;
+ ga_derivative(dtree, *this, m, var.varname, var.transname,
1+order);
+ // cout << "Result : " << ga_tree_to_string(dtree) << endl;
+ GA_TOCTIC("Derivative time");
+ ga_semantic_analysis(expr, dtree, *this, m.dim(),
+ ref_elt_dim_of_mesh(m), false, function_expr);
+ GA_TOCTIC("Analysis after Derivative time");
+ // cout << "after analysis " << ga_tree_to_string(dtree) << endl;
+ add_tree(dtree, m, mim, rg, expr, add_derivative_order,
+ function_expr, for_interpolation, varname_interpolation);
}
- pnode->test_function_type = test;
}
}
- break;
-
- case GA_NODE_PARAMS:
- if (child0->node_type == GA_NODE_X) {
- child0->init_scalar_tensor(0);
- if (pnode->children.size() != 2)
- ga_throw_error(expr, child1->pos, "X stands for the coordinates on "
- "the real elements. It accepts only one index.");
- if (!(child1->node_type == GA_NODE_CONSTANT) ||
- child1->tensor().size() != 1)
- ga_throw_error(expr, child1->pos, "Index for X has to be constant "
- "and of size 1.");
- child0->nbc1 = size_type(round(child1->tensor()[0]));
- if (child0->nbc1 == 0 || child0->nbc1 > meshdim)
- ga_throw_error(expr, child1->pos, "Index for X not convenient. "
- "Found " << child0->nbc1 << " with meshdim = "
- << meshdim);
- tree.replace_node_by_child(pnode, 0);
- pnode = child0;
-
- } else if (child0->node_type == GA_NODE_RESHAPE) {
- if (pnode->children.size() < 3)
- ga_throw_error(expr, child1->pos,
- "Not enough parameters for Reshape");
- if (pnode->children.size() > 8)
- ga_throw_error(expr, child1->pos,
- "Too many parameters for Reshape");
- pnode->t = child1->t;
- pnode->test_function_type = child1->test_function_type;
- pnode->name_test1 = child1->name_test1;
- pnode->name_test2 = child1->name_test2;
- pnode->interpolate_name_test1 = child1->interpolate_name_test1;
- pnode->interpolate_name_test2 = child1->interpolate_name_test2;
- pnode->qdim1 = child1->qdim1;
- pnode->qdim2 = child1->qdim2;
- mi.resize(0);
- for (size_type i = 0; i < pnode->nb_test_functions(); ++i)
- mi.push_back(size1[i]);
-
- for (size_type i = 2; i < pnode->children.size(); ++i) {
- if (pnode->children[i]->node_type != GA_NODE_CONSTANT)
- ga_throw_error(expr, pnode->children[i]->pos, "Reshape sizes "
- "should be constant positive integers.");
- mi.push_back(size_type(round(pnode->children[i]->tensor()[0])));
- if (mi.back() == 0)
- ga_throw_error(expr, pnode->children[i]->pos, "Wrong zero size "
- "for Reshape.");
- }
- size_type total_size(1);
- for (size_type i = 0; i < mi.size(); ++i)
- total_size *= mi[i];
- if (total_size != pnode->tensor().size())
- ga_throw_error(expr, pnode->pos, "Invalid sizes for reshape.");
- pnode->t.adjust_sizes(mi);
-
- if (child1->node_type == GA_NODE_CONSTANT) {
- pnode->node_type = GA_NODE_CONSTANT;
- tree.clear_children(pnode);
- } else if (child1->node_type == GA_NODE_ZERO) {
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- }
- } else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
-
- // Evaluation of a predefined function
+ }
+ }
- for (size_type i = 1; i < pnode->children.size(); ++i)
- ga_valid_operand(expr, pnode->children[i]);
- std::string name = child0->name;
- ga_predef_function_tab::const_iterator it =
PREDEF_FUNCTIONS.find(name);
- const ga_predef_function &F = it->second;
- size_type nbargs = F.nbargs();
- if (nbargs+1 != pnode->children.size()) {
- ga_throw_error(expr, pnode->pos, "Bad number of arguments for "
- "predefined function " << name << ". Found "
- << pnode->children.size()-1 << ", should be "<<nbargs << ".");
- }
- pnode->test_function_type = 0;
- pga_tree_node child2 = (nbargs == 2) ? pnode->children[2] : child1;
- all_cte = child1->node_type == GA_NODE_CONSTANT;
- if (nbargs == 2)
- all_cte = all_cte && (child2->node_type == GA_NODE_CONSTANT);
- if (child1->test_function_type || child2->test_function_type)
- ga_throw_error(expr, pnode->pos, "Test functions cannot be passed "
- "as argument of a predefined function.");
- if (child1->tensor_order() > 2 || child2->tensor_order() > 2)
- ga_throw_error(expr, pnode->pos, "Sorry, function can be applied "
- "to scalar, vector and matrices only.");
- size_type s1 = child1->tensor().size();
- size_type s2 = (nbargs == 2) ? child2->tensor().size() : s1;
- if (s1 != s2 && (s1 != 1 || s2 != 1))
- ga_throw_error(expr, pnode->pos,
- "Invalid argument size for a scalar function. "
- "Size of first argument: " << s1 <<
- ". Size of second argument: " << s2 << ".");
+ ga_workspace::m_tree::~m_tree() { if (ptree) delete ptree; }
+ ga_workspace::m_tree::m_tree(const m_tree& o)
+ : ptree(o.ptree), meshdim(o.meshdim), ignore_X(o.ignore_X)
+ { if (o.ptree) ptree = new ga_tree(*(o.ptree)); }
+ ga_workspace::m_tree &ga_workspace::m_tree::operator =(const m_tree& o) {
+ if (ptree) delete ptree;
+ ptree = o.ptree; meshdim = o.meshdim; ignore_X = o.ignore_X;
+ if (o.ptree) ptree = new ga_tree(*(o.ptree));
+ return *this;
+ }
- if (nbargs == 1) {
- pnode->t = child1->t;
- } else {
- if (s1 == s2) {
- pnode->t = child1->t;
- } else if (s1 == 1) {
- pnode->t = child2->t;
- } else {
- pnode->t = child1->t;
+ size_type ga_workspace::add_expression(const std::string &expr,
+ const mesh_im &mim,
+ const mesh_region &rg_,
+ size_type add_derivative_order) {
+ const mesh_region &rg = register_region(mim.linked_mesh(), rg_);
+ // cout << "adding expression " << expr << endl;
+ GA_TIC;
+ size_type max_order = 0;
+ std::vector<ga_tree> ltrees(1);
+ ga_read_string(expr, ltrees[0]);
+ // cout << "read : " << ga_tree_to_string(ltrees[0]) << endl;
+ ga_semantic_analysis(expr, ltrees[0], *this, mim.linked_mesh().dim(),
+ ref_elt_dim_of_mesh(mim.linked_mesh()),
+ false, false, 1);
+ // cout << "analysed : " << ga_tree_to_string(ltrees[0]) << endl;
+ GA_TOC("First analysis time");
+ if (ltrees[0].root) {
+ if (test1.size() > 1 || test2.size() > 1) {
+ size_type ntest2 = std::max(size_type(1), test2.size());
+ size_type nb_ltrees = test1.size()*ntest2;
+ ltrees.resize(nb_ltrees);
+ for (size_type i = 1; i < nb_ltrees; ++i) ltrees[i] = ltrees[0];
+ std::set<var_trans_pair>::iterator it1 = test1.begin();
+ for (size_type i = 0; i < test1.size(); ++i, ++it1) {
+ std::set<var_trans_pair>::iterator it2 = test2.begin();
+ for (size_type j = 0; j < ntest2; ++j) {
+ selected_test1 = *it1;
+ if (test2.size()) selected_test2 = *it2++;
+ // cout << "analysis with " << selected_test1.first << endl;
+ ga_semantic_analysis(expr, ltrees[i*ntest2+j], *this,
+ mim.linked_mesh().dim(),
+ ref_elt_dim_of_mesh(mim.linked_mesh()),
+ false, false, 2);
+ // cout <<"split: "<< ga_tree_to_string(ltrees[i*ntest2+j]) <<
endl;
}
}
+ }
- if (all_cte) {
- if (pnode->der1)
- GMM_ASSERT1(false, "Sorry, to be done");
- pnode->node_type = GA_NODE_CONSTANT;
- if (nbargs == 1) {
- for (size_type i = 0; i < s1; ++i)
- pnode->tensor()[i] = F(child1->tensor()[i]);
- } else {
- if (s1 == s2) {
- for (size_type i = 0; i < s1; ++i)
- pnode->tensor()[i] = F(child1->tensor()[i],
- child2->tensor()[i]);
- } else if (s1 == 1) {
- for (size_type i = 0; i < s2; ++i)
- pnode->tensor()[i] = F(child1->tensor()[0],
- child2->tensor()[i]);
- } else {
- for (size_type i = 0; i < s1; ++i)
- pnode->tensor()[i] = F(child1->tensor()[i],
- child2->tensor()[0]);
- }
- }
- tree.clear_children(pnode);
+ for (size_type i = 0; i < ltrees.size(); ++i) {
+ if (ltrees[i].root) {
+ // cout << "adding tree " << ga_tree_to_string(ltrees[i]) << endl;
+ max_order = std::max(ltrees[i].root->nb_test_functions(), max_order);
+ add_tree(ltrees[i], mim.linked_mesh(), mim, rg, expr,
+ add_derivative_order, true, 0, "");
}
- } else if (child0->node_type == GA_NODE_SPEC_FUNC) {
+ }
+ }
+ GA_TOC("Time for add expression");
+ return max_order;
+ }
- // Special constant functions: meshdim, qdim(u) ...
+ void ga_workspace::add_function_expression(const std::string &expr) {
+ ga_tree tree;
+ ga_read_string(expr, tree);
+ ga_semantic_analysis(expr, tree, *this, 1, 1, false, true);
+ if (tree.root) {
+ // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
+ // "Invalid function expression");
+ add_tree(tree, dummy_mesh(), dummy_mesh_im(), dummy_mesh_region(),
+ expr, 0, true, 0, "");
+ }
+ }
- for (size_type i = 1; i < pnode->children.size(); ++i)
- ga_valid_operand(expr, pnode->children[i]);
- if (pnode->children.size() != 2)
- ga_throw_error(expr, pnode->pos,
- "One and only one argument is allowed for function "
- +child0->name+".");
-
- if (!(child0->name.compare("qdim"))) {
- if (child1->node_type != GA_NODE_VAL)
- ga_throw_error(expr, pnode->pos, "The argument of qdim "
- "function can only be a variable name.");
- pnode->node_type = GA_NODE_CONSTANT;
- pnode->init_scalar_tensor(scalar_type(workspace.qdim(child1->name)));
- if (pnode->tensor()[0] <= 0)
- ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable");
- } else if (!(child0->name.compare("qdims"))) {
- if (child1->node_type != GA_NODE_VAL)
- ga_throw_error(expr, pnode->pos, "The argument of qdim "
- "function can only be a variable name.");
- pnode->node_type = GA_NODE_CONSTANT;
- bgeot::multi_index mii = workspace.qdims(child1->name);
- if (mii.size() > 6)
- ga_throw_error(expr, pnode->pos,
- "Tensor with too much dimensions. Limited to 6");
- if (mii.size() == 0 || scalar_type(mii[0]) <= 0)
- ga_throw_error(expr, pnode->pos,
- "Invalid null size of variable");
- if (mii.size() == 1)
- pnode->init_scalar_tensor(scalar_type(mii[0]));
- if (mii.size() >= 1) {
- pnode->init_vector_tensor(mii.size());
- for (size_type i = 0; i < mii.size(); ++i)
- pnode->tensor()[i] = scalar_type(mii[i]);
- }
- } else if (!(child0->name.compare("Id"))) {
- bool valid = (child1->node_type == GA_NODE_CONSTANT);
- int n = valid ? int(round(child1->tensor()[0])) : -1;
- if (n <= 0 || n > 100 || child1->tensor_order() > 0)
- ga_throw_error(expr, pnode->pos, "The argument of Id "
- "should be a (small) positive integer.");
- pnode->node_type = GA_NODE_CONSTANT;
- if (n == 1)
- pnode->init_scalar_tensor(scalar_type(1));
- else {
- pnode->init_matrix_tensor(n,n);
- for (int i = 0; i < n; ++i) pnode->tensor()(i,i) = scalar_type(1);
- }
- } else ga_throw_error(expr, pnode->children[0]->pos,
- "Unknown special function.");
- tree.clear_children(pnode);
- } else if (child0->node_type == GA_NODE_OPERATOR) {
+ void ga_workspace::add_interpolation_expression(const std::string &expr,
+ const mesh &m,
+ const mesh_region &rg_) {
+ const mesh_region &rg = register_region(m, rg_);
+ ga_tree tree;
+ ga_read_string(expr, tree);
+ ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
+ false, false);
+ if (tree.root) {
+ // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
+ // "Invalid expression containing test functions");
+ add_tree(tree, m, dummy_mesh_im(), rg, expr, 0, false, 1, "");
+ }
+ }
- // Call to a nonlinear operator
+ void ga_workspace::add_interpolation_expression(const std::string &expr,
+ const mesh_im &mim,
+ const mesh_region &rg_) {
+ const mesh &m = mim.linked_mesh();
+ const mesh_region &rg = register_region(m, rg_);
+ ga_tree tree;
+ ga_read_string(expr, tree);
+ ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
+ false, false);
+ if (tree.root) {
+ GMM_ASSERT1(tree.root->nb_test_functions() == 0,
+ "Invalid expression containing test functions");
+ add_tree(tree, m, mim, rg, expr, 0, false, 1, "");
+ }
+ }
- for (size_type i = 1; i < pnode->children.size(); ++i)
- ga_valid_operand(expr, pnode->children[i]);
- all_cte = true;
- ga_nonlinear_operator::arg_list args;
- for (size_type i = 1; i < pnode->children.size(); ++i) {
- all_cte = all_cte
- && (pnode->children[i]->node_type == GA_NODE_CONSTANT);
- args.push_back(&(pnode->children[i]->tensor()));
- if (pnode->children[i]->node_type == GA_NODE_ALLINDICES)
- ga_throw_error(expr, pnode->children[i]->pos,
- "Colon operator is not allowed in nonlinear "
- "operator call.");
- if (pnode->children[i]->test_function_type)
- ga_throw_error(expr, pnode->pos, "Test functions cannot be passed "
- "as argument of a nonlinear operator.");
- if (pnode->children[i]->tensor_order() > 2)
- ga_throw_error(expr, pnode->pos, "Sorry, arguments to nonlinear "
- "operators should only be scalar, vector or matrices");
- }
- ga_predef_operator_tab::T::const_iterator it
- = PREDEF_OPERATORS.tab.find(child0->name);
- const ga_nonlinear_operator &OP = *(it->second);
- mi.resize(0);
- if (!(OP.result_size(args, mi)))
- ga_throw_error(expr, pnode->pos,
- "Wrong number or wrong size of arguments for the "
- "call of nonlinear operator " + child0->name);
+ void ga_workspace::add_assignment_expression
+ (const std::string &varname, const std::string &expr, const mesh_region &rg_,
+ size_type order, bool before) {
+ const im_data *imd = associated_im_data(varname);
+ GMM_ASSERT1(imd != 0, "Only applicable to im_data");
+ const mesh_im &mim = imd->linked_mesh_im();
+ const mesh &m = mim.linked_mesh();
+ const mesh_region &rg = register_region(m, rg_);
+ ga_tree tree;
+ ga_read_string(expr, tree);
+ ga_semantic_analysis(expr, tree, *this, m.dim(), ref_elt_dim_of_mesh(m),
+ false, false);
+ if (tree.root) {
+ GMM_ASSERT1(tree.root->nb_test_functions() == 0,
+ "Invalid expression containing test functions");
+ add_tree(tree, m, mim, rg, expr, order+1, false, (before ? 1 : 2),
+ varname);
+ }
+ }
- pnode->test_function_type = 0;
+ size_type ga_workspace::nb_trees() const { return trees.size(); }
- if (child0->der1 > args.size() || child0->der2 > args.size())
- ga_throw_error(expr, child0->pos,
- "Invalid derivative number for nonlinear operator "
- + child0->name);
+ ga_workspace::tree_description &ga_workspace::tree_info(size_type i)
+ { return trees[i]; }
- if (child0->der1 && child0->der2 == 0) {
- for (size_type i = 0; i < args[child0->der1-1]->sizes().size(); ++i)
- mi.push_back(args[child0->der1-1]->sizes()[i]);
- pnode->t.adjust_sizes(mi);
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- OP.derivative(args, child0->der1, pnode->tensor());
- tree.clear_children(pnode);
- }
- } else if (child0->der1 && child0->der2) {
- for (size_type i = 0; i < args[child0->der1-1]->sizes().size(); ++i)
- mi.push_back(args[child0->der1-1]->sizes()[i]);
- for (size_type i = 0; i < args[child0->der2-1]->sizes().size(); ++i)
- mi.push_back(args[child0->der2-1]->sizes()[i]);
- pnode->t.adjust_sizes(mi);
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- OP.second_derivative(args, child0->der1, child0->der2,
- pnode->tensor());
- tree.clear_children(pnode);
- }
- } else {
- pnode->t.adjust_sizes(mi);
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- OP.value(args, pnode->tensor());
- tree.clear_children(pnode);
+ bool ga_workspace::used_variables(std::vector<std::string> &vl,
+ std::vector<std::string> &vl_test1,
+ std::vector<std::string> &vl_test2,
+ std::vector<std::string> &dl,
+ size_type order) {
+ bool islin = true;
+ std::set<var_trans_pair> vll, dll;
+ for (size_type i = 0; i < vl.size(); ++i)
+ vll.insert(var_trans_pair(vl[i], ""));
+ for (size_type i = 0; i < dl.size(); ++i)
+ dll.insert(var_trans_pair(dl[i], ""));
+
+ for (size_type i = 0; i < trees.size(); ++i) {
+ ga_workspace::tree_description &td = trees[i];
+ std::set<var_trans_pair> dllaux;
+ bool fv = ga_extract_variables(td.ptree->root, *this, *(td.m),
+ dllaux, false);
+
+ if (td.order == order) {
+ for (std::set<var_trans_pair>::iterator it = dllaux.begin();
+ it!=dllaux.end(); ++it)
+ dll.insert(*it);
+ }
+ switch (td.order) {
+ case 0: break;
+ case 1:
+ if (td.order == order) {
+ if (variable_group_exists(td.name_test1)) {
+ for (const std::string &t : variable_group(td.name_test1))
+ vll.insert(var_trans_pair(t, td.interpolate_name_test1));
+ } else {
+ vll.insert(var_trans_pair(td.name_test1,
+ td.interpolate_name_test1));
}
+ bool found = false;
+ for (const std::string &t : vl_test1)
+ if (td.name_test1.compare(t) == 0)
+ found = true;
+ if (!found)
+ vl_test1.push_back(td.name_test1);
}
- } else {
-
- // Access to components of a tensor
- all_cte = (child0->node_type == GA_NODE_CONSTANT);
- // cout << "child0->tensor_order() = " << child0->tensor_order();
- // cout << endl << "child0->t.sizes() = "
- // << child0->t.sizes() << endl;
- if (pnode->children.size() != child0->tensor_order() + 1)
- ga_throw_error(expr, pnode->pos, "Bad number of indices.");
- for (size_type i = 1; i < pnode->children.size(); ++i)
- if (pnode->children[i]->node_type != GA_NODE_ALLINDICES &&
- (pnode->children[i]->node_type != GA_NODE_CONSTANT ||
- pnode->children[i]->tensor().size() != 1))
- ga_throw_error(expr, pnode->children[i]->pos,
- "Indices should be constant integers or colon.");
-
- bgeot::multi_index mi1(size0.size()), mi2, indices;
- for (size_type i = 0; i < child0->tensor_order(); ++i) {
- if (pnode->children[i+1]->node_type == GA_NODE_ALLINDICES) {
- mi2.push_back(child0->tensor_proper_size(i));
- indices.push_back(i);
- mi1[i] = 0;
+ break;
+ case 2:
+ if (td.order == order) {
+ if (variable_group_exists(td.name_test1)) {
+ for (const std::string &t : variable_group(td.name_test1))
+ vll.insert(var_trans_pair(t, td.interpolate_name_test1));
} else {
- mi1[i] = size_type(round(pnode->children[i+1]->tensor()[0])-1);
- if (mi1[i] >= child0->tensor_proper_size(i))
- ga_throw_error(expr, pnode->children[i+1]->pos,
- "Index out of range, " << mi1[i]+1
- << ". Should be between 1 and "
- << child0->tensor_proper_size(i) << ".");
+ vll.insert(var_trans_pair(td.name_test1,
+ td.interpolate_name_test1));
}
- }
- mi.resize(0);
- for (size_type i = 0; i < child0->nb_test_functions(); ++i)
- mi.push_back(child0->t.sizes()[i]);
- for (size_type i = 0; i < mi2.size(); ++i) mi.push_back(mi2[i]);
- pnode->t.adjust_sizes(mi);
- pnode->test_function_type = child0->test_function_type;
- pnode->name_test1 = child0->name_test1;
- pnode->name_test2 = child0->name_test2;
- pnode->interpolate_name_test1 = child0->interpolate_name_test1;
- pnode->interpolate_name_test2 = child0->interpolate_name_test2;
- pnode->qdim1 = child0->qdim1;
- pnode->qdim2 = child0->qdim2;
-
- if (all_cte) {
- pnode->node_type = GA_NODE_CONSTANT;
- for (bgeot::multi_index mi3(mi2.size()); !mi3.finished(mi2);
- mi3.incrementation(mi2)) {
- for (size_type j = 0; j < mi2.size(); ++j) {
- mi1[indices[j]] = mi3[j];
- }
- pnode->tensor()(mi3) = pnode->children[0]->tensor()(mi1);
+ if (variable_group_exists(td.name_test2)) {
+ for (const std::string &t : variable_group(td.name_test2))
+ vll.insert(var_trans_pair(t, td.interpolate_name_test2));
+ } else {
+ vll.insert(var_trans_pair(td.name_test2,
+ td.interpolate_name_test2));
}
- tree.clear_children(pnode);
- } else {
- if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
- gmm::clear(pnode->tensor().as_vector());
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
+ bool found = false;
+ for (size_type j = 0; j < vl_test1.size(); ++j)
+ if ((td.name_test1.compare(vl_test1[j]) == 0) &&
+ (td.name_test2.compare(vl_test2[j]) == 0))
+ found = true;
+ if (!found) {
+ vl_test1.push_back(td.name_test1);
+ vl_test2.push_back(td.name_test2);
}
}
+ if (fv) islin = false;
+ break;
}
- break;
-
- default:GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
- << " in semantic analysis. Internal error.");
}
- // cout << " begin hash code = " << pnode->hash_value << endl;
- pnode->hash_value = ga_hash_code(pnode);
- // cout << "node_type = " << pnode->node_type << " op_type = "
- // << pnode->op_type << " proper hash code = " << pnode->hash_value;
- for (size_type i = 0; i < pnode->children.size(); ++i) {
- pnode->hash_value += (pnode->children[i]->hash_value)
- * 1.0101 * (pnode->symmetric_op ? scalar_type(1) : scalar_type(i+1));
- }
- // cout << " final hash code = " << pnode->hash_value << endl;
- }
-
-
-
-
- //=========================================================================
- // Extract a sub tree which consists of the corresponding node and of
- // the terms multiplying this term, but not the term in addition.
- // The aim is to expand an expression is a sum of elementary factors.
- // Complains if a nonlinear term is encountered.
- //=========================================================================
- static void ga_extract_factor(ga_tree &result_tree, pga_tree_node pnode,
- pga_tree_node &new_pnode) {
- result_tree.clear();
- result_tree.copy_node(pnode, 0, result_tree.root);
- new_pnode = result_tree.root;
-
- bool minus_sign = false;
+ vl.clear();
+ for (const auto &var : vll)
+ if (vl.size() == 0 || var.varname.compare(vl.back()))
+ vl.push_back(var.varname);
+ dl.clear();
+ for (const auto &var : dll)
+ if (dl.size() == 0 || var.varname.compare(dl.back()))
+ dl.push_back(var.varname);
- pga_tree_node pnode_child = pnode;
- pnode = pnode->parent;
+ return islin;
+ }
- while (pnode) {
+ void ga_workspace::define_variable_group(const std::string &group_name,
+ const std::vector<std::string> &nl)
{
+ GMM_ASSERT1(!(variable_exists(group_name)), "The name of a group of "
+ "variables cannot be the same as a variable name");
- size_type nbch = pnode->children.size();
- pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
- pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
+ std::set<const mesh *> ms;
+ bool is_data_ = false;
+ for (size_type i = 0; i < nl.size(); ++i) {
+ if (i == 0)
+ is_data_ = is_constant(nl[i]);
+ else {
+ GMM_ASSERT1(is_data_ == is_constant(nl[i]),
+ "It is not possible to mix variables and data in a group");
+ }
+ GMM_ASSERT1(variable_exists(nl[i]),
+ "All variables in a group have to exist in the model");
+ const mesh_fem *mf = associated_mf(nl[i]);
+ GMM_ASSERT1(mf, "Variables in a group should be fem variables");
+ GMM_ASSERT1(ms.find(&(mf->linked_mesh())) == ms.end(),
+ "Two variables in a group cannot share the same mesh");
+ ms.insert(&(mf->linked_mesh()));
+ }
+ variable_groups[group_name] = nl;
+ }
- switch (pnode->node_type) {
- case GA_NODE_OP:
- switch(pnode->op_type) {
- case GA_PLUS:
- // Nothing to do
- break;
- case GA_MINUS:
- if (child1 == pnode_child) minus_sign = !(minus_sign);
- // A remaining minus sign is added at the end if necessary.
- break;
- case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
- case GA_TRACE: case GA_DEVIATOR: case GA_PRINT:
- // Copy of the term
- result_tree.insert_node(result_tree.root, pnode->node_type);
- result_tree.root->op_type = pnode->op_type;
- result_tree.root->pos = pnode->pos;
- break;
- case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
- case GA_DOTMULT: case GA_DIV: case GA_DOTDIV:
- // Copy of the term and other child
- result_tree.insert_node(result_tree.root, pnode->node_type);
- result_tree.root->op_type = pnode->op_type;
- result_tree.root->pos = pnode->pos;
- result_tree.root->children.resize(2, nullptr);
- if (child0 == pnode_child) {
- result_tree.copy_node(child1, result_tree.root,
- result_tree.root->children[1]);
- } else if (child1 == pnode_child) {
- std::swap(result_tree.root->children[1],
- result_tree.root->children[0]);
- result_tree.copy_node(child0, result_tree.root,
- result_tree.root->children[0]);
- } else GMM_ASSERT1(false, "Corrupted tree");
- break;
- default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
- }
- break;
+ const std::string &ga_workspace::variable_in_group
+ (const std::string &group_name, const mesh &m) const {
+ if (variable_group_exists(group_name)) {
+ for (const std::string &t : variable_group(group_name))
+ if (&(associated_mf(t)->linked_mesh()) == &m)
+ return t;
+ GMM_ASSERT1(false, "No variable in this group for the given mesh");
+ } else
+ return group_name;
+ }
- case GA_NODE_PARAMS:
- GMM_ASSERT1(child0->node_type == GA_NODE_RESHAPE, "Cannot extract a "
- "factor which is a parameter of a nonlinear "
- "operator/function");
- GMM_ASSERT1(child1 == pnode_child, "Cannot extract a factor of a "
- "Reshape size parameter");
- // Copy of the term and other children
- result_tree.insert_node(result_tree.root, pnode->node_type);
- result_tree.root->pos = pnode->pos;
- result_tree.root->children.resize(pnode->children.size(), nullptr);
- std::swap(result_tree.root->children[1], result_tree.root->children[0]);
- for (size_type i = 0; i < pnode->children.size(); ++i)
- if (i != 1)
- result_tree.copy_node(pnode->children[i], result_tree.root,
- result_tree.root->children[i]);
- break;
- case GA_NODE_C_MATRIX:
- result_tree.insert_node(result_tree.root, pnode->node_type);
- result_tree.root->pos = pnode->pos;
- result_tree.root->children.resize(pnode->children.size());
- for (size_type i = 0; i < pnode->children.size(); ++i)
- if (pnode_child == pnode->children[i]) {
- result_tree.root->children[i] = result_tree.root->children[0];
- result_tree.root->children[0] = 0;
- }
+ void ga_workspace::assembly(size_type order) {
+ size_type ndof;
+ const ga_workspace *w = this;
+ while (w->parent_workspace) w = w->parent_workspace;
+ if (w->md) ndof = w->md->nb_dof(); // To eventually call actualize_sizes()
- for (size_type i = 0; i < pnode->children.size(); ++i) {
- if (pnode_child == pnode->children[i]) {
- pnode->children[i] = new ga_tree_node(GA_NODE_ZERO, pnode->pos);
- pnode->children[i]->init_scalar_tensor(scalar_type(0));
- pnode->children[i]->parent = pnode;
- }
- }
- break;
+ GA_TIC;
+ ga_instruction_set gis;
+ ga_compile(*this, gis, order);
+ ndof = gis.nb_dof;
+ size_type max_dof = gis.max_dof;
+ GA_TOCTIC("Compile time");
- default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
- << " in extract constant term. Internal error.");
+ if (order == 2) {
+ if (K.use_count()) {
+ gmm::clear(*K);
+ gmm::resize(*K, max_dof, max_dof);
}
-
- pnode_child = pnode;
- pnode = pnode->parent;
+ gmm::clear(unreduced_K);
+ gmm::resize(unreduced_K, ndof, ndof);
}
-
- if (minus_sign) {
- result_tree.insert_node(result_tree.root, GA_NODE_OP);
- result_tree.root->op_type = GA_UNARY_MINUS;
- result_tree.root->pos = pnode->children[0]->pos;
+ if (order == 1) {
+ if (V.use_count()) {
+ gmm::clear(*V);
+ gmm::resize(*V, max_dof);
+ }
+ gmm::clear(unreduced_V);
+ gmm::resize(unreduced_V, ndof);
}
- }
-
- //=========================================================================
- // Extract the constant term of degree 1 expressions
- //=========================================================================
-
- static bool ga_node_extract_constant_term
- (ga_tree &tree, pga_tree_node pnode, const ga_workspace &workspace,
- const mesh &m) {
- bool is_constant = true;
- size_type nbch = pnode->children.size();
- pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
- // pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
- bool child_0_is_constant = (nbch <= 0) ? true :
- ga_node_extract_constant_term(tree, pnode->children[0], workspace, m);
- bool child_1_is_constant = (nbch <= 1) ? true :
- ga_node_extract_constant_term(tree, pnode->children[1], workspace, m);
-
- switch (pnode->node_type) {
- case GA_NODE_ZERO: is_constant = false; break;
-
- case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
- case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
- case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
- case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
- case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
- case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
- case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST: case GA_NODE_PREDEF_FUNC:
- case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST: case GA_NODE_RESHAPE:
- case GA_NODE_ELT_SIZE: case GA_NODE_ELT_K: case GA_NODE_ELT_B:
- case GA_NODE_CONSTANT: case GA_NODE_X:
- case GA_NODE_NORMAL: case GA_NODE_OPERATOR:
- is_constant = true; break;
+ E = 0;
+ GA_TOCTIC("Init time");
- case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
- case GA_NODE_VAL: case GA_NODE_GRAD: case GA_NODE_HESS:
- case GA_NODE_DIVERG:
- is_constant = workspace.is_constant(pnode->name);
- break;
+ ga_exec(gis, *this);
+ GA_TOCTIC("Exec time");
- case GA_NODE_INTERPOLATE_VAL:
- case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_INTERPOLATE_HESS:
- case GA_NODE_INTERPOLATE_DIVERG:
- {
- if (!(workspace.is_constant(pnode->name))) {
- is_constant = false; break;
- }
- std::set<var_trans_pair> vars;
- workspace.interpolate_transformation(pnode->interpolate_name)
- ->extract_variables(workspace, vars, true, m,
- pnode->interpolate_name);
- for (const var_trans_pair &var : vars) {
- if (!(workspace.is_constant(var.varname)))
- { is_constant = false; break; }
- }
- }
- break;
+ if (order == 1) {
+ MPI_SUM_VECTOR(assembled_vector());
+ MPI_SUM_VECTOR(unreduced_V);
+ } else if (order == 0) {
+ assembled_potential() = MPI_SUM_SCALAR(assembled_potential());
+ }
- case GA_NODE_INTERPOLATE_FILTER:
- if (!child_0_is_constant) { is_constant = false; break; }
- // No break intentionally
- case GA_NODE_INTERPOLATE_VAL_TEST:
- case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_DIVERG_TEST:
- case GA_NODE_INTERPOLATE_HESS_TEST:
- case GA_NODE_INTERPOLATE_X:
- case GA_NODE_INTERPOLATE_NORMAL:
- case GA_NODE_INTERPOLATE_DERIVATIVE:
- {
- std::set<var_trans_pair> vars;
- workspace.interpolate_transformation(pnode->interpolate_name)
- ->extract_variables(workspace, vars, true, m,
- pnode->interpolate_name);
- for (const var_trans_pair &var : vars) {
- if (!(workspace.is_constant(var.varname)))
- { is_constant = false; break; }
+ // Deal with reduced fems.
+ if (order > 0) {
+ std::set<std::string> vars_vec_done;
+ std::set<std::pair<std::string, std::string> > vars_mat_done;
+ for (ga_tree &tree : gis.trees) {
+ if (tree.root) {
+ if (order == 1) {
+ const std::string &name = tree.root->name_test1;
+ const std::vector<std::string> vnames_(1,name);
+ const std::vector<std::string> &vnames
+ = variable_group_exists(name) ? variable_group(name)
+ : vnames_;
+ for (const std::string &vname : vnames) {
+ const mesh_fem *mf = associated_mf(vname);
+ if (mf && mf->is_reduced() &&
+ vars_vec_done.find(vname) == vars_vec_done.end()) {
+ gmm::mult_add(gmm::transposed(mf->extension_matrix()),
+ gmm::sub_vector(unreduced_V,
+ gis.var_intervals[vname]),
+ gmm::sub_vector(*V,
+ interval_of_variable(vname)));
+ vars_vec_done.insert(vname);
+ }
+ }
+ } else {
+ std::string &name1 = tree.root->name_test1;
+ std::string &name2 = tree.root->name_test2;
+ const std::vector<std::string> vnames1_(1,name1),
+ vnames2_(2,name2);
+ const std::vector<std::string> &vnames1
+ = variable_group_exists(name1) ? variable_group(name1)
+ : vnames1_;
+ const std::vector<std::string> &vnames2
+ = variable_group_exists(name2) ? variable_group(name2)
+ : vnames2_;
+ for (const std::string &vname1 : vnames1) {
+ for (const std::string &vname2 : vnames2) {
+ const mesh_fem *mf1 = associated_mf(vname1);
+ const mesh_fem *mf2 = associated_mf(vname2);
+ if (((mf1 && mf1->is_reduced())
+ || (mf2 && mf2->is_reduced()))) {
+ std::pair<std::string, std::string> p(vname1, vname2);
+ if (vars_mat_done.find(p) == vars_mat_done.end()) {
+ gmm::sub_interval uI1 = gis.var_intervals[vname1];
+ gmm::sub_interval uI2 = gis.var_intervals[vname2];
+ gmm::sub_interval I1 = interval_of_variable(vname1);
+ gmm::sub_interval I2 = interval_of_variable(vname2);
+ if ((mf1 && mf1->is_reduced()) &&
+ (mf2 && mf2->is_reduced())) {
+ model_real_sparse_matrix aux(I1.size(), uI2.size());
+ model_real_row_sparse_matrix M(I1.size(), I2.size());
+ gmm::mult(gmm::transposed(mf1->extension_matrix()),
+ gmm::sub_matrix(unreduced_K, uI1, uI2), aux);
+ gmm::mult(aux, mf2->extension_matrix(), M);
+ gmm::add(M, gmm::sub_matrix(*K, I1, I2));
+ } else if (mf1 && mf1->is_reduced()) {
+ model_real_sparse_matrix M(I1.size(), I2.size());
+ gmm::mult(gmm::transposed(mf1->extension_matrix()),
+ gmm::sub_matrix(unreduced_K, uI1, uI2), M);
+ gmm::add(M, gmm::sub_matrix(*K, I1, I2));
+ } else {
+ model_real_row_sparse_matrix M(I1.size(), I2.size());
+ gmm::mult(gmm::sub_matrix(unreduced_K, uI1, uI2),
+ mf2->extension_matrix(), M);
+ gmm::add(M, gmm::sub_matrix(*K, I1, I2));
+ }
+ vars_mat_done.insert(p);
+ }
+ }
+ }
+ }
+ }
}
}
- break;
-
- case GA_NODE_OP:
- switch(pnode->op_type) {
- case GA_PLUS: case GA_MINUS:
- if (!child_0_is_constant && !child_1_is_constant)
- { is_constant = false; break; }
- break;
-
- case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
- case GA_TRACE: case GA_DEVIATOR: case GA_PRINT:
- is_constant = child_0_is_constant;
- break;
+ }
+ }
- case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
- case GA_DOTMULT: case GA_DIV: case GA_DOTDIV:
- is_constant = (child_0_is_constant && child_1_is_constant);
- break;
+ void ga_workspace::clear_expressions() {
+ trees.clear();
+ macro_trees.clear();
+ }
- default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
+ void ga_workspace::print(std::ostream &str) {
+ for (size_type i = 0; i < trees.size(); ++i)
+ if (trees[i].ptree->root) {
+ cout << "Expression tree " << i << " of order " <<
+ trees[i].ptree->root->nb_test_functions() << " :" << endl;
+ ga_print_node(trees[i].ptree->root, str);
+ cout << endl;
}
- break;
+ }
- case GA_NODE_C_MATRIX:
- for (size_type i = 0; i < pnode->children.size(); ++i) {
- if (!(ga_node_extract_constant_term(tree, pnode->children[i],
- workspace, m)))
- { is_constant = false; break; }
- }
- break;
+ void ga_workspace::tree_description::copy(const tree_description& td) {
+ order = td.order;
+ interpolation = td.interpolation;
+ varname_interpolation = td.varname_interpolation;
+ name_test1 = td.name_test1;
+ name_test2 = td.name_test2;
+ interpolate_name_test1 = td.interpolate_name_test1;
+ interpolate_name_test2 = td.interpolate_name_test2;
+ mim = td.mim;
+ m = td.m;
+ rg = td.rg;
+ ptree = 0;
+ if (td.ptree) ptree = new ga_tree(*(td.ptree));
+ }
- case GA_NODE_PARAMS:
- if (child0->node_type == GA_NODE_RESHAPE) {
- is_constant = child_1_is_constant;
- } else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
- for (size_type i = 1; i < pnode->children.size(); ++i) {
- if (!(ga_node_extract_constant_term(tree, pnode->children[i],
- workspace, m)))
- { is_constant = false; break; }
- }
- } else if (child0->node_type == GA_NODE_SPEC_FUNC) {
- GMM_ASSERT1(false, "internal error");
- } else if (child0->node_type == GA_NODE_OPERATOR) {
- for (size_type i = 1; i < pnode->children.size(); ++i) {
- if (!(ga_node_extract_constant_term(tree, pnode->children[i],
- workspace, m)))
- { is_constant = false; break; }
- }
- } else {
- is_constant = child_0_is_constant;
- }
- break;
+ ga_workspace::tree_description &ga_workspace::tree_description::operator =
+ (const ga_workspace::tree_description& td)
+ { if (ptree) delete ptree; ptree = 0; copy(td); return *this; }
+ ga_workspace::tree_description::~tree_description()
+ { if (ptree) delete ptree; ptree = 0; }
- default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
- << " in extract constant term. Internal error.");
- }
- if (!is_constant) {
- pnode->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode);
- }
- return is_constant;
- }
+
+ //=========================================================================
+ // Extract the constant term of degree 1 expressions
+ //=========================================================================
std::string ga_workspace::extract_constant_term(const mesh &m) {
std::string constant_term;
@@ -10287,187 +5256,10 @@ namespace getfem {
return term;
}
-
//=========================================================================
// Extract Neumann terms
//=========================================================================
- static std::string ga_extract_one_Neumann_term
- (const std::string &varname,
- ga_workspace &workspace, pga_tree_node pnode) {
- size_type N = workspace.qdim(varname);
- const mesh_fem *mf = workspace.associated_mf(varname);
- GMM_ASSERT1(mf, "Works only with fem variables.");
- size_type meshdim = mf->linked_mesh().dim();
- ga_tree factor;
- pga_tree_node new_pnode = nullptr;
- ga_extract_factor(factor, pnode, new_pnode);
- std::string result;
- pga_tree_node nnew_pnode = new_pnode;
-
- int cas = new_pnode->node_type == GA_NODE_GRAD_TEST ? 0 : 1;
- // Allow to detect Trace(Grad_Test_u)
- if (cas == 0 && new_pnode->parent &&
- new_pnode->parent->node_type == GA_NODE_OP &&
- new_pnode->parent->op_type == GA_TRACE) {
- cas = 2; nnew_pnode = new_pnode->parent;
- }
- bool ok = true;
- pga_tree_node colon_pnode = nullptr;
- bool quote_before_colon = false;
-
- // A:Grad_Test_u --> A*Normal if A is a matrix
- // Grad_Test_u:A --> A*Normal if A is a matrix
- // A*Div_Test_u --> A*Normal if A is a scalar
- // Div_Test_u*A --> Normal*A if A is a scalar
- // A*(Grad_Test_u)' --> (A)'*Normal if A is a matrix
- // intercaled scalar multplications and divisions are taken into account
- while (nnew_pnode->parent) {
- pga_tree_node previous_node = nnew_pnode;
- nnew_pnode = nnew_pnode->parent;
-
- if (nnew_pnode->node_type == GA_NODE_OP &&
- nnew_pnode->op_type == GA_MULT &&
- nnew_pnode->children[0] == previous_node &&
- nnew_pnode->children[1]->tensor_proper_size() == 1) {
- } else if (nnew_pnode->node_type == GA_NODE_OP &&
- nnew_pnode->op_type == GA_MULT &&
- nnew_pnode->children[1] == previous_node &&
- nnew_pnode->children[0]->tensor_proper_size() == 1) {
-
- } else if (nnew_pnode->node_type == GA_NODE_OP &&
- nnew_pnode->op_type == GA_DIV &&
- nnew_pnode->children[0] == previous_node &&
- nnew_pnode->children[1]->tensor_proper_size() == 1) {
-
- } else if (nnew_pnode->node_type == GA_NODE_OP &&
- nnew_pnode->op_type == GA_COLON &&
- nnew_pnode->children[0] == previous_node &&
- nnew_pnode->children[1]->tensor_order() == 2 &&
- colon_pnode == 0 && cas == 0) {
- std::swap(nnew_pnode->children[0], nnew_pnode->children[1]);
- colon_pnode = nnew_pnode;
- } else if (nnew_pnode->node_type == GA_NODE_OP &&
- nnew_pnode->op_type == GA_COLON &&
- nnew_pnode->children[1] == previous_node &&
- nnew_pnode->children[0]->tensor_order() == 2 &&
- colon_pnode == 0 && cas == 0) {
- colon_pnode = nnew_pnode;
- } else if (nnew_pnode->node_type == GA_NODE_OP &&
- nnew_pnode->op_type == GA_QUOTE &&
- colon_pnode == 0 && cas == 0 && !quote_before_colon) {
- quote_before_colon = true;
- } else ok = false;
- }
-
- // cout << "analyzing factor : " << ga_tree_to_string(factor) << endl;
- // cout << "ok = " << int(ok) << endl;
- // cout << "colon_pnode = " << colon_pnode << endl;
-
- if (ok && cas == 0 && !colon_pnode) ok = false;
-
- if (N == 1) {
- new_pnode->node_type = GA_NODE_NORMAL;
- result = "(" + ga_tree_to_string(factor) + ")";
- } else if (ok) {
- switch (cas) {
- case 0:
- new_pnode->node_type = GA_NODE_NORMAL;
- colon_pnode->op_type = GA_MULT;
- if (quote_before_colon) {
- factor.insert_node(colon_pnode->children[0], GA_NODE_OP);
- colon_pnode->children[0]->op_type = GA_QUOTE;
- nnew_pnode = new_pnode->parent;
- while(nnew_pnode->node_type != GA_NODE_OP ||
- nnew_pnode->op_type != GA_QUOTE)
- nnew_pnode = nnew_pnode->parent;
- factor.replace_node_by_child(nnew_pnode,0);
- }
- break;
- case 1:
- new_pnode->node_type = GA_NODE_NORMAL;
- break;
- case 2:
- new_pnode->parent->node_type = GA_NODE_NORMAL;
- factor.clear_children(new_pnode->parent);
- break;
- }
- result = "(" + ga_tree_to_string(factor) + ")";
-
- } else {
- // General case
-
- result = "[";
- bgeot::multi_index mi(2); mi[0] = N; mi[1] = meshdim;
-
- for (size_type i = 0; i < N; ++i) {
- factor.clear_children(new_pnode);
- new_pnode->node_type = GA_NODE_C_MATRIX;
- new_pnode->nbc1 = meshdim;
- new_pnode->nbc2 = new_pnode->nbc3 = 1;
- new_pnode->t.adjust_sizes(mi);
- new_pnode->children.resize(N*meshdim);
- for (size_type j = 0; j < N; ++j) {
- for (size_type k = 0; k < meshdim; ++k) {
- if (j == i) {
- pga_tree_node param_node = new_pnode->children[k*N+j]
- = new ga_tree_node(GA_NODE_PARAMS, pnode->pos);
- new_pnode->children[k*N+j]->parent = new_pnode;
- param_node->children.resize(2);
- param_node->children[0] = new ga_tree_node(GA_NODE_NORMAL,
- pnode->pos);
- param_node->children[0]->parent = param_node;
- param_node->children[1] = new ga_tree_node(GA_NODE_CONSTANT,
- pnode->pos);
- param_node->children[1]->parent = param_node;
- param_node->children[1]->init_scalar_tensor(scalar_type(k));
-
- } else {
- new_pnode->children[k*N+j] = new ga_tree_node(GA_NODE_ZERO,
- pnode->pos);
- new_pnode->children[k*N+j]->init_scalar_tensor(scalar_type(0));
- new_pnode->children[k*N+j]->parent = new_pnode;
- }
- }
- }
- result += "(" + ga_tree_to_string(factor) + ")";
- if (i < N-1) result += ";";
- }
- result += "]";
- GMM_TRACE2("Warning, generic Neumann term used: " << result);
- }
-
- return result;
- }
-
-
- static void ga_extract_Neumann_term_rec
- (ga_tree &tree, const std::string &varname,
- ga_workspace &workspace, pga_tree_node pnode, std::string &result) {
-
- for (size_type i = 0; i < pnode->children.size(); ++i)
- ga_extract_Neumann_term_rec(tree, varname, workspace,
- pnode->children[i], result);
-
-
- switch (pnode->node_type) {
- case GA_NODE_DIVERG_TEST: case GA_NODE_GRAD_TEST:
- case GA_NODE_ELEMENTARY_GRAD_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
- if (pnode->name.compare(varname) == 0) {
- if (result.size()) result += " + ";
- result += ga_extract_one_Neumann_term(varname, workspace, pnode);
- }
- break;
- case GA_NODE_INTERPOLATE_GRAD_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
- if (pnode->name.compare(varname) == 0)
- GMM_ASSERT1(false, "Do not know how to extract a "
- "Neumann term with an interpolate transformation");
- break;
- default:
- break;
- }
- }
-
std::string ga_workspace::extract_Neumann_term(const std::string &varname) {
std::string result;
for (size_type i = 0; i < trees.size(); ++i) {
@@ -10475,7 +5267,7 @@ namespace getfem {
if (td.order == 1 && td.name_test1.compare(varname) == 0) {
ga_tree &local_tree = *(td.ptree);
if (local_tree.root)
- ga_extract_Neumann_term_rec(local_tree, varname, *this,
+ ga_extract_Neumann_term(local_tree, varname, *this,
local_tree.root, result);
}
}
@@ -10483,794 +5275,6 @@ namespace getfem {
}
//=========================================================================
- // Derivation algorithm: derivation of a tree with respect to a variable
- // The result tree is not ready to use. It has to be passed again in
- // ga_semantic_analysis for enrichment.
- //=========================================================================
-
- static bool ga_node_mark_tree_for_variable
- (pga_tree_node pnode, const ga_workspace &workspace, const mesh &m,
- const std::string &varname,
- const std::string &interpolatename) {
- bool marked = false;
- for (size_type i = 0; i < pnode->children.size(); ++i)
- if (ga_node_mark_tree_for_variable(pnode->children[i], workspace, m,
- varname, interpolatename))
- marked = true;
-
- bool plain_node(pnode->node_type == GA_NODE_VAL ||
- pnode->node_type == GA_NODE_GRAD ||
- pnode->node_type == GA_NODE_HESS ||
- pnode->node_type == GA_NODE_DIVERG);
- bool interpolate_node(pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
- pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
- pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
- pnode->node_type == GA_NODE_INTERPOLATE_DIVERG);
- bool elementary_node(pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
- pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
- pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
- pnode->node_type == GA_NODE_ELEMENTARY_DIVERG);
- bool xfem_node(pnode->node_type == GA_NODE_XFEM_PLUS_VAL ||
- pnode->node_type == GA_NODE_XFEM_PLUS_GRAD ||
- pnode->node_type == GA_NODE_XFEM_PLUS_HESS ||
- pnode->node_type == GA_NODE_XFEM_PLUS_DIVERG ||
- pnode->node_type == GA_NODE_XFEM_MINUS_VAL ||
- pnode->node_type == GA_NODE_XFEM_MINUS_GRAD ||
- pnode->node_type == GA_NODE_XFEM_MINUS_HESS ||
- pnode->node_type == GA_NODE_XFEM_MINUS_DIVERG);
- bool interpolate_test_node
- (pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST ||
- pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST ||
- pnode->node_type == GA_NODE_INTERPOLATE_HESS_TEST ||
- pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST);
-
- if ((plain_node || interpolate_node || elementary_node || xfem_node) &&
- (pnode->name.compare(varname) == 0 &&
- pnode->interpolate_name.compare(interpolatename) == 0)) marked = true;
-
- if (interpolate_node || interpolate_test_node ||
- pnode->node_type == GA_NODE_INTERPOLATE_X ||
- pnode->node_type == GA_NODE_INTERPOLATE_NORMAL) {
- std::set<var_trans_pair> vars;
- workspace.interpolate_transformation(pnode->interpolate_name)
- ->extract_variables(workspace, vars, true,
- m, pnode->interpolate_name);
- for (std::set<var_trans_pair>::iterator it=vars.begin();
- it != vars.end(); ++it) {
- if (it->varname.compare(varname) == 0 &&
- it->transname.compare(interpolatename) == 0) marked = true;
- }
- }
- pnode->marked = marked;
- return marked;
- }
-
- static void ga_node_derivation(ga_tree &tree, const ga_workspace &workspace,
- const mesh &m,
- pga_tree_node pnode,
- const std::string &varname,
- const std::string &interpolatename,
- size_type order) {
-
- size_type nbch = pnode->children.size();
- pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
- pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
- bool mark0 = ((nbch > 0) ? child0->marked : false);
- bool mark1 = ((nbch > 1) ? child1->marked : false);
- bgeot::multi_index mi;
-
- const ga_predef_function_tab &PREDEF_FUNCTIONS
- = dal::singleton<ga_predef_function_tab>::instance(0);
-
- switch (pnode->node_type) {
- case GA_NODE_VAL: case GA_NODE_GRAD:
- case GA_NODE_HESS: case GA_NODE_DIVERG:
- mi.resize(1); mi[0] = 2;
- for (size_type i = 0; i < pnode->tensor_order(); ++i)
- mi.push_back(pnode->tensor_proper_size(i));
- pnode->t.adjust_sizes(mi);
- if (pnode->node_type == GA_NODE_VAL)
- pnode->node_type = GA_NODE_VAL_TEST;
- else if (pnode->node_type == GA_NODE_GRAD)
- pnode->node_type = GA_NODE_GRAD_TEST;
- else if (pnode->node_type == GA_NODE_HESS)
- pnode->node_type = GA_NODE_HESS_TEST;
- else if (pnode->node_type == GA_NODE_DIVERG)
- pnode->node_type = GA_NODE_DIVERG_TEST;
- pnode->test_function_type = order;
- break;
-
- case GA_NODE_INTERPOLATE_VAL:
- case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_INTERPOLATE_HESS:
- case GA_NODE_INTERPOLATE_DIVERG:
- {
- bool is_val(pnode->node_type == GA_NODE_INTERPOLATE_VAL);
- bool is_grad(pnode->node_type == GA_NODE_INTERPOLATE_GRAD);
- bool is_hess(pnode->node_type == GA_NODE_INTERPOLATE_HESS);
- bool is_diverg(pnode->node_type == GA_NODE_INTERPOLATE_DIVERG);
-
- bool ivar = (pnode->name.compare(varname) == 0 &&
- pnode->interpolate_name.compare(interpolatename) == 0);
- bool itrans = !ivar;
- if (!itrans) {
- std::set<var_trans_pair> vars;
- workspace.interpolate_transformation(pnode->interpolate_name)
- ->extract_variables(workspace, vars, true, m,
- pnode->interpolate_name);
- for (const var_trans_pair &var : vars) {
- if (var.varname.compare(varname) == 0 &&
- var.transname.compare(interpolatename) == 0)
- itrans = true;
- }
- }
-
- pga_tree_node pnode_trans = pnode;
- if (is_hess) {
- GMM_ASSERT1(!itrans, "Sorry, cannot derive a hessian once more");
- } else if (itrans && ivar) {
- tree.duplicate_with_addition(pnode);
- pnode_trans = pnode->parent->children[1];
- }
-
- if (ivar) {
- mi.resize(1); mi[0] = 2;
- for (size_type i = 0; i < pnode->tensor_order(); ++i)
- mi.push_back(pnode->tensor_proper_size(i));
- pnode->t.adjust_sizes(mi);
- if (is_val) // --> t(Qmult*ndof,Qmult*target_dim)
- pnode->node_type = GA_NODE_INTERPOLATE_VAL_TEST;
- else if (is_grad) // --> t(Qmult*ndof,Qmult*target_dim,N)
- pnode->node_type = GA_NODE_INTERPOLATE_GRAD_TEST;
- else if (is_hess) // --> t(Qmult*ndof,Qmult*target_dim,N,N)
- pnode->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
- else if (is_diverg) // --> t(Qmult*ndof)
- pnode->node_type = GA_NODE_INTERPOLATE_DIVERG_TEST;
- pnode->test_function_type = order;
- }
-
- if (itrans) {
- const mesh_fem *mf = workspace.associated_mf(pnode_trans->name);
- size_type q = workspace.qdim(pnode_trans->name);
- size_type n = mf->linked_mesh().dim();
- bgeot::multi_index mii = workspace.qdims(pnode_trans->name);
-
- if (is_val) // --> t(target_dim*Qmult,N)
- pnode_trans->node_type = GA_NODE_INTERPOLATE_GRAD;
- else if (is_grad || is_diverg) // --> t(target_dim*Qmult,N,N)
- pnode_trans->node_type = GA_NODE_INTERPOLATE_HESS;
-
- if (n > 1) {
- if (q == 1 && mii.size() <= 1) { mii.resize(1); mii[0] = n; }
- else mii.push_back(n);
-
- if (is_grad || is_diverg) mii.push_back(n);
- }
- pnode_trans->t.adjust_sizes(mii);
- tree.duplicate_with_operation(pnode_trans,
- (n > 1) ? GA_DOT : GA_MULT);
- pga_tree_node pnode_der = pnode_trans->parent->children[1];
- pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
- if (n == 1)
- pnode_der->init_vector_tensor(2);
- else
- pnode_der->init_matrix_tensor(2, n);
- pnode_der->test_function_type = order;
- pnode_der->name = varname;
- pnode_der->interpolate_name_der = pnode_der->interpolate_name;
- pnode_der->interpolate_name = interpolatename;
-
- if (is_diverg) { // --> t(Qmult*ndof)
- tree.insert_node(pnode_trans->parent, GA_NODE_OP);
- pga_tree_node pnode_tr = pnode_trans->parent->parent;
- pnode_tr->op_type = GA_TRACE;
- pnode_tr->init_vector_tensor(2);
-// pnode_tr->test_function_type = order;
-// pnode_tr->name_test1 = pnode_trans->name_test1;
-// pnode_tr->name_test2 = pnode_trans->name_test2;
- }
- }
- }
- break;
-
- case GA_NODE_INTERPOLATE_VAL_TEST:
- case GA_NODE_INTERPOLATE_GRAD_TEST:
- case GA_NODE_INTERPOLATE_DIVERG_TEST:
- {
- bool is_val(pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST);
- bool is_grad(pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST);
- bool is_diverg(pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST);
-
- pga_tree_node pnode_trans = pnode;
- const mesh_fem *mf = workspace.associated_mf(pnode_trans->name);
- size_type q = workspace.qdim(pnode_trans->name);
- size_type n = mf->linked_mesh().dim();
- bgeot::multi_index mii = workspace.qdims(pnode_trans->name);
- if (is_val) // --> t(Qmult*ndof,Qmult*target_dim,N)
- pnode_trans->node_type = GA_NODE_INTERPOLATE_GRAD_TEST;
- else if (is_grad || is_diverg) // -->
t(Qmult*ndof,Qmult*target_dim,N,N)
- pnode_trans->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
-
- if (q == 1 && mii.size() <= 1) { mii.resize(1); mii[0] = 2; }
- else mii.insert(mii.begin(), 2);
-
- if (n > 1) {
- mii.push_back(n);
- if (is_grad || is_diverg) mii.push_back(n);
- }
- pnode_trans->t.adjust_sizes(mii);
- // pnode_trans->test_function_type = order;
- tree.duplicate_with_operation(pnode_trans,
- (n > 1 ? GA_DOT : GA_MULT));
- pga_tree_node pnode_der = pnode_trans->parent->children[1];
- pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
- if (n == 1)
- pnode_der->init_vector_tensor(2);
- else
- pnode_der->init_matrix_tensor(2, n);
- pnode_der->test_function_type = order;
- pnode_der->name = varname;
- pnode_der->interpolate_name_der = pnode_der->interpolate_name;
- pnode_der->interpolate_name = interpolatename;
-
- if (is_diverg) { // --> t(Qmult*ndof)
- tree.insert_node(pnode_trans->parent, GA_NODE_OP);
- pga_tree_node pnode_tr = pnode_trans->parent->parent;
- pnode_tr->op_type = GA_TRACE;
- pnode_tr->init_vector_tensor(2);
-// pnode_tr->test_function_type = order;
-// pnode_tr->name_test1 = pnode_trans->name_test1;
-// pnode_tr->name_test2 = pnode_trans->name_test2;
- }
- }
- break;
-
- case GA_NODE_INTERPOLATE_HESS_TEST:
- GMM_ASSERT1(false, "Sorry, cannot derive a hessian once more");
- break;
-
- case GA_NODE_INTERPOLATE_X:
- {
- size_type n = m.dim();
- pga_tree_node pnode_der = pnode;
- pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
- if (n == 1)
- pnode_der->init_vector_tensor(2);
- else
- pnode_der->init_matrix_tensor(2, n);
- pnode_der->test_function_type = order;
- pnode_der->name = varname;
- pnode_der->interpolate_name_der = pnode_der->interpolate_name;
- pnode_der->interpolate_name = interpolatename;
- }
- break;
-
- case GA_NODE_INTERPOLATE_NORMAL:
- GMM_ASSERT1(false, "Sorry, cannot derive the interpolated Normal");
- break;
-
- case GA_NODE_INTERPOLATE_DERIVATIVE:
- GMM_ASSERT1(false, "Sorry, second order transformation derivative "
- "not taken into account");
- break;
-
- case GA_NODE_INTERPOLATE_FILTER:
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- break;
-
- case GA_NODE_ELEMENTARY_VAL:
- case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_ELEMENTARY_HESS:
- case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_XFEM_PLUS_VAL:
- case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_PLUS_HESS:
- case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_MINUS_VAL:
- case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_XFEM_MINUS_HESS:
- case GA_NODE_XFEM_MINUS_DIVERG:
- mi.resize(1); mi[0] = 2;
- for (size_type i = 0; i < pnode->tensor_order(); ++i)
- mi.push_back(pnode->tensor_proper_size(i));
- pnode->t.adjust_sizes(mi);
- switch(pnode->node_type) {
- case GA_NODE_ELEMENTARY_VAL:
- pnode->node_type = GA_NODE_ELEMENTARY_VAL_TEST; break;
- case GA_NODE_ELEMENTARY_GRAD:
- pnode->node_type = GA_NODE_ELEMENTARY_GRAD_TEST; break;
- case GA_NODE_ELEMENTARY_HESS:
- pnode->node_type = GA_NODE_ELEMENTARY_HESS_TEST; break;
- case GA_NODE_ELEMENTARY_DIVERG:
- pnode->node_type = GA_NODE_ELEMENTARY_DIVERG_TEST; break;
- case GA_NODE_XFEM_PLUS_VAL:
- pnode->node_type = GA_NODE_XFEM_PLUS_VAL_TEST; break;
- case GA_NODE_XFEM_PLUS_GRAD:
- pnode->node_type = GA_NODE_XFEM_PLUS_GRAD_TEST; break;
- case GA_NODE_XFEM_PLUS_HESS:
- pnode->node_type = GA_NODE_XFEM_PLUS_HESS_TEST; break;
- case GA_NODE_XFEM_PLUS_DIVERG:
- pnode->node_type = GA_NODE_XFEM_PLUS_DIVERG_TEST; break;
- case GA_NODE_XFEM_MINUS_VAL:
- pnode->node_type = GA_NODE_XFEM_MINUS_VAL_TEST; break;
- case GA_NODE_XFEM_MINUS_GRAD:
- pnode->node_type = GA_NODE_XFEM_MINUS_GRAD_TEST; break;
- case GA_NODE_XFEM_MINUS_HESS:
- pnode->node_type = GA_NODE_XFEM_MINUS_HESS_TEST; break;
- case GA_NODE_XFEM_MINUS_DIVERG:
- pnode->node_type = GA_NODE_XFEM_MINUS_DIVERG_TEST; break;
- default : GMM_ASSERT1(false, "internal error");
- }
- pnode->test_function_type = order;
- break;
-
- case GA_NODE_OP:
- switch(pnode->op_type) {
- case GA_PLUS: case GA_MINUS:
- if (mark0 && mark1) {
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- ga_node_derivation(tree, workspace, m, child1, varname,
- interpolatename, order);
- } else if (mark0) {
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- tree.replace_node_by_child(pnode, 0);
- } else {
- ga_node_derivation(tree, workspace, m, child1, varname,
- interpolatename, order);
- if (pnode->op_type == GA_MINUS) {
- pnode->op_type = GA_UNARY_MINUS;
- tree.clear_node(child0);
- }
- else
- tree.replace_node_by_child(pnode, 1);
- }
- break;
-
- case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
- case GA_TRACE: case GA_DEVIATOR: case GA_PRINT:
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- break;
-
- case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
- case GA_DOTMULT:
- if (mark0 && mark1) {
- if (sub_tree_are_equal(child0, child1, workspace, 0) &&
- (pnode->op_type != GA_MULT || child0->tensor_order() < 2)) {
- ga_node_derivation(tree, workspace, m, child1, varname,
- interpolatename, order);
- tree.insert_node(pnode, GA_NODE_OP);
- pnode->parent->op_type = GA_MULT;
- tree.add_child(pnode->parent);
- pnode->parent->children[1]->node_type = GA_NODE_CONSTANT;
- pnode->parent->children[1]->init_scalar_tensor(scalar_type(2));
- } else {
- tree.duplicate_with_addition(pnode);
- if ((pnode->op_type == GA_COLON && child0->tensor_order() == 2) ||
- (pnode->op_type == GA_DOT && child0->tensor_order() == 1) ||
- pnode->op_type == GA_DOTMULT ||
- (child0->tensor_proper_size()== 1 &&
- child1->tensor_proper_size()== 1))
- std::swap(pnode->children[0], pnode->children[1]);
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- ga_node_derivation(tree, workspace, m,
- pnode->parent->children[1]->children[1],
- varname, interpolatename, order);
- }
- } else if (mark0) {
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- } else
- ga_node_derivation(tree, workspace, m, child1, varname,
- interpolatename, order);
- break;
-
- case GA_DIV: case GA_DOTDIV:
- if (mark1) {
- if (pnode->children[0]->node_type == GA_NODE_CONSTANT)
- gmm::scale(pnode->children[0]->tensor().as_vector(),
- scalar_type(-1));
- else {
- if (mark0) {
- tree.duplicate_with_subtraction(pnode);
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- pnode = pnode->parent->children[1];
- } else {
- tree.insert_node(pnode, GA_NODE_OP);
- pnode->parent->op_type = GA_UNARY_MINUS;
- }
- }
- tree.insert_node(pnode->children[1], GA_NODE_PARAMS);
- pga_tree_node pnode_param = pnode->children[1];
- tree.add_child(pnode_param);
- std::swap(pnode_param->children[0], pnode_param->children[1]);
- pnode_param->children[0]->node_type = GA_NODE_PREDEF_FUNC;
- pnode_param->children[0]->name = "sqr";
- tree.insert_node(pnode, GA_NODE_OP);
- pga_tree_node pnode_mult = pnode->parent;
- if (pnode->op_type == GA_DOTDIV)
- pnode_mult->op_type = GA_DOTMULT;
- else
- pnode_mult->op_type = GA_MULT;
- pnode_mult->children.resize(2, nullptr);
- tree.copy_node(pnode_param->children[1],
- pnode_mult, pnode_mult->children[1]);
- ga_node_derivation(tree, workspace, m, pnode_mult->children[1],
- varname, interpolatename, order);
- } else {
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- }
- break;
-
- default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
- }
- break;
-
- case GA_NODE_C_MATRIX:
- for (size_type i = 0; i < pnode->children.size(); ++i) {
- if (pnode->children[i]->marked)
- ga_node_derivation(tree, workspace, m, pnode->children[i],
- varname, interpolatename, order);
- else {
- pnode->children[i]->init_scalar_tensor(scalar_type(0));
- pnode->children[i]->node_type = GA_NODE_ZERO;
- tree.clear_children(pnode->children[i]);
- }
- }
- break;
-
- case GA_NODE_PARAMS:
- if (child0->node_type == GA_NODE_RESHAPE) {
- ga_node_derivation(tree, workspace, m, pnode->children[1],
- varname, interpolatename, order);
- } else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
- std::string name = child0->name;
- ga_predef_function_tab::const_iterator it =
PREDEF_FUNCTIONS.find(name);
- const ga_predef_function &F = it->second;
-
- if (F.nbargs() == 1) {
- switch (F.dtype()) {
- case 0:
- GMM_ASSERT1(false, "Cannot derive function " << child0->name
- << ". No derivative provided or not derivable function.");
- case 1:
- child0->name = F.derivative1();
- break;
- case 2: case 3:
- {
- child0->name = "DER_PDFUNC_" + child0->name;
- if (!(ga_function_exists(child0->name))) {
- if (F.dtype() == 2)
- ga_define_function(child0->name, 1, F.derivative1());
- else {
- std::string expr=ga_derivative_scalar_function(F.expr(),"t");
- ga_define_function(child0->name, 1, expr);
- }
- }
- // Inline extension if the derivative is affine (for instance
- // for sqr)
- ga_predef_function_tab::const_iterator
- itp = PREDEF_FUNCTIONS.find(child0->name);
- const ga_predef_function &Fp = itp->second;
- if (Fp.is_affine("t")) {
- scalar_type b = Fp(scalar_type(0));
- scalar_type a = Fp(scalar_type(1)) - b;
- pnode->node_type = GA_NODE_OP;
- pnode->op_type = GA_MULT;
- child0->init_scalar_tensor(a);
- child0->node_type = ((a == scalar_type(0)) ?
- GA_NODE_ZERO : GA_NODE_CONSTANT);
- if (b != scalar_type(0)) {
- tree.insert_node(pnode, GA_NODE_OP);
- pnode->parent->op_type = (b > 0) ? GA_PLUS : GA_MINUS;
- tree.add_child(pnode->parent);
- pga_tree_node pnode_cte = pnode->parent->children[1];
- pnode_cte->node_type = GA_NODE_CONSTANT;
- pnode_cte->t = pnode->t;
- std::fill(pnode_cte->tensor().begin(),
- pnode_cte->tensor().end(), gmm::abs(b));
- pnode = pnode->parent;
- }
- }
- }
- break;
- }
- if (pnode->children.size() >= 2) {
- tree.insert_node(pnode, GA_NODE_OP);
- pga_tree_node pnode_op = pnode->parent;
- if (child1->tensor_order() == 0)
- pnode_op->op_type = GA_MULT;
- else
- pnode_op->op_type = GA_DOTMULT;
- pnode_op->children.resize(2, nullptr);
- tree.copy_node(child1, pnode_op, pnode_op->children[1]);
- ga_node_derivation(tree, workspace, m, pnode_op->children[1],
- varname, interpolatename, order);
- }
- } else {
- pga_tree_node child2 = pnode->children[2];
-
- if (child1->marked && child2->marked)
- tree.duplicate_with_addition(pnode);
-
- if (child1->marked) {
- switch (F.dtype()) {
- case 0:
- GMM_ASSERT1(false, "Cannot derive function " << child0->name
- << ". No derivative provided");
- case 1:
- child0->name = F.derivative1();
- break;
- case 2:
- child0->name = "DER_PDFUNC1_" + child0->name;
- if (!(ga_function_exists(child0->name)))
- ga_define_function(child0->name, 2, F.derivative1());
- break;
- case 3:
- child0->name = "DER_PDFUNC1_" + child0->name;
- if (!(ga_function_exists(child0->name))) {
- std::string expr = ga_derivative_scalar_function(F.expr(),
"t");
- ga_define_function(child0->name, 2, expr);
- }
- break;
- }
- tree.insert_node(pnode, GA_NODE_OP);
- pga_tree_node pnode_op = pnode->parent;
- if (child1->tensor_order() == 0)
- pnode_op->op_type = GA_MULT;
- else
- pnode_op->op_type = GA_DOTMULT;
- pnode_op->children.resize(2, nullptr);
- tree.copy_node(child1, pnode_op, pnode_op->children[1]);
- ga_node_derivation(tree, workspace, m, pnode_op->children[1],
- varname, interpolatename, order);
- }
- if (child2->marked) {
- if (child1->marked && child2->marked)
- pnode = pnode->parent->parent->children[1];
- child0 = pnode->children[0]; child1 = pnode->children[1];
- child2 = pnode->children[2];
-
- switch (F.dtype()) {
- case 0:
- GMM_ASSERT1(false, "Cannot derive function " << child0->name
- << ". No derivative provided");
- case 1:
- child0->name = F.derivative2();
- break;
- case 2:
- child0->name = "DER_PDFUNC2_" + child0->name;
- if (!(ga_function_exists(child0->name)))
- ga_define_function(child0->name, 2, F.derivative2());
- break;
- case 3:
- child0->name = "DER_PDFUNC2_" + child0->name;
- if (!(ga_function_exists(child0->name))) {
- std::string expr = ga_derivative_scalar_function(F.expr(),
"u");
- ga_define_function(child0->name, 2, expr);
- }
- break;
- }
- tree.insert_node(pnode, GA_NODE_OP);
- pga_tree_node pnode_op = pnode->parent;
- if (child2->tensor_order() == 0)
- pnode_op->op_type = GA_MULT;
- else
- pnode_op->op_type = GA_DOTMULT;
- pnode_op->children.resize(2, nullptr);
- tree.copy_node(child2, pnode_op, pnode_op->children[1]);
- ga_node_derivation(tree, workspace, m, pnode_op->children[1],
- varname, interpolatename, order);
- }
- }
- } else if (child0->node_type == GA_NODE_SPEC_FUNC) {
- GMM_ASSERT1(false, "internal error");
- } else if (child0->node_type == GA_NODE_OPERATOR) {
- if (child0->der2)
- GMM_ASSERT1(false, "Error in derivation of the assembly string. "
- "Cannot derive again operator " << child0->name);
-
- size_type nbargs_der = 0;
- for (size_type i = 1; i < pnode->children.size(); ++i)
- if (pnode->children[i]->marked) ++nbargs_der;
- pga_tree_node pnode2 = 0;
-
- size_type j = 0;
- for (size_type i = 1; i < pnode->children.size(); ++i) {
- if (pnode->children[i]->marked) {
- ++j;
- if (j != nbargs_der) {
- tree.insert_node(pnode, GA_NODE_OP);
- pga_tree_node pnode_op = pnode->parent;
- pnode_op->node_type = GA_NODE_OP;
- pnode_op->op_type = GA_PLUS;
- pnode_op->children.resize(2, nullptr);
- tree.copy_node(pnode, pnode_op , pnode_op->children[1]);
- pnode2 = pnode_op->children[1];
- }
- else pnode2 = pnode;
-
- if (child0->der1)
- pnode2->children[0]->der2 = i;
- else
- pnode2->children[0]->der1 = i;
- tree.insert_node(pnode2, GA_NODE_OP);
- pga_tree_node pnode_op = pnode2->parent;
- // calcul de l'ordre de reduction
- size_type red = pnode->children[i]->tensor_order();
- switch (red) {
- case 0 : pnode_op->op_type = GA_MULT; break;
- case 1 : pnode_op->op_type = GA_DOT; break;
- case 2 : pnode_op->op_type = GA_COLON; break;
- default: GMM_ASSERT1(false, "Error in derivation of the assembly "
- "string. Bad reduction order.")
- }
- pnode_op->children.resize(2, nullptr);
- tree.copy_node(pnode->children[i], pnode_op,
- pnode_op->children[1]);
- ga_node_derivation(tree, workspace, m, pnode_op->children[1],
- varname, interpolatename, order);
-
- if (pnode2->children[0]->name.compare("Norm_sqr") == 0
- && pnode2->children[0]->der1 == 1) {
- pnode2->node_type = GA_NODE_OP;
- pnode2->op_type = GA_MULT;
- pnode2->children[0]->node_type = GA_NODE_CONSTANT;
- pnode2->children[0]->init_scalar_tensor(scalar_type(2));
- }
-
-
- }
- }
-
- } else {
- ga_node_derivation(tree, workspace, m, child0, varname,
- interpolatename, order);
- }
- break;
-
- default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
- << " in derivation. Internal error.");
- }
- }
-
- // The tree is modified. Should be copied first and passed to
- // ga_semantic_analysis after for enrichment
- static void ga_derivative(ga_tree &tree, const ga_workspace &workspace,
- const mesh &m, const std::string &varname,
- const std::string &interpolatename,
- size_type order) {
- // cout << "compute derivative of " << ga_tree_to_string(tree)
- // << " with respect to " << varname << " : " << interpolatename << endl;
- if (!(tree.root)) return;
- if (ga_node_mark_tree_for_variable(tree.root, workspace, m, varname,
- interpolatename))
- ga_node_derivation(tree, workspace, m, tree.root, varname,
- interpolatename, order);
- else
- tree.clear();
- // cout << "derived tree : " << ga_tree_to_string(tree) << endl;
- }
-
- static void ga_replace_test_by_cte(pga_tree_node pnode, bool full_replace) {
- for (size_type i = 0; i < pnode->children.size(); ++i)
- ga_replace_test_by_cte(pnode->children[i], full_replace);
- GMM_ASSERT1(pnode->node_type != GA_NODE_GRAD_TEST, "Invalid tree");
- GMM_ASSERT1(pnode->node_type != GA_NODE_HESS_TEST, "Invalid tree");
- GMM_ASSERT1(pnode->node_type != GA_NODE_DIVERG_TEST, "Invalid tree");
- if (pnode->node_type == GA_NODE_VAL_TEST) {
- pnode->node_type = GA_NODE_CONSTANT;
- if (full_replace) pnode->init_scalar_tensor(scalar_type(1));
- }
- }
-
- static std::string ga_derivative_scalar_function(const std::string &expr,
- const std::string &var) {
- base_vector t(1), u(1);
- ga_workspace workspace;
- workspace.add_fixed_size_variable("t", gmm::sub_interval(0,1), t);
- workspace.add_fixed_size_variable("u", gmm::sub_interval(0,1), u);
- workspace.add_function_expression(expr);
- GMM_ASSERT1(workspace.nb_trees() <= 1, "Internal error");
- if (workspace.nb_trees()) {
- ga_tree tree = *(workspace.tree_info(0).ptree);
- ga_derivative(tree, workspace, *((const mesh *)(0)), var, "", 1);
- if (tree.root) {
- ga_replace_test_by_cte(tree.root, true);
- ga_semantic_analysis(expr, tree, workspace, 1, 1, false, true);
- }
- return ga_tree_to_string(tree);
- } else return "0";
- }
-
- static bool ga_node_is_affine(const pga_tree_node pnode) {
-
- size_type nbch = pnode->children.size();
- pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
- pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
- bool mark0 = ((nbch > 0) ? child0->marked : false);
- bool mark1 = ((nbch > 1) ? child1->marked : false);
-
- switch (pnode->node_type) {
- case GA_NODE_VAL: case GA_NODE_GRAD:
- case GA_NODE_HESS: case GA_NODE_DIVERG:
- case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
- case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
- case GA_NODE_INTERPOLATE_DERIVATIVE:
- case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
- case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
- case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
- case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
- case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
- case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
- return true;
- case GA_NODE_OP:
- switch(pnode->op_type) {
- case GA_PLUS: case GA_MINUS:
- if (mark0 && mark1)
- return ga_node_is_affine(child0) &&
- ga_node_is_affine(child1);
- if (mark0) return ga_node_is_affine(child0);
- return ga_node_is_affine(child1);
-
- case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
- case GA_TRACE: case GA_DEVIATOR:
- case GA_PRINT: case GA_NODE_INTERPOLATE_FILTER:
- return ga_node_is_affine(child0);
-
- case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
- case GA_DOTMULT:
- if (mark0 && mark1) return false;
- if (mark0) return ga_node_is_affine(child0);
- return ga_node_is_affine(child1);
-
- case GA_DIV: case GA_DOTDIV:
- if (mark1) return false;
- if (mark0) return ga_node_is_affine(child0);
-
- default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
- }
- break;
-
- case GA_NODE_C_MATRIX:
- for (size_type i = 0; i < pnode->children.size(); ++i)
- if (pnode->children[i]->marked &&
- !(ga_node_is_affine(pnode->children[i])))
- return false;
- return true;
-
- case GA_NODE_PARAMS:
- if (child0->node_type == GA_NODE_RESHAPE)
- return ga_node_is_affine(child1);
- if (child0->node_type == GA_NODE_PREDEF_FUNC)
- return false;
- if (child0->node_type == GA_NODE_OPERATOR)
- return false;
- return ga_node_is_affine(child0);
-
- default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
- << " in derivation. Internal error.");
- }
- }
-
- static bool ga_is_affine(const ga_tree &tree, const ga_workspace &workspace,
- const std::string &varname,
- const std::string &interpolatename) {
- const mesh &m = *((const mesh *)(0));
- if (tree.root && ga_node_mark_tree_for_variable(tree.root, workspace, m,
- varname, interpolatename))
- return ga_node_is_affine(tree.root);
- return true;
- }
-
-
- //=========================================================================
// Compilation of assembly trees into a list of basic instructions
//=========================================================================
@@ -12772,7 +6776,7 @@ namespace getfem {
rmi.node_list[pnode->hash_value].push_back(pnode);
}
- static void ga_compile_function(ga_workspace &workspace,
+ void ga_compile_function(ga_workspace &workspace,
ga_instruction_set &gis, bool scalar) {
for (size_type i = 0; i < workspace.nb_trees(); ++i) {
const ga_workspace::tree_description &td = workspace.tree_info(i);
@@ -12926,7 +6930,7 @@ namespace getfem {
}
}
- static void ga_compile(ga_workspace &workspace,
+ void ga_compile(ga_workspace &workspace,
ga_instruction_set &gis, size_type order) {
gis.transformations.clear();
gis.whole_instructions.clear();
@@ -13137,7 +7141,7 @@ namespace getfem {
//=========================================================================
- static void ga_function_exec(ga_instruction_set &gis) {
+ void ga_function_exec(ga_instruction_set &gis) {
ga_instruction_set::instructions_set::iterator it
= gis.whole_instructions.begin();
@@ -13265,7 +7269,7 @@ namespace getfem {
}
}
- static void ga_exec(ga_instruction_set &gis, ga_workspace &workspace) {
+ void ga_exec(ga_instruction_set &gis, ga_workspace &workspace) {
base_matrix G;
base_small_vector un;
scalar_type J(0);
diff --git a/src/getfem_generic_assembly_functions_and_operators.cc
b/src/getfem_generic_assembly_functions_and_operators.cc
new file mode 100644
index 0000000..05f6d85
--- /dev/null
+++ b/src/getfem_generic_assembly_functions_and_operators.cc
@@ -0,0 +1,645 @@
+/*===========================================================================
+
+ Copyright (C) 2013-2018 Yves Renard
+
+ This file is a part of GetFEM++
+
+ GetFEM++ is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+===========================================================================*/
+
+#include "getfem/getfem_generic_assembly_semantic.h"
+#include "getfem/getfem_generic_assembly_functions_and_operators.h"
+#include "getfem/getfem_generic_assembly_compile_and_exec.h"
+
+/**
+ Providing for special Math functions unavailable on Intel or MSVS C++
+ compilers
+*/
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#include <boost/math/special_functions/acosh.hpp>
+#include <boost/math/special_functions/asinh.hpp>
+#include <boost/math/special_functions/atanh.hpp>
+#include <boost/math/special_functions/erf.hpp>
+typedef double (*BoostMathFunction)(double);
+BoostMathFunction const acosh = boost::math::acosh<double>;
+BoostMathFunction const asinh = boost::math::asinh<double>;
+BoostMathFunction const atanh = boost::math::atanh<double>;
+BoostMathFunction const erf = boost::math::erf<double>;
+BoostMathFunction const erfc = boost::math::erfc<double>;
+#endif
+
+namespace getfem {
+
+ extern bool predef_operators_nonlinear_elasticity_initialized;
+ extern bool predef_operators_plasticity_initialized;
+ extern bool predef_operators_contact_initialized;
+
+ base_matrix& __mat_aux1()
+ {
+ DEFINE_STATIC_THREAD_LOCAL(base_matrix, m);
+ return m;
+ }
+
+ //=========================================================================
+ // Structure dealing with predefined special functions
+ // such as mesh_dim, pi, qdim ...
+ //=========================================================================
+
+ typedef std::set<std::string> ga_spec_function_tab;
+ static ga_spec_function_tab SPEC_FUNCTIONS;
+
+ //=========================================================================
+ // Structure dealing with predefined scalar functions.
+ //=========================================================================
+
+ scalar_type ga_predef_function::operator()(scalar_type t_,
+ scalar_type u_) const {
+ switch(ftype_) {
+ case 0:
+ if (nbargs_ == 2)
+ return (*f2_)(t_, u_);
+ else
+ return (*f1_)(t_);
+ break;
+ case 1:
+ t.thrd_cast()[0] = t_; u.thrd_cast()[0] = u_;
+ workspace.thrd_cast().assembled_potential() = scalar_type(0);
+ ga_function_exec(*gis);
+ return workspace.thrd_cast().assembled_potential();
+ break;
+ }
+ return 0.;
+ }
+
+ bool ga_predef_function::is_affine(const std::string &varname) const {
+ if (ftype_ == 1) {
+ for (size_type i = 0; i < workspace.thrd_cast().nb_trees(); ++i) {
+ const ga_workspace::tree_description &
+ td = workspace.thrd_cast().tree_info(i);
+ if (!(ga_is_affine(*(td.ptree), workspace, varname, "")))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ static scalar_type ga_Heaviside(scalar_type t) { return (t >= 0.) ? 1.: 0.; }
+ static scalar_type ga_pos_part(scalar_type t) { return (t >= 0.) ? t : 0.; }
+ static scalar_type ga_reg_pos_part(scalar_type t, scalar_type eps)
+ { return (t >= eps) ? t-eps/2. : ((t <= 0) ? 0. : t*t/(2.*eps)); }
+ static scalar_type ga_der_reg_pos_part(scalar_type t, scalar_type eps)
+ { return (t >= eps) ? 1. : ((t <= 0) ? 0. : t/eps); }
+ static scalar_type ga_der2_reg_pos_part(scalar_type t, scalar_type eps)
+ { return (t >= eps) ? 0. : ((t <= 0) ? 0. : 1./eps); }
+
+
+ static scalar_type ga_half_sqr_pos_part(scalar_type t)
+ { return (t >= 0.) ? 0.5*t*t : 0.; }
+ static scalar_type ga_neg_part(scalar_type t) { return (t >= 0.) ? 0. : -t; }
+ static scalar_type ga_half_sqr_neg_part(scalar_type t)
+ { return (t >= 0.) ? 0. : 0.5*t*t; }
+ static scalar_type ga_sinc(scalar_type t) {// cardinal sine function sin(t)/t
+ if (gmm::abs(t) < 1E-4) {
+ scalar_type t2 = t*t;
+ return 1-t2/6.+ t2*t2/120.;
+ } else {
+ return sin(t)/t;
+ }
+ }
+ static scalar_type ga_sqr(scalar_type t) { return t*t; }
+ static scalar_type ga_max(scalar_type t, scalar_type u)
+ { return std::max(t,u); }
+ static scalar_type ga_min(scalar_type t, scalar_type u)
+ { return std::min(t,u); }
+ static scalar_type ga_abs(scalar_type t) { return gmm::abs(t); }
+ static scalar_type ga_sign(scalar_type t) { return (t >= 0.) ? 1.: -1.; }
+
+ // Derivatives of predefined functions
+ static scalar_type ga_der_sinc(scalar_type t) {
+ if (gmm::abs(t) < 1E-4) {
+ scalar_type t2 = t*t;
+ return -t/3. + t*t2/30. -t*t2*t2/840.;
+ } else {
+ return (t*cos(t) - sin(t))/(t*t);
+ }
+ }
+ static scalar_type ga_der2_sinc(scalar_type t) {
+ if (gmm::abs(t) < 1E-4) {
+ scalar_type t2 = t*t;
+ return -1./3. + t2/10. -t2*t2/168.;
+ } else {
+ return ((2. - t*t)*sin(t) - 2.*t*cos(t))/(t*t*t);
+ }
+ }
+ static scalar_type ga_der_sqrt(scalar_type t) { return 0.5/sqrt(t); }
+ // static scalar_type ga_der_sqr(scalar_type t) { return 2*t; }
+ static scalar_type ga_der_t_pow(scalar_type t, scalar_type u)
+ { return u*pow(t,u-1.); }
+ static scalar_type ga_der_u_pow(scalar_type t, scalar_type u)
+ { return pow(t,u)*log(gmm::abs(t)); }
+ static scalar_type ga_der_log(scalar_type t) { return 1./t; }
+ static scalar_type ga_der_log10(scalar_type t) { return 1./(t*log(10.)); }
+ static scalar_type ga_der_tanh(scalar_type t)
+ { return 1.-gmm::sqr(tanh(t)); }
+ static scalar_type ga_der_asinh(scalar_type t)
+ { return 1./(sqrt(t*t+1.)); }
+ static scalar_type ga_der_acosh(scalar_type t)
+ { return 1./(sqrt(t*t-1.)); }
+ static scalar_type ga_der_atanh(scalar_type t)
+ { return 1./(1.-t*t); }
+ static scalar_type ga_der_cos(scalar_type t)
+ { return -sin(t); }
+ static scalar_type ga_der_tan(scalar_type t)
+ { return 1.+gmm::sqr(tan(t)); }
+ static scalar_type ga_der_asin(scalar_type t)
+ { return 1./(sqrt(1.-t*t)); }
+ static scalar_type ga_der_acos(scalar_type t)
+ { return -1./(sqrt(1.-t*t)); }
+ static scalar_type ga_der_atan(scalar_type t)
+ { return 1./(1.+t*t); }
+ static scalar_type ga_der_t_atan2(scalar_type t, scalar_type u)
+ { return u/(t*t+u*u); }
+ static scalar_type ga_der_u_atan2(scalar_type t, scalar_type u)
+ { return -t/(t*t+u*u); }
+ static scalar_type ga_der_erf(scalar_type t)
+ { return exp(-t*t)*2./sqrt(M_PI); }
+ static scalar_type ga_der_erfc(scalar_type t)
+ { return -exp(-t*t)*2./sqrt(M_PI); }
+ static scalar_type ga_der_neg_part(scalar_type t)
+ { return (t >= 0) ? 0. : -1.; }
+ static scalar_type ga_der_t_max(scalar_type t, scalar_type u)
+ { return (t-u >= 0) ? 1. : 0.; }
+ static scalar_type ga_der_u_max(scalar_type t, scalar_type u)
+ { return (u-t >= 0) ? 1. : 0.; }
+
+
+
+ //=========================================================================
+ // Structure dealing with predefined operators.
+ //=========================================================================
+
+ static void ga_init_scalar(bgeot::multi_index &mi) { mi.resize(0); }
+ static void ga_init_square_matrix(bgeot::multi_index &mi, size_type N)
+ { mi.resize(2); mi[0] = mi[1] = N; }
+
+ // Norm Operator
+ struct norm_operator : public ga_nonlinear_operator {
+ bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
+ if (args.size() != 1 || args[0]->sizes().size() > 2) return false;
+ ga_init_scalar(sizes);
+ return true;
+ }
+
+ void value(const arg_list &args, base_tensor &result) const
+ { result[0] = gmm::vect_norm2(args[0]->as_vector()); }
+
+ // Derivative : u/|u|
+ void derivative(const arg_list &args, size_type,
+ base_tensor &result) const {
+ scalar_type no = gmm::vect_norm2(args[0]->as_vector());
+ if (no == scalar_type(0))
+ gmm::clear(result.as_vector());
+ else
+ gmm::copy(gmm::scaled(args[0]->as_vector(), scalar_type(1)/no),
+ result.as_vector());
+ }
+
+ // Second derivative : (|u|^2 Id - u x u)/|u|^3
+ void second_derivative(const arg_list &args, size_type, size_type,
+ base_tensor &result) const {
+ const base_tensor &t = *args[0];
+ size_type N = t.size();
+ scalar_type no = gmm::vect_norm2(t.as_vector());
+ scalar_type no3 = no*no*no;
+
+ if (no < 1E-25) no = 1E-25; // In order to avoid infinite values
+
+ for (size_type i = 0; i < N; ++i)
+ for (size_type j = 0; j < N; ++j) {
+ result[j*N+i] = - t[i]*t[j] / no3;
+ if (i == j) result[j*N+i] += scalar_type(1)/no;
+ }
+ }
+ };
+
+ // Norm_sqr Operator
+ struct norm_sqr_operator : public ga_nonlinear_operator {
+ bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
+ if (args.size() != 1 || args[0]->sizes().size() > 2) return false;
+ ga_init_scalar(sizes);
+ return true;
+ }
+
+ void value(const arg_list &args, base_tensor &result) const
+ { result[0] = gmm::vect_norm2_sqr(args[0]->as_vector()); }
+
+ // Derivative : 2*u
+ void derivative(const arg_list &args, size_type,
+ base_tensor &result) const {
+ gmm::copy(gmm::scaled(args[0]->as_vector(), scalar_type(2)),
+ result.as_vector());
+ }
+
+ // Second derivative : Id
+ void second_derivative(const arg_list &args, size_type, size_type,
+ base_tensor &result) const {
+ const base_tensor &t = *args[0];
+ size_type N = t.size();
+ gmm::clear(result.as_vector());
+ for (size_type i = 0; i < N; ++i)
+ result[i*N+i] = scalar_type(2);
+ }
+ };
+
+ // Det Operator
+ struct det_operator : public ga_nonlinear_operator {
+ bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
+ if (args.size() != 1 || args[0]->sizes().size() != 2
+ || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
+ ga_init_scalar(sizes);
+ return true;
+ }
+
+ void value(const arg_list &args, base_tensor &result) const {
+ size_type N = args[0]->sizes()[0];
+ // base_matrix M(N, N);
+ // gmm::copy(args[0]->as_vector(), M.as_vector());
+ // result[0] = gmm::lu_det(M);
+ result[0] = bgeot::lu_det(&(*(args[0]->begin())), N);
+ }
+
+ // Derivative : det(M)M^{-T}
+ void derivative(const arg_list &args, size_type,
+ base_tensor &result) const {
+ size_type N = args[0]->sizes()[0];
+ if (N) {
+ __mat_aux1().base_resize(N, N);
+ gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
+ scalar_type det = bgeot::lu_inverse(__mat_aux1());
+ if (det == scalar_type(0))
+ gmm::clear(result.as_vector());
+ else {
+ auto it = result.begin();
+ auto ita = __mat_aux1().begin();
+ for (size_type j = 0; j < N; ++j, ++ita) {
+ auto itaa = ita;
+ *it = (*itaa) * det; ++it;
+ for (size_type i = 1; i < N; ++i, ++it)
+ { itaa += N; *it = (*itaa) * det; }
+ }
+ GA_DEBUG_ASSERT(it == result.end(), "Internal error");
+ }
+ }
+ }
+
+ // Second derivative : det(M)(address@hidden - M^{-T}_{jk}M^{-T}_{li})
+ void second_derivative(const arg_list &args, size_type, size_type,
+ base_tensor &result) const {
+ size_type N = args[0]->sizes()[0];
+ __mat_aux1().base_resize(N, N);
+ gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
+ scalar_type det = bgeot::lu_inverse(__mat_aux1());
+ if (det == scalar_type(0))
+ gmm::clear(result.as_vector());
+ else {
+ auto it = result.begin();
+ auto ita = __mat_aux1().begin(), ita_l = ita;
+ for (size_type l = 0; l < N; ++l, ++ita_l) {
+ auto ita_lk = ita_l, ita_jk = ita;
+ for (size_type k = 0; k < N; ++k, ita_lk += N, ita_jk += N) {
+ auto ita_j = ita;
+ for (size_type j = 0; j < N; ++j, ++ita_j, ++ita_jk) {
+ auto ita_ji = ita_j, ita_li = ita_l;
+ for (size_type i = 0; i < N; ++i, ++it, ita_ji += N, ita_li += N)
+ *it = ((*ita_ji) * (*ita_lk) - (*ita_jk) * (*ita_li)) * det;
+ }
+ }
+ }
+ GA_DEBUG_ASSERT(it == result.end(), "Internal error");
+ }
+ }
+ };
+
+ // Inverse Operator (for square matrices)
+ struct inverse_operator : public ga_nonlinear_operator {
+ bool result_size(const arg_list &args, bgeot::multi_index &sizes) const {
+ if (args.size() != 1 || args[0]->sizes().size() != 2
+ || args[0]->sizes()[0] != args[0]->sizes()[1]) return false;
+ ga_init_square_matrix(sizes, args[0]->sizes()[0]);
+ return true;
+ }
+
+ // Value : M^{-1}
+ void value(const arg_list &args, base_tensor &result) const {
+ size_type N = args[0]->sizes()[0];
+ __mat_aux1().base_resize(N, N);
+ gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
+ bgeot::lu_inverse(__mat_aux1());
+ gmm::copy(__mat_aux1().as_vector(), result.as_vector());
+ }
+
+ // Derivative : -M^{-1}{ik}M^{-1}{lj} (comes from H -> M^{-1}HM^{-1})
+ void derivative(const arg_list &args, size_type,
+ base_tensor &result) const { // to be verified
+ size_type N = args[0]->sizes()[0];
+ __mat_aux1().base_resize(N, N);
+ gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
+ bgeot::lu_inverse(__mat_aux1());
+ auto it = result.begin();
+ auto ita = __mat_aux1().begin(), ita_l = ita;
+ for (size_type l = 0; l < N; ++l, ++ita_l) {
+ auto ita_k = ita;
+ for (size_type k = 0; k < N; ++k, ita_k += N) {
+ auto ita_lj = ita_l;
+ for (size_type j = 0; j < N; ++j, ++ita_lj) {
+ auto ita_ik = ita_k;
+ for (size_type i = 0; i < N; ++i, ++it, ++ita_ik)
+ *it = -(*ita_ik) * (*ita_lj);
+ }
+ }
+ }
+ GA_DEBUG_ASSERT(it == result.end(), "Internal error");
+ }
+
+ // Second derivative :
+ // M^{-1}{ik}M^{-1}{lm}M^{-1}{nj} + M^{-1}{im}M^{-1}{mk}M^{-1}{lj}
+ // comes from (H,K) -> M^{-1}HM^{-1}KM^{-1} + M^{-1}KM^{-1}HM^{-1}
+ void second_derivative(const arg_list &args, size_type, size_type,
+ base_tensor &result) const { // to be verified
+ size_type N = args[0]->sizes()[0];
+ __mat_aux1().base_resize(N, N);
+ gmm::copy(args[0]->as_vector(), __mat_aux1().as_vector());
+ bgeot::lu_inverse(__mat_aux1());
+ base_tensor::iterator it = result.begin();
+ for (size_type n = 0; n < N; ++n)
+ for (size_type m = 0; m < N; ++m)
+ for (size_type l = 0; l < N; ++l)
+ for (size_type k = 0; k < N; ++k)
+ for (size_type j = 0; j < N; ++j)
+ for (size_type i = 0; i < N; ++i, ++it)
+ *it = __mat_aux1()(i,k)*__mat_aux1()(l,m)*__mat_aux1()(n,j)
+ + __mat_aux1()(i,m)*__mat_aux1()(m,k)*__mat_aux1()(l,j);
+ GA_DEBUG_ASSERT(it == result.end(), "Internal error");
+ }
+ };
+
+ //=========================================================================
+ // Initialization of predefined functions and operators.
+ //=========================================================================
+
+
+ bool init_predef_functions() {
+
+ // Predefined functions
+ ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+
+ // Power functions and their derivatives
+ PREDEF_FUNCTIONS["sqrt"] = ga_predef_function(sqrt, 1, "DER_PDFUNC_SQRT");
+ PREDEF_FUNCTIONS["sqr"] = ga_predef_function(ga_sqr, 2, "2*t");
+ PREDEF_FUNCTIONS["pow"] = ga_predef_function(pow, 1, "DER_PDFUNC1_POW",
+ "DER_PDFUNC2_POW");
+
+ PREDEF_FUNCTIONS["DER_PDFUNC_SQRT"] =
+ ga_predef_function(ga_der_sqrt, 2, "-0.25/(t*sqrt(t))");
+ PREDEF_FUNCTIONS["DER_PDFUNC1_POW"] =
+ ga_predef_function(ga_der_t_pow, 2, "u*(u-1)*pow(t,u-2)",
+ "pow(t,u-1)*(u*log(t)+1)");
+ PREDEF_FUNCTIONS["DER_PDFUNC2_POW"] =
+ ga_predef_function(ga_der_u_pow, 2, "pow(t,u-1)*(u*log(t)+1)",
+ "pow(t,u)*sqr(log(t))");
+
+ // Hyperbolic functions
+ PREDEF_FUNCTIONS["exp"] = ga_predef_function(exp, 1, "exp");
+ PREDEF_FUNCTIONS["log"] = ga_predef_function(log, 1, "DER_PDFUNC_LOG");
+ PREDEF_FUNCTIONS["log10"] =
+ ga_predef_function(log10, 1, "DER_PDFUNC_LOG10");
+ PREDEF_FUNCTIONS["sinh"] = ga_predef_function(sinh, 1, "cosh");
+ PREDEF_FUNCTIONS["cosh"] = ga_predef_function(cosh, 1, "sinh");
+ PREDEF_FUNCTIONS["tanh"] = ga_predef_function(tanh, 1, "DER_PDFUNC_TANH");
+ PREDEF_FUNCTIONS["asinh"] =
+ ga_predef_function(asinh, 1, "DER_PDFUNC_ASINH");
+ PREDEF_FUNCTIONS["acosh"] =
+ ga_predef_function(acosh, 1, "DER_PDFUNC_ACOSH");
+ PREDEF_FUNCTIONS["atanh"] =
+ ga_predef_function(atanh, 1, "DER_PDFUNC_ATANH");
+
+
+ PREDEF_FUNCTIONS["DER_PDFUNC_LOG"] =
+ ga_predef_function(ga_der_log, 2, "-1/sqr(t)");
+ PREDEF_FUNCTIONS["DER_PDFUNC_LOG10"] =
+ ga_predef_function(ga_der_log10, 2, "-1/(sqr(t)*log(10))");
+ PREDEF_FUNCTIONS["DER_PDFUNC_TANH"] =
+ ga_predef_function(ga_der_tanh, 2, "2*tanh(t)*(sqr(tanh(t))-1)");
+ PREDEF_FUNCTIONS["DER_PDFUNC_ASINH"] =
+ ga_predef_function(ga_der_asinh, 2, "-t/(pow(t*t+1,1.5))");
+ PREDEF_FUNCTIONS["DER_PDFUNC_ACOSH"] =
+ ga_predef_function(ga_der_acosh, 2, "-t/(pow(t*t-1,1.5))");
+ PREDEF_FUNCTIONS["DER_PDFUNC_ATANH"] =
+ ga_predef_function(ga_der_atanh, 2, "2*t/sqr(1-t*t)");
+
+
+ // Trigonometric functions
+ PREDEF_FUNCTIONS["sin"] = ga_predef_function(sin, 1, "cos");
+ PREDEF_FUNCTIONS["cos"] = ga_predef_function(cos, 1, "DER_PDFUNC_COS");
+ PREDEF_FUNCTIONS["tan"] = ga_predef_function(tan, 1, "DER_PDFUNC_TAN");
+ PREDEF_FUNCTIONS["asin"] = ga_predef_function(asin, 1, "DER_PDFUNC_ASIN");
+ PREDEF_FUNCTIONS["acos"] = ga_predef_function(acos, 1, "DER_PDFUNC_ACOS");
+ PREDEF_FUNCTIONS["atan"] = ga_predef_function(atan, 1, "DER_PDFUNC_ATAN");
+ PREDEF_FUNCTIONS["atan2"] = ga_predef_function(atan2,1,"DER_PDFUNC1_ATAN2",
+
"DER_PDFUNC2_ATAN2");
+ PREDEF_FUNCTIONS["sinc"] = ga_predef_function(ga_sinc, 1,
+ "DER_PDFUNC_SINC");
+ PREDEF_FUNCTIONS["DER_PDFUNC_SINC"] =ga_predef_function(ga_der_sinc, 1,
+
"DER2_PDFUNC_SINC");
+ PREDEF_FUNCTIONS["DER2_PDFUNC_SINC"] = ga_predef_function(ga_der2_sinc);
+
+
+ PREDEF_FUNCTIONS["DER_PDFUNC_COS"] =
+ ga_predef_function(ga_der_cos, 2, "-cos(t)");
+ PREDEF_FUNCTIONS["DER_PDFUNC_TAN"] =
+ ga_predef_function(ga_der_tan, 2, "2*tan(t)/sqr(cos(t))");
+ // PREDEF_FUNCTIONS["DER_PDFUNC_TAN"] =
+ // ga_predef_function(ga_der_tan, 2, "2*tan(t)*(1+sqr(tan(t)))");
+ PREDEF_FUNCTIONS["DER_PDFUNC_ASIN"] =
+ ga_predef_function(ga_der_asin, 2, "t/(pow(1-t*t,1.5))");
+ PREDEF_FUNCTIONS["DER_PDFUNC_ACOS"] =
+ ga_predef_function(ga_der_acos, 2, "-t/(pow(1-t*t,1.5))");
+ PREDEF_FUNCTIONS["DER_PDFUNC_ATAN"] =
+ ga_predef_function(ga_der_atan, 2, "-2*t/sqr(1+t*t)");
+ PREDEF_FUNCTIONS["DER_PDFUNC1_ATAN2"] =
+ ga_predef_function(ga_der_t_atan2, 2, "-2*t*u/sqr(sqr(u)+sqr(t))",
+ "(sqrt(t)-sqr(u))/sqr(sqr(u)+sqr(t))");
+ PREDEF_FUNCTIONS["DER_PDFUNC2_ATAN2"] =
+ ga_predef_function(ga_der_u_atan2, 2,
+ "(sqrt(t)-sqr(u))/sqr(sqr(u)+sqr(t))",
+ "2*t*u/sqr(sqr(u)+sqr(t))");
+
+
+ // Error functions
+ PREDEF_FUNCTIONS["erf"]
+ = ga_predef_function(erf, 1, "DER_PDFUNC_ERF");
+ PREDEF_FUNCTIONS["erfc"]
+ = ga_predef_function(erfc, 1, "DER_PDFUNC_ERFC");
+
+ PREDEF_FUNCTIONS["DER_PDFUNC_ERF"] =
+ ga_predef_function(ga_der_erf, 2, "exp(-t*t)*2/sqrt(pi)");
+ PREDEF_FUNCTIONS["DER_PDFUNC_ERFC"] =
+ ga_predef_function(ga_der_erfc, 2, "-exp(-t*t)*2/sqrt(pi)");
+
+
+
+ // Miscellaneous functions
+ PREDEF_FUNCTIONS["Heaviside"] = ga_predef_function(ga_Heaviside); //
ga_predef_function(ga_Heaviside, 2, "(0)");
+ PREDEF_FUNCTIONS["sign"] = ga_predef_function(ga_sign);
+ PREDEF_FUNCTIONS["abs"] = ga_predef_function(ga_abs, 1, "sign");
+ PREDEF_FUNCTIONS["pos_part"]
+ = ga_predef_function(ga_pos_part, 1, "Heaviside");
+ PREDEF_FUNCTIONS["half_sqr_pos_part"]
+ = ga_predef_function(ga_half_sqr_pos_part, 1, "pos_part");
+ PREDEF_FUNCTIONS["neg_part"]
+ = ga_predef_function(ga_neg_part, 1, "DER_PDFUNC_NEG_PART");
+ PREDEF_FUNCTIONS["half_sqr_neg_part"]
+ = ga_predef_function(ga_half_sqr_neg_part, 2, "-neg_part(t)");
+ PREDEF_FUNCTIONS["reg_pos_part"]
+ = ga_predef_function(ga_reg_pos_part, 1, "DER_REG_POS_PART", "");
+ PREDEF_FUNCTIONS["DER_REG_POS_PART"]
+ = ga_predef_function(ga_der_reg_pos_part, 1, "DER2_REG_POS_PART", "");
+ PREDEF_FUNCTIONS["DER_REG_POS_PART"]
+ = ga_predef_function(ga_der2_reg_pos_part);
+
+ PREDEF_FUNCTIONS["max"]
+ = ga_predef_function(ga_max, 1, "DER_PDFUNC1_MAX", "DER_PDFUNC2_MAX");
+ PREDEF_FUNCTIONS["min"]
+ = ga_predef_function(ga_min, 1, "DER_PDFUNC2_MAX", "DER_PDFUNC1_MAX");
+
+ PREDEF_FUNCTIONS["DER_PDFUNC_NEG_PART"]
+ = ga_predef_function(ga_der_neg_part, 2, "-Heaviside(-t)");
+ PREDEF_FUNCTIONS["DER_PDFUNC1_MAX"] = ga_predef_function(ga_der_t_max);
+ PREDEF_FUNCTIONS["DER_PDFUNC2_MAX"] = ga_predef_function(ga_der_u_max);
+
+
+ // Predefined special functions
+
+ SPEC_FUNCTIONS.insert("pi");
+ SPEC_FUNCTIONS.insert("meshdim");
+ SPEC_FUNCTIONS.insert("timestep");
+ SPEC_FUNCTIONS.insert("qdim");
+ SPEC_FUNCTIONS.insert("qdims");
+ SPEC_FUNCTIONS.insert("Id");
+
+ // Predefined operators
+ ga_predef_operator_tab &PREDEF_OPERATORS
+ = dal::singleton<ga_predef_operator_tab>::instance();
+
+ PREDEF_OPERATORS.add_method("Norm", std::make_shared<norm_operator>());
+ PREDEF_OPERATORS.add_method("Norm_sqr",
+ std::make_shared<norm_sqr_operator>());
+ PREDEF_OPERATORS.add_method("Det", std::make_shared<det_operator>());
+ PREDEF_OPERATORS.add_method("Inv", std::make_shared<inverse_operator>());
+ return true;
+ }
+
+ bool predef_functions_initialized = init_predef_functions();
+
+ bool ga_function_exists(const std::string &name) {
+ const ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+ return PREDEF_FUNCTIONS.find(name) != PREDEF_FUNCTIONS.end();
+ }
+
+
+ void ga_define_function(const std::string &name, size_type nbargs,
+ const std::string &expr, const std::string &der1,
+ const std::string &der2) {
+ auto guard = omp_guard{};
+
+ auto &PREDEF_FUNCTIONS =
dal::singleton<ga_predef_function_tab>::instance(0);
+ if(PREDEF_FUNCTIONS.find(name) != PREDEF_FUNCTIONS.end()) return;
+ GMM_ASSERT1(nbargs >= 1 && nbargs <= 2, "Generic assembly only allows "
+ "the definition of scalar function with one or two arguments");
+ { // Only for syntax analysis
+ base_vector t(1);
+ ga_workspace workspace;
+ workspace.add_fixed_size_variable("t", gmm::sub_interval(0,1), t);
+ if (nbargs == 2)
+ workspace.add_fixed_size_variable("u", gmm::sub_interval(0,1), t);
+ workspace.add_function_expression(expr);
+ }
+
+ PREDEF_FUNCTIONS[name] = ga_predef_function(expr);
+ ga_predef_function &F = PREDEF_FUNCTIONS[name];
+ F.gis = std::make_unique<instruction_set>();
+ for (size_type thread = 0; thread < num_threads(); ++thread)
+ {
+ F.workspace(thread).add_fixed_size_variable("t", gmm::sub_interval(0,1),
+ F.t(thread));
+ if (nbargs == 2)
+ F.workspace(thread).add_fixed_size_variable("u",
gmm::sub_interval(0,1),
+ F.u(thread));
+ F.workspace(thread).add_function_expression(expr);
+ ga_compile_function(F.workspace(thread), (*F.gis)(thread), true);
+ }
+ F.nbargs_ = nbargs;
+ if (nbargs == 1) {
+ if (der1.size()) { F.derivative1_ = der1; F.dtype_ = 2; }
+ } else {
+ if (der1.size() && der2.size()) {
+ F.derivative1_ = der1; F.derivative2_ = der2; F.dtype_ = 2;
+ }
+ }
+ }
+
+ void ga_define_function(const std::string &name, pscalar_func_onearg f,
+ const std::string &der) {
+ ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+ PREDEF_FUNCTIONS[name] = ga_predef_function(f, 1, der);
+ ga_predef_function &F = PREDEF_FUNCTIONS[name];
+ if (der.size() == 0) F.dtype_ = 0;
+ else if (!(ga_function_exists(der))) F.dtype_ = 2;
+ }
+
+ void ga_define_function(const std::string &name, pscalar_func_twoargs f,
+ const std::string &der1, const std::string &der2) {
+ ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+ PREDEF_FUNCTIONS[name] = ga_predef_function(f, 1, der1, der2);
+ ga_predef_function &F = PREDEF_FUNCTIONS[name];
+ if (der1.size() == 0 || der2.size() == 0)
+ F.dtype_ = 0;
+ else if (!(ga_function_exists(der1)) || !(ga_function_exists(der2)))
+ F.dtype_ = 2;
+ }
+
+ void ga_undefine_function(const std::string &name) {
+ ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+ ga_predef_function_tab::iterator it = PREDEF_FUNCTIONS.find(name);
+ if (it != PREDEF_FUNCTIONS.end()) {
+ PREDEF_FUNCTIONS.erase(name);
+ std::string name0 = "DER_PDFUNC_" + name;
+ ga_undefine_function(name0);
+ std::string name1 = "DER_PDFUNC1_" + name;
+ ga_undefine_function(name1);
+ std::string name2 = "DER_PDFUNC2_" + name;
+ ga_undefine_function(name2);
+ }
+ }
+
+} /* end of namespace */
diff --git a/src/getfem_generic_assembly_semantic.cc
b/src/getfem_generic_assembly_semantic.cc
new file mode 100644
index 0000000..006d573
--- /dev/null
+++ b/src/getfem_generic_assembly_semantic.cc
@@ -0,0 +1,3187 @@
+/*===========================================================================
+
+ Copyright (C) 2013-2018 Yves Renard
+
+ This file is a part of GetFEM++
+
+ GetFEM++ is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+===========================================================================*/
+
+// Semantic analysis of assembly trees and semantic manipulations.
+
+
+#include <getfem/getfem_generic_assembly_functions_and_operators.h>
+#include <getfem/getfem_generic_assembly_semantic.h>
+
+namespace getfem {
+
+
+ bool ga_extract_variables(const pga_tree_node pnode,
+ const ga_workspace &workspace,
+ const mesh &m,
+ std::set<var_trans_pair> &vars,
+ bool ignore_data) {
+ bool expand_groups = !ignore_data;
+ bool found_var = false;
+ if (pnode->node_type == GA_NODE_VAL ||
+ pnode->node_type == GA_NODE_GRAD ||
+ pnode->node_type == GA_NODE_HESS ||
+ pnode->node_type == GA_NODE_DIVERG ||
+ pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
+ pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
+ pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
+ pnode->node_type == GA_NODE_INTERPOLATE_DIVERG ||
+ pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
+ pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
+ pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
+ pnode->node_type == GA_NODE_ELEMENTARY_DIVERG ||
+ pnode->node_type == GA_NODE_XFEM_PLUS_VAL ||
+ pnode->node_type == GA_NODE_XFEM_PLUS_GRAD ||
+ pnode->node_type == GA_NODE_XFEM_PLUS_HESS ||
+ pnode->node_type == GA_NODE_XFEM_PLUS_DIVERG ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_VAL ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_GRAD ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_HESS ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_DIVERG) {
+ bool group = workspace.variable_group_exists(pnode->name);
+ bool iscte = (!group) && workspace.is_constant(pnode->name);
+ if (!iscte) found_var = true;
+ if (!ignore_data || !iscte) {
+ if (group && expand_groups) {
+ for (const std::string &t : workspace.variable_group(pnode->name))
+ vars.insert(var_trans_pair(t, pnode->interpolate_name));
+ } else
+ vars.insert(var_trans_pair(pnode->name, pnode->interpolate_name));
+ }
+ }
+ if (pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
+ pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
+ pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
+ pnode->node_type == GA_NODE_INTERPOLATE_DIVERG ||
+ pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST ||
+ pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST ||
+ pnode->node_type == GA_NODE_INTERPOLATE_HESS_TEST ||
+ pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST ||
+ pnode->node_type == GA_NODE_INTERPOLATE_X ||
+ pnode->node_type == GA_NODE_INTERPOLATE_NORMAL) {
+ workspace.interpolate_transformation(pnode->interpolate_name)
+ ->extract_variables(workspace, vars, ignore_data, m,
+ pnode->interpolate_name);
+ }
+ for (auto&& child : pnode->children)
+ found_var = ga_extract_variables(child, workspace, m,
+ vars, ignore_data)
+ || found_var;
+ return found_var;
+ }
+
+ //=========================================================================
+ // Some hash code functions for node identification
+ //=========================================================================
+
+ static scalar_type ga_hash_code(const std::string &s) {
+ scalar_type c(0);
+ for (size_type i = 0; i < s.size(); ++i)
+ c += sin(M_E+scalar_type(s[i]))+M_PI*M_E*scalar_type(i+1);
+ return c;
+ }
+
+ static scalar_type ga_hash_code(const base_tensor &t) {
+ scalar_type c(0);
+ for (size_type i = 0; i < t.size(); ++i)
+ c += sin(M_E+t[i]+M_E*M_E*scalar_type(i+1))+scalar_type(i+1)*M_PI;
+ return c;
+ }
+
+ static scalar_type ga_hash_code(GA_NODE_TYPE e) {
+ return cos(M_E + scalar_type((e == GA_NODE_ZERO) ? GA_NODE_CONSTANT : e));
+ }
+
+ static scalar_type ga_hash_code(const pga_tree_node pnode) {
+ scalar_type c = ga_hash_code(pnode->node_type);
+
+ switch (pnode->node_type) {
+ case GA_NODE_CONSTANT: case GA_NODE_ZERO:
+ c += ga_hash_code(pnode->tensor());
+ if (pnode->test_function_type & 1)
+ c += 34.731 * ga_hash_code(pnode->name_test1);
+ if (pnode->test_function_type & 2)
+ c += 34.731 * ga_hash_code(pnode->name_test2);
+ break;
+
+ case GA_NODE_OP: c += scalar_type(pnode->op_type)*M_E*M_PI*M_PI; break;
+ case GA_NODE_X: c += scalar_type(pnode->nbc1) + M_E*M_PI; break;
+ case GA_NODE_VAL: case GA_NODE_GRAD:
+ case GA_NODE_HESS: case GA_NODE_DIVERG:
+ case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST:
+ case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST:
+ c += ga_hash_code(pnode->name); break;
+
+ case GA_NODE_INTERPOLATE_FILTER:
+ c += 1.73*ga_hash_code(pnode->interpolate_name)
+ + 2.486*double(pnode->nbc1 + 1);
+ break;
+ case GA_NODE_INTERPOLATE_DERIVATIVE:
+ c += 2.321*ga_hash_code(pnode->interpolate_name_der);
+ // No break. The hash code is completed with the next item
+ case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
+ case GA_NODE_INTERPOLATE_VAL_TEST: case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_HESS_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ c += 1.33*(1.22+ga_hash_code(pnode->name))
+ + 1.66*ga_hash_code(pnode->interpolate_name);
+ break;
+ case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ c += 1.33*(1.22+ga_hash_code(pnode->name))
+ + 2.63*ga_hash_code(pnode->elementary_name);
+ break;
+ case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
+ case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
+ case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
+ case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
+ c += 1.33*(1.22+ga_hash_code(pnode->name));
+ break;
+ case GA_NODE_INTERPOLATE_X: case GA_NODE_INTERPOLATE_NORMAL:
+ c += M_PI*1.33*ga_hash_code(pnode->interpolate_name);
+ break;
+ case GA_NODE_PREDEF_FUNC: case GA_NODE_SPEC_FUNC: case GA_NODE_OPERATOR:
+ c += ga_hash_code(pnode->name)
+ + tanh(scalar_type(pnode->der1)/M_PI + scalar_type(pnode->der2)*M_PI);
+ break;
+ default: break;
+ }
+ return c;
+ }
+
+ static void ga_node_analysis(const std::string &expr, ga_tree &tree,
+ const ga_workspace &workspace,
+ pga_tree_node pnode, size_type meshdim,
+ size_type ref_elt_dim, bool eval_fixed_size,
+ bool ignore_X, int option) {
+ bool all_cte = true, all_sc = true;
+ pnode->symmetric_op = false;
+
+ for (size_type i = 0; i < pnode->children.size(); ++i) {
+ ga_node_analysis(expr, tree, workspace, pnode->children[i], meshdim,
+ ref_elt_dim, eval_fixed_size, ignore_X, option);
+ all_cte = all_cte && (pnode->children[i]->node_type == GA_NODE_CONSTANT);
+ all_sc = all_sc && (pnode->children[i]->tensor_proper_size() == 1);
+ GMM_ASSERT1(pnode->children[i]->test_function_type != size_type(-1),
+ "internal error on child " << i);
+ if (pnode->node_type != GA_NODE_PARAMS)
+ ga_valid_operand(expr, pnode->children[i]);
+ }
+
+ size_type nbch = pnode->children.size();
+ pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
+ pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
+ bgeot::multi_index mi;
+ const bgeot::multi_index &size0 = child0 ? child0->t.sizes() : mi;
+ const bgeot::multi_index &size1 = child1 ? child1->t.sizes() : mi;
+ size_type dim0 = child0 ? child0->tensor_order() : 0;
+ size_type dim1 = child1 ? child1->tensor_order() : 0;
+
+ // cout << "child1 = " << child1 << endl;
+ // cout << "child0 = " << child0 << endl;
+ // cout << "nbch = " << nbch << endl;
+ // cout<<"begin analysis of node "; ga_print_node(pnode, cout); cout<<endl;
+
+ const ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+ const ga_predef_operator_tab &PREDEF_OPERATORS
+ = dal::singleton<ga_predef_operator_tab>::instance(0);
+
+ switch (pnode->node_type) {
+ case GA_NODE_PREDEF_FUNC: case GA_NODE_OPERATOR: case GA_NODE_SPEC_FUNC :
+ case GA_NODE_CONSTANT: case GA_NODE_X: case GA_NODE_ELT_SIZE:
+ case GA_NODE_ELT_K: case GA_NODE_ELT_B:
+ case GA_NODE_NORMAL: case GA_NODE_RESHAPE:
+ case GA_NODE_INTERPOLATE_X: case GA_NODE_INTERPOLATE_NORMAL:
+ pnode->test_function_type = 0; break;
+
+ case GA_NODE_ALLINDICES: pnode->test_function_type = 0; break;
+ case GA_NODE_VAL:
+ if (eval_fixed_size && !(workspace.associated_mf(pnode->name))
+ && !(workspace.associated_im_data(pnode->name))) {
+ gmm::copy(workspace.value(pnode->name), pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_CONSTANT;
+ }
+ break;
+
+ case GA_NODE_ZERO: case GA_NODE_GRAD:
+ case GA_NODE_HESS: case GA_NODE_DIVERG:
+ case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
+ case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
+ break;
+
+ case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST:
+ case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST:
+ case GA_NODE_INTERPOLATE_VAL_TEST: case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_HESS_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ case GA_NODE_INTERPOLATE_DERIVATIVE:
+ case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
+ case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
+ case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
+ case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
+ {
+ const mesh_fem *mf = workspace.associated_mf(pnode->name);
+ size_type t_type = pnode->test_function_type;
+ if (t_type == 1) {
+ pnode->name_test1 = pnode->name;
+ pnode->interpolate_name_test1 = pnode->interpolate_name;
+ pnode->interpolate_name_test2 = pnode->name_test2 = "";
+ pnode->qdim1 = (mf ? workspace.qdim(pnode->name)
+ : gmm::vect_size(workspace.value(pnode->name)));
+ if (option == 1)
+ workspace.test1.insert
+ (var_trans_pair(pnode->name_test1,
+ pnode->interpolate_name_test1));
+ if (!(pnode->qdim1))
+ ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
+ } else {
+ pnode->interpolate_name_test1 = pnode->name_test1 = "";
+ pnode->name_test2 = pnode->name;
+ pnode->interpolate_name_test2 = pnode->interpolate_name;
+ pnode->qdim2 = (mf ? workspace.qdim(pnode->name)
+ : gmm::vect_size(workspace.value(pnode->name)));
+ if (option == 1)
+ workspace.test2.insert
+ (var_trans_pair(pnode->name_test2,
+ pnode->interpolate_name_test2));
+ if (!(pnode->qdim2))
+ ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
+ }
+ if (!mf) {
+ size_type n = workspace.qdim(pnode->name);
+ if (!n)
+ ga_throw_error(expr, pnode->pos, "Invalid null size of variable");
+ if (n == 1) {
+ pnode->init_vector_tensor(1);
+ pnode->tensor()[0] = scalar_type(1);
+ pnode->test_function_type = t_type;
+ } else {
+ pnode->init_matrix_tensor(n,n);
+ pnode->test_function_type = t_type;
+ for (size_type i = 0; i < n; ++i)
+ for (size_type j = 0; j < n; ++j)
+ pnode->tensor()(i,j) = (i==j) ? scalar_type(1) :
scalar_type(0);
+ }
+ }
+ }
+ break;
+
+ case GA_NODE_INTERPOLATE:
+ if (pnode->name.compare("X") == 0) {
+ pnode->node_type = GA_NODE_INTERPOLATE_X;
+ pnode->init_vector_tensor(meshdim);
+ break;
+ }
+ if (pnode->name.compare("Normal") == 0) {
+ pnode->node_type = GA_NODE_INTERPOLATE_NORMAL;
+ pnode->init_vector_tensor(meshdim);
+ break;
+ }
+ // else continue with what follows
+ case GA_NODE_ELEMENTARY: // and ... case GA_NODE_INTERPOLATE:
+ case GA_NODE_XFEM_PLUS:
+ case GA_NODE_XFEM_MINUS:
+ {
+ int ndt = ((pnode->node_type == GA_NODE_INTERPOLATE) ? 1 : 0)
+ + ((pnode->node_type == GA_NODE_ELEMENTARY) ? 2 : 0)
+ + ((pnode->node_type == GA_NODE_XFEM_PLUS) ? 3 : 0)
+ + ((pnode->node_type == GA_NODE_XFEM_MINUS) ? 4 : 0);
+ std::string op__name =
+ (pnode->node_type == GA_NODE_INTERPOLATE) ? "Interpolation" : ""
+ + (pnode->node_type == GA_NODE_ELEMENTARY) ?
+ "Elementary transformation" : ""
+ + (pnode->node_type == GA_NODE_XFEM_PLUS) ? "Xfem_plus" : ""
+ + (pnode->node_type == GA_NODE_XFEM_MINUS) ? "Xfem_minus" : "";
+
+ std::string name = pnode->name;
+ size_type prefix_id = ga_parse_prefix_operator(name);
+ size_type test = ga_parse_prefix_test(name);
+ pnode->name = name;
+
+ // Group must be tested and it should be a fem variable
+ if (!(workspace.variable_or_group_exists(name)))
+ ga_throw_error(expr, pnode->pos,
+ "Unknown variable or group of variables");
+
+ const mesh_fem *mf = workspace.associated_mf(name);
+ if (!mf)
+ ga_throw_error(expr, pnode->pos, op__name
+ << " can only apply to finite element
variables/data");
+
+ size_type q = workspace.qdim(name), n = mf->linked_mesh().dim();
+ if (!q) ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable");
+
+ bgeot::multi_index mii = workspace.qdims(name);
+ if (mii.size() > 6)
+ ga_throw_error(expr, pnode->pos,
+ "Tensor with too many dimensions. Limited to 6");
+
+ if (test == 1) {
+ pnode->name_test1 = name;
+ pnode->interpolate_name_test1 = pnode->interpolate_name;
+ if (option == 1)
+ workspace.test1.insert
+ (var_trans_pair(pnode->name_test1,
+ pnode->interpolate_name_test1));
+ pnode->qdim1 = workspace.qdim(name);
+ if (!(pnode->qdim1))
+ ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable");
+ } else if (test == 2) {
+ pnode->name_test2 = name;
+ pnode->interpolate_name_test2 = pnode->interpolate_name;
+ if (option == 1)
+ workspace.test2.insert
+ (var_trans_pair(pnode->name_test2,
+ pnode->interpolate_name_test2));
+ pnode->qdim2 = workspace.qdim(name);
+ if (!(pnode->qdim2))
+ ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable");
+ }
+
+ switch (prefix_id) {
+ case 0: // value
+ if (!test) {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_VAL; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_VAL; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_VAL; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_VAL; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ } else {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_VAL_TEST; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_VAL_TEST; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_VAL_TEST; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_VAL_TEST; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ if (q == 1 && mii.size() <= 1) {
+ mii.resize(1);
+ mii[0] = 2;
+ } else
+ mii.insert(mii.begin(), 2);
+ }
+ break;
+ case 1: // grad
+ if (!test) {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_GRAD; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_GRAD; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_GRAD; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_GRAD; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ if (n > 1) {
+ if (q == 1 && mii.size() == 1) mii[0] = n;
+ else mii.push_back(n);
+ }
+ } else {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_GRAD_TEST; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_GRAD_TEST; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_GRAD_TEST; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_GRAD_TEST; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ if (q == 1 && mii.size() <= 1) {
+ mii.resize(1);
+ mii[0] = 2;
+ } else
+ mii.insert(mii.begin(), 2);
+ if (n > 1) mii.push_back(n);
+ }
+ break;
+ case 2: // Hessian
+ if (!test) {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_HESS; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_HESS; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_HESS; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_HESS; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ if (n > 1) {
+ if (q == 1 && mii.size() == 1) { mii[0] = n; mii.push_back(n); }
+ else { mii.push_back(n); mii.push_back(n); }
+ }
+ } else {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_HESS_TEST; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_HESS_TEST; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_HESS_TEST; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_HESS_TEST; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ if (q == 1 && mii.size() <= 1) {
+ mii.resize(1);
+ mii[0] = 2;
+ } else
+ mii.insert(mii.begin(), 2);
+ if (n > 1) { mii.push_back(n); mii.push_back(n); }
+ }
+ break;
+ case 3: // divergence
+ if (q != n)
+ ga_throw_error(expr, pnode->pos,
+ "Divergence operator requires fem qdim ("
+ << q << ") to be equal to dim (" << n << ")");
+ if (!test) {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_DIVERG; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_DIVERG; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_DIVERG; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_DIVERG; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ mii.resize(1);
+ mii[0] = 1;
+ } else {
+ switch (ndt) {
+ case 1: pnode->node_type = GA_NODE_INTERPOLATE_DIVERG_TEST; break;
+ case 2: pnode->node_type = GA_NODE_ELEMENTARY_DIVERG_TEST; break;
+ case 3: pnode->node_type = GA_NODE_XFEM_PLUS_DIVERG_TEST; break;
+ case 4: pnode->node_type = GA_NODE_XFEM_MINUS_DIVERG_TEST; break;
+ default: GMM_ASSERT1(false, "internal error");
+ }
+ mii.resize(1);
+ mii[0] = 2;
+ }
+ break;
+ }
+ pnode->t.adjust_sizes(mii);
+ pnode->test_function_type = test;
+
+ if (ndt == 1) {
+ if (!(workspace.interpolate_transformation_exists
+ (pnode->interpolate_name))) {
+ ga_throw_error(expr, pnode->pos,
+ "Unknown interpolate transformation");
+ }
+ } else if (ndt == 2) {
+ if (!(workspace.elementary_transformation_exists
+ (pnode->elementary_name))) {
+ ga_throw_error(expr, pnode->pos,
+ "Unknown elementary transformation");
+ }
+ }
+ }
+ break;
+
+ case GA_NODE_INTERPOLATE_FILTER:
+ {
+ if (pnode->children.size() == 2) {
+ bool valid = (child1->node_type == GA_NODE_CONSTANT);
+ int n = valid ? int(round(child1->tensor()[0])) : -1;
+ if (n < 0 || n > 100 || child1->tensor_order() > 0)
+ ga_throw_error(expr, pnode->pos, "The third argument of "
+ "Interpolate_filter should be a (small) "
+ "non-negative integer.");
+ pnode->nbc1 = size_type(n);
+ tree.clear_node(child1);
+ }
+ if (!(workspace.interpolate_transformation_exists
+ (pnode->interpolate_name)))
+ ga_throw_error(expr, pnode->pos,
+ "Unknown interpolate transformation");
+ pnode->t = child0->t;
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+ }
+ break;
+
+
+ case GA_NODE_OP:
+ switch(pnode->op_type) {
+
+ case GA_PLUS: case GA_MINUS:
+ {
+ if (pnode->op_type == GA_PLUS) pnode->symmetric_op = true;
+ size_type c_size = std::min(size0.size(), size1.size());
+ bool compatible = true;
+
+ size_type f_ind = 0;
+ if (child0->test_function_type &&
+ child1->test_function_type == child0->test_function_type)
+ f_ind = (child0->test_function_type == 3) ? 2:1;
+
+ for (size_type i = f_ind; i < c_size; ++i)
+ if (size0[i] != size1[i]) compatible = false;
+ for (size_type i = c_size; i < size0.size(); ++i)
+ if (size0[i] != 1) compatible = false;
+ for (size_type i = c_size; i < size1.size(); ++i)
+ if (size1[i] != 1) compatible = false;
+
+ if (!compatible)
+ ga_throw_error(expr, pnode->pos, "Addition or subtraction of "
+ "expressions of different sizes: "
+ << size0 << " != " << size1);
+ if (child0->test_function_type || child1->test_function_type) {
+ switch (option) {
+ case 0: case 2:
+ if (child0->name_test1.compare(child1->name_test1) ||
+ child0->name_test2.compare(child1->name_test2) ||
+ child0->interpolate_name_test1.compare
+ (child1->interpolate_name_test1) ||
+ child0->interpolate_name_test2.compare
+ (child1->interpolate_name_test2))
+ compatible = false;
+ break;
+ case 1: case 3: break;
+ default: GMM_ASSERT1(false, "Unknown option");
+ }
+ }
+
+ if (child0->test_function_type != child1->test_function_type ||
+ (!compatible && option != 2))
+ ga_throw_error(expr, pnode->pos, "Addition or subtraction of "
+ "incompatible test functions");
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ pnode->tensor() = pnode->children[0]->tensor();
+ if (pnode->op_type == GA_MINUS)
+ pnode->tensor() -= pnode->children[1]->tensor();
+ else
+ pnode->tensor() += pnode->children[1]->tensor();
+ tree.clear_children(pnode);
+ } else {
+ pnode->t = child0->t;
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+
+ // simplification if one of the two operands is constant and zero
+ if (child0->tensor_is_zero()) {
+ if (pnode->op_type == GA_MINUS) {
+ pnode->op_type = GA_UNARY_MINUS;
+ tree.clear_node(child0);
+ } else {
+ tree.replace_node_by_child(pnode, 1);
+ pnode = child1;
+ }
+ } else if (child1->tensor_is_zero()) {
+ tree.replace_node_by_child(pnode, 0);
+ pnode = child0;
+ } else if (option == 2 && !compatible) {
+ bool child0_compatible = true, child1_compatible = true;
+ if (pnode->test_function_type & 1) {
+ if
(child0->name_test1.compare(workspace.selected_test1.varname)
+ || child0->interpolate_name_test1.compare
+ (workspace.selected_test1.transname))
+ child0_compatible = false;
+ if
(child1->name_test1.compare(workspace.selected_test1.varname)
+ || child1->interpolate_name_test1.compare
+ (workspace.selected_test1.transname))
+ child1_compatible = false;
+ }
+ if (pnode->test_function_type & 2) {
+ if
(child0->name_test2.compare(workspace.selected_test2.varname)
+ || child0->interpolate_name_test2.compare
+ (workspace.selected_test2.transname))
+ child0_compatible = false;
+ if
(child1->name_test2.compare(workspace.selected_test2.varname)
+ || child1->interpolate_name_test1.compare
+ (workspace.selected_test2.transname))
+ child1_compatible = false;
+ }
+ if (child0_compatible) {
+ tree.replace_node_by_child(pnode, 0);
+ pnode = child0;
+ } else if (child1_compatible) {
+ if (pnode->op_type == GA_MINUS) {
+ pnode->op_type = GA_UNARY_MINUS;
+ pnode->t = child1->t;
+ pnode->test_function_type = child1->test_function_type;
+ pnode->name_test1 = child1->name_test1;
+ pnode->name_test2 = child1->name_test2;
+ pnode->interpolate_name_test1=child1->interpolate_name_test1;
+ pnode->interpolate_name_test2=child1->interpolate_name_test2;
+ pnode->qdim1 = child1->qdim1;
+ pnode->qdim2 = child1->qdim2;
+ tree.clear_node(child0);
+ } else {
+ tree.replace_node_by_child(pnode, 1);
+ pnode = child1;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case GA_DOTMULT: case GA_DOTDIV:
+ {
+ if (pnode->op_type == GA_DOTMULT) pnode->symmetric_op = true;
+ bool compatible = true;
+ if (child0->tensor_proper_size() != child1->tensor_proper_size())
+ compatible = false;
+
+ if (child0->tensor_proper_size() != 1) {
+ if (child0->tensor_order() != child1->tensor_order())
+ compatible = false;
+
+ for (size_type i = 0; i < child0->tensor_order(); ++i)
+ if (child0->tensor_proper_size(i)!=child1->tensor_proper_size(i))
+ compatible = false;
+ }
+
+ if (!compatible)
+ ga_throw_error(expr, pnode->pos,
+ "Arguments of different sizes for .* or ./");
+
+ if (pnode->op_type == GA_DOTDIV && child1->test_function_type)
+ ga_throw_error(expr, pnode->pos,
+ "Division by test functions is not allowed");
+
+ pnode->mult_test(child0, child1, expr);
+ mi = pnode->t.sizes();
+ for (size_type i = 0; i < child0->tensor_order(); ++i)
+ mi.push_back(child0->tensor_proper_size(i));
+ pnode->t.adjust_sizes(mi);
+
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ if (pnode->op_type == GA_DOTMULT) {
+ for (size_type i = 0; i < child0->tensor().size(); ++i)
+ pnode->tensor()[i] = child0->tensor()[i] * child1->tensor()[i];
+ } else {
+ for (size_type i = 0; i < child0->tensor().size(); ++i) {
+ if (child1->tensor()[i] == scalar_type(0))
+ ga_throw_error(expr, pnode->pos, "Division by zero.");
+ pnode->tensor()[i] = child0->tensor()[i] / child1->tensor()[i];
+ }
+ }
+ tree.clear_children(pnode);
+ } else {
+ if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
+ gmm::clear(pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ }
+ if (child1->tensor_is_zero() && pnode->op_type == GA_DOTDIV)
+ ga_throw_error(expr, pnode->pos, "Division by zero.");
+ }
+ }
+ break;
+
+ case GA_UNARY_MINUS:
+ pnode->t = child0->t;
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ gmm::scale(pnode->tensor().as_vector(), scalar_type(-1));
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_ZERO) {
+ tree.replace_node_by_child(pnode, 0);
+ pnode = child0;
+ }
+ break;
+
+ case GA_QUOTE:
+ if (dim0 > 2)
+ ga_throw_error(expr, pnode->pos, "Transpose operator is for "
+ "vectors or matrices only.");
+ mi = size0;
+ if (child0->tensor_proper_size() == 1)
+ { tree.replace_node_by_child(pnode, 0); pnode = child0; break; }
+ else if (dim0 == 2) std::swap(mi.back(), mi[size0.size()-2]);
+ else { size_type N = mi.back(); mi.back() = 1; mi.push_back(N); }
+
+ pnode->t.adjust_sizes(mi);
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ if (dim0 == 2) {
+ for (size_type i = 0; i < mi.back(); ++i)
+ for (size_type j = 0; j < mi[size0.size()-2]; ++j)
+ pnode->tensor()(j, i) = child0->tensor()(i,j);
+ } else if (dim0 == 1) {
+ for (size_type i = 0; i < mi.back(); ++i)
+ pnode->tensor()(0, i) = child0->tensor()[i];
+ }
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_ZERO) {
+ pnode->node_type = GA_NODE_ZERO;
+ gmm::clear(pnode->tensor().as_vector());
+ tree.clear_children(pnode);
+ }
+ break;
+
+ case GA_SYM: case GA_SKEW:
+ if (child0->tensor_proper_size() != 1 &&
+ (dim0 != 2 || size0.back() != size0[size0.size()-2]))
+ ga_throw_error(expr, pnode->pos, "Sym and Skew operators are for "
+ "square matrices only.");
+ mi = size0;
+ if (child0->tensor_proper_size() == 1) {
+ if (pnode->op_type == GA_SYM)
+ { tree.replace_node_by_child(pnode, 0); pnode = child0; break; }
+ else {
+ pnode->node_type = GA_NODE_ZERO;
+ gmm::clear(pnode->tensor().as_vector());
+ tree.clear_children(pnode);
+ break;
+ }
+ }
+
+ pnode->t.adjust_sizes(mi);
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ for (size_type i = 0; i < mi.back(); ++i)
+ for (size_type j = 0; j < mi.back(); ++j)
+ if (pnode->op_type == GA_SYM)
+ pnode->tensor()(j, i) = 0.5*(child0->tensor()(j,i)
+ + child0->tensor()(i,j));
+ else
+ pnode->tensor()(j, i) = 0.5*(child0->tensor()(j,i)
+ - child0->tensor()(i,j));
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_ZERO) {
+ pnode->node_type = GA_NODE_ZERO;
+ gmm::clear(pnode->tensor().as_vector());
+ tree.clear_children(pnode);
+ }
+ break;
+
+ case GA_TRACE:
+ {
+ mi = size0;
+ size_type N = (child0->tensor_proper_size() == 1) ? 1 : mi.back();
+
+ if (child0->tensor_proper_size() == 1)
+ { tree.replace_node_by_child(pnode, 0); pnode = child0; break; }
+
+ if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
+ (dim0 == 2 && mi[mi.size()-2] != N))
+ ga_throw_error(expr, pnode->pos,
+ "Trace operator is for square matrices only.");
+
+ if (dim0 == 2) { mi.pop_back(); mi.pop_back(); }
+ pnode->t.adjust_sizes(mi);
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ if (dim0 == 2) {
+ pnode->tensor()[0] = scalar_type(0);
+ for (size_type i = 0; i < N; ++i)
+ pnode->tensor()[0] += child0->tensor()(i,i);
+ } else {
+ pnode->tensor()[0] += child0->tensor()[0];
+ }
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_ZERO) {
+ pnode->node_type = GA_NODE_ZERO;
+ gmm::clear(pnode->tensor().as_vector());
+ tree.clear_children(pnode);
+ }
+ }
+ break;
+
+ case GA_DEVIATOR:
+ {
+ mi = size0;
+ size_type N = (child0->tensor_proper_size() == 1) ? 1 : mi.back();
+
+ if ((dim0 != 2 && child0->tensor_proper_size() != 1) ||
+ (dim0 == 2 && mi[mi.size()-2] != N))
+ ga_throw_error(expr, pnode->pos,
+ "Deviator operator is for square matrices only.");
+
+ if (child0->tensor_proper_size() == 1) {
+ pnode->node_type = GA_NODE_ZERO;
+ gmm::clear(pnode->tensor().as_vector());
+ tree.clear_children(pnode);
+ break;
+ }
+
+ pnode->t.adjust_sizes(mi);
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ if (dim0 == 2) {
+ scalar_type tr(0);
+ gmm::copy(child0->tensor().as_vector(),
+ pnode->tensor().as_vector());
+ for (size_type i = 0; i < N; ++i)
+ tr += child0->tensor()(i,i);
+ for (size_type i = 0; i < N; ++i)
+ pnode->tensor()(i,i) -= tr / scalar_type(N);
+ } else {
+ pnode->tensor()[0] = scalar_type(0);
+ }
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_ZERO) {
+ pnode->node_type = GA_NODE_ZERO;
+ gmm::clear(pnode->tensor().as_vector());
+ tree.clear_children(pnode);
+ }
+ }
+ break;
+
+ case GA_PRINT:
+ {
+ pnode->t = child0->t;
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ cout << "Print constant term "; ga_print_node(child0, cout);
+ cout << ": " << pnode->tensor() << endl;
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_ZERO) {
+ pnode->node_type = GA_NODE_ZERO;
+ gmm::clear(pnode->tensor().as_vector());
+ cout << "Print zero term "; ga_print_node(child0, cout);
+ cout << ": " << pnode->tensor() << endl;
+ tree.clear_children(pnode);
+ }
+ }
+ break;
+
+ case GA_DOT:
+ if (dim1 > 1)
+ ga_throw_error(expr, pnode->pos, "The second argument of the dot "
+ "product has to be a vector.")
+ else {
+ size_type s0 = dim0 == 0 ? 1 : size0.back();
+ size_type s1 = dim1 == 0 ? 1 : size1.back();
+ if (s0 != s1) ga_throw_error(expr, pnode->pos, "Dot product "
+ "of expressions of different sizes ("
+ << s0 << " != " << s1 << ").");
+ if (child0->tensor_order() <= 1) pnode->symmetric_op = true;
+ pnode->mult_test(child0, child1, expr);
+ if (dim0 > 1) {
+ mi = pnode->t.sizes();
+ for (size_type i = 1; i < dim0; ++i)
+ mi.push_back(child0->tensor_proper_size(i-1));
+ pnode->t.adjust_sizes(mi);
+ }
+
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ gmm::clear(pnode->tensor().as_vector());
+ size_type k = 0;
+ for (size_type i = 0, j = 0; i < child0->tensor().size(); ++i) {
+ pnode->tensor()[j] += child0->tensor()[i] * child1->tensor()[k];
+ ++j; if (j == pnode->tensor().size()) { j = 0; ++k; }
+ }
+ GMM_ASSERT1(k == child1->tensor().size(), "Internal error");
+ tree.clear_children(pnode);
+ } else {
+ if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
+ gmm::clear(pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ }
+ }
+ }
+ break;
+
+ case GA_COLON:
+ if (dim1 > 2)
+ ga_throw_error(expr, pnode->pos,
+ "Frobenius product acts only on matrices.")
+ else {
+ size_type s00 = (dim0 == 0) ? 1
+ : (dim0 == 1 ? size0.back() : size0[size0.size()-2]);
+ size_type s01 = (dim0 >= 2) ? size0.back() : 1;
+ size_type s10 = (dim1 == 0) ? 1
+ : (dim1 == 1 ? size1.back() : size1[size1.size()-2]);
+ size_type s11 = (dim1 >= 2) ? size1.back() : 1;
+ if (s00 != s10 || s01 != s11)
+ ga_throw_error(expr, pnode->pos, "Frobenius product "
+ "of expressions of different sizes ("
+ << s00 << "," << s01 << " != " << s10 << ","
+ << s11 << ").");
+ if (child0->tensor_order() <= 2) pnode->symmetric_op = true;
+ pnode->mult_test(child0, child1, expr);
+ if (dim0 > 2) {
+ mi = pnode->t.sizes();
+ for (size_type i = 2; i < dim0; ++i)
+ mi.push_back(child0->tensor_proper_size(i-2));
+ pnode->t.adjust_sizes(mi);
+ }
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ gmm::clear(pnode->tensor().as_vector());
+ size_type k = 0;
+ for (size_type i = 0, j = 0; i < child0->tensor().size(); ++i) {
+ pnode->tensor()[j] += child0->tensor()[i] * child1->tensor()[k];
+ ++j; if (j == pnode->tensor().size()) { j = 0; ++k; }
+ }
+ GMM_ASSERT1(k == child1->tensor().size(), "Internal error");
+ tree.clear_children(pnode);
+ } else {
+ if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
+ gmm::clear(pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ }
+ }
+ }
+ break;
+
+ case GA_TMULT:
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ if (child0->tensor().size() == 1 && child1->tensor().size() == 1) {
+ pnode->init_scalar_tensor
+ (child0->tensor()[0] * child1->tensor()[0]);
+ } else if (child0->tensor().size() == 1) {
+ pnode->t = child1->t;
+ gmm::scale(pnode->tensor().as_vector(),
+ scalar_type(child0->tensor()[0]));
+ } else if (child1->tensor().size() == 1) {
+ pnode->t = child0->t;
+ gmm::scale(pnode->tensor().as_vector(),
+ scalar_type(child1->tensor()[0]));
+ } else {
+ if (dim0+dim1 > 6)
+ ga_throw_error(expr, pnode->pos, "Unauthorized "
+ "tensor multiplication.");
+ for (size_type i = 0; i < dim0; ++i)
+ mi.push_back(child0->tensor().size(i));
+ for (size_type i = 0; i < dim1; ++i)
+ mi.push_back(child1->tensor().size(i));
+ pnode->t.adjust_sizes(mi);
+ size_type n0 = child0->tensor().size();
+ size_type n1 = child1->tensor().size();
+ for (size_type i = 0; i < n0; ++i)
+ for (size_type j = 0; j < n1; ++j)
+
pnode->tensor()[i+j*n0]=child0->tensor()[i]*child1->tensor()[j];
+ }
+ tree.clear_children(pnode);
+ } else {
+ pnode->mult_test(child0, child1, expr);
+ mi = pnode->t.sizes();
+ if (child0->tensor_proper_size() != 1
+ || child1->tensor_proper_size() != 1) {
+ if (child0->tensor_proper_size() == 1) {
+ for (size_type i = 0; i < dim1; ++i)
+ mi.push_back(child1->tensor_proper_size(i));
+ } else if (child1->tensor().size() == 1) {
+ for (size_type i = 0; i < dim0; ++i)
+ mi.push_back(child0->tensor_proper_size(i));
+ } else {
+ if (dim0+dim1 > 6)
+ ga_throw_error(expr, pnode->pos, "Unauthorized "
+ "tensor multiplication.");
+ for (size_type i = 0; i < dim0; ++i)
+ mi.push_back(child0->tensor_proper_size(i));
+ for (size_type i = 0; i < dim1; ++i)
+ mi.push_back(child1->tensor_proper_size(i));
+ }
+ pnode->t.adjust_sizes(mi);
+ }
+ if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
+ gmm::clear(pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ }
+ }
+ break;
+
+ case GA_MULT:
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ if (child0->tensor_proper_size() == 1 &&
+ child1->tensor_proper_size() == 1) {
+ pnode->init_scalar_tensor(child0->tensor()[0]*child1->tensor()[0]);
+ } else if (child0->tensor_proper_size() == 1) {
+ pnode->t = child1->t;
+ gmm::scale(pnode->tensor().as_vector(), child0->tensor()[0]);
+ } else if (child1->tensor_proper_size() == 1) {
+ pnode->t = child0->t;
+ gmm::scale(pnode->tensor().as_vector(), child1->tensor()[0]);
+ } else if (dim0 == 2 && dim1 == 1) {
+ size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
+ if (n != child1->tensor().size(0))
+ ga_throw_error(expr, pnode->pos,
+ "Incompatible sizes in matrix-vector "
+ "multiplication (" << n << " != "
+ << child1->tensor().size(0) << ").");
+ pnode->init_vector_tensor(m);
+ gmm::clear(pnode->tensor().as_vector());
+ for (size_type i = 0; i < m; ++i)
+ for (size_type j = 0; j < n; ++j)
+ pnode->tensor()[i] +=
child0->tensor()(i,j)*child1->tensor()[j];
+ } else if (dim0 == 2 && dim1 == 2) {
+ size_type m = child0->tensor().size(0);
+ size_type n = child0->tensor().size(1);
+ size_type p = child1->tensor().size(1);
+ if (n != child1->tensor().size(0))
+ ga_throw_error(expr, pnode->pos,
+ "Incompatible sizes in matrix-matrix "
+ "multiplication (" << n << " != "
+ << child1->tensor().size(0) << ").");
+ pnode->init_matrix_tensor(m,p);
+ gmm::clear(pnode->tensor().as_vector());
+ for (size_type i = 0; i < m; ++i)
+ for (size_type j = 0; j < n; ++j)
+ for (size_type k = 0; k < p; ++k)
+ pnode->tensor()(i,k) += child0->tensor()(i,j)
+ * child1->tensor()(j,k);
+ }
+ else if (dim0 == 4 && dim1 == 2) {
+ size_type m=child0->tensor().size(0), n=child0->tensor().size(1);
+ size_type o=child0->tensor().size(2), p=child0->tensor().size(3);
+ if (o != child1->tensor().size(0) || p != child1->tensor().size(1))
+ ga_throw_error(expr, pnode->pos,
+ "Incompatible sizes in tensor-matrix "
+ "multiplication (" << o << "," << p << " != "
+ << child1->tensor().size(0) << ","
+ << child1->tensor().size(1) << ").");
+ pnode->init_matrix_tensor(m,n);
+ gmm::clear(pnode->tensor().as_vector());
+ for (size_type i = 0; i < m; ++i)
+ for (size_type j = 0; j < n; ++j)
+ for (size_type k = 0; k < o; ++k)
+ for (size_type l = 0; l < p; ++l)
+ pnode->tensor()(i,j) += child0->tensor()(i,j,k,l)
+ * child1->tensor()(k,l);
+ } else ga_throw_error(expr, pnode->pos,
+ "Unauthorized multiplication.");
+ tree.clear_children(pnode);
+ } else {
+ pnode->mult_test(child0, child1, expr);
+ mi = pnode->t.sizes();
+
+ if (child0->tensor_proper_size() == 1 &&
+ child1->tensor_proper_size() == 1) {
+ pnode->symmetric_op = true;
+ } else if (child0->tensor_proper_size() == 1) {
+ pnode->symmetric_op = true;
+ for (size_type i = 0; i < dim1; ++i)
+ mi.push_back(child1->tensor_proper_size(i));
+ } else if (child1->tensor_proper_size() == 1) {
+ pnode->symmetric_op = true;
+ for (size_type i = 0; i < dim0; ++i)
+ mi.push_back(child0->tensor_proper_size(i));
+ } else if (child0->tensor_order() == 2 &&
+ child1->tensor_order() == 1) {
+ size_type m = child0->tensor_proper_size(0);
+ size_type n = child0->tensor_proper_size(1);
+ mi.push_back(m);
+ if (n != child1->tensor_proper_size(0))
+ ga_throw_error(expr, pnode->pos,
+ "Incompatible sizes in matrix-vector "
+ "multiplication (" << n << " != "
+ << child1->tensor_proper_size(0) << ").");
+ } else if (child0->tensor_order() == 2 &&
+ child1->tensor_order() == 2) {
+ size_type m = child0->tensor_proper_size(0);
+ size_type n = child0->tensor_proper_size(1);
+ size_type p = child1->tensor_proper_size(1);
+ mi.push_back(m); mi.push_back(p);
+ if (n != child1->tensor_proper_size(0))
+ ga_throw_error(expr, pnode->pos,
+ "Incompatible sizes in matrix-matrix "
+ "multiplication (" << n << " != "
+ << child1->tensor_proper_size(0) << ").");
+ }
+ else if (pnode->children[0]->tensor_order() == 4 &&
+ pnode->children[1]->tensor_order() == 2) {
+ size_type m = child0->tensor_proper_size(0);
+ size_type n = child0->tensor_proper_size(1);
+ size_type o = child0->tensor_proper_size(2);
+ size_type p = child0->tensor_proper_size(3);
+ mi.push_back(m); mi.push_back(n);
+ if (o != child1->tensor_proper_size(0) ||
+ p != child1->tensor_proper_size(1))
+ ga_throw_error(expr, pnode->pos,
+ "Incompatible sizes in tensor-matrix "
+ "multiplication (" << o << "," << p << " != "
+ << child1->tensor_proper_size(0) << ","
+ << child1->tensor_proper_size(1) << ").");
+ } else ga_throw_error(expr, pnode->pos,
+ "Unauthorized multiplication.");
+ pnode->t.adjust_sizes(mi);
+ // Simplifications
+ if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
+ gmm::clear(pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_CONSTANT &&
+ child0->tensor().size() == 1 &&
+ child0->tensor()[0] == scalar_type(1)) {
+ tree.replace_node_by_child(pnode, 1);
+ pnode = child1;
+ } else if (child1->node_type == GA_NODE_CONSTANT &&
+ child1->tensor().size() == 1 &&
+ child1->tensor()[0] == scalar_type(1)) {
+ tree.replace_node_by_child(pnode, 0);
+ pnode = child0;
+ }
+ }
+ break;
+
+ case GA_DIV:
+ if (child1->tensor_proper_size() > 1)
+ ga_throw_error(expr, pnode->pos,
+ "Only the division by a scalar is allowed. "
+ "Got a size of " << child1->tensor_proper_size());
+ if (child1->test_function_type)
+ ga_throw_error(expr, pnode->pos,
+ "Division by test functions is not allowed.");
+ if (child1->node_type == GA_NODE_CONSTANT &&
+ child1->tensor()[0] == scalar_type(0))
+ ga_throw_error(expr, pnode->children[1]->pos, "Division by zero");
+
+ pnode->t = child0->t;
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->t = pnode->children[0]->t;
+ pnode->test_function_type = 0;
+ gmm::scale(pnode->tensor().as_vector(),
+ scalar_type(1) / pnode->children[1]->tensor()[0]);
+ tree.clear_children(pnode);
+ } else if (child0->tensor_is_zero()) {
+ gmm::clear(pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ } else if (child1->node_type == GA_NODE_CONSTANT &&
+ child1->tensor().size() == 1 &&
+ child1->tensor()[0] == scalar_type(1)) {
+ tree.replace_node_by_child(pnode, 0);
+ pnode = child0;
+ }
+ break;
+
+ default:GMM_ASSERT1(false, "Unexpected operation. Internal error.");
+ }
+ break;
+
+ case GA_NODE_C_MATRIX:
+ {
+ if (!all_sc) {
+ ga_throw_error(expr, pnode->pos, "Constant vector/matrix/tensor "
+ "components should be scalar valued.");
+ }
+
+ size_type nbc1 = pnode->nbc1, nbc2 = pnode->nbc2, nbc3 = pnode->nbc3;
+ size_type nbl = pnode->children.size() / (nbc1*nbc2*nbc3);
+ if (all_cte) pnode->node_type = GA_NODE_CONSTANT;
+ pnode->test_function_type = 0;
+ for (size_type i = 0; i < pnode->children.size(); ++i) {
+ if (pnode->children[i]->test_function_type) {
+ if (pnode->test_function_type == 0) {
+ pnode->test_function_type=pnode->children[i]->test_function_type;
+ pnode->name_test1 = pnode->children[i]->name_test1;
+ pnode->name_test2 = pnode->children[i]->name_test2;
+ pnode->interpolate_name_test1
+ = pnode->children[i]->interpolate_name_test1;
+ pnode->interpolate_name_test2
+ = pnode->children[i]->interpolate_name_test2;
+ pnode->qdim1 = pnode->children[i]->qdim1;
+ pnode->qdim2 = pnode->children[i]->qdim2;
+ } else {
+ if (pnode->test_function_type !=
+ pnode->children[i]->test_function_type ||
+ pnode->name_test1.compare(pnode->children[i]->name_test1) ||
+ pnode->name_test2.compare(pnode->children[i]->name_test2) ||
+ pnode->interpolate_name_test1.compare
+ (pnode->children[i]->interpolate_name_test1) ||
+ pnode->interpolate_name_test2.compare
+ (pnode->children[i]->interpolate_name_test2))
+ ga_throw_error(expr, pnode->pos, "Inconsistent use of test "
+ "function in constant matrix.");
+ }
+ }
+ }
+ mi.resize(0);
+ if (pnode->test_function_type) mi.push_back(2);
+ if (pnode->test_function_type >= 3) mi.push_back(2);
+ if (nbc1 == 1 && nbc2 == 1 && nbc3 == 1 && nbl == 1) {
+ pnode->t.adjust_sizes(mi);
+ if (all_cte) pnode->tensor()[0] = child0->tensor()[0];
+ } else {
+ mi.push_back(nbl);
+ if (nbc3 != 1) mi.push_back(nbc3);
+ if (nbc2 != 1) mi.push_back(nbc2);
+ if (nbc1 != 1) mi.push_back(nbc1);
+ pnode->t.adjust_sizes(mi);
+ if (all_cte) {
+ size_type n = 0;
+ if (nbc1 == 1 && nbc2 == 1 && nbc3 == 1)
+ for (size_type i = 0; i < nbl; ++i)
+ pnode->tensor()[i] = pnode->children[i]->tensor()[0];
+ else if (nbc2 == 1 && nbc3 == 1) // TODO: verify order
+ for (size_type i = 0; i < nbl; ++i)
+ for (size_type j = 0; j < nbc1; ++j)
+ pnode->tensor()(i,j) = pnode->children[n++]->tensor()[0];
+ else if (nbc3 == 1) // TODO: verify order
+ for (size_type i = 0; i < nbl; ++i)
+ for (size_type j = 0; j < nbc2; ++j)
+ for (size_type k = 0; k < nbc1; ++k)
+ pnode->tensor()(i,j,k) = pnode->children[n++]->tensor()[0];
+ else // TODO: verify order
+ for (size_type i = 0; i < nbl; ++i)
+ for (size_type j = 0; j < nbc3; ++j)
+ for (size_type k = 0; k < nbc2; ++k)
+ for (size_type l = 0; l < nbc1; ++l)
+ pnode->tensor()(i,j,k,l)
+ = pnode->children[n++]->tensor()[0];
+ }
+ }
+ if (all_cte) tree.clear_children(pnode);
+ }
+ break;
+
+
+ case GA_NODE_NAME:
+ {
+ std::string name = pnode->name;
+
+ if (!ignore_X && !(name.compare("X"))) {
+ pnode->node_type = GA_NODE_X;
+ pnode->nbc1 = 0;
+ pnode->init_vector_tensor(meshdim);
+ break;
+ }
+ if (!(name.compare("element_size"))) {
+ pnode->node_type = GA_NODE_ELT_SIZE;
+ pnode->init_scalar_tensor(0);
+ break;
+ }
+ if (!(name.compare("element_K"))) {
+ pnode->node_type = GA_NODE_ELT_K;
+ if (ref_elt_dim == 1)
+ pnode->init_vector_tensor(meshdim);
+ else
+ pnode->init_matrix_tensor(meshdim, ref_elt_dim);
+ break;
+ }
+ if (!(name.compare("element_B"))) {
+ pnode->node_type = GA_NODE_ELT_B;
+ pnode->init_matrix_tensor(ref_elt_dim, meshdim);
+ break;
+ }
+ if (!(name.compare("Normal"))) {
+ pnode->node_type = GA_NODE_NORMAL;
+ pnode->init_vector_tensor(meshdim);
+ break;
+ }
+ if (!(name.compare("Reshape"))) {
+ pnode->node_type = GA_NODE_RESHAPE;
+ pnode->init_vector_tensor(meshdim);
+ break;
+ }
+
+ if (name.compare(0, 11, "Derivative_") == 0) {
+ name = name.substr(11);
+ bool valid = true;
+ pnode->der1 = 1; pnode->der2 = 0;
+ char *p;
+ size_type d = strtol(name.c_str(), &p, 10);
+ size_type s = p - name.c_str();
+ if (s > 0) {
+ pnode->der1 = d;
+ if (name[s] != '_') valid = false; else
+ name = name.substr(s+1);
+ }
+ d = strtol(name.c_str(), &p, 10);
+ s = p - name.c_str();
+ if (s > 0) {
+ pnode->der2 = d;
+ if (name[s] != '_') valid = false; else
+ name = name.substr(s+1);
+ }
+ if (!valid || pnode->der1 == 0)
+ ga_throw_error(expr, pnode->pos, "Invalid derivative format");
+ }
+
+ ga_predef_function_tab::const_iterator it=PREDEF_FUNCTIONS.find(name);
+ if (it != PREDEF_FUNCTIONS.end()) {
+ // Predefined function found
+ pnode->node_type = GA_NODE_PREDEF_FUNC;
+ pnode->name = name;
+ pnode->test_function_type = 0;
+ if (pnode->der1) {
+ if (pnode->der1 > it->second.nbargs()
+ || pnode->der2 > it->second.nbargs())
+ ga_throw_error(expr, pnode->pos, "Invalid derivative.");
+ const ga_predef_function &F = it->second;
+ if ((F.ftype() == 0 || F.dtype() == 2) && !(pnode->der2)) {
+ pnode->name = ((pnode->der1 == 1) ?
+ F.derivative1() : F.derivative2());
+ pnode->der1 = pnode->der2 = 0;
+ }
+ }
+ } else if (SPEC_FUNCTIONS.find(name) != SPEC_FUNCTIONS.end()) {
+ // Special function found
+ if (pnode->der1)
+ ga_throw_error(expr, pnode->pos, "Special functions do not "
+ "support derivatives.");
+ pnode->node_type = GA_NODE_SPEC_FUNC;
+ pnode->name = name;
+ pnode->test_function_type = 0;
+ if (!name.compare("pi")) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->init_scalar_tensor(M_PI);
+ } else if (!name.compare("meshdim")) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->init_scalar_tensor(scalar_type(meshdim));
+ } else if (!name.compare("timestep")) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->init_scalar_tensor(scalar_type(workspace.get_time_step()));
+ }
+ } else if (PREDEF_OPERATORS.tab.find(name)
+ != PREDEF_OPERATORS.tab.end()) {
+ // Nonlinear operator found
+ pnode->node_type = GA_NODE_OPERATOR;
+ pnode->name = name;
+ pnode->test_function_type = 0;
+ } else if (workspace.macro_exists(name)) {
+ GMM_ASSERT1(pnode->der1 == 0 && pnode->der2 == 0,
+ "Derivativation of a macro is not allowed");
+ ga_tree &ma_tree
+ = workspace.macro_tree(name, meshdim, ref_elt_dim, ignore_X);
+ pga_tree_node pnode_old = pnode;
+ pnode = nullptr;
+ tree.copy_node(ma_tree.root, pnode_old->parent, pnode);
+ if (pnode_old->parent)
+ pnode_old->parent->replace_child(pnode_old, pnode);
+ else
+ tree.root = pnode;
+ GMM_ASSERT1(pnode_old->children.empty(), "Internal error");
+ delete pnode_old;
+ ga_node_analysis(expr, tree, workspace, pnode, meshdim,
+ ref_elt_dim, eval_fixed_size, ignore_X, option);
+ } else {
+ // Search for a variable name with optional gradient, Hessian,
+ // divergence or test functions
+
+ size_type prefix_id = ga_parse_prefix_operator(name);
+ size_type test = ga_parse_prefix_test(name);
+
+ if (!(workspace.variable_exists(name)))
+ ga_throw_error(expr, pnode->pos, "Unknown variable, function, "
+ "operator or data " + name);
+
+ if (pnode->der1)
+ ga_throw_error(expr, pnode->pos, "Derivative is for functions or "
+ "operators, not for variables. Use Grad instead.");
+ pnode->name = name;
+
+ const mesh_fem *mf = workspace.associated_mf(name);
+ const im_data *imd = workspace.associated_im_data(name);
+
+ if (test && workspace.is_constant(name) &&
+ !(workspace.is_disabled_variable(name)))
+ ga_throw_error(expr, pnode->pos, "Test functions of constants "
+ "are not allowed.");
+ if (test == 1) {
+ pnode->name_test1 = name;
+ pnode->interpolate_name_test1 = "";
+ if (option == 1)
+ workspace.test1.insert
+ (var_trans_pair(pnode->name_test1,
+ pnode->interpolate_name_test1));
+ pnode->qdim1 = mf ? workspace.qdim(name)
+ : gmm::vect_size(workspace.value(name));
+ if (!(pnode->qdim1))
+ ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable");
+ } else if (test == 2) {
+ pnode->name_test2 = name;
+ pnode->interpolate_name_test2 = "";
+ if (option == 1)
+ workspace.test2.insert
+ (var_trans_pair(pnode->name_test2,
+ pnode->interpolate_name_test2));
+ pnode->qdim2 = mf ? workspace.qdim(name)
+ : gmm::vect_size(workspace.value(name));
+ if (!(pnode->qdim2))
+ ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable");
+ }
+
+ if (!mf && (test || !imd)) {
+ if (prefix_id)
+ ga_throw_error(expr, pnode->pos, "Gradient, Hessian or
Divergence"
+ " cannot be evaluated for fixed size data.");
+ if (test)
+ pnode->node_type = GA_NODE_VAL_TEST;
+ else if (eval_fixed_size)
+ pnode->node_type = GA_NODE_CONSTANT;
+ else
+ pnode->node_type = GA_NODE_VAL;
+
+ size_type n = gmm::vect_size(workspace.value(name));
+ if (n == 1) {
+ if (test) {
+ pnode->init_vector_tensor(1);
+ pnode->tensor()[0]=scalar_type(1);
+ }
+ else pnode->init_scalar_tensor(workspace.value(name)[0]);
+ } else {
+ if (test) {
+ pnode->init_matrix_tensor(n,n);
+ for (size_type i = 0; i < n; ++i)
+ for (size_type j = 0; j < n; ++j)
+ pnode->tensor()(i,j)
+ = ((i == j) ? scalar_type(1) : scalar_type(0));
+ } else {
+ pnode->t.adjust_sizes(workspace.qdims(name));
+ gmm::copy(workspace.value(name), pnode->tensor().as_vector());
+ }
+ }
+ } else if (!test && imd) {
+ if (prefix_id)
+ ga_throw_error(expr, pnode->pos, "Gradient, Hessian or
Divergence"
+ " cannot be evaluated for im data.");
+ pnode->node_type = GA_NODE_VAL;
+ pnode->t.adjust_sizes(workspace.qdims(name));
+ } else {
+ size_type q = workspace.qdim(name);
+ size_type n = mf->linked_mesh().dim();
+ bgeot::multi_index mii = workspace.qdims(name);
+
+ if (!q) ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable " << name);
+ if (mii.size() > 6)
+ ga_throw_error(expr, pnode->pos,
+ "Tensor with too much dimensions. Limited to 6");
+
+ switch (prefix_id) {
+ case 0: // value
+ pnode->node_type = test ? GA_NODE_VAL_TEST : GA_NODE_VAL;
+ // For Test nodes a first dimension of size equal to 2 has to be
+ // prepended by convention (to be adapted later)
+ if (test && q == 1 && mii.size() <= 1) {
+ mii.resize(1);
+ mii[0] = 2;
+ } else if (test) {
+ mii.insert(mii.begin(), 2);
+ pnode->t.adjust_sizes(mii);
+ }
+ break;
+ case 1: // grad
+ pnode->node_type = test ? GA_NODE_GRAD_TEST : GA_NODE_GRAD;
+ if (test) {
+ if (q == 1 && mii.size() <= 1) {
+ mii.resize(1);
+ mii[0] = 2;
+ } else
+ mii.insert(mii.begin(), 2);
+ }
+ if (n > 1) {
+ if (mii.size() == 1 && mii[0] == 1) mii[0] = n;
+ else mii.push_back(n);
+ }
+ break;
+ case 2: // Hessian
+ pnode->node_type = test ? GA_NODE_HESS_TEST : GA_NODE_HESS;
+ if (test) {
+ if (q == 1 && mii.size() <= 1) {
+ mii.resize(1);
+ mii[0] = 2;
+ } else
+ mii.insert(mii.begin(), 2);
+ }
+ if (n > 1) {
+ if (mii.size() == 1 && mii[0] == 1) mii[0] = n;
+ else mii.push_back(n);
+ mii.push_back(n);
+ }
+ break;
+ case 3: // divergence
+ pnode->node_type = test ? GA_NODE_DIVERG_TEST : GA_NODE_DIVERG;
+ if (q != n)
+ ga_throw_error(expr, pnode->pos,
+ "Divergence operator can only be applied to"
+ "Fields with qdim (" << q << ") equal to dim ("
+ << n << ")");
+ mii.resize(1);
+ mii[0] = test ? 2 : 1;
+ break;
+ }
+ pnode->t.adjust_sizes(mii);
+ }
+ pnode->test_function_type = test;
+ }
+ }
+ break;
+
+ case GA_NODE_PARAMS:
+ if (child0->node_type == GA_NODE_X) {
+ child0->init_scalar_tensor(0);
+ if (pnode->children.size() != 2)
+ ga_throw_error(expr, child1->pos, "X stands for the coordinates on "
+ "the real elements. It accepts only one index.");
+ if (!(child1->node_type == GA_NODE_CONSTANT) ||
+ child1->tensor().size() != 1)
+ ga_throw_error(expr, child1->pos, "Index for X has to be constant "
+ "and of size 1.");
+ child0->nbc1 = size_type(round(child1->tensor()[0]));
+ if (child0->nbc1 == 0 || child0->nbc1 > meshdim)
+ ga_throw_error(expr, child1->pos, "Index for X not convenient. "
+ "Found " << child0->nbc1 << " with meshdim = "
+ << meshdim);
+ tree.replace_node_by_child(pnode, 0);
+ pnode = child0;
+
+ } else if (child0->node_type == GA_NODE_RESHAPE) {
+ if (pnode->children.size() < 3)
+ ga_throw_error(expr, child1->pos,
+ "Not enough parameters for Reshape");
+ if (pnode->children.size() > 8)
+ ga_throw_error(expr, child1->pos,
+ "Too many parameters for Reshape");
+ pnode->t = child1->t;
+ pnode->test_function_type = child1->test_function_type;
+ pnode->name_test1 = child1->name_test1;
+ pnode->name_test2 = child1->name_test2;
+ pnode->interpolate_name_test1 = child1->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child1->interpolate_name_test2;
+ pnode->qdim1 = child1->qdim1;
+ pnode->qdim2 = child1->qdim2;
+ mi.resize(0);
+ for (size_type i = 0; i < pnode->nb_test_functions(); ++i)
+ mi.push_back(size1[i]);
+
+ for (size_type i = 2; i < pnode->children.size(); ++i) {
+ if (pnode->children[i]->node_type != GA_NODE_CONSTANT)
+ ga_throw_error(expr, pnode->children[i]->pos, "Reshape sizes "
+ "should be constant positive integers.");
+ mi.push_back(size_type(round(pnode->children[i]->tensor()[0])));
+ if (mi.back() == 0)
+ ga_throw_error(expr, pnode->children[i]->pos, "Wrong zero size "
+ "for Reshape.");
+ }
+ size_type total_size(1);
+ for (size_type i = 0; i < mi.size(); ++i)
+ total_size *= mi[i];
+ if (total_size != pnode->tensor().size())
+ ga_throw_error(expr, pnode->pos, "Invalid sizes for reshape.");
+ pnode->t.adjust_sizes(mi);
+
+ if (child1->node_type == GA_NODE_CONSTANT) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ tree.clear_children(pnode);
+ } else if (child1->node_type == GA_NODE_ZERO) {
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ }
+ } else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
+
+ // Evaluation of a predefined function
+
+ for (size_type i = 1; i < pnode->children.size(); ++i)
+ ga_valid_operand(expr, pnode->children[i]);
+ std::string name = child0->name;
+ ga_predef_function_tab::const_iterator it =
PREDEF_FUNCTIONS.find(name);
+ const ga_predef_function &F = it->second;
+ size_type nbargs = F.nbargs();
+ if (nbargs+1 != pnode->children.size()) {
+ ga_throw_error(expr, pnode->pos, "Bad number of arguments for "
+ "predefined function " << name << ". Found "
+ << pnode->children.size()-1 << ", should be "<<nbargs << ".");
+ }
+ pnode->test_function_type = 0;
+ pga_tree_node child2 = (nbargs == 2) ? pnode->children[2] : child1;
+ all_cte = child1->node_type == GA_NODE_CONSTANT;
+ if (nbargs == 2)
+ all_cte = all_cte && (child2->node_type == GA_NODE_CONSTANT);
+ if (child1->test_function_type || child2->test_function_type)
+ ga_throw_error(expr, pnode->pos, "Test functions cannot be passed "
+ "as argument of a predefined function.");
+ if (child1->tensor_order() > 2 || child2->tensor_order() > 2)
+ ga_throw_error(expr, pnode->pos, "Sorry, function can be applied "
+ "to scalar, vector and matrices only.");
+ size_type s1 = child1->tensor().size();
+ size_type s2 = (nbargs == 2) ? child2->tensor().size() : s1;
+ if (s1 != s2 && (s1 != 1 || s2 != 1))
+ ga_throw_error(expr, pnode->pos,
+ "Invalid argument size for a scalar function. "
+ "Size of first argument: " << s1 <<
+ ". Size of second argument: " << s2 << ".");
+
+ if (nbargs == 1) {
+ pnode->t = child1->t;
+ } else {
+ if (s1 == s2) {
+ pnode->t = child1->t;
+ } else if (s1 == 1) {
+ pnode->t = child2->t;
+ } else {
+ pnode->t = child1->t;
+ }
+ }
+
+ if (all_cte) {
+ if (pnode->der1)
+ GMM_ASSERT1(false, "Sorry, to be done");
+ pnode->node_type = GA_NODE_CONSTANT;
+ if (nbargs == 1) {
+ for (size_type i = 0; i < s1; ++i)
+ pnode->tensor()[i] = F(child1->tensor()[i]);
+ } else {
+ if (s1 == s2) {
+ for (size_type i = 0; i < s1; ++i)
+ pnode->tensor()[i] = F(child1->tensor()[i],
+ child2->tensor()[i]);
+ } else if (s1 == 1) {
+ for (size_type i = 0; i < s2; ++i)
+ pnode->tensor()[i] = F(child1->tensor()[0],
+ child2->tensor()[i]);
+ } else {
+ for (size_type i = 0; i < s1; ++i)
+ pnode->tensor()[i] = F(child1->tensor()[i],
+ child2->tensor()[0]);
+ }
+ }
+ tree.clear_children(pnode);
+ }
+ } else if (child0->node_type == GA_NODE_SPEC_FUNC) {
+
+ // Special constant functions: meshdim, qdim(u) ...
+
+ for (size_type i = 1; i < pnode->children.size(); ++i)
+ ga_valid_operand(expr, pnode->children[i]);
+ if (pnode->children.size() != 2)
+ ga_throw_error(expr, pnode->pos,
+ "One and only one argument is allowed for function "
+ +child0->name+".");
+
+ if (!(child0->name.compare("qdim"))) {
+ if (child1->node_type != GA_NODE_VAL)
+ ga_throw_error(expr, pnode->pos, "The argument of qdim "
+ "function can only be a variable name.");
+ pnode->node_type = GA_NODE_CONSTANT;
+ pnode->init_scalar_tensor(scalar_type(workspace.qdim(child1->name)));
+ if (pnode->tensor()[0] <= 0)
+ ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable");
+ } else if (!(child0->name.compare("qdims"))) {
+ if (child1->node_type != GA_NODE_VAL)
+ ga_throw_error(expr, pnode->pos, "The argument of qdim "
+ "function can only be a variable name.");
+ pnode->node_type = GA_NODE_CONSTANT;
+ bgeot::multi_index mii = workspace.qdims(child1->name);
+ if (mii.size() > 6)
+ ga_throw_error(expr, pnode->pos,
+ "Tensor with too much dimensions. Limited to 6");
+ if (mii.size() == 0 || scalar_type(mii[0]) <= 0)
+ ga_throw_error(expr, pnode->pos,
+ "Invalid null size of variable");
+ if (mii.size() == 1)
+ pnode->init_scalar_tensor(scalar_type(mii[0]));
+ if (mii.size() >= 1) {
+ pnode->init_vector_tensor(mii.size());
+ for (size_type i = 0; i < mii.size(); ++i)
+ pnode->tensor()[i] = scalar_type(mii[i]);
+ }
+ } else if (!(child0->name.compare("Id"))) {
+ bool valid = (child1->node_type == GA_NODE_CONSTANT);
+ int n = valid ? int(round(child1->tensor()[0])) : -1;
+ if (n <= 0 || n > 100 || child1->tensor_order() > 0)
+ ga_throw_error(expr, pnode->pos, "The argument of Id "
+ "should be a (small) positive integer.");
+ pnode->node_type = GA_NODE_CONSTANT;
+ if (n == 1)
+ pnode->init_scalar_tensor(scalar_type(1));
+ else {
+ pnode->init_matrix_tensor(n,n);
+ for (int i = 0; i < n; ++i) pnode->tensor()(i,i) = scalar_type(1);
+ }
+ } else ga_throw_error(expr, pnode->children[0]->pos,
+ "Unknown special function.");
+ tree.clear_children(pnode);
+ } else if (child0->node_type == GA_NODE_OPERATOR) {
+
+ // Call to a nonlinear operator
+
+ for (size_type i = 1; i < pnode->children.size(); ++i)
+ ga_valid_operand(expr, pnode->children[i]);
+ all_cte = true;
+ ga_nonlinear_operator::arg_list args;
+ for (size_type i = 1; i < pnode->children.size(); ++i) {
+ all_cte = all_cte
+ && (pnode->children[i]->node_type == GA_NODE_CONSTANT);
+ args.push_back(&(pnode->children[i]->tensor()));
+ if (pnode->children[i]->node_type == GA_NODE_ALLINDICES)
+ ga_throw_error(expr, pnode->children[i]->pos,
+ "Colon operator is not allowed in nonlinear "
+ "operator call.");
+ if (pnode->children[i]->test_function_type)
+ ga_throw_error(expr, pnode->pos, "Test functions cannot be passed "
+ "as argument of a nonlinear operator.");
+ if (pnode->children[i]->tensor_order() > 2)
+ ga_throw_error(expr, pnode->pos, "Sorry, arguments to nonlinear "
+ "operators should only be scalar, vector or matrices");
+ }
+ ga_predef_operator_tab::T::const_iterator it
+ = PREDEF_OPERATORS.tab.find(child0->name);
+ const ga_nonlinear_operator &OP = *(it->second);
+ mi.resize(0);
+ if (!(OP.result_size(args, mi)))
+ ga_throw_error(expr, pnode->pos,
+ "Wrong number or wrong size of arguments for the "
+ "call of nonlinear operator " + child0->name);
+
+ pnode->test_function_type = 0;
+
+ if (child0->der1 > args.size() || child0->der2 > args.size())
+ ga_throw_error(expr, child0->pos,
+ "Invalid derivative number for nonlinear operator "
+ + child0->name);
+
+ if (child0->der1 && child0->der2 == 0) {
+ for (size_type i = 0; i < args[child0->der1-1]->sizes().size(); ++i)
+ mi.push_back(args[child0->der1-1]->sizes()[i]);
+ pnode->t.adjust_sizes(mi);
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ OP.derivative(args, child0->der1, pnode->tensor());
+ tree.clear_children(pnode);
+ }
+ } else if (child0->der1 && child0->der2) {
+ for (size_type i = 0; i < args[child0->der1-1]->sizes().size(); ++i)
+ mi.push_back(args[child0->der1-1]->sizes()[i]);
+ for (size_type i = 0; i < args[child0->der2-1]->sizes().size(); ++i)
+ mi.push_back(args[child0->der2-1]->sizes()[i]);
+ pnode->t.adjust_sizes(mi);
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ OP.second_derivative(args, child0->der1, child0->der2,
+ pnode->tensor());
+ tree.clear_children(pnode);
+ }
+ } else {
+ pnode->t.adjust_sizes(mi);
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ OP.value(args, pnode->tensor());
+ tree.clear_children(pnode);
+ }
+ }
+ } else {
+
+ // Access to components of a tensor
+ all_cte = (child0->node_type == GA_NODE_CONSTANT);
+ // cout << "child0->tensor_order() = " << child0->tensor_order();
+ // cout << endl << "child0->t.sizes() = "
+ // << child0->t.sizes() << endl;
+ if (pnode->children.size() != child0->tensor_order() + 1)
+ ga_throw_error(expr, pnode->pos, "Bad number of indices.");
+ for (size_type i = 1; i < pnode->children.size(); ++i)
+ if (pnode->children[i]->node_type != GA_NODE_ALLINDICES &&
+ (pnode->children[i]->node_type != GA_NODE_CONSTANT ||
+ pnode->children[i]->tensor().size() != 1))
+ ga_throw_error(expr, pnode->children[i]->pos,
+ "Indices should be constant integers or colon.");
+
+ bgeot::multi_index mi1(size0.size()), mi2, indices;
+ for (size_type i = 0; i < child0->tensor_order(); ++i) {
+ if (pnode->children[i+1]->node_type == GA_NODE_ALLINDICES) {
+ mi2.push_back(child0->tensor_proper_size(i));
+ indices.push_back(i);
+ mi1[i] = 0;
+ } else {
+ mi1[i] = size_type(round(pnode->children[i+1]->tensor()[0])-1);
+ if (mi1[i] >= child0->tensor_proper_size(i))
+ ga_throw_error(expr, pnode->children[i+1]->pos,
+ "Index out of range, " << mi1[i]+1
+ << ". Should be between 1 and "
+ << child0->tensor_proper_size(i) << ".");
+ }
+ }
+ mi.resize(0);
+ for (size_type i = 0; i < child0->nb_test_functions(); ++i)
+ mi.push_back(child0->t.sizes()[i]);
+ for (size_type i = 0; i < mi2.size(); ++i) mi.push_back(mi2[i]);
+ pnode->t.adjust_sizes(mi);
+ pnode->test_function_type = child0->test_function_type;
+ pnode->name_test1 = child0->name_test1;
+ pnode->name_test2 = child0->name_test2;
+ pnode->interpolate_name_test1 = child0->interpolate_name_test1;
+ pnode->interpolate_name_test2 = child0->interpolate_name_test2;
+ pnode->qdim1 = child0->qdim1;
+ pnode->qdim2 = child0->qdim2;
+
+ if (all_cte) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ for (bgeot::multi_index mi3(mi2.size()); !mi3.finished(mi2);
+ mi3.incrementation(mi2)) {
+ for (size_type j = 0; j < mi2.size(); ++j) {
+ mi1[indices[j]] = mi3[j];
+ }
+ pnode->tensor()(mi3) = pnode->children[0]->tensor()(mi1);
+ }
+ tree.clear_children(pnode);
+ } else {
+ if (child0->tensor_is_zero() || child1->tensor_is_zero()) {
+ gmm::clear(pnode->tensor().as_vector());
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ }
+ }
+ }
+ break;
+
+ default:GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
+ << " in semantic analysis. Internal error.");
+ }
+ // cout << " begin hash code = " << pnode->hash_value << endl;
+ pnode->hash_value = ga_hash_code(pnode);
+ // cout << "node_type = " << pnode->node_type << " op_type = "
+ // << pnode->op_type << " proper hash code = " << pnode->hash_value;
+ for (size_type i = 0; i < pnode->children.size(); ++i) {
+ pnode->hash_value += (pnode->children[i]->hash_value)
+ * 1.0101 * (pnode->symmetric_op ? scalar_type(1) : scalar_type(i+1));
+ }
+ // cout << " final hash code = " << pnode->hash_value << endl;
+ }
+
+ extern bool predef_operators_nonlinear_elasticity_initialized;
+ extern bool predef_operators_plasticity_initialized;
+ extern bool predef_operators_contact_initialized;
+ extern bool predef_functions_initialized;
+
+ void ga_semantic_analysis(const std::string &expr, ga_tree &tree,
+ const ga_workspace &workspace,
+ size_type meshdim,
+ size_type ref_elt_dim,
+ bool eval_fixed_size,
+ bool ignore_X, int option) {
+ GMM_ASSERT1(predef_functions_initialized &&
+ predef_operators_nonlinear_elasticity_initialized &&
+ predef_operators_plasticity_initialized &&
+ predef_operators_contact_initialized, "Internal error");
+ if (!(tree.root)) return;
+ if (option == 1) { workspace.test1.clear(); workspace.test2.clear(); }
+ // cout << "semantic analysis of " << ga_tree_to_string(tree) << endl;
+ ga_node_analysis(expr, tree, workspace, tree.root, meshdim, ref_elt_dim,
+ eval_fixed_size, ignore_X, option);
+ if (tree.root && option == 2) {
+ if (((tree.root->test_function_type & 1) &&
+ (tree.root->name_test1.compare(workspace.selected_test1.varname)
+ || tree.root->interpolate_name_test1.compare
+ (workspace.selected_test1.transname)))
+ ||
+ ((tree.root->test_function_type & 2) &&
+ (tree.root->name_test2.compare(workspace.selected_test2.varname)
+ || tree.root->interpolate_name_test2.compare
+ (workspace.selected_test2.transname))))
+ tree.clear();
+ }
+ // cout << "semantic analysis done " << endl;
+ ga_valid_operand(expr, tree.root);
+ }
+
+
+ void ga_extract_factor(ga_tree &result_tree, pga_tree_node pnode,
+ pga_tree_node &new_pnode) {
+ result_tree.clear();
+ result_tree.copy_node(pnode, 0, result_tree.root);
+ new_pnode = result_tree.root;
+
+ bool minus_sign = false;
+
+ pga_tree_node pnode_child = pnode;
+ pnode = pnode->parent;
+
+ while (pnode) {
+
+ size_type nbch = pnode->children.size();
+ pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
+ pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
+
+ switch (pnode->node_type) {
+
+ case GA_NODE_OP:
+ switch(pnode->op_type) {
+ case GA_PLUS:
+ // Nothing to do
+ break;
+ case GA_MINUS:
+ if (child1 == pnode_child) minus_sign = !(minus_sign);
+ // A remaining minus sign is added at the end if necessary.
+ break;
+ case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
+ case GA_TRACE: case GA_DEVIATOR: case GA_PRINT:
+ // Copy of the term
+ result_tree.insert_node(result_tree.root, pnode->node_type);
+ result_tree.root->op_type = pnode->op_type;
+ result_tree.root->pos = pnode->pos;
+ break;
+ case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
+ case GA_DOTMULT: case GA_DIV: case GA_DOTDIV:
+ // Copy of the term and other child
+ result_tree.insert_node(result_tree.root, pnode->node_type);
+ result_tree.root->op_type = pnode->op_type;
+ result_tree.root->pos = pnode->pos;
+ result_tree.root->children.resize(2, nullptr);
+ if (child0 == pnode_child) {
+ result_tree.copy_node(child1, result_tree.root,
+ result_tree.root->children[1]);
+ } else if (child1 == pnode_child) {
+ std::swap(result_tree.root->children[1],
+ result_tree.root->children[0]);
+ result_tree.copy_node(child0, result_tree.root,
+ result_tree.root->children[0]);
+ } else GMM_ASSERT1(false, "Corrupted tree");
+ break;
+ default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
+ }
+ break;
+
+ case GA_NODE_PARAMS:
+ GMM_ASSERT1(child0->node_type == GA_NODE_RESHAPE, "Cannot extract a "
+ "factor which is a parameter of a nonlinear "
+ "operator/function");
+ GMM_ASSERT1(child1 == pnode_child, "Cannot extract a factor of a "
+ "Reshape size parameter");
+ // Copy of the term and other children
+ result_tree.insert_node(result_tree.root, pnode->node_type);
+ result_tree.root->pos = pnode->pos;
+ result_tree.root->children.resize(pnode->children.size(), nullptr);
+ std::swap(result_tree.root->children[1], result_tree.root->children[0]);
+ for (size_type i = 0; i < pnode->children.size(); ++i)
+ if (i != 1)
+ result_tree.copy_node(pnode->children[i], result_tree.root,
+ result_tree.root->children[i]);
+ break;
+
+ case GA_NODE_C_MATRIX:
+ result_tree.insert_node(result_tree.root, pnode->node_type);
+ result_tree.root->pos = pnode->pos;
+ result_tree.root->children.resize(pnode->children.size());
+ for (size_type i = 0; i < pnode->children.size(); ++i)
+ if (pnode_child == pnode->children[i]) {
+ result_tree.root->children[i] = result_tree.root->children[0];
+ result_tree.root->children[0] = 0;
+ }
+
+ for (size_type i = 0; i < pnode->children.size(); ++i) {
+ if (pnode_child == pnode->children[i]) {
+ pnode->children[i] = new ga_tree_node(GA_NODE_ZERO, pnode->pos);
+ pnode->children[i]->init_scalar_tensor(scalar_type(0));
+ pnode->children[i]->parent = pnode;
+ }
+ }
+ break;
+
+ default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
+ << " in extract constant term. Internal error.");
+ }
+
+ pnode_child = pnode;
+ pnode = pnode->parent;
+ }
+
+ if (minus_sign) {
+ result_tree.insert_node(result_tree.root, GA_NODE_OP);
+ result_tree.root->op_type = GA_UNARY_MINUS;
+ result_tree.root->pos = pnode->children[0]->pos;
+ }
+ }
+
+ bool ga_node_extract_constant_term
+ (ga_tree &tree, pga_tree_node pnode, const ga_workspace &workspace,
+ const mesh &m) {
+ bool is_constant = true;
+ size_type nbch = pnode->children.size();
+ pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
+ // pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
+ bool child_0_is_constant = (nbch <= 0) ? true :
+ ga_node_extract_constant_term(tree, pnode->children[0], workspace, m);
+ bool child_1_is_constant = (nbch <= 1) ? true :
+ ga_node_extract_constant_term(tree, pnode->children[1], workspace, m);
+
+ switch (pnode->node_type) {
+ case GA_NODE_ZERO: is_constant = false; break;
+
+ case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
+ case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
+ case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
+ case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
+ case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST: case GA_NODE_PREDEF_FUNC:
+ case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST: case GA_NODE_RESHAPE:
+ case GA_NODE_ELT_SIZE: case GA_NODE_ELT_K: case GA_NODE_ELT_B:
+ case GA_NODE_CONSTANT: case GA_NODE_X:
+ case GA_NODE_NORMAL: case GA_NODE_OPERATOR:
+ is_constant = true; break;
+
+ case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
+ case GA_NODE_VAL: case GA_NODE_GRAD: case GA_NODE_HESS:
+ case GA_NODE_DIVERG:
+ is_constant = workspace.is_constant(pnode->name);
+ break;
+
+ case GA_NODE_INTERPOLATE_VAL:
+ case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_INTERPOLATE_HESS:
+ case GA_NODE_INTERPOLATE_DIVERG:
+ {
+ if (!(workspace.is_constant(pnode->name))) {
+ is_constant = false; break;
+ }
+ std::set<var_trans_pair> vars;
+ workspace.interpolate_transformation(pnode->interpolate_name)
+ ->extract_variables(workspace, vars, true, m,
+ pnode->interpolate_name);
+ for (const var_trans_pair &var : vars) {
+ if (!(workspace.is_constant(var.varname)))
+ { is_constant = false; break; }
+ }
+ }
+ break;
+
+ case GA_NODE_INTERPOLATE_FILTER:
+ if (!child_0_is_constant) { is_constant = false; break; }
+ // No break intentionally
+ case GA_NODE_INTERPOLATE_VAL_TEST:
+ case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ case GA_NODE_INTERPOLATE_HESS_TEST:
+ case GA_NODE_INTERPOLATE_X:
+ case GA_NODE_INTERPOLATE_NORMAL:
+ case GA_NODE_INTERPOLATE_DERIVATIVE:
+ {
+ std::set<var_trans_pair> vars;
+ workspace.interpolate_transformation(pnode->interpolate_name)
+ ->extract_variables(workspace, vars, true, m,
+ pnode->interpolate_name);
+ for (const var_trans_pair &var : vars) {
+ if (!(workspace.is_constant(var.varname)))
+ { is_constant = false; break; }
+ }
+ }
+ break;
+
+ case GA_NODE_OP:
+ switch(pnode->op_type) {
+ case GA_PLUS: case GA_MINUS:
+ if (!child_0_is_constant && !child_1_is_constant)
+ { is_constant = false; break; }
+ break;
+
+ case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
+ case GA_TRACE: case GA_DEVIATOR: case GA_PRINT:
+ is_constant = child_0_is_constant;
+ break;
+
+ case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
+ case GA_DOTMULT: case GA_DIV: case GA_DOTDIV:
+ is_constant = (child_0_is_constant && child_1_is_constant);
+ break;
+
+ default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
+ }
+ break;
+
+ case GA_NODE_C_MATRIX:
+ for (size_type i = 0; i < pnode->children.size(); ++i) {
+ if (!(ga_node_extract_constant_term(tree, pnode->children[i],
+ workspace, m)))
+ { is_constant = false; break; }
+ }
+ break;
+
+ case GA_NODE_PARAMS:
+ if (child0->node_type == GA_NODE_RESHAPE) {
+ is_constant = child_1_is_constant;
+ } else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
+ for (size_type i = 1; i < pnode->children.size(); ++i) {
+ if (!(ga_node_extract_constant_term(tree, pnode->children[i],
+ workspace, m)))
+ { is_constant = false; break; }
+ }
+ } else if (child0->node_type == GA_NODE_SPEC_FUNC) {
+ GMM_ASSERT1(false, "internal error");
+ } else if (child0->node_type == GA_NODE_OPERATOR) {
+ for (size_type i = 1; i < pnode->children.size(); ++i) {
+ if (!(ga_node_extract_constant_term(tree, pnode->children[i],
+ workspace, m)))
+ { is_constant = false; break; }
+ }
+ } else {
+ is_constant = child_0_is_constant;
+ }
+ break;
+
+ default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
+ << " in extract constant term. Internal error.");
+ }
+
+ if (!is_constant) {
+ pnode->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode);
+ }
+ return is_constant;
+ }
+
+
+ //=========================================================================
+ // Extract Neumann terms
+ //=========================================================================
+
+ static std::string ga_extract_one_Neumann_term
+ (const std::string &varname,
+ ga_workspace &workspace, pga_tree_node pnode) {
+ size_type N = workspace.qdim(varname);
+ const mesh_fem *mf = workspace.associated_mf(varname);
+ GMM_ASSERT1(mf, "Works only with fem variables.");
+ size_type meshdim = mf->linked_mesh().dim();
+ ga_tree factor;
+ pga_tree_node new_pnode = nullptr;
+ ga_extract_factor(factor, pnode, new_pnode);
+ std::string result;
+ pga_tree_node nnew_pnode = new_pnode;
+
+ int cas = new_pnode->node_type == GA_NODE_GRAD_TEST ? 0 : 1;
+ // Allow to detect Trace(Grad_Test_u)
+ if (cas == 0 && new_pnode->parent &&
+ new_pnode->parent->node_type == GA_NODE_OP &&
+ new_pnode->parent->op_type == GA_TRACE) {
+ cas = 2; nnew_pnode = new_pnode->parent;
+ }
+ bool ok = true;
+ pga_tree_node colon_pnode = nullptr;
+ bool quote_before_colon = false;
+
+ // A:Grad_Test_u --> A*Normal if A is a matrix
+ // Grad_Test_u:A --> A*Normal if A is a matrix
+ // A*Div_Test_u --> A*Normal if A is a scalar
+ // Div_Test_u*A --> Normal*A if A is a scalar
+ // A*(Grad_Test_u)' --> (A)'*Normal if A is a matrix
+ // intercaled scalar multplications and divisions are taken into account
+ while (nnew_pnode->parent) {
+ pga_tree_node previous_node = nnew_pnode;
+ nnew_pnode = nnew_pnode->parent;
+
+ if (nnew_pnode->node_type == GA_NODE_OP &&
+ nnew_pnode->op_type == GA_MULT &&
+ nnew_pnode->children[0] == previous_node &&
+ nnew_pnode->children[1]->tensor_proper_size() == 1) {
+ } else if (nnew_pnode->node_type == GA_NODE_OP &&
+ nnew_pnode->op_type == GA_MULT &&
+ nnew_pnode->children[1] == previous_node &&
+ nnew_pnode->children[0]->tensor_proper_size() == 1) {
+
+ } else if (nnew_pnode->node_type == GA_NODE_OP &&
+ nnew_pnode->op_type == GA_DIV &&
+ nnew_pnode->children[0] == previous_node &&
+ nnew_pnode->children[1]->tensor_proper_size() == 1) {
+
+ } else if (nnew_pnode->node_type == GA_NODE_OP &&
+ nnew_pnode->op_type == GA_COLON &&
+ nnew_pnode->children[0] == previous_node &&
+ nnew_pnode->children[1]->tensor_order() == 2 &&
+ colon_pnode == 0 && cas == 0) {
+ std::swap(nnew_pnode->children[0], nnew_pnode->children[1]);
+ colon_pnode = nnew_pnode;
+ } else if (nnew_pnode->node_type == GA_NODE_OP &&
+ nnew_pnode->op_type == GA_COLON &&
+ nnew_pnode->children[1] == previous_node &&
+ nnew_pnode->children[0]->tensor_order() == 2 &&
+ colon_pnode == 0 && cas == 0) {
+ colon_pnode = nnew_pnode;
+ } else if (nnew_pnode->node_type == GA_NODE_OP &&
+ nnew_pnode->op_type == GA_QUOTE &&
+ colon_pnode == 0 && cas == 0 && !quote_before_colon) {
+ quote_before_colon = true;
+ } else ok = false;
+ }
+
+ // cout << "analyzing factor : " << ga_tree_to_string(factor) << endl;
+ // cout << "ok = " << int(ok) << endl;
+ // cout << "colon_pnode = " << colon_pnode << endl;
+
+ if (ok && cas == 0 && !colon_pnode) ok = false;
+
+ if (N == 1) {
+ new_pnode->node_type = GA_NODE_NORMAL;
+ result = "(" + ga_tree_to_string(factor) + ")";
+ } else if (ok) {
+ switch (cas) {
+ case 0:
+ new_pnode->node_type = GA_NODE_NORMAL;
+ colon_pnode->op_type = GA_MULT;
+ if (quote_before_colon) {
+ factor.insert_node(colon_pnode->children[0], GA_NODE_OP);
+ colon_pnode->children[0]->op_type = GA_QUOTE;
+ nnew_pnode = new_pnode->parent;
+ while(nnew_pnode->node_type != GA_NODE_OP ||
+ nnew_pnode->op_type != GA_QUOTE)
+ nnew_pnode = nnew_pnode->parent;
+ factor.replace_node_by_child(nnew_pnode,0);
+ }
+ break;
+ case 1:
+ new_pnode->node_type = GA_NODE_NORMAL;
+ break;
+ case 2:
+ new_pnode->parent->node_type = GA_NODE_NORMAL;
+ factor.clear_children(new_pnode->parent);
+ break;
+ }
+ result = "(" + ga_tree_to_string(factor) + ")";
+
+ } else {
+ // General case
+
+ result = "[";
+ bgeot::multi_index mi(2); mi[0] = N; mi[1] = meshdim;
+
+ for (size_type i = 0; i < N; ++i) {
+ factor.clear_children(new_pnode);
+ new_pnode->node_type = GA_NODE_C_MATRIX;
+ new_pnode->nbc1 = meshdim;
+ new_pnode->nbc2 = new_pnode->nbc3 = 1;
+ new_pnode->t.adjust_sizes(mi);
+ new_pnode->children.resize(N*meshdim);
+ for (size_type j = 0; j < N; ++j) {
+ for (size_type k = 0; k < meshdim; ++k) {
+ if (j == i) {
+ pga_tree_node param_node = new_pnode->children[k*N+j]
+ = new ga_tree_node(GA_NODE_PARAMS, pnode->pos);
+ new_pnode->children[k*N+j]->parent = new_pnode;
+ param_node->children.resize(2);
+ param_node->children[0] = new ga_tree_node(GA_NODE_NORMAL,
+ pnode->pos);
+ param_node->children[0]->parent = param_node;
+ param_node->children[1] = new ga_tree_node(GA_NODE_CONSTANT,
+ pnode->pos);
+ param_node->children[1]->parent = param_node;
+ param_node->children[1]->init_scalar_tensor(scalar_type(k));
+
+ } else {
+ new_pnode->children[k*N+j] = new ga_tree_node(GA_NODE_ZERO,
+ pnode->pos);
+ new_pnode->children[k*N+j]->init_scalar_tensor(scalar_type(0));
+ new_pnode->children[k*N+j]->parent = new_pnode;
+ }
+ }
+ }
+ result += "(" + ga_tree_to_string(factor) + ")";
+ if (i < N-1) result += ";";
+ }
+ result += "]";
+ GMM_TRACE2("Warning, generic Neumann term used: " << result);
+ }
+
+ return result;
+ }
+
+
+ void ga_extract_Neumann_term
+ (ga_tree &tree, const std::string &varname,
+ ga_workspace &workspace, pga_tree_node pnode, std::string &result) {
+
+ for (size_type i = 0; i < pnode->children.size(); ++i)
+ ga_extract_Neumann_term(tree, varname, workspace,
+ pnode->children[i], result);
+
+
+ switch (pnode->node_type) {
+ case GA_NODE_DIVERG_TEST: case GA_NODE_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_GRAD_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ if (pnode->name.compare(varname) == 0) {
+ if (result.size()) result += " + ";
+ result += ga_extract_one_Neumann_term(varname, workspace, pnode);
+ }
+ break;
+ case GA_NODE_INTERPOLATE_GRAD_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ if (pnode->name.compare(varname) == 0)
+ GMM_ASSERT1(false, "Do not know how to extract a "
+ "Neumann term with an interpolate transformation");
+ break;
+ default:
+ break;
+ }
+ }
+
+ //=========================================================================
+ // Derivation algorithm: derivation of a tree with respect to a variable
+ // The result tree is not ready to use. It has to be passed again in
+ // ga_semantic_analysis for enrichment.
+ //=========================================================================
+
+ static bool ga_node_mark_tree_for_variable
+ (pga_tree_node pnode, const ga_workspace &workspace, const mesh &m,
+ const std::string &varname,
+ const std::string &interpolatename) {
+ bool marked = false;
+ for (size_type i = 0; i < pnode->children.size(); ++i)
+ if (ga_node_mark_tree_for_variable(pnode->children[i], workspace, m,
+ varname, interpolatename))
+ marked = true;
+
+ bool plain_node(pnode->node_type == GA_NODE_VAL ||
+ pnode->node_type == GA_NODE_GRAD ||
+ pnode->node_type == GA_NODE_HESS ||
+ pnode->node_type == GA_NODE_DIVERG);
+ bool interpolate_node(pnode->node_type == GA_NODE_INTERPOLATE_VAL ||
+ pnode->node_type == GA_NODE_INTERPOLATE_GRAD ||
+ pnode->node_type == GA_NODE_INTERPOLATE_HESS ||
+ pnode->node_type == GA_NODE_INTERPOLATE_DIVERG);
+ bool elementary_node(pnode->node_type == GA_NODE_ELEMENTARY_VAL ||
+ pnode->node_type == GA_NODE_ELEMENTARY_GRAD ||
+ pnode->node_type == GA_NODE_ELEMENTARY_HESS ||
+ pnode->node_type == GA_NODE_ELEMENTARY_DIVERG);
+ bool xfem_node(pnode->node_type == GA_NODE_XFEM_PLUS_VAL ||
+ pnode->node_type == GA_NODE_XFEM_PLUS_GRAD ||
+ pnode->node_type == GA_NODE_XFEM_PLUS_HESS ||
+ pnode->node_type == GA_NODE_XFEM_PLUS_DIVERG ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_VAL ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_GRAD ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_HESS ||
+ pnode->node_type == GA_NODE_XFEM_MINUS_DIVERG);
+ bool interpolate_test_node
+ (pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST ||
+ pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST ||
+ pnode->node_type == GA_NODE_INTERPOLATE_HESS_TEST ||
+ pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST);
+
+ if ((plain_node || interpolate_node || elementary_node || xfem_node) &&
+ (pnode->name.compare(varname) == 0 &&
+ pnode->interpolate_name.compare(interpolatename) == 0)) marked = true;
+
+ if (interpolate_node || interpolate_test_node ||
+ pnode->node_type == GA_NODE_INTERPOLATE_X ||
+ pnode->node_type == GA_NODE_INTERPOLATE_NORMAL) {
+ std::set<var_trans_pair> vars;
+ workspace.interpolate_transformation(pnode->interpolate_name)
+ ->extract_variables(workspace, vars, true,
+ m, pnode->interpolate_name);
+ for (std::set<var_trans_pair>::iterator it=vars.begin();
+ it != vars.end(); ++it) {
+ if (it->varname.compare(varname) == 0 &&
+ it->transname.compare(interpolatename) == 0) marked = true;
+ }
+ }
+ pnode->marked = marked;
+ return marked;
+ }
+
+ static void ga_node_derivation(ga_tree &tree, const ga_workspace &workspace,
+ const mesh &m,
+ pga_tree_node pnode,
+ const std::string &varname,
+ const std::string &interpolatename,
+ size_type order) {
+
+ size_type nbch = pnode->children.size();
+ pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
+ pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
+ bool mark0 = ((nbch > 0) ? child0->marked : false);
+ bool mark1 = ((nbch > 1) ? child1->marked : false);
+ bgeot::multi_index mi;
+
+ const ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+
+ switch (pnode->node_type) {
+ case GA_NODE_VAL: case GA_NODE_GRAD:
+ case GA_NODE_HESS: case GA_NODE_DIVERG:
+ mi.resize(1); mi[0] = 2;
+ for (size_type i = 0; i < pnode->tensor_order(); ++i)
+ mi.push_back(pnode->tensor_proper_size(i));
+ pnode->t.adjust_sizes(mi);
+ if (pnode->node_type == GA_NODE_VAL)
+ pnode->node_type = GA_NODE_VAL_TEST;
+ else if (pnode->node_type == GA_NODE_GRAD)
+ pnode->node_type = GA_NODE_GRAD_TEST;
+ else if (pnode->node_type == GA_NODE_HESS)
+ pnode->node_type = GA_NODE_HESS_TEST;
+ else if (pnode->node_type == GA_NODE_DIVERG)
+ pnode->node_type = GA_NODE_DIVERG_TEST;
+ pnode->test_function_type = order;
+ break;
+
+ case GA_NODE_INTERPOLATE_VAL:
+ case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_INTERPOLATE_HESS:
+ case GA_NODE_INTERPOLATE_DIVERG:
+ {
+ bool is_val(pnode->node_type == GA_NODE_INTERPOLATE_VAL);
+ bool is_grad(pnode->node_type == GA_NODE_INTERPOLATE_GRAD);
+ bool is_hess(pnode->node_type == GA_NODE_INTERPOLATE_HESS);
+ bool is_diverg(pnode->node_type == GA_NODE_INTERPOLATE_DIVERG);
+
+ bool ivar = (pnode->name.compare(varname) == 0 &&
+ pnode->interpolate_name.compare(interpolatename) == 0);
+ bool itrans = !ivar;
+ if (!itrans) {
+ std::set<var_trans_pair> vars;
+ workspace.interpolate_transformation(pnode->interpolate_name)
+ ->extract_variables(workspace, vars, true, m,
+ pnode->interpolate_name);
+ for (const var_trans_pair &var : vars) {
+ if (var.varname.compare(varname) == 0 &&
+ var.transname.compare(interpolatename) == 0)
+ itrans = true;
+ }
+ }
+
+ pga_tree_node pnode_trans = pnode;
+ if (is_hess) {
+ GMM_ASSERT1(!itrans, "Sorry, cannot derive a hessian once more");
+ } else if (itrans && ivar) {
+ tree.duplicate_with_addition(pnode);
+ pnode_trans = pnode->parent->children[1];
+ }
+
+ if (ivar) {
+ mi.resize(1); mi[0] = 2;
+ for (size_type i = 0; i < pnode->tensor_order(); ++i)
+ mi.push_back(pnode->tensor_proper_size(i));
+ pnode->t.adjust_sizes(mi);
+ if (is_val) // --> t(Qmult*ndof,Qmult*target_dim)
+ pnode->node_type = GA_NODE_INTERPOLATE_VAL_TEST;
+ else if (is_grad) // --> t(Qmult*ndof,Qmult*target_dim,N)
+ pnode->node_type = GA_NODE_INTERPOLATE_GRAD_TEST;
+ else if (is_hess) // --> t(Qmult*ndof,Qmult*target_dim,N,N)
+ pnode->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
+ else if (is_diverg) // --> t(Qmult*ndof)
+ pnode->node_type = GA_NODE_INTERPOLATE_DIVERG_TEST;
+ pnode->test_function_type = order;
+ }
+
+ if (itrans) {
+ const mesh_fem *mf = workspace.associated_mf(pnode_trans->name);
+ size_type q = workspace.qdim(pnode_trans->name);
+ size_type n = mf->linked_mesh().dim();
+ bgeot::multi_index mii = workspace.qdims(pnode_trans->name);
+
+ if (is_val) // --> t(target_dim*Qmult,N)
+ pnode_trans->node_type = GA_NODE_INTERPOLATE_GRAD;
+ else if (is_grad || is_diverg) // --> t(target_dim*Qmult,N,N)
+ pnode_trans->node_type = GA_NODE_INTERPOLATE_HESS;
+
+ if (n > 1) {
+ if (q == 1 && mii.size() <= 1) { mii.resize(1); mii[0] = n; }
+ else mii.push_back(n);
+
+ if (is_grad || is_diverg) mii.push_back(n);
+ }
+ pnode_trans->t.adjust_sizes(mii);
+ tree.duplicate_with_operation(pnode_trans,
+ (n > 1) ? GA_DOT : GA_MULT);
+ pga_tree_node pnode_der = pnode_trans->parent->children[1];
+ pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
+ if (n == 1)
+ pnode_der->init_vector_tensor(2);
+ else
+ pnode_der->init_matrix_tensor(2, n);
+ pnode_der->test_function_type = order;
+ pnode_der->name = varname;
+ pnode_der->interpolate_name_der = pnode_der->interpolate_name;
+ pnode_der->interpolate_name = interpolatename;
+
+ if (is_diverg) { // --> t(Qmult*ndof)
+ tree.insert_node(pnode_trans->parent, GA_NODE_OP);
+ pga_tree_node pnode_tr = pnode_trans->parent->parent;
+ pnode_tr->op_type = GA_TRACE;
+ pnode_tr->init_vector_tensor(2);
+// pnode_tr->test_function_type = order;
+// pnode_tr->name_test1 = pnode_trans->name_test1;
+// pnode_tr->name_test2 = pnode_trans->name_test2;
+ }
+ }
+ }
+ break;
+
+ case GA_NODE_INTERPOLATE_VAL_TEST:
+ case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ {
+ bool is_val(pnode->node_type == GA_NODE_INTERPOLATE_VAL_TEST);
+ bool is_grad(pnode->node_type == GA_NODE_INTERPOLATE_GRAD_TEST);
+ bool is_diverg(pnode->node_type == GA_NODE_INTERPOLATE_DIVERG_TEST);
+
+ pga_tree_node pnode_trans = pnode;
+ const mesh_fem *mf = workspace.associated_mf(pnode_trans->name);
+ size_type q = workspace.qdim(pnode_trans->name);
+ size_type n = mf->linked_mesh().dim();
+ bgeot::multi_index mii = workspace.qdims(pnode_trans->name);
+ if (is_val) // --> t(Qmult*ndof,Qmult*target_dim,N)
+ pnode_trans->node_type = GA_NODE_INTERPOLATE_GRAD_TEST;
+ else if (is_grad || is_diverg) // -->
t(Qmult*ndof,Qmult*target_dim,N,N)
+ pnode_trans->node_type = GA_NODE_INTERPOLATE_HESS_TEST;
+
+ if (q == 1 && mii.size() <= 1) { mii.resize(1); mii[0] = 2; }
+ else mii.insert(mii.begin(), 2);
+
+ if (n > 1) {
+ mii.push_back(n);
+ if (is_grad || is_diverg) mii.push_back(n);
+ }
+ pnode_trans->t.adjust_sizes(mii);
+ // pnode_trans->test_function_type = order;
+ tree.duplicate_with_operation(pnode_trans,
+ (n > 1 ? GA_DOT : GA_MULT));
+ pga_tree_node pnode_der = pnode_trans->parent->children[1];
+ pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
+ if (n == 1)
+ pnode_der->init_vector_tensor(2);
+ else
+ pnode_der->init_matrix_tensor(2, n);
+ pnode_der->test_function_type = order;
+ pnode_der->name = varname;
+ pnode_der->interpolate_name_der = pnode_der->interpolate_name;
+ pnode_der->interpolate_name = interpolatename;
+
+ if (is_diverg) { // --> t(Qmult*ndof)
+ tree.insert_node(pnode_trans->parent, GA_NODE_OP);
+ pga_tree_node pnode_tr = pnode_trans->parent->parent;
+ pnode_tr->op_type = GA_TRACE;
+ pnode_tr->init_vector_tensor(2);
+// pnode_tr->test_function_type = order;
+// pnode_tr->name_test1 = pnode_trans->name_test1;
+// pnode_tr->name_test2 = pnode_trans->name_test2;
+ }
+ }
+ break;
+
+ case GA_NODE_INTERPOLATE_HESS_TEST:
+ GMM_ASSERT1(false, "Sorry, cannot derive a hessian once more");
+ break;
+
+ case GA_NODE_INTERPOLATE_X:
+ {
+ size_type n = m.dim();
+ pga_tree_node pnode_der = pnode;
+ pnode_der->node_type = GA_NODE_INTERPOLATE_DERIVATIVE;
+ if (n == 1)
+ pnode_der->init_vector_tensor(2);
+ else
+ pnode_der->init_matrix_tensor(2, n);
+ pnode_der->test_function_type = order;
+ pnode_der->name = varname;
+ pnode_der->interpolate_name_der = pnode_der->interpolate_name;
+ pnode_der->interpolate_name = interpolatename;
+ }
+ break;
+
+ case GA_NODE_INTERPOLATE_NORMAL:
+ GMM_ASSERT1(false, "Sorry, cannot derive the interpolated Normal");
+ break;
+
+ case GA_NODE_INTERPOLATE_DERIVATIVE:
+ GMM_ASSERT1(false, "Sorry, second order transformation derivative "
+ "not taken into account");
+ break;
+
+ case GA_NODE_INTERPOLATE_FILTER:
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ break;
+
+ case GA_NODE_ELEMENTARY_VAL:
+ case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_ELEMENTARY_HESS:
+ case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_XFEM_PLUS_VAL:
+ case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_PLUS_HESS:
+ case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_VAL:
+ case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_XFEM_MINUS_HESS:
+ case GA_NODE_XFEM_MINUS_DIVERG:
+ mi.resize(1); mi[0] = 2;
+ for (size_type i = 0; i < pnode->tensor_order(); ++i)
+ mi.push_back(pnode->tensor_proper_size(i));
+ pnode->t.adjust_sizes(mi);
+ switch(pnode->node_type) {
+ case GA_NODE_ELEMENTARY_VAL:
+ pnode->node_type = GA_NODE_ELEMENTARY_VAL_TEST; break;
+ case GA_NODE_ELEMENTARY_GRAD:
+ pnode->node_type = GA_NODE_ELEMENTARY_GRAD_TEST; break;
+ case GA_NODE_ELEMENTARY_HESS:
+ pnode->node_type = GA_NODE_ELEMENTARY_HESS_TEST; break;
+ case GA_NODE_ELEMENTARY_DIVERG:
+ pnode->node_type = GA_NODE_ELEMENTARY_DIVERG_TEST; break;
+ case GA_NODE_XFEM_PLUS_VAL:
+ pnode->node_type = GA_NODE_XFEM_PLUS_VAL_TEST; break;
+ case GA_NODE_XFEM_PLUS_GRAD:
+ pnode->node_type = GA_NODE_XFEM_PLUS_GRAD_TEST; break;
+ case GA_NODE_XFEM_PLUS_HESS:
+ pnode->node_type = GA_NODE_XFEM_PLUS_HESS_TEST; break;
+ case GA_NODE_XFEM_PLUS_DIVERG:
+ pnode->node_type = GA_NODE_XFEM_PLUS_DIVERG_TEST; break;
+ case GA_NODE_XFEM_MINUS_VAL:
+ pnode->node_type = GA_NODE_XFEM_MINUS_VAL_TEST; break;
+ case GA_NODE_XFEM_MINUS_GRAD:
+ pnode->node_type = GA_NODE_XFEM_MINUS_GRAD_TEST; break;
+ case GA_NODE_XFEM_MINUS_HESS:
+ pnode->node_type = GA_NODE_XFEM_MINUS_HESS_TEST; break;
+ case GA_NODE_XFEM_MINUS_DIVERG:
+ pnode->node_type = GA_NODE_XFEM_MINUS_DIVERG_TEST; break;
+ default : GMM_ASSERT1(false, "internal error");
+ }
+ pnode->test_function_type = order;
+ break;
+
+ case GA_NODE_OP:
+ switch(pnode->op_type) {
+ case GA_PLUS: case GA_MINUS:
+ if (mark0 && mark1) {
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ ga_node_derivation(tree, workspace, m, child1, varname,
+ interpolatename, order);
+ } else if (mark0) {
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ tree.replace_node_by_child(pnode, 0);
+ } else {
+ ga_node_derivation(tree, workspace, m, child1, varname,
+ interpolatename, order);
+ if (pnode->op_type == GA_MINUS) {
+ pnode->op_type = GA_UNARY_MINUS;
+ tree.clear_node(child0);
+ }
+ else
+ tree.replace_node_by_child(pnode, 1);
+ }
+ break;
+
+ case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
+ case GA_TRACE: case GA_DEVIATOR: case GA_PRINT:
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ break;
+
+ case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
+ case GA_DOTMULT:
+ if (mark0 && mark1) {
+ if (sub_tree_are_equal(child0, child1, workspace, 0) &&
+ (pnode->op_type != GA_MULT || child0->tensor_order() < 2)) {
+ ga_node_derivation(tree, workspace, m, child1, varname,
+ interpolatename, order);
+ tree.insert_node(pnode, GA_NODE_OP);
+ pnode->parent->op_type = GA_MULT;
+ tree.add_child(pnode->parent);
+ pnode->parent->children[1]->node_type = GA_NODE_CONSTANT;
+ pnode->parent->children[1]->init_scalar_tensor(scalar_type(2));
+ } else {
+ tree.duplicate_with_addition(pnode);
+ if ((pnode->op_type == GA_COLON && child0->tensor_order() == 2) ||
+ (pnode->op_type == GA_DOT && child0->tensor_order() == 1) ||
+ pnode->op_type == GA_DOTMULT ||
+ (child0->tensor_proper_size()== 1 &&
+ child1->tensor_proper_size()== 1))
+ std::swap(pnode->children[0], pnode->children[1]);
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ ga_node_derivation(tree, workspace, m,
+ pnode->parent->children[1]->children[1],
+ varname, interpolatename, order);
+ }
+ } else if (mark0) {
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ } else
+ ga_node_derivation(tree, workspace, m, child1, varname,
+ interpolatename, order);
+ break;
+
+ case GA_DIV: case GA_DOTDIV:
+ if (mark1) {
+ if (pnode->children[0]->node_type == GA_NODE_CONSTANT)
+ gmm::scale(pnode->children[0]->tensor().as_vector(),
+ scalar_type(-1));
+ else {
+ if (mark0) {
+ tree.duplicate_with_subtraction(pnode);
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ pnode = pnode->parent->children[1];
+ } else {
+ tree.insert_node(pnode, GA_NODE_OP);
+ pnode->parent->op_type = GA_UNARY_MINUS;
+ }
+ }
+ tree.insert_node(pnode->children[1], GA_NODE_PARAMS);
+ pga_tree_node pnode_param = pnode->children[1];
+ tree.add_child(pnode_param);
+ std::swap(pnode_param->children[0], pnode_param->children[1]);
+ pnode_param->children[0]->node_type = GA_NODE_PREDEF_FUNC;
+ pnode_param->children[0]->name = "sqr";
+ tree.insert_node(pnode, GA_NODE_OP);
+ pga_tree_node pnode_mult = pnode->parent;
+ if (pnode->op_type == GA_DOTDIV)
+ pnode_mult->op_type = GA_DOTMULT;
+ else
+ pnode_mult->op_type = GA_MULT;
+ pnode_mult->children.resize(2, nullptr);
+ tree.copy_node(pnode_param->children[1],
+ pnode_mult, pnode_mult->children[1]);
+ ga_node_derivation(tree, workspace, m, pnode_mult->children[1],
+ varname, interpolatename, order);
+ } else {
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ }
+ break;
+
+ default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
+ }
+ break;
+
+ case GA_NODE_C_MATRIX:
+ for (size_type i = 0; i < pnode->children.size(); ++i) {
+ if (pnode->children[i]->marked)
+ ga_node_derivation(tree, workspace, m, pnode->children[i],
+ varname, interpolatename, order);
+ else {
+ pnode->children[i]->init_scalar_tensor(scalar_type(0));
+ pnode->children[i]->node_type = GA_NODE_ZERO;
+ tree.clear_children(pnode->children[i]);
+ }
+ }
+ break;
+
+ case GA_NODE_PARAMS:
+ if (child0->node_type == GA_NODE_RESHAPE) {
+ ga_node_derivation(tree, workspace, m, pnode->children[1],
+ varname, interpolatename, order);
+ } else if (child0->node_type == GA_NODE_PREDEF_FUNC) {
+ std::string name = child0->name;
+ ga_predef_function_tab::const_iterator it =
PREDEF_FUNCTIONS.find(name);
+ const ga_predef_function &F = it->second;
+
+ if (F.nbargs() == 1) {
+ switch (F.dtype()) {
+ case 0:
+ GMM_ASSERT1(false, "Cannot derive function " << child0->name
+ << ". No derivative provided or not derivable function.");
+ case 1:
+ child0->name = F.derivative1();
+ break;
+ case 2: case 3:
+ {
+ child0->name = "DER_PDFUNC_" + child0->name;
+ if (!(ga_function_exists(child0->name))) {
+ if (F.dtype() == 2)
+ ga_define_function(child0->name, 1, F.derivative1());
+ else {
+ std::string expr=ga_derivative_scalar_function(F.expr(),"t");
+ ga_define_function(child0->name, 1, expr);
+ }
+ }
+ // Inline extension if the derivative is affine (for instance
+ // for sqr)
+ ga_predef_function_tab::const_iterator
+ itp = PREDEF_FUNCTIONS.find(child0->name);
+ const ga_predef_function &Fp = itp->second;
+ if (Fp.is_affine("t")) {
+ scalar_type b = Fp(scalar_type(0));
+ scalar_type a = Fp(scalar_type(1)) - b;
+ pnode->node_type = GA_NODE_OP;
+ pnode->op_type = GA_MULT;
+ child0->init_scalar_tensor(a);
+ child0->node_type = ((a == scalar_type(0)) ?
+ GA_NODE_ZERO : GA_NODE_CONSTANT);
+ if (b != scalar_type(0)) {
+ tree.insert_node(pnode, GA_NODE_OP);
+ pnode->parent->op_type = (b > 0) ? GA_PLUS : GA_MINUS;
+ tree.add_child(pnode->parent);
+ pga_tree_node pnode_cte = pnode->parent->children[1];
+ pnode_cte->node_type = GA_NODE_CONSTANT;
+ pnode_cte->t = pnode->t;
+ std::fill(pnode_cte->tensor().begin(),
+ pnode_cte->tensor().end(), gmm::abs(b));
+ pnode = pnode->parent;
+ }
+ }
+ }
+ break;
+ }
+ if (pnode->children.size() >= 2) {
+ tree.insert_node(pnode, GA_NODE_OP);
+ pga_tree_node pnode_op = pnode->parent;
+ if (child1->tensor_order() == 0)
+ pnode_op->op_type = GA_MULT;
+ else
+ pnode_op->op_type = GA_DOTMULT;
+ pnode_op->children.resize(2, nullptr);
+ tree.copy_node(child1, pnode_op, pnode_op->children[1]);
+ ga_node_derivation(tree, workspace, m, pnode_op->children[1],
+ varname, interpolatename, order);
+ }
+ } else {
+ pga_tree_node child2 = pnode->children[2];
+
+ if (child1->marked && child2->marked)
+ tree.duplicate_with_addition(pnode);
+
+ if (child1->marked) {
+ switch (F.dtype()) {
+ case 0:
+ GMM_ASSERT1(false, "Cannot derive function " << child0->name
+ << ". No derivative provided");
+ case 1:
+ child0->name = F.derivative1();
+ break;
+ case 2:
+ child0->name = "DER_PDFUNC1_" + child0->name;
+ if (!(ga_function_exists(child0->name)))
+ ga_define_function(child0->name, 2, F.derivative1());
+ break;
+ case 3:
+ child0->name = "DER_PDFUNC1_" + child0->name;
+ if (!(ga_function_exists(child0->name))) {
+ std::string expr = ga_derivative_scalar_function(F.expr(),
"t");
+ ga_define_function(child0->name, 2, expr);
+ }
+ break;
+ }
+ tree.insert_node(pnode, GA_NODE_OP);
+ pga_tree_node pnode_op = pnode->parent;
+ if (child1->tensor_order() == 0)
+ pnode_op->op_type = GA_MULT;
+ else
+ pnode_op->op_type = GA_DOTMULT;
+ pnode_op->children.resize(2, nullptr);
+ tree.copy_node(child1, pnode_op, pnode_op->children[1]);
+ ga_node_derivation(tree, workspace, m, pnode_op->children[1],
+ varname, interpolatename, order);
+ }
+ if (child2->marked) {
+ if (child1->marked && child2->marked)
+ pnode = pnode->parent->parent->children[1];
+ child0 = pnode->children[0]; child1 = pnode->children[1];
+ child2 = pnode->children[2];
+
+ switch (F.dtype()) {
+ case 0:
+ GMM_ASSERT1(false, "Cannot derive function " << child0->name
+ << ". No derivative provided");
+ case 1:
+ child0->name = F.derivative2();
+ break;
+ case 2:
+ child0->name = "DER_PDFUNC2_" + child0->name;
+ if (!(ga_function_exists(child0->name)))
+ ga_define_function(child0->name, 2, F.derivative2());
+ break;
+ case 3:
+ child0->name = "DER_PDFUNC2_" + child0->name;
+ if (!(ga_function_exists(child0->name))) {
+ std::string expr = ga_derivative_scalar_function(F.expr(),
"u");
+ ga_define_function(child0->name, 2, expr);
+ }
+ break;
+ }
+ tree.insert_node(pnode, GA_NODE_OP);
+ pga_tree_node pnode_op = pnode->parent;
+ if (child2->tensor_order() == 0)
+ pnode_op->op_type = GA_MULT;
+ else
+ pnode_op->op_type = GA_DOTMULT;
+ pnode_op->children.resize(2, nullptr);
+ tree.copy_node(child2, pnode_op, pnode_op->children[1]);
+ ga_node_derivation(tree, workspace, m, pnode_op->children[1],
+ varname, interpolatename, order);
+ }
+ }
+ } else if (child0->node_type == GA_NODE_SPEC_FUNC) {
+ GMM_ASSERT1(false, "internal error");
+ } else if (child0->node_type == GA_NODE_OPERATOR) {
+ if (child0->der2)
+ GMM_ASSERT1(false, "Error in derivation of the assembly string. "
+ "Cannot derive again operator " << child0->name);
+
+ size_type nbargs_der = 0;
+ for (size_type i = 1; i < pnode->children.size(); ++i)
+ if (pnode->children[i]->marked) ++nbargs_der;
+ pga_tree_node pnode2 = 0;
+
+ size_type j = 0;
+ for (size_type i = 1; i < pnode->children.size(); ++i) {
+ if (pnode->children[i]->marked) {
+ ++j;
+ if (j != nbargs_der) {
+ tree.insert_node(pnode, GA_NODE_OP);
+ pga_tree_node pnode_op = pnode->parent;
+ pnode_op->node_type = GA_NODE_OP;
+ pnode_op->op_type = GA_PLUS;
+ pnode_op->children.resize(2, nullptr);
+ tree.copy_node(pnode, pnode_op , pnode_op->children[1]);
+ pnode2 = pnode_op->children[1];
+ }
+ else pnode2 = pnode;
+
+ if (child0->der1)
+ pnode2->children[0]->der2 = i;
+ else
+ pnode2->children[0]->der1 = i;
+ tree.insert_node(pnode2, GA_NODE_OP);
+ pga_tree_node pnode_op = pnode2->parent;
+ // calcul de l'ordre de reduction
+ size_type red = pnode->children[i]->tensor_order();
+ switch (red) {
+ case 0 : pnode_op->op_type = GA_MULT; break;
+ case 1 : pnode_op->op_type = GA_DOT; break;
+ case 2 : pnode_op->op_type = GA_COLON; break;
+ default: GMM_ASSERT1(false, "Error in derivation of the assembly "
+ "string. Bad reduction order.")
+ }
+ pnode_op->children.resize(2, nullptr);
+ tree.copy_node(pnode->children[i], pnode_op,
+ pnode_op->children[1]);
+ ga_node_derivation(tree, workspace, m, pnode_op->children[1],
+ varname, interpolatename, order);
+
+ if (pnode2->children[0]->name.compare("Norm_sqr") == 0
+ && pnode2->children[0]->der1 == 1) {
+ pnode2->node_type = GA_NODE_OP;
+ pnode2->op_type = GA_MULT;
+ pnode2->children[0]->node_type = GA_NODE_CONSTANT;
+ pnode2->children[0]->init_scalar_tensor(scalar_type(2));
+ }
+
+
+ }
+ }
+
+ } else {
+ ga_node_derivation(tree, workspace, m, child0, varname,
+ interpolatename, order);
+ }
+ break;
+
+ default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
+ << " in derivation. Internal error.");
+ }
+ }
+
+ // The tree is modified. Should be copied first and passed to
+ // ga_semantic_analysis after for enrichment
+ void ga_derivative(ga_tree &tree, const ga_workspace &workspace,
+ const mesh &m, const std::string &varname,
+ const std::string &interpolatename,
+ size_type order) {
+ // cout << "compute derivative of " << ga_tree_to_string(tree)
+ // << " with respect to " << varname << " : " << interpolatename << endl;
+ if (!(tree.root)) return;
+ if (ga_node_mark_tree_for_variable(tree.root, workspace, m, varname,
+ interpolatename))
+ ga_node_derivation(tree, workspace, m, tree.root, varname,
+ interpolatename, order);
+ else
+ tree.clear();
+ // cout << "derived tree : " << ga_tree_to_string(tree) << endl;
+ }
+
+ static void ga_replace_test_by_cte(pga_tree_node pnode, bool full_replace) {
+ for (size_type i = 0; i < pnode->children.size(); ++i)
+ ga_replace_test_by_cte(pnode->children[i], full_replace);
+ GMM_ASSERT1(pnode->node_type != GA_NODE_GRAD_TEST, "Invalid tree");
+ GMM_ASSERT1(pnode->node_type != GA_NODE_HESS_TEST, "Invalid tree");
+ GMM_ASSERT1(pnode->node_type != GA_NODE_DIVERG_TEST, "Invalid tree");
+ if (pnode->node_type == GA_NODE_VAL_TEST) {
+ pnode->node_type = GA_NODE_CONSTANT;
+ if (full_replace) pnode->init_scalar_tensor(scalar_type(1));
+ }
+ }
+
+ std::string ga_derivative_scalar_function(const std::string &expr,
+ const std::string &var) {
+ base_vector t(1), u(1);
+ ga_workspace workspace;
+ workspace.add_fixed_size_variable("t", gmm::sub_interval(0,1), t);
+ workspace.add_fixed_size_variable("u", gmm::sub_interval(0,1), u);
+ workspace.add_function_expression(expr);
+ GMM_ASSERT1(workspace.nb_trees() <= 1, "Internal error");
+ if (workspace.nb_trees()) {
+ ga_tree tree = *(workspace.tree_info(0).ptree);
+ ga_derivative(tree, workspace, *((const mesh *)(0)), var, "", 1);
+ if (tree.root) {
+ ga_replace_test_by_cte(tree.root, true);
+ ga_semantic_analysis(expr, tree, workspace, 1, 1, false, true);
+ }
+ return ga_tree_to_string(tree);
+ } else return "0";
+ }
+
+ static bool ga_node_is_affine(const pga_tree_node pnode) {
+
+ size_type nbch = pnode->children.size();
+ pga_tree_node child0 = (nbch > 0) ? pnode->children[0] : 0;
+ pga_tree_node child1 = (nbch > 1) ? pnode->children[1] : 0;
+ bool mark0 = ((nbch > 0) ? child0->marked : false);
+ bool mark1 = ((nbch > 1) ? child1->marked : false);
+
+ switch (pnode->node_type) {
+ case GA_NODE_VAL: case GA_NODE_GRAD:
+ case GA_NODE_HESS: case GA_NODE_DIVERG:
+ case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
+ case GA_NODE_INTERPOLATE_DERIVATIVE:
+ case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
+ return true;
+ case GA_NODE_OP:
+ switch(pnode->op_type) {
+ case GA_PLUS: case GA_MINUS:
+ if (mark0 && mark1)
+ return ga_node_is_affine(child0) &&
+ ga_node_is_affine(child1);
+ if (mark0) return ga_node_is_affine(child0);
+ return ga_node_is_affine(child1);
+
+ case GA_UNARY_MINUS: case GA_QUOTE: case GA_SYM: case GA_SKEW:
+ case GA_TRACE: case GA_DEVIATOR:
+ case GA_PRINT: case GA_NODE_INTERPOLATE_FILTER:
+ return ga_node_is_affine(child0);
+
+ case GA_DOT: case GA_MULT: case GA_COLON: case GA_TMULT:
+ case GA_DOTMULT:
+ if (mark0 && mark1) return false;
+ if (mark0) return ga_node_is_affine(child0);
+ return ga_node_is_affine(child1);
+
+ case GA_DIV: case GA_DOTDIV:
+ if (mark1) return false;
+ if (mark0) return ga_node_is_affine(child0);
+
+ default: GMM_ASSERT1(false, "Unexpected operation. Internal error.");
+ }
+ break;
+
+ case GA_NODE_C_MATRIX:
+ for (size_type i = 0; i < pnode->children.size(); ++i)
+ if (pnode->children[i]->marked &&
+ !(ga_node_is_affine(pnode->children[i])))
+ return false;
+ return true;
+
+ case GA_NODE_PARAMS:
+ if (child0->node_type == GA_NODE_RESHAPE)
+ return ga_node_is_affine(child1);
+ if (child0->node_type == GA_NODE_PREDEF_FUNC)
+ return false;
+ if (child0->node_type == GA_NODE_OPERATOR)
+ return false;
+ return ga_node_is_affine(child0);
+
+ default: GMM_ASSERT1(false, "Unexpected node type " << pnode->node_type
+ << " in derivation. Internal error.");
+ }
+ }
+
+ bool ga_is_affine(const ga_tree &tree, const ga_workspace &workspace,
+ const std::string &varname,
+ const std::string &interpolatename) {
+ const mesh &m = *((const mesh *)(0));
+ if (tree.root && ga_node_mark_tree_for_variable(tree.root, workspace, m,
+ varname, interpolatename))
+ return ga_node_is_affine(tree.root);
+ return true;
+ }
+
+} /* end of namespace */
diff --git a/src/getfem_generic_assembly_tree.cc
b/src/getfem_generic_assembly_tree.cc
new file mode 100644
index 0000000..7f9ce6c
--- /dev/null
+++ b/src/getfem_generic_assembly_tree.cc
@@ -0,0 +1,1597 @@
+/*===========================================================================
+
+ Copyright (C) 2013-2018 Yves Renard
+
+ This file is a part of GetFEM++
+
+ GetFEM++ is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+===========================================================================*/
+
+#include "getfem/getfem_generic_assembly_tree.h"
+#include "getfem/getfem_generic_assembly_functions_and_operators.h"
+
+
+namespace getfem {
+
+ //=========================================================================
+ // Lexical analysis for the generic assembly language
+ //=========================================================================
+
+ static GA_TOKEN_TYPE ga_char_type[256];
+ static int ga_operator_priorities[GA_NB_TOKEN_TYPE];
+
+ // Initialize ga_char_type and ga_operator_priorities arrays
+ static bool init_ga_char_type() {
+ for (int i = 0; i < 256; ++i) ga_char_type[i] = GA_INVALID;
+ ga_char_type['+'] = GA_PLUS; ga_char_type['-'] = GA_MINUS;
+ ga_char_type['*'] = GA_MULT; ga_char_type['/'] = GA_DIV;
+ ga_char_type[':'] = GA_COLON; ga_char_type['\''] = GA_QUOTE;
+ ga_char_type['.'] = GA_DOT; ga_char_type['@'] = GA_TMULT;
+ ga_char_type[','] = GA_COMMA; ga_char_type[';'] = GA_SEMICOLON;
+ ga_char_type['('] = GA_LPAR; ga_char_type[')'] = GA_RPAR;
+ ga_char_type['['] = GA_LBRACKET; ga_char_type[']'] = GA_RBRACKET;
+ ga_char_type['_'] = GA_NAME;
+ for (unsigned i = 'a'; i <= 'z'; ++i) ga_char_type[i] = GA_NAME;
+ for (unsigned i = 'A'; i <= 'Z'; ++i) ga_char_type[i] = GA_NAME;
+ for (unsigned i = '0'; i <= '9'; ++i) ga_char_type[i] = GA_SCALAR;
+
+ for (unsigned i = 0; i < GA_NB_TOKEN_TYPE; ++i)
+ ga_operator_priorities[i] = 0;
+ ga_operator_priorities[GA_PLUS] = 1;
+ ga_operator_priorities[GA_MINUS] = 1;
+ ga_operator_priorities[GA_MULT] = 2;
+ ga_operator_priorities[GA_DIV] = 2;
+ ga_operator_priorities[GA_COLON] = 2;
+ ga_operator_priorities[GA_DOT] = 2;
+ ga_operator_priorities[GA_DOTMULT] = 2;
+ ga_operator_priorities[GA_DOTDIV] = 2;
+ ga_operator_priorities[GA_TMULT] = 2;
+ ga_operator_priorities[GA_QUOTE] = 3;
+ ga_operator_priorities[GA_UNARY_MINUS] = 3;
+ ga_operator_priorities[GA_SYM] = 4;
+ ga_operator_priorities[GA_SKEW] = 4;
+ ga_operator_priorities[GA_TRACE] = 4;
+ ga_operator_priorities[GA_DEVIATOR] = 4;
+ ga_operator_priorities[GA_PRINT] = 4;
+
+ return true;
+ }
+
+ static bool ga_initialized = init_ga_char_type();
+
+ // Get the next token in the string at position 'pos' end return its type
+ static GA_TOKEN_TYPE ga_get_token(const std::string &expr,
+ size_type &pos,
+ size_type &token_pos,
+ size_type &token_length) {
+ bool fdot = false, fE = false;
+ GMM_ASSERT1(ga_initialized, "Internal error");
+
+ // Ignore white spaces
+ while (expr[pos] == ' ' && pos < expr.size()) ++pos;
+ token_pos = pos;
+ token_length = 0;
+
+ // Detecting end of expression
+ if (pos >= expr.size()) return GA_END;
+
+ // Treating the different cases (Operation, name or number)
+ GA_TOKEN_TYPE type = ga_char_type[unsigned(expr[pos])];
+ ++pos; ++token_length;
+ switch (type) {
+ case GA_DOT:
+ if (pos >= expr.size()) return type;
+ if (expr[pos] == '*') { ++pos; ++token_length; return GA_DOTMULT; }
+ if (expr[pos] == '/') { ++pos; ++token_length; return GA_DOTDIV; }
+ if (ga_char_type[unsigned(expr[pos])] != GA_SCALAR)
+ return type;
+ fdot = true; type = GA_SCALAR;
+ case GA_SCALAR:
+ while (pos < expr.size()) {
+ GA_TOKEN_TYPE ctype = ga_char_type[unsigned(expr[pos])];
+ switch (ctype) {
+ case GA_DOT:
+ if (fdot) return type;
+ fdot = true; ++pos; ++token_length;
+ break;
+ case GA_NAME:
+ if (fE || (expr[pos] != 'E' && expr[pos] != 'e')) return type;
+ fE = true; fdot = true; ++pos; ++token_length;
+ if (pos < expr.size()) {
+ if (expr[pos] == '+' || expr[pos] == '-')
+ { ++pos; ++token_length; }
+ }
+ if (pos >= expr.size()
+ || ga_char_type[unsigned(expr[pos])] != GA_SCALAR)
+ return GA_INVALID;
+ break;
+ case GA_SCALAR:
+ ++pos; ++token_length; break;
+ default:
+ return type;
+ }
+ }
+ return type;
+ case GA_NAME:
+ while (pos < expr.size()) {
+ GA_TOKEN_TYPE ctype = ga_char_type[unsigned(expr[pos])];
+ if (ctype != GA_SCALAR && ctype != GA_NAME) break;
+ ++pos; ++token_length;
+ }
+ if (expr.compare(token_pos, token_length, "Sym") == 0)
+ return GA_SYM;
+ if (expr.compare(token_pos, token_length, "Skew") == 0)
+ return GA_SKEW;
+ if (expr.compare(token_pos, token_length, "Trace") == 0)
+ return GA_TRACE;
+ if (expr.compare(token_pos, token_length, "Deviator") == 0)
+ return GA_DEVIATOR;
+ if (expr.compare(token_pos, token_length, "Interpolate") == 0)
+ return GA_INTERPOLATE;
+ if (expr.compare(token_pos, token_length, "Interpolate_filter") == 0)
+ return GA_INTERPOLATE_FILTER;
+ if (expr.compare(token_pos, token_length,
+ "Elementary_transformation") == 0)
+ return GA_ELEMENTARY;
+ if (expr.compare(token_pos, token_length, "Xfem_plus") == 0)
+ return GA_XFEM_PLUS;
+ if (expr.compare(token_pos, token_length, "Xfem_minus") == 0)
+ return GA_XFEM_MINUS;
+ if (expr.compare(token_pos, token_length, "Print") == 0)
+ return GA_PRINT;
+ return type;
+ case GA_COMMA:
+ if (pos < expr.size() &&
+ ga_char_type[unsigned(expr[pos])] == GA_COMMA) {
+ ++pos; return GA_DCOMMA;
+ }
+ return type;
+ case GA_SEMICOLON:
+ if (pos < expr.size() &&
+ ga_char_type[unsigned(expr[pos])] == GA_SEMICOLON) {
+ ++pos; return GA_DSEMICOLON;
+ }
+ return type;
+ default: return type;
+ }
+ }
+
+
+ //=========================================================================
+ // Error handling
+ //=========================================================================
+
+ void ga_throw_error_msg(const std::string &expr, size_type pos,
+ const std::string &msg) {
+ int length_before = 70, length_after = 70;
+ if (expr.size()) {
+ int first = std::max(0, int(pos)-length_before);
+ int last = std::min(int(pos)+length_after, int(expr.size()));
+ if (last - first < length_before+length_after)
+ first = std::max(0, int(pos)-length_before
+ -(length_before+length_after-last+first));
+ if (last - first < length_before+length_after)
+ last = std::min(int(pos)+length_after
+ +(length_before+length_after-last+first),
+ int(expr.size()));
+ if (first > 0) cerr << "...";
+ cerr << expr.substr(first, last-first);
+ if (last < int(expr.size())) cerr << "...";
+ cerr << endl;
+ if (first > 0) cerr << " ";
+ if (int(pos) > first)
+ cerr << std::setfill ('-') << std::setw(int(pos)-first) << '-'
+ << std::setfill (' ');
+ cerr << "^" << endl;
+ }
+ cerr << msg << endl;
+ }
+
+ //=========================================================================
+ // Tree structure
+ //=========================================================================
+
+ void ga_tree_node::mult_test(const pga_tree_node n0, const pga_tree_node n1,
+ const std::string &expr) {
+
+ size_type test0 = n0->test_function_type, test1 = n1->test_function_type;
+ if (test0 && test1 && (test0 == test1 ||
+ test0 >= 3 || test1 >= 3))
+ ga_throw_error(expr, pos,
+ "Incompatibility of test functions in product.");
+ GMM_ASSERT1(test0 != size_type(-1) && test1 != size_type(-1),
+ "internal error");
+
+ test_function_type = test0 + test1;
+
+ size_type st = nb_test_functions();
+ bgeot::multi_index mi(st);
+
+ switch (test0) {
+ case 1: mi[0] = n0->t.sizes()[0]; break;
+ case 2: mi[st-1] = n0->t.sizes()[0]; break;
+ case 3: mi[0] = n0->t.sizes()[0]; mi[1] = n0->t.sizes()[1]; break;
+ }
+ switch (test1) {
+ case 1: mi[0] = n1->t.sizes()[0]; break;
+ case 2: mi[st-1] = n1->t.sizes()[0]; break;
+ case 3: mi[0] = n1->t.sizes()[0]; mi[1] = n1->t.sizes()[1]; break;
+ }
+
+ if (n0->name_test1.size()) {
+ name_test1 = n0->name_test1; qdim1 = n0->qdim1;
+ interpolate_name_test1 = n0->interpolate_name_test1;
+ } else {
+ name_test1 = n1->name_test1; qdim1 = n1->qdim1;
+ interpolate_name_test1 = n1->interpolate_name_test1;
+ }
+
+ if (n0->name_test2.size()) {
+ name_test2 = n0->name_test2; qdim2 = n0->qdim2;
+ interpolate_name_test2 = n0->interpolate_name_test2;
+ } else {
+ name_test2 = n1->name_test2; qdim2 = n1->qdim2;
+ interpolate_name_test2 = n1->interpolate_name_test2;
+ }
+ t.adjust_sizes(mi);
+ }
+
+ void ga_tree::add_scalar(scalar_type val, size_type pos) {
+ while (current_node && current_node->node_type != GA_NODE_OP)
+ current_node = current_node->parent;
+ if (current_node) {
+ current_node->adopt_child(new ga_tree_node(val, pos));
+ current_node = current_node->children.back();
+ }
+ else {
+ GMM_ASSERT1(root == nullptr, "Invalid tree operation");
+ current_node = root = new ga_tree_node(val, pos);
+ root->parent = nullptr;
+ }
+ }
+
+ void ga_tree::add_allindices(size_type pos) {
+ while (current_node && current_node->node_type != GA_NODE_OP)
+ current_node = current_node->parent;
+ if (current_node) {
+ current_node->adopt_child(new ga_tree_node(GA_NODE_ALLINDICES, pos));
+ current_node = current_node->children.back();
+ }
+ else {
+ GMM_ASSERT1(root == nullptr, "Invalid tree operation");
+ current_node = root = new ga_tree_node(GA_NODE_ALLINDICES, pos);
+ root->parent = nullptr;
+ }
+ }
+
+ void ga_tree::add_name(const char *name, size_type length, size_type pos) {
+ while (current_node && current_node->node_type != GA_NODE_OP)
+ current_node = current_node->parent;
+ if (current_node) {
+ current_node->adopt_child(new ga_tree_node(name, length, pos));
+ current_node = current_node->children.back();
+ }
+ else {
+ GMM_ASSERT1(root == nullptr, "Invalid tree operation");
+ current_node = root = new ga_tree_node(name, length, pos);
+ root->parent = nullptr;
+ }
+ }
+
+ void ga_tree::add_sub_tree(ga_tree &sub_tree) {
+ if (current_node &&
+ (current_node->node_type == GA_NODE_PARAMS ||
+ current_node->node_type == GA_NODE_INTERPOLATE_FILTER ||
+ current_node->node_type == GA_NODE_C_MATRIX)) {
+ GMM_ASSERT1(sub_tree.root, "Invalid tree operation");
+ current_node->adopt_child(sub_tree.root);
+ } else {
+ GMM_ASSERT1(sub_tree.root, "Invalid tree operation");
+ while (current_node && current_node->node_type != GA_NODE_OP)
+ current_node = current_node->parent;
+ if (current_node) {
+ current_node->adopt_child(sub_tree.root);
+ current_node = sub_tree.root;
+ }
+ else {
+ GMM_ASSERT1(root == nullptr, "Invalid tree operation");
+ current_node = root = sub_tree.root;
+ root->parent = nullptr;
+ }
+ }
+ sub_tree.root = sub_tree.current_node = nullptr;
+ }
+
+ void ga_tree::add_params(size_type pos) {
+ GMM_ASSERT1(current_node, "internal error");
+ while (current_node && current_node->parent &&
+ current_node->parent->node_type == GA_NODE_OP &&
+ ga_operator_priorities[current_node->parent->op_type] >= 4)
+ current_node = current_node->parent;
+ pga_tree_node new_node = new ga_tree_node(GA_NODE_PARAMS, pos);
+ new_node->parent = current_node->parent;
+ if (current_node->parent)
+ current_node->parent->replace_child(current_node, new_node);
+ else
+ root = new_node;
+ new_node->adopt_child(current_node);
+ current_node = new_node;
+ }
+
+ void ga_tree::add_matrix(size_type pos) {
+ while (current_node && current_node->node_type != GA_NODE_OP)
+ current_node = current_node->parent;
+ if (current_node) {
+ current_node->adopt_child(new ga_tree_node(GA_NODE_C_MATRIX, pos));
+ current_node = current_node->children.back();
+ }
+ else {
+ GMM_ASSERT1(root == nullptr, "Invalid tree operation");
+ current_node = root = new ga_tree_node(GA_NODE_C_MATRIX, pos);
+ root->parent = nullptr;
+ }
+ current_node->nbc1 = current_node->nbc2 = current_node->nbc3 = 0;
+ }
+
+ void ga_tree::zip_matrix(const pga_tree_node source_node) {
+ GMM_ASSERT1(current_node->node_type == GA_NODE_C_MATRIX &&
+ source_node->node_type == GA_NODE_C_MATRIX,
+ "Internal error");
+ size_type target_size = current_node->children.size();
+ size_type source_size = source_node->children.size();
+ size_type last_dim_size = target_size/source_size;
+ GMM_ASSERT1(target_size == source_size*last_dim_size,
+ "Internal error, " << target_size << " != " <<
+ source_size << "*" << last_dim_size);
+ std::vector<pga_tree_node> new_children;
+ for (size_type i = 0; i < source_size; ++i) {
+ for (size_type j = 0; j < last_dim_size; ++j)
+ new_children.push_back(current_node->children[i*last_dim_size+j]);
+ new_children.push_back(source_node->children[i]);
+ source_node->children[i]->parent = current_node;
+ }
+ source_node->children.resize(0); // so that the destructor of source_node
+ // will not destruct the children
+ current_node->children = new_children;
+ }
+
+ void ga_tree::add_op(GA_TOKEN_TYPE op_type, size_type pos) {
+ while (current_node && current_node->parent &&
+ current_node->parent->node_type == GA_NODE_OP &&
+ ga_operator_priorities[current_node->parent->op_type]
+ >= ga_operator_priorities[op_type])
+ current_node = current_node->parent;
+ pga_tree_node new_node = new ga_tree_node(op_type, pos);
+ if (current_node) {
+ if (op_type == GA_UNARY_MINUS
+ || op_type == GA_SYM || op_type == GA_SKEW
+ || op_type == GA_TRACE || op_type == GA_DEVIATOR
+ || op_type == GA_PRINT) {
+ current_node->adopt_child(new_node);
+ } else {
+ new_node->parent = current_node->parent;
+ if (current_node->parent)
+ current_node->parent->replace_child(current_node, new_node);
+ else
+ root = new_node;
+ new_node->adopt_child(current_node);
+ }
+ } else {
+ if (root) new_node->adopt_child(root);
+ root = new_node;
+ root->parent = nullptr;
+ }
+ current_node = new_node;
+ }
+
+ void ga_tree::clear_node_rec(pga_tree_node pnode) {
+ if (pnode) {
+ for (pga_tree_node &child : pnode->children)
+ clear_node_rec(child);
+ delete pnode;
+ current_node = nullptr;
+ }
+ }
+
+ void ga_tree::clear_node(pga_tree_node pnode) {
+ if (pnode) {
+ pga_tree_node parent = pnode->parent;
+ if (parent) { // keep all siblings of pnode
+ size_type j = 0;
+ for (pga_tree_node &sibling : parent->children)
+ if (sibling != pnode)
+ parent->children[j++] = sibling;
+ parent->children.resize(j);
+ } else
+ root = nullptr;
+ }
+ clear_node_rec(pnode);
+ }
+
+ void ga_tree::clear_children(pga_tree_node pnode) {
+ for (pga_tree_node &child : pnode->children)
+ clear_node_rec(child);
+ pnode->children.resize(0);
+ }
+
+ void ga_tree::replace_node_by_child(pga_tree_node pnode, size_type i) {
+ GMM_ASSERT1(i < pnode->children.size(), "Internal error");
+ pga_tree_node child = pnode->children[i];
+ child->parent = pnode->parent;
+ if (pnode->parent)
+ pnode->parent->replace_child(pnode, child);
+ else
+ root = child;
+ current_node = nullptr;
+ for (pga_tree_node &sibling : pnode->children)
+ if (sibling != child) clear_node_rec(sibling);
+ delete pnode;
+ }
+
+ void ga_tree::copy_node(pga_tree_node pnode, pga_tree_node parent,
+ pga_tree_node &child) {
+ GMM_ASSERT1(child == nullptr, "Internal error");
+ child = new ga_tree_node();
+ *child = *pnode;
+ child->parent = parent;
+ for (pga_tree_node &grandchild : child->children)
+ grandchild = nullptr;
+ for (size_type j = 0; j < child->children.size(); ++j)
+ copy_node(pnode->children[j], child, child->children[j]);
+ }
+
+ void ga_tree::duplicate_with_operation(pga_tree_node pnode,
+ GA_TOKEN_TYPE op_type) {
+ pga_tree_node newop = new ga_tree_node(op_type, pnode->pos);
+ newop->children.resize(2, nullptr);
+ newop->children[0] = pnode;
+ newop->parent = pnode->parent;
+ if (pnode->parent)
+ pnode->parent->replace_child(pnode, newop);
+ else
+ root = newop;
+ pnode->parent = newop;
+ copy_node(pnode, newop, newop->children[1]);
+ }
+
+ void ga_tree::insert_node(pga_tree_node pnode, GA_NODE_TYPE node_type) {
+ pga_tree_node newnode = new ga_tree_node();
+ newnode->node_type = node_type;
+ newnode->parent = pnode->parent;
+ if (pnode->parent)
+ pnode->parent->replace_child(pnode, newnode);
+ else
+ root = newnode;
+ newnode->adopt_child(pnode);
+ }
+
+ bool sub_tree_are_equal
+ (const pga_tree_node pnode1, const pga_tree_node pnode2,
+ const ga_workspace &workspace, int version) {
+ size_type ntype1 = pnode1->node_type;
+ if (ntype1 == GA_NODE_ZERO) ntype1 = GA_NODE_CONSTANT;
+ size_type ntype2 = pnode2->node_type;
+ if (ntype2 == GA_NODE_ZERO) ntype2 = GA_NODE_CONSTANT;
+
+ if (ntype1 != ntype2) return false;
+ if (pnode1->children.size() != pnode2->children.size()) return false;
+
+ switch(ntype1) {
+ case GA_NODE_OP:
+ if (pnode1->op_type != pnode2->op_type) return false;
+ if (pnode1->symmetric_op != pnode2->symmetric_op) return false;
+ break;
+ case GA_NODE_OPERATOR:
+ if (pnode1->der1 != pnode2->der1 || pnode1->der2 != pnode2->der2)
+ return false;
+ case GA_NODE_PREDEF_FUNC: case GA_NODE_SPEC_FUNC:
+ if (pnode1->name.compare(pnode2->name)) return false;
+ break;
+ case GA_NODE_CONSTANT: case GA_NODE_ZERO:
+ if (pnode1->tensor().size() != pnode2->tensor().size()) return false;
+
+ switch(version) {
+ case 0: case 1:
+ if (pnode1->test_function_type != pnode2->test_function_type)
+ return false;
+ if ((pnode1->test_function_type & 1) &&
+ pnode1->name_test1.compare(pnode2->name_test1) != 0)
+ return false;
+ if ((pnode1->test_function_type & 2) &&
+ pnode1->name_test2.compare(pnode2->name_test2) != 0)
+ return false;
+ break;
+ case 2:
+ if ((pnode1->test_function_type == 1 &&
+ pnode2->test_function_type == 1) ||
+ (pnode1->test_function_type == 2 &&
+ pnode2->test_function_type == 2))
+ return false;
+ if ((pnode1->test_function_type & 1) &&
+ pnode1->name_test1.compare(pnode2->name_test2) != 0)
+ return false;
+ if ((pnode1->test_function_type & 2) &&
+ pnode1->name_test2.compare(pnode2->name_test1) != 0)
+ return false;
+ break;
+ }
+ if (pnode1->tensor().size() != 1 &&
+ pnode1->t.sizes().size() != pnode2->t.sizes().size()) return false;
+ for (size_type i = 0; i < pnode1->t.sizes().size(); ++i)
+ if (pnode1->t.sizes()[i] != pnode2->t.sizes()[i]) return false;
+ for (size_type i = 0; i < pnode1->tensor().size(); ++i)
+ if (gmm::abs(pnode1->tensor()[i] - pnode2->tensor()[i]) > 1E-25)
+ return false;
+ break;
+ case GA_NODE_C_MATRIX:
+ if (pnode1->nbc1 != pnode2->nbc1 || pnode1->nbc2 != pnode2->nbc2 ||
+ pnode1->nbc3 != pnode2->nbc3)
+ return false;
+ break;
+ case GA_NODE_INTERPOLATE_FILTER:
+ if (pnode1->interpolate_name.compare(pnode2->interpolate_name) ||
+ pnode1->nbc1 != pnode2->nbc1)
+ return false;
+ break;
+ case GA_NODE_INTERPOLATE_X: case GA_NODE_INTERPOLATE_NORMAL:
+ if (pnode1->interpolate_name.compare(pnode2->interpolate_name))
+ return false;
+ break;
+ case GA_NODE_INTERPOLATE_DERIVATIVE:
+ if (pnode1->interpolate_name_der.compare(pnode2->interpolate_name_der))
+ return false;
+ // The test continues with what follows
+ case GA_NODE_INTERPOLATE_VAL_TEST: case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_HESS_TEST: case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ case GA_NODE_ELEMENTARY_VAL_TEST: case GA_NODE_ELEMENTARY_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_HESS_TEST: case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ case GA_NODE_XFEM_PLUS_VAL_TEST: case GA_NODE_XFEM_PLUS_GRAD_TEST:
+ case GA_NODE_XFEM_PLUS_HESS_TEST: case GA_NODE_XFEM_PLUS_DIVERG_TEST:
+ case GA_NODE_XFEM_MINUS_VAL_TEST: case GA_NODE_XFEM_MINUS_GRAD_TEST:
+ case GA_NODE_XFEM_MINUS_HESS_TEST: case GA_NODE_XFEM_MINUS_DIVERG_TEST:
+ if (pnode1->interpolate_name.compare(pnode2->interpolate_name) ||
+ pnode1->elementary_name.compare(pnode2->elementary_name))
+ return false;
+ // The test continues with what follows
+ case GA_NODE_VAL_TEST: case GA_NODE_GRAD_TEST:
+ case GA_NODE_HESS_TEST: case GA_NODE_DIVERG_TEST:
+ {
+ const mesh_fem *mf1 = workspace.associated_mf(pnode1->name);
+ const mesh_fem *mf2 = workspace.associated_mf(pnode2->name);
+ switch (version) {
+ case 0:
+ if (pnode1->name.compare(pnode2->name) ||
+ pnode1->test_function_type != pnode2->test_function_type)
+ return false;
+ break;
+ case 1:
+ if (mf1 != mf2 ||
+ workspace.qdim(pnode1->name) != workspace.qdim(pnode2->name) ||
+ pnode1->test_function_type != pnode2->test_function_type)
+ return false;
+ break;
+ case 2:
+ if (mf1 != mf2 ||
+ workspace.qdim(pnode1->name) != workspace.qdim(pnode2->name) ||
+ pnode1->test_function_type == pnode2->test_function_type)
+ return false;
+ break;
+ }
+ }
+ break;
+ case GA_NODE_VAL: case GA_NODE_GRAD:
+ case GA_NODE_HESS: case GA_NODE_DIVERG:
+ if (pnode1->name.compare(pnode2->name)) return false;
+ break;
+ case GA_NODE_INTERPOLATE_VAL: case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_INTERPOLATE_HESS: case GA_NODE_INTERPOLATE_DIVERG:
+ case GA_NODE_ELEMENTARY_VAL: case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_ELEMENTARY_HESS: case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_XFEM_PLUS_VAL: case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_PLUS_HESS: case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_VAL: case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_XFEM_MINUS_HESS: case GA_NODE_XFEM_MINUS_DIVERG:
+ if (pnode1->interpolate_name.compare(pnode2->interpolate_name) ||
+ pnode1->elementary_name.compare(pnode2->elementary_name) ||
+ pnode1->name.compare(pnode2->name))
+ return false;
+ break;
+ case GA_NODE_X:
+ if (pnode1->nbc1 != pnode2->nbc1) return false;
+ break;
+
+ default:break;
+ }
+
+ if (version && ntype1 == GA_NODE_OP && pnode1->symmetric_op) {
+ if (sub_tree_are_equal(pnode1->children[0], pnode2->children[0],
+ workspace, version) &&
+ sub_tree_are_equal(pnode1->children[1], pnode2->children[1],
+ workspace, version))
+ return true;
+ if (sub_tree_are_equal(pnode1->children[1], pnode2->children[0],
+ workspace, version) &&
+ sub_tree_are_equal(pnode1->children[0], pnode2->children[1],
+ workspace, version) )
+ return true;
+ return false;
+ } else {
+ for (size_type i = 0; i < pnode1->children.size(); ++i)
+ if (!(sub_tree_are_equal(pnode1->children[i], pnode2->children[i],
+ workspace, version)))
+ return false;
+ }
+ return true;
+ }
+
+ static void verify_tree(const pga_tree_node pnode,
+ const pga_tree_node parent) {
+ GMM_ASSERT1(pnode->parent == parent,
+ "Invalid tree node " << pnode->node_type);
+ for (pga_tree_node &child : pnode->children)
+ verify_tree(child, pnode);
+ }
+
+
+ static void ga_print_constant_tensor(const pga_tree_node pnode,
+ std::ostream &str) {
+ size_type nt = pnode->nb_test_functions(); // for printing zero tensors
+ switch (pnode->tensor_order()) {
+ case 0:
+ str << (nt ? scalar_type(0) : pnode->tensor()[0]);
+ break;
+
+ case 1:
+ str << "[";
+ for (size_type i = 0; i < pnode->tensor_proper_size(0); ++i) {
+ if (i != 0) str << "; ";
+ str << (nt ? scalar_type(0) : pnode->tensor()[i]);
+ }
+ str << "]";
+ break;
+
+ case 2: case 3: case 4:
+ {
+ size_type ii(0);
+ size_type n0 = pnode->tensor_proper_size(0);
+ size_type n1 = pnode->tensor_proper_size(1);
+ size_type n2 = ((pnode->tensor_order() > 2) ?
+ pnode->tensor_proper_size(2) : 1);
+ size_type n3 = ((pnode->tensor_order() > 3) ?
+ pnode->tensor_proper_size(3) : 1);
+ if (n3 > 1) str << "[";
+ for (size_type l = 0; l < n3; ++l) {
+ if (l != 0) str << ",";
+ if (n2 > 1) str << "[";
+ for (size_type k = 0; k < n2; ++k) {
+ if (k != 0) str << ",";
+ if (n1 > 1) str << "[";
+ for (size_type j = 0; j < n1; ++j) {
+ if (j != 0) str << ",";
+ if (n0 > 1) str << "[";
+ for (size_type i = 0; i < n0; ++i) {
+ if (i != 0) str << ",";
+ str << (nt ? scalar_type(0) : pnode->tensor()[ii++]);
+ }
+ if (n0 > 1) str << "]";
+ }
+ if (n1 > 1) str << "]";
+ }
+ if (n2 > 1) str << "]";
+ }
+ if (n3 > 1) str << "]";
+ }
+ break;
+
+ case 5: case 6:
+ str << "Reshape([";
+ for (size_type i = 0; i < pnode->tensor_proper_size(); ++i) {
+ if (i != 0) str << "; ";
+ str << (nt ? scalar_type(0) : pnode->tensor()[i]);
+ }
+ str << "]";
+ for (size_type i = 0; i < pnode->tensor_order(); ++i) {
+ if (i != 0) str << ", ";
+ str << pnode->tensor_proper_size(i);
+ }
+ str << ")";
+ break;
+
+ default: GMM_ASSERT1(false, "Invalid tensor dimension");
+ }
+ GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
+ }
+
+ void ga_print_node(const pga_tree_node pnode,
+ std::ostream &str) {
+ if (!pnode) return;
+ long prec = str.precision(16);
+
+ bool is_interpolate(false), is_elementary(false);
+ bool is_xfem_plus(false), is_xfem_minus(false);
+ switch(pnode->node_type) {
+ case GA_NODE_INTERPOLATE:
+ case GA_NODE_INTERPOLATE_FILTER:
+ case GA_NODE_INTERPOLATE_X:
+ case GA_NODE_INTERPOLATE_NORMAL:
+ case GA_NODE_INTERPOLATE_VAL:
+ case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_INTERPOLATE_HESS:
+ case GA_NODE_INTERPOLATE_DIVERG:
+ case GA_NODE_INTERPOLATE_VAL_TEST:
+ case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_HESS_TEST:
+ case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ str << "Interpolate(";
+ is_interpolate = true;
+ break;
+ case GA_NODE_ELEMENTARY:
+ case GA_NODE_ELEMENTARY_VAL:
+ case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_ELEMENTARY_HESS:
+ case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_ELEMENTARY_VAL_TEST:
+ case GA_NODE_ELEMENTARY_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_HESS_TEST:
+ case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ is_elementary = true;
+ str << "Elementary_transformation(";
+ break;
+ case GA_NODE_XFEM_PLUS:
+ case GA_NODE_XFEM_PLUS_VAL:
+ case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_PLUS_HESS:
+ case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_PLUS_VAL_TEST:
+ case GA_NODE_XFEM_PLUS_GRAD_TEST:
+ case GA_NODE_XFEM_PLUS_HESS_TEST:
+ case GA_NODE_XFEM_PLUS_DIVERG_TEST:
+ is_xfem_plus = true;
+ str << "Xfem_plus(";
+ break;
+ case GA_NODE_XFEM_MINUS:
+ case GA_NODE_XFEM_MINUS_VAL:
+ case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_XFEM_MINUS_HESS:
+ case GA_NODE_XFEM_MINUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_VAL_TEST:
+ case GA_NODE_XFEM_MINUS_GRAD_TEST:
+ case GA_NODE_XFEM_MINUS_HESS_TEST:
+ case GA_NODE_XFEM_MINUS_DIVERG_TEST:
+ is_xfem_minus = true;
+ str << "Xfem_minus(";
+ break;
+ default:
+ break;
+ }
+
+ switch(pnode->node_type) {
+ case GA_NODE_GRAD:
+ case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_GRAD_TEST:
+ case GA_NODE_XFEM_PLUS_GRAD_TEST:
+ case GA_NODE_XFEM_MINUS_GRAD_TEST:
+ str << "Grad_";
+ break;
+ case GA_NODE_HESS:
+ case GA_NODE_INTERPOLATE_HESS:
+ case GA_NODE_ELEMENTARY_HESS:
+ case GA_NODE_XFEM_PLUS_HESS:
+ case GA_NODE_XFEM_MINUS_HESS:
+ case GA_NODE_HESS_TEST:
+ case GA_NODE_INTERPOLATE_HESS_TEST:
+ case GA_NODE_ELEMENTARY_HESS_TEST:
+ case GA_NODE_XFEM_PLUS_HESS_TEST:
+ case GA_NODE_XFEM_MINUS_HESS_TEST:
+ str << "Hess_";
+ break;
+ case GA_NODE_DIVERG:
+ case GA_NODE_INTERPOLATE_DIVERG:
+ case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_DIVERG:
+ case GA_NODE_DIVERG_TEST:
+ case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ case GA_NODE_XFEM_PLUS_DIVERG_TEST:
+ case GA_NODE_XFEM_MINUS_DIVERG_TEST:
+ str << "Div_";
+ break;
+ default:
+ break;
+ }
+
+ switch(pnode->node_type) {
+ case GA_NODE_OP:
+ {
+ bool par = false;
+ if (pnode->parent) {
+ if (pnode->parent->node_type == GA_NODE_OP &&
+ (ga_operator_priorities[pnode->op_type] >= 2 ||
+ ga_operator_priorities[pnode->op_type]
+ < ga_operator_priorities[pnode->parent->op_type]))
+ par = true;
+ if (pnode->parent->node_type == GA_NODE_PARAMS) par = true;
+ }
+
+
+ if (par) str << "(";
+ if (pnode->op_type == GA_UNARY_MINUS) {
+ GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
+ str << "-"; ga_print_node(pnode->children[0], str);
+ } else if (pnode->op_type == GA_QUOTE) {
+ GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
+ ga_print_node(pnode->children[0], str); str << "'";
+ } else if (pnode->op_type == GA_SYM) {
+ GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
+ str << "Sym("; ga_print_node(pnode->children[0], str); str << ")";
+ } else if (pnode->op_type == GA_SKEW) {
+ GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
+ str << "Skew("; ga_print_node(pnode->children[0], str); str << ")";
+ } else if (pnode->op_type == GA_TRACE) {
+ GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
+ str << "Trace("; ga_print_node(pnode->children[0], str); str << ")";
+ } else if (pnode->op_type == GA_DEVIATOR) {
+ GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree with "
+ << pnode->children.size() << " children instead of 1");
+ str << "Deviator("; ga_print_node(pnode->children[0], str); str<<")";
+ } else if (pnode->op_type == GA_PRINT) {
+ GMM_ASSERT1(pnode->children.size() == 1, "Invalid tree");
+ str << "Print("; ga_print_node(pnode->children[0], str); str << ")";
+ } else {
+ // GMM_ASSERT1(pnode->children.size() == 2, "Invalid tree");
+ if (!par && pnode->op_type == GA_MULT &&
+ (pnode->children.size() == 1 ||
+ pnode->test_function_type == size_type(-1) ||
+ (pnode->children[0]->tensor_order() == 4 &&
+ pnode->children[1]->tensor_order() == 2)))
+ { par = true; str << "("; }
+ ga_print_node(pnode->children[0], str);
+ switch (pnode->op_type) {
+ case GA_PLUS: str << "+"; break;
+ case GA_MINUS: str << "-"; break;
+ case GA_MULT: str << "*"; break;
+ case GA_DIV: str << "/"; break;
+ case GA_COLON: str << ":"; break;
+ case GA_DOT: str << "."; break;
+ case GA_DOTMULT: str << ".*"; break;
+ case GA_DOTDIV: str << "./"; break;
+ case GA_TMULT: str << "@"; break;
+ default: GMM_ASSERT1(false, "Invalid or not taken into account "
+ "operation");
+ }
+ if (pnode->children.size() >= 2)
+ ga_print_node(pnode->children[1], str);
+ else
+ str << "(unknown second argument)";
+ }
+ if (par) str << ")";
+ }
+ break;
+
+ case GA_NODE_X:
+ if (pnode->nbc1) str << "X(" << pnode->nbc1 << ")"; else str << "X";
+ break;
+ case GA_NODE_ELT_SIZE: str << "element_size"; break;
+ case GA_NODE_ELT_K: str << "element_K"; break;
+ case GA_NODE_ELT_B: str << "element_B"; break;
+ case GA_NODE_NORMAL: str << "Normal"; break;
+ case GA_NODE_INTERPOLATE_FILTER:
+ str << "Interpolate_filter(" << pnode->interpolate_name << ",";
+ ga_print_node(pnode->children[0], str);
+ if (pnode->children.size() == 2)
+ { str << ","; ga_print_node(pnode->children[1], str); }
+ else if (pnode->nbc1 != size_type(-1)) str << "," << pnode->nbc1;
+ str << ")";
+ break;
+ case GA_NODE_INTERPOLATE_X:
+ str << "X";
+ break;
+ case GA_NODE_INTERPOLATE_NORMAL:
+ str << "Normal";
+ break;
+ case GA_NODE_INTERPOLATE_DERIVATIVE:
+ str << (pnode->test_function_type == 1 ? "Test_" : "Test2_")
+ << "Interpolate_derivative(" << pnode->interpolate_name_der << ","
+ << pnode->interpolate_name << "," << pnode->name << ")";
+ break;
+ case GA_NODE_INTERPOLATE:
+ case GA_NODE_ELEMENTARY:
+ case GA_NODE_XFEM_PLUS:
+ case GA_NODE_XFEM_MINUS:
+ case GA_NODE_VAL:
+ case GA_NODE_INTERPOLATE_VAL:
+ case GA_NODE_ELEMENTARY_VAL:
+ case GA_NODE_XFEM_PLUS_VAL:
+ case GA_NODE_XFEM_MINUS_VAL:
+ case GA_NODE_GRAD:
+ case GA_NODE_INTERPOLATE_GRAD:
+ case GA_NODE_ELEMENTARY_GRAD:
+ case GA_NODE_XFEM_PLUS_GRAD:
+ case GA_NODE_XFEM_MINUS_GRAD:
+ case GA_NODE_HESS:
+ case GA_NODE_INTERPOLATE_HESS:
+ case GA_NODE_ELEMENTARY_HESS:
+ case GA_NODE_XFEM_PLUS_HESS:
+ case GA_NODE_XFEM_MINUS_HESS:
+ case GA_NODE_DIVERG:
+ case GA_NODE_INTERPOLATE_DIVERG:
+ case GA_NODE_ELEMENTARY_DIVERG:
+ case GA_NODE_XFEM_PLUS_DIVERG:
+ case GA_NODE_XFEM_MINUS_DIVERG:
+ str << pnode->name;
+ break;
+ case GA_NODE_VAL_TEST:
+ case GA_NODE_INTERPOLATE_VAL_TEST:
+ case GA_NODE_ELEMENTARY_VAL_TEST:
+ case GA_NODE_XFEM_PLUS_VAL_TEST:
+ case GA_NODE_XFEM_MINUS_VAL_TEST:
+ case GA_NODE_GRAD_TEST:
+ case GA_NODE_INTERPOLATE_GRAD_TEST:
+ case GA_NODE_ELEMENTARY_GRAD_TEST:
+ case GA_NODE_XFEM_PLUS_GRAD_TEST:
+ case GA_NODE_XFEM_MINUS_GRAD_TEST:
+ case GA_NODE_HESS_TEST:
+ case GA_NODE_INTERPOLATE_HESS_TEST:
+ case GA_NODE_ELEMENTARY_HESS_TEST:
+ case GA_NODE_XFEM_PLUS_HESS_TEST:
+ case GA_NODE_XFEM_MINUS_HESS_TEST:
+ case GA_NODE_DIVERG_TEST:
+ case GA_NODE_INTERPOLATE_DIVERG_TEST:
+ case GA_NODE_ELEMENTARY_DIVERG_TEST:
+ case GA_NODE_XFEM_PLUS_DIVERG_TEST:
+ case GA_NODE_XFEM_MINUS_DIVERG_TEST:
+ str << (pnode->test_function_type == 1 ? "Test_" : "Test2_")
+ << pnode->name;
+ break;
+ case GA_NODE_SPEC_FUNC: str << pnode->name; break;
+ case GA_NODE_OPERATOR:
+ case GA_NODE_PREDEF_FUNC:
+ if (pnode->der1) {
+ str << "Derivative_" << pnode->der1 << "_";
+ if (pnode->der2) str << pnode->der2 << "_";
+ }
+ str << pnode->name; break;
+ case GA_NODE_ZERO:
+ GMM_ASSERT1(pnode->test_function_type != size_type(-1),
+ "Internal error");
+ if (pnode->test_function_type) str << "(";
+ ga_print_constant_tensor(pnode, str);
+ if (pnode->name_test1.size()) {
+ GMM_ASSERT1(pnode->qdim1 > 0, "Internal error");
+ if (pnode->qdim1 == 1)
+ str << "*Test_" << pnode->name_test1;
+ else {
+ str << "*(Reshape(Test_" << pnode->name_test1 << ","
+ << pnode->qdim1<< ")(1))";
+ }
+ }
+ if (pnode->name_test2.size()) {
+ GMM_ASSERT1(pnode->qdim2 > 0, "Internal error");
+ if (pnode->qdim2 == 1)
+ str << "*Test2_" << pnode->name_test2;
+ else {
+ str << "*(Reshape(Test2_" << pnode->name_test2 << ","
+ << pnode->qdim2<< ")(1))";
+ }
+ }
+ if (pnode->test_function_type) str << ")";
+ break;
+
+ case GA_NODE_CONSTANT:
+ ga_print_constant_tensor(pnode, str);
+ break;
+
+ case GA_NODE_ALLINDICES:
+ str << ":";
+ GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
+ break;
+
+ case GA_NODE_PARAMS:
+ GMM_ASSERT1(pnode->children.size(), "Invalid tree");
+ ga_print_node(pnode->children[0], str);
+ str << "(";
+ for (size_type i = 1; i < pnode->children.size(); ++i) {
+ if (i > 1) str << ", ";
+ ga_print_node(pnode->children[i], str);
+ }
+ str << ")";
+ break;
+
+ case GA_NODE_NAME:
+ str << pnode->name;
+ GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
+ break;
+
+ case GA_NODE_RESHAPE:
+ str << "Reshape";
+ GMM_ASSERT1(pnode->children.size() == 0, "Invalid tree");
+ break;
+
+ case GA_NODE_C_MATRIX:
+ {
+ GMM_ASSERT1(pnode->children.size(), "Invalid tree");
+ size_type nbc1 = pnode->nbc1;
+ size_type nbc2 = pnode->nbc2;
+ size_type nbc3 = pnode->nbc3;
+ size_type nbcl = pnode->children.size()/(nbc1*nbc2*nbc3);
+ if (nbc1 > 1) str << "[";
+ for (size_type i1 = 0; i1 < nbc1; ++i1) {
+ if (i1 != 0) str << ",";
+ if (nbc2 > 1) str << "[";
+ for (size_type i2 = 0; i2 < nbc2; ++i2) {
+ if (i2 != 0) str << ",";
+ if (nbc3 > 1) str << "[";
+ for (size_type i3 = 0; i3 < nbc3; ++i3) {
+ if (i3 != 0) str << ",";
+ if (nbcl > 1) str << "[";
+ for (size_type i4 = 0; i4 < nbcl; ++i4) {
+ if (i4 != 0) str << ",";
+ size_type ii = ((i4*nbc3 + i3)*nbc2 + i2)*nbc1 + i1;
+ ga_print_node(pnode->children[ii], str);
+ }
+ if (nbcl > 1) str << "]";
+ }
+ if (nbc3 > 1) str << "]";
+ }
+ if (nbc2 > 1) str << "]";
+ }
+ if (nbc1 > 1) str << "]";
+ }
+ break;
+
+ default:
+ str << "Invalid or not taken into account node type "
+ << pnode->node_type;
+ break;
+ }
+
+ if (is_interpolate)
+ str << "," << pnode->interpolate_name << ")";
+ else if (is_elementary)
+ str << "," << pnode->elementary_name << ")";
+ else if (is_xfem_plus || is_xfem_minus)
+ str << ")";
+
+ str.precision(prec);
+ }
+
+ std::string ga_tree_to_string(const ga_tree &tree) {
+ std::stringstream str;
+ str.precision(16);
+ if (tree.root) verify_tree(tree.root, 0);
+ if (tree.root) ga_print_node(tree.root, str); else str << "0";
+ return str.str();
+ }
+
+
+ size_type ga_parse_prefix_operator(std::string &name) {
+ if (name.size() >= 5 && name.compare(0, 5, "Grad_") == 0)
+ { name = name.substr(5); return 1; }
+ else if (name.size() >= 5 && name.compare(0, 5, "Hess_") == 0)
+ { name = name.substr(5); return 2; }
+ else if (name.size() >= 4 && name.compare(0, 4, "Div_") == 0)
+ { name = name.substr(4); return 3; }
+ return 0;
+ }
+
+ size_type ga_parse_prefix_test(std::string &name) {
+ if (name.size() >= 5 && name.compare(0, 5, "Test_") == 0)
+ { name = name.substr(5); return 1; }
+ else if (name.size() >= 6 && name.compare(0, 6, "Test2_") == 0)
+ { name = name.substr(6); return 2; }
+ return 0;
+ }
+
+ // 0 : ok
+ // 1 : function or operator name or "X"
+ // 2 : reserved prefix Grad, Hess, Div, Test and Test2
+ // 3 : reserved prefix Dot and Previous
+ int ga_check_name_validity(const std::string &name) {
+
+ if (!(name.compare("X")) ||
+ !(name.compare("Normal")) ||
+ !(name.compare("Reshape")))
+ return 1;
+
+
+ if (name.compare(0, 11, "Derivative_") == 0)
+ return 2;
+
+ ga_predef_function_tab &PREDEF_FUNCTIONS
+ = dal::singleton<ga_predef_function_tab>::instance(0);
+ ga_predef_operator_tab &PREDEF_OPERATORS
+ = dal::singleton<ga_predef_operator_tab>::instance(0);
+ ga_predef_function_tab::const_iterator it=PREDEF_FUNCTIONS.find(name);
+ if (it != PREDEF_FUNCTIONS.end())
+ return 1;
+
+ if (SPEC_FUNCTIONS.find(name) != SPEC_FUNCTIONS.end())
+ return 1;
+
+ if (PREDEF_OPERATORS.tab.find(name) != PREDEF_OPERATORS.tab.end())
+ return 1;
+
+ if (name.size() >= 5 && name.compare(0, 5, "Grad_") == 0)
+ return 2;
+
+ if (name.size() >= 5 && name.compare(0, 5, "Hess_") == 0)
+ return 2;
+
+ if (name.size() >= 4 && name.compare(0, 4, "Div_") == 0)
+ return 2;
+
+ if (name.size() >= 6 && name.compare(0, 6, "Test2_") == 0)
+ return 2;
+
+ if (name.size() >= 5 && name.compare(0, 5, "Test_") == 0)
+ return 2;
+
+// if (name.size() >= 4 && name.compare(0, 4, "Dot_") == 0)
+// return 3;
+// if (name.size() >= 5 && name.compare(0, 5, "Dot2_") == 0)
+// return 3;
+
+// if (name.size() >= 9 && name.compare(0, 9, "Previous_") == 0)
+// return 3;
+// if (name.size() >= 10 && name.compare(0, 10, "Previous2_") == 0)
+// return 3;
+// if (name.size() >= 12 && name.compare(0, 12, "Previous1_2_") == 0)
+// return 3;
+
+
+ return 0;
+ }
+
+ //=========================================================================
+ // Syntax analysis for the generic assembly langage
+ //=========================================================================
+
+ // Read a term with an (implicit) pushdown automaton.
+ static GA_TOKEN_TYPE ga_read_term(const std::string &expr, size_type &pos,
+ ga_tree &tree) {
+ size_type token_pos, token_length;
+ GA_TOKEN_TYPE t_type;
+ int state = 1; // 1 = reading term, 2 = reading after term
+
+ for (;;) {
+
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+
+ switch (state) {
+
+ case 1:
+ switch (t_type) {
+ case GA_SCALAR:
+ {
+ char *endptr; const char *nptr = &(expr[token_pos]);
+ scalar_type s_read = ::strtod(nptr, &endptr);
+ if (endptr == nptr)
+ ga_throw_error(expr, token_pos, "Bad numeric format.");
+ tree.add_scalar(s_read, token_pos);
+ }
+ state = 2; break;
+
+ case GA_COLON:
+ tree.add_allindices(token_pos);
+ state = 2; break;
+
+ case GA_NAME:
+ tree.add_name(&(expr[token_pos]), token_length, token_pos);
+ state = 2; break;
+
+ case GA_MINUS: // unary -
+ tree.add_op(GA_UNARY_MINUS, token_pos);
+ case GA_PLUS: // unary +
+ state = 1; break;
+
+ case GA_SYM:
+ tree.add_op(GA_SYM, token_pos);
+ state = 1; break;
+
+ case GA_SKEW:
+ tree.add_op(GA_SKEW, token_pos);
+ state = 1; break;
+
+ case GA_TRACE:
+ tree.add_op(GA_TRACE, token_pos);
+ state = 1; break;
+
+ case GA_DEVIATOR:
+ tree.add_op(GA_DEVIATOR, token_pos);
+ state = 1; break;
+
+ case GA_INTERPOLATE:
+ {
+ tree.add_scalar(scalar_type(0), token_pos);
+ tree.current_node->node_type = GA_NODE_INTERPOLATE;
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_LPAR)
+ ga_throw_error(expr, pos-1, "Missing interpolate arguments.");
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_NAME)
+ ga_throw_error(expr, pos,
+ "First argument of Interpolate should be a "
+ "variable, test function, X or Normal.");
+ tree.current_node->name = std::string(&(expr[token_pos]),
+ token_length);
+
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_COMMA)
+ ga_throw_error(expr, pos, "Bad format for Interpolate "
+ "arguments.");
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_NAME)
+ ga_throw_error(expr, pos,
+ "Second argument of Interpolate should be a "
+ "transformation name.");
+ tree.current_node->interpolate_name
+ = std::string(&(expr[token_pos]), token_length);
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_RPAR)
+ ga_throw_error(expr, pos-1, "Missing a parenthesis after "
+ "interpolate arguments.");
+ state = 2;
+ }
+ break;
+
+ case GA_ELEMENTARY:
+ {
+ tree.add_scalar(scalar_type(0), token_pos);
+ tree.current_node->node_type = GA_NODE_ELEMENTARY;
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_LPAR)
+ ga_throw_error(expr, pos-1,
+ "Missing Elementary_transformation arguments.");
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_NAME)
+ ga_throw_error(expr, pos,
+ "First argument of Elementary_transformation "
+ "should be a variable or a test function.");
+ tree.current_node->name = std::string(&(expr[token_pos]),
+ token_length);
+
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_COMMA)
+ ga_throw_error(expr, pos, "Bad format for "
+ "Elementary_transformation arguments.");
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_NAME)
+ ga_throw_error(expr, pos,
+ "Second argument of Elementary_transformation "
+ "should be a transformation name.");
+ tree.current_node->elementary_name
+ = std::string(&(expr[token_pos]), token_length);
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_RPAR)
+ ga_throw_error(expr, pos-1, "Missing a parenthesis after "
+ "Elementary_transformation arguments.");
+ state = 2;
+ }
+ break;
+
+ case GA_XFEM_PLUS:
+ {
+ tree.add_scalar(scalar_type(0), token_pos);
+ tree.current_node->node_type = GA_NODE_XFEM_PLUS;
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_LPAR)
+ ga_throw_error(expr, pos-1,
+ "Missing Xfem_plus arguments.");
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_NAME)
+ ga_throw_error(expr, pos,
+ "The argument of Xfem_plus should be a "
+ "variable or a test function.");
+ tree.current_node->name = std::string(&(expr[token_pos]),
+ token_length);
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_RPAR)
+ ga_throw_error(expr, pos-1, "Missing a parenthesis after "
+ "Xfem_plus argument.");
+ state = 2;
+ }
+ break;
+
+ case GA_XFEM_MINUS:
+ {
+ tree.add_scalar(scalar_type(0), token_pos);
+ tree.current_node->node_type = GA_NODE_XFEM_MINUS;
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_LPAR)
+ ga_throw_error(expr, pos-1,
+ "Missing Xfem_minus arguments.");
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_NAME)
+ ga_throw_error(expr, pos,
+ "The argument of Xfem_minus should be a "
+ "variable or a test function.");
+ tree.current_node->name = std::string(&(expr[token_pos]),
+ token_length);
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_RPAR)
+ ga_throw_error(expr, pos-1, "Missing a parenthesis after "
+ "Xfem_minus argument.");
+ state = 2;
+ }
+ break;
+
+ case GA_INTERPOLATE_FILTER:
+ {
+ tree.add_scalar(scalar_type(0), token_pos);
+ tree.current_node->node_type = GA_NODE_INTERPOLATE_FILTER;
+ tree.current_node->nbc1 = size_type(-1);
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_LPAR)
+ ga_throw_error(expr, pos-1, "Missing interpolate arguments.");
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_NAME)
+ ga_throw_error(expr, pos, "First argument of Interpolate_filter "
+ "should be a transformation name.");
+ tree.current_node->interpolate_name
+ = std::string(&(expr[token_pos]), token_length);
+ t_type = ga_get_token(expr, pos, token_pos, token_length);
+ if (t_type != GA_COMMA)
+ ga_throw_error(expr,pos,
+ "Bad format for Interpolate_filter arguments.");
+ ga_tree sub_tree;
+ t_type = ga_read_term(expr, pos, sub_tree);
+ if (t_type != GA_RPAR && t_type != GA_COMMA)
+ ga_throw_error(expr, pos-1,
+ "Bad format for Interpolate_filter arguments.");
+ tree.add_sub_tree(sub_tree);
+ if (t_type == GA_COMMA) {
+ ga_tree sub_tree2;
+ t_type = ga_read_term(expr, pos, sub_tree2);
+ tree.add_sub_tree(sub_tree2);
+ }
+ if (t_type != GA_RPAR)
+ ga_throw_error(expr, pos-1, "Unbalanced parenthesis.");
+ state = 2;
+ }
+ break;
+
+ case GA_PRINT:
+ tree.add_op(GA_PRINT, token_pos);
+ state = 1; break;
+
+ case GA_LPAR: // Parenthesed expression
+ {
+ ga_tree sub_tree;
+ GA_TOKEN_TYPE r_type;
+ r_type = ga_read_term(expr, pos, sub_tree);
+ if (r_type != GA_RPAR)
+ ga_throw_error(expr, pos-1, "Unbalanced parenthesis.");
+ tree.add_sub_tree(sub_tree);
+ state = 2;
+ }
+ break;
+
+ case GA_LBRACKET: // Explicit vector/matrix or tensor
+ {
+ ga_tree sub_tree;
+ GA_TOKEN_TYPE r_type;
+ size_type nbc1(0), nbc2(0), nbc3(0), n1(0), n2(0), n3(0);
+ size_type tensor_order(1);
+ bool foundcomma(false), foundsemi(false), nested_format(false);
+
+ tree.add_matrix(token_pos);
+ do {
+ r_type = ga_read_term(expr, pos, sub_tree);
+
+ if (sub_tree.root->node_type == GA_NODE_C_MATRIX) {
+ // nested format
+ if (r_type != GA_COMMA && r_type != GA_RBRACKET)
+ // in the nested format only "," and "]" are expected
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.")
+ else if (sub_tree.root->nbc3 != 1)
+ // the sub-tensor to be merged cannot be of fourth order
+ ga_throw_error(expr, pos-1, "Definition of explicit "
+ "tensors is limitted to the fourth order. "
+ "Limit exceeded.")
+ else if (foundsemi || // Cannot mix with the non-nested format.
+ (sub_tree.root->children.size() > 1 &&
+ // The sub-tensor cannot be a column vector [a;b],
+ sub_tree.root->nbc1 == 1))
+ // the nested format only accepts row vectors [a,b]
+ // and converts them to column vectors internally
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.") // (see
below)
+
+ // convert a row vector [a,b] to a column vector [a;b]
+ if (sub_tree.root->children.size() == sub_tree.root->nbc1)
+ sub_tree.root->nbc1 = 1;
+
+ nested_format = true;
+
+ size_type sub_tensor_order = 3;
+ if (sub_tree.root->nbc1 == 1)
+ sub_tensor_order = 1;
+ else if (sub_tree.root->nbc2 == 1)
+ sub_tensor_order = 2;
+
+ if (tensor_order == 1) {
+ if (nbc1 != 0 || nbc2 != 0 || nbc3 != 0)
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.");
+ nbc1 = 1;
+ nbc2 = sub_tree.root->nbc1;
+ nbc3 = sub_tree.root->nbc2;
+ tensor_order = sub_tensor_order + 1;
+ } else {
+ if ((tensor_order != sub_tensor_order + 1) ||
+ (tensor_order > 2 && nbc2 != sub_tree.root->nbc1) ||
+ (tensor_order > 3 && nbc3 != sub_tree.root->nbc2))
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.");
+ nbc1 += 1;
+ }
+
+ tree.zip_matrix(sub_tree.root);
+ sub_tree.clear();
+ if (r_type == GA_RBRACKET) {
+ tree.current_node->nbc1 = nbc1;
+ tree.current_node->nbc2 = nbc2;
+ tree.current_node->nbc3 = nbc3;
+ }
+
+ } else {
+
+ // non-nested format
+
+ tree.add_sub_tree(sub_tree);
+
+ ++n1; ++n2; ++n3;
+ if (tensor_order < 2) ++nbc1;
+ if (tensor_order < 3) ++nbc2;
+ if (tensor_order < 4) ++nbc3;
+
+ if (r_type == GA_COMMA) {
+ if (!foundcomma && tensor_order > 1)
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.");
+ foundcomma = true;
+ } else if (r_type == GA_SEMICOLON) {
+ if (n1 != nbc1)
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.");
+ n1 = 0;
+ tensor_order = std::max(tensor_order, size_type(2));
+ } else if (r_type == GA_DCOMMA) {
+ if (n1 != nbc1 || n2 != nbc2)
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.");
+ foundsemi = true;
+ n2 = n1 = 0;
+ tensor_order = std::max(tensor_order, size_type(3));
+ } else if (r_type == GA_DSEMICOLON) {
+ if (n1 != nbc1 || n2 != nbc2 || n3 != nbc3 ||
+ tensor_order < 3)
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.");
+ n3 = n2 = n1 = 0;
+ tensor_order = std::max(tensor_order, size_type(4));
+ } else if (r_type == GA_RBRACKET) {
+ if (n1 != nbc1 || n2 != nbc2 || n3 != nbc3 ||
+ tensor_order == 3)
+ ga_throw_error(expr, pos-1, "Bad explicit "
+ "vector/matrix/tensor format.");
+ tree.current_node->nbc1 = nbc1;
+ if (tensor_order == 4) {
+ tree.current_node->nbc2 = nbc2/nbc1;
+ tree.current_node->nbc3 = nbc3/nbc2;
+ } else {
+ tree.current_node->nbc2 = tree.current_node->nbc3 = 1;
+ }
+ } else {
+ ga_throw_error(expr, pos-1, "The explicit "
+ "vector/matrix/tensor components should be "
+ "separated by ',', ';', ',,' and ';;' and "
+ "be ended by ']'.");
+ }
+ }
+
+ } while (r_type != GA_RBRACKET);
+
+ state = 2;
+ }
+ break;
+
+ default:
+ ga_throw_error(expr, token_pos, "Unexpected token.");
+ }
+ break;
+
+ case 2:
+ switch (t_type) {
+ case GA_PLUS: case GA_MINUS: case GA_MULT: case GA_DIV:
+ case GA_COLON: case GA_DOT: case GA_DOTMULT: case GA_DOTDIV:
+ case GA_TMULT:
+ tree.add_op(t_type, token_pos);
+ state = 1; break;
+ case GA_QUOTE:
+ tree.add_op(t_type, token_pos);
+ state = 2; break;
+ case GA_END: case GA_RPAR: case GA_COMMA: case GA_DCOMMA:
+ case GA_RBRACKET: case GA_SEMICOLON: case GA_DSEMICOLON:
+ return t_type;
+ case GA_LPAR: // Parameter list
+ {
+ ga_tree sub_tree;
+ GA_TOKEN_TYPE r_type;
+ tree.add_params(token_pos);
+ do {
+ r_type = ga_read_term(expr, pos, sub_tree);
+ if (r_type != GA_RPAR && r_type != GA_COMMA)
+ ga_throw_error(expr, pos-((r_type != GA_END)?1:0),
+ "Parameters should be separated "
+ "by ',' and parameter list ended by ')'.");
+ tree.add_sub_tree(sub_tree);
+ } while (r_type != GA_RPAR);
+ state = 2;
+ }
+ break;
+
+ default:
+ ga_throw_error(expr, token_pos, "Unexpected token.");
+ }
+ break;
+ }
+ }
+
+ return GA_INVALID;
+ }
+
+ // Syntax analysis of a string. Conversion to a tree.
+ void ga_read_string(const std::string &expr, ga_tree &tree) {
+ size_type pos = 0, token_pos, token_length;
+ tree.clear();
+ GA_TOKEN_TYPE t = ga_get_token(expr, pos, token_pos, token_length);
+ if (t == GA_END) return;
+ pos = 0;
+ t = ga_read_term(expr, pos, tree);
+ switch (t) {
+ case GA_RPAR: ga_throw_error(expr, pos-1, "Unbalanced parenthesis.");
+ case GA_RBRACKET: ga_throw_error(expr, pos-1, "Unbalanced braket.");
+ case GA_END: break;
+ default: ga_throw_error(expr, pos-1, "Unexpected token.");
+ }
+ }
+
+ // Small tool to make basic substitutions into an assembly string
+ std::string ga_substitute(const std::string &expr,
+ const std::map<std::string, std::string> &dict) {
+ if (dict.size()) {
+ size_type pos = 0, token_pos, token_length;
+ std::stringstream exprs;
+
+ while (true) {
+ GA_TOKEN_TYPE t_type = ga_get_token(expr, pos, token_pos,
token_length);
+ if (t_type == GA_END) return exprs.str();
+ std::string name(&(expr[token_pos]), token_length);
+ if (t_type == GA_NAME && dict.find(name) != dict.end())
+ exprs << dict.at(name); else exprs << name;
+ }
+ }
+ return expr;
+ }
+
+} /* end of namespace */