From 43e5937b42981e0a239604022b10b7c016059f86 Mon Sep 17 00:00:00 2001
From: Marcel Koch <marcel.koch@uni-muenster.de>
Date: Mon, 15 Oct 2018 14:09:56 +0200
Subject: [PATCH] adds computation of determinant in 3d

---
 .../dune/perftool/blockstructured/geometry.py | 124 ++++++++++++------
 1 file changed, 87 insertions(+), 37 deletions(-)

diff --git a/python/dune/perftool/blockstructured/geometry.py b/python/dune/perftool/blockstructured/geometry.py
index c43ac2c1..627f09da 100644
--- a/python/dune/perftool/blockstructured/geometry.py
+++ b/python/dune/perftool/blockstructured/geometry.py
@@ -17,50 +17,90 @@ import pymbolic.primitives as prim
 from loopy.match import Writes
 
 
-# TODO warum muss within_inames_is_final=True gesetzt werden?
-def compute_jacobian_2d(name):
-    pymbolic_pos = get_backend("quad_pos", selector=option_switch("blockstructured"))()
+def compute_corner_diff(first, second, additional_terms=tuple()):
     corners = name_element_corners()
+    simplified_names = tuple("cd" + n.split('_')[2] + n.split('_')[3] for n in additional_terms)
+    name = "corner_diff_"+"_".join((str(first), str(second))+simplified_names)
+    temporary_variable(name, shape_impl=('fv',), shape=(world_dimension(),))
+    diminame = component_iname(context='corner')
 
-    jac_inames = tuple(component_iname(context="jac", count=i) for i in range(world_dimension()))
+    if additional_terms:
+        xs_sum = prim.Sum(tuple(prim.Subscript(prim.Variable(x), (prim.Variable(diminame),)) for x in additional_terms))
+    else:
+        xs_sum = 0
+
+    instruction(expression=prim.Sum((prim.Subscript(prim.Variable(corners), (first, prim.Variable(diminame))),
+                                     -1 * prim.Subscript(prim.Variable(corners), (second, prim.Variable(diminame))),
+                                     -1 * xs_sum)),
+                assignee=prim.Subscript(prim.Variable(name), prim.Variable(diminame)),
+                within_inames=frozenset(), within_inames_is_final=True,
+                depends_on=frozenset({Writes(corners)} | {Writes(term) for term in additional_terms}))
+    return name
 
-    def _corner_diff(first, second, additional_terms=tuple()):
-        simplified_names = tuple("cd" + n.split('_')[2] + n.split('_')[3] for n in additional_terms)
-        name = "corner_diff_"+"_".join((str(first), str(second))+simplified_names)
-        temporary_variable(name, shape_impl=('fv',), shape=(world_dimension(),))
-        diminame = component_iname(context='corner')
 
-        if additional_terms:
-            xs_sum = prim.Sum(tuple(prim.Subscript(prim.Variable(x), (prim.Variable(diminame),)) for x in additional_terms))
-        else:
-            xs_sum = 0
-
-        instruction(expression=prim.Sum((prim.Subscript(prim.Variable(corners), (first, prim.Variable(diminame))),
-                                         -1 * prim.Subscript(prim.Variable(corners), (second, prim.Variable(diminame))),
-                                         -1 * xs_sum)),
-                    assignee=prim.Subscript(prim.Variable(name), prim.Variable(diminame)),
-                    within_inames=frozenset(), within_inames_is_final=True,
-                    depends_on=frozenset({Writes(corners)}))
-        return name
+# TODO warum muss within_inames_is_final=True gesetzt werden?
+# Transformation T(x,y) = a * xy + b * x + c * y + d
+def compute_jacobian_2d(name):
+    pymbolic_pos = get_backend("quad_pos", selector=option_switch("blockstructured"))()
+    jac_iname = tuple(component_iname(context="jac", count=i) for i in range(world_dimension()))
 
-    c = _corner_diff(2, 0)
-    b = _corner_diff(1, 0)
-    a = _corner_diff(3, 0, (b, c))
+    c = compute_corner_diff(2, 0)
+    b = compute_corner_diff(1, 0)
+    a = compute_corner_diff(3, 0, (b, c))
 
     expr_jac = [None, None]
     expr_jac[0] = prim.Sum((prim.Product((prim.Subscript(pymbolic_pos, (1,)),
-                                          prim.Subscript(prim.Variable(a), (prim.Variable(jac_inames[0]),)))),
-                            prim.Subscript(prim.Variable(b), (prim.Variable(jac_inames[0]),))))
+                                          prim.Subscript(prim.Variable(a), (prim.Variable(jac_iname),)))),
+                            prim.Subscript(prim.Variable(b), (prim.Variable(jac_iname),))))
     expr_jac[1] = prim.Sum((prim.Product((prim.Subscript(pymbolic_pos, (0,)),
-                                          prim.Subscript(prim.Variable(a), (prim.Variable(jac_inames[1]),)))),
-                            prim.Subscript(prim.Variable(c), (prim.Variable(jac_inames[1]),))))
+                                          prim.Subscript(prim.Variable(a), (prim.Variable(jac_iname),)))),
+                            prim.Subscript(prim.Variable(c), (prim.Variable(jac_iname),))))
+
+    for i, expr in enumerate(expr_jac):
+        instruction(expression=expr,
+                    assignee=prim.Subscript(prim.Variable(name), (prim.Variable(jac_iname),i)),
+                    within_inames=frozenset(sub_element_inames()+get_backend(interface="quad_inames")()),
+                    within_inames_is_final=True,
+                    depends_on=frozenset({Writes(a), Writes(b), Writes(c), Writes(get_pymbolic_basename(pymbolic_pos))})
+                    )
+
+
+# Transformation T(x,y,z) = a * xyz + b * xy + c * xz + d * yz + e * x + f * y + g * z + h
+def compute_jacobian_3d(name):
+    pymbolic_pos = get_backend("quad_pos", selector=option_switch("blockstructured"))()
+    jac_iname = component_iname(context="jac")
+
+    g = compute_corner_diff(4, 0)
+    f = compute_corner_diff(2, 0)
+    e = compute_corner_diff(1, 0)
+    d = compute_corner_diff(6, 0, (f, g))
+    c = compute_corner_diff(5, 0, (e, g))
+    b = compute_corner_diff(3, 0, (e, f))
+    a = compute_corner_diff(7, 0, (b, c, d, e, f, g))
+    all_cds = [a, b, c, d, e, f, g]
+
+    expr_jac = [None, None, None]
+    terms = [[b, c, e], [b, d, f], [c, d, g]]
+
+    # j[:][i] = a * qp[k]*qp[l] + v1 * qp[k] + v2 * qp[l] + v3
+    # with k, l in {0,1,2} != i and k<l and vj = terms[i][j]
+    for i in range(3):
+        k, l = sorted(set(range(3))-{i})
+        expr_jac[i] = prim.Sum((prim.Product((prim.Subscript(pymbolic_pos, (k,)), prim.Subscript(pymbolic_pos, (l,)),
+                                              prim.Subscript(prim.Variable(a), (prim.Variable(jac_iname),)))),
+                                prim.Product((prim.Subscript(pymbolic_pos, (k,)),
+                                              prim.Subscript(prim.Variable(terms[i][0]), (prim.Variable(jac_iname),)))),
+                                prim.Product((prim.Subscript(pymbolic_pos, (l,)),
+                                              prim.Subscript(prim.Variable(terms[i][1]), (prim.Variable(jac_iname),)))),
+                                prim.Subscript(prim.Variable(terms[i][2]), (prim.Variable(jac_iname),))
+                                ))
 
     for i, expr in enumerate(expr_jac):
         instruction(expression=expr,
-                    assignee=prim.Subscript(prim.Variable(name), (prim.Variable(jac_inames[i]),i)),
+                    assignee=prim.Subscript(prim.Variable(name), (prim.Variable(jac_iname),i)),
                     within_inames=frozenset(sub_element_inames()+get_backend(interface="quad_inames")()),
                     within_inames_is_final=True,
-                    depends_on=frozenset({Writes(b), Writes(get_pymbolic_basename(pymbolic_pos))})
+                    depends_on=frozenset({Writes(get_pymbolic_basename(pymbolic_pos))}).union(frozenset([Writes(cd) for cd in all_cds]))
                     )
 
 
@@ -68,6 +108,8 @@ def define_jacobian_matrix(name):
     temporary_variable(name, shape_impl=('fm',), shape=(world_dimension(), world_dimension()))
     if world_dimension() == 2:
         compute_jacobian_2d(name)
+    elif world_dimension() == 3:
+        compute_jacobian_3d(name)
     else:
         raise NotImplementedError()
 
@@ -80,18 +122,26 @@ def name_jacobian_matrix():
 
 def compute_determinant(name, matrix):
     dim = world_dimension()
+    matrix_entry = [[prim.Subscript(prim.Variable(matrix), (i, j)) for j in range(dim)] for i in range(dim)]
     if dim == 2:
-        matrix_entry = [[prim.Subscript(prim.Variable(matrix), (i, j)) for j in range(dim)] for i in range(dim)]
         expr_determinant = prim.Sum((prim.Product((matrix_entry[0][0], matrix_entry[1][1])),
                                      -1*prim.Product((matrix_entry[1][0], matrix_entry[0][1]))))
-        instruction(expression=expr_determinant,
-                    assignee=prim.Variable(name),
-                    within_inames=frozenset(sub_element_inames()+get_backend(interface="quad_inames")()),
-                    within_inames_is_final=True,
-                    depends_on=frozenset({Writes(matrix)})
-                    )
+    elif dim == 3:
+        expr_determinant = prim.Sum((prim.Product((matrix_entry[0][0], matrix_entry[1][1], matrix_entry[2][2])),
+                                     prim.Product((matrix_entry[0][1], matrix_entry[1][2], matrix_entry[2][0])),
+                                     prim.Product((matrix_entry[0][2], matrix_entry[1][0], matrix_entry[2][1])),
+                                     -1 * prim.Product((matrix_entry[0][2], matrix_entry[1][1], matrix_entry[2][0])),
+                                     -1 * prim.Product((matrix_entry[0][0], matrix_entry[1][2], matrix_entry[2][1])),
+                                     -1 * prim.Product((matrix_entry[0][1], matrix_entry[1][0], matrix_entry[2][2]))
+                                     ))
     else:
         raise NotImplementedError()
+    instruction(expression=expr_determinant,
+                assignee=prim.Variable(name),
+                within_inames=frozenset(sub_element_inames()+get_backend(interface="quad_inames")()),
+                within_inames_is_final=True,
+                depends_on=frozenset({Writes(matrix)})
+                )
 
 
 def define_jacobian_determinant(name):
-- 
GitLab