|
8 | 8 | from firedrake.nullspace import VectorSpaceBasis, MixedVectorSpaceBasis |
9 | 9 | from firedrake.solving_utils import _SNESContext |
10 | 10 | from firedrake.tsfc_interface import extract_numbered_coefficients |
11 | | -from firedrake.utils import ScalarType_c, IntType_c, cached_property |
| 11 | +from firedrake.utils import IntType_c, cached_property |
12 | 12 | from finat.element_factory import create_element |
13 | 13 | from tsfc import compile_expression_dual_evaluation |
14 | 14 | from pyop2 import op2 |
@@ -1220,44 +1220,57 @@ def work_function(self, V): |
1220 | 1220 |
|
1221 | 1221 | @cached_property |
1222 | 1222 | def _weight(self): |
| 1223 | + cell_set = self.Vf.mesh().topology.unique().cell_set |
1223 | 1224 | weight = firedrake.Function(self.Vf) |
1224 | | - size = self.Vf.finat_element.space_dimension() * self.Vf.block_size |
| 1225 | + wsize = self.Vf.finat_element.space_dimension() * self.Vf.block_size |
1225 | 1226 | kernel_code = f""" |
1226 | | - void weight(PetscScalar *restrict w){{ |
1227 | | - for(PetscInt i=0; i<{size}; i++) w[i] += 1.0; |
1228 | | - return; |
1229 | | - }} |
1230 | | - """ |
1231 | | - kernel = op2.Kernel(kernel_code, "weight", requires_zeroed_output_arguments=True) |
1232 | | - op2.par_loop(kernel, weight.function_space().mesh().topology.unique().cell_set, weight.dat(op2.INC, weight.cell_node_map())) |
| 1227 | + void multiplicity(PetscScalar *restrict w) {{ |
| 1228 | + for (PetscInt i=0; i<{wsize}; i++) w[i] += 1; |
| 1229 | + }}""" |
| 1230 | + kernel = op2.Kernel(kernel_code, "multiplicity") |
| 1231 | + op2.par_loop(kernel, cell_set, weight.dat(op2.INC, weight.cell_node_map())) |
1233 | 1232 | with weight.dat.vec as w: |
1234 | 1233 | w.reciprocal() |
1235 | 1234 | return weight |
1236 | 1235 |
|
1237 | 1236 | @cached_property |
1238 | 1237 | def _kernels(self): |
1239 | 1238 | try: |
1240 | | - # We generate custom prolongation and restriction kernels mainly because: |
1241 | | - # 1. Code generation for the transpose of prolongation is not readily available |
1242 | | - # 2. Dual evaluation of EnrichedElement is not yet implemented in FInAT |
1243 | | - uf_map = get_permuted_map(self.Vf) |
1244 | | - uc_map = get_permuted_map(self.Vc) |
1245 | | - prolong_kernel, restrict_kernel, coefficients = self.make_blas_kernels(self.Vf, self.Vc) |
1246 | | - prolong_args = [prolong_kernel, self.uf.function_space().mesh().topology.unique().cell_set, |
1247 | | - self.uf.dat(op2.INC, uf_map), |
1248 | | - self.uc.dat(op2.READ, uc_map), |
1249 | | - self._weight.dat(op2.READ, uf_map)] |
1250 | | - except ValueError: |
1251 | | - # The elements do not have the expected tensor product structure |
1252 | | - # Fall back to aij kernels |
1253 | | - uf_map = self.Vf.cell_node_map() |
1254 | | - uc_map = self.Vc.cell_node_map() |
1255 | | - prolong_kernel, restrict_kernel, coefficients = self.make_kernels(self.Vf, self.Vc) |
1256 | | - prolong_args = [prolong_kernel, self.uf.function_space().mesh().topology.unique().cell_set, |
1257 | | - self.uf.dat(op2.WRITE, uf_map), |
1258 | | - self.uc.dat(op2.READ, uc_map)] |
1259 | | - |
1260 | | - restrict_args = [restrict_kernel, self.uf.function_space().mesh().topology.unique().cell_set, |
| 1239 | + self.Vf.finat_element.dual_basis |
| 1240 | + self.Vc.finat_element.dual_basis |
| 1241 | + native_interpolation_supported = True |
| 1242 | + except NotImplementedError: |
| 1243 | + native_interpolation_supported = False |
| 1244 | + |
| 1245 | + if native_interpolation_supported: |
| 1246 | + return self._build_native_interpolators() |
| 1247 | + else: |
| 1248 | + return self._build_custom_interpolators() |
| 1249 | + |
| 1250 | + def _build_native_interpolators(self): |
| 1251 | + from firedrake.interpolation import interpolate, Interpolator |
| 1252 | + P = Interpolator(interpolate(self.uc, self.Vf), self.Vf) |
| 1253 | + prolong = partial(P.assemble, tensor=self.uf) |
| 1254 | + |
| 1255 | + rf = firedrake.Function(self.Vf.dual(), val=self.uf.dat) |
| 1256 | + rc = firedrake.Function(self.Vc.dual(), val=self.uc.dat) |
| 1257 | + vc = firedrake.TestFunction(self.Vc) |
| 1258 | + R = Interpolator(interpolate(vc, rf), self.Vf) |
| 1259 | + restrict = partial(R.assemble, tensor=rc) |
| 1260 | + return prolong, restrict |
| 1261 | + |
| 1262 | + def _build_custom_interpolators(self): |
| 1263 | + # We generate custom prolongation and restriction kernels because |
| 1264 | + # dual evaluation of EnrichedElement is not yet implemented in FInAT |
| 1265 | + uf_map = get_permuted_map(self.Vf) |
| 1266 | + uc_map = get_permuted_map(self.Vc) |
| 1267 | + prolong_kernel, restrict_kernel, coefficients = self.make_blas_kernels(self.Vf, self.Vc) |
| 1268 | + cell_set = self.Vf.mesh().topology.unique().cell_set |
| 1269 | + prolong_args = [prolong_kernel, cell_set, |
| 1270 | + self.uf.dat(op2.INC, uf_map), |
| 1271 | + self.uc.dat(op2.READ, uc_map), |
| 1272 | + self._weight.dat(op2.READ, uf_map)] |
| 1273 | + restrict_args = [restrict_kernel, cell_set, |
1261 | 1274 | self.uc.dat(op2.INC, uc_map), |
1262 | 1275 | self.uf.dat(op2.READ, uf_map), |
1263 | 1276 | self._weight.dat(op2.READ, uf_map)] |
@@ -1444,49 +1457,6 @@ def make_blas_kernels(self, Vf, Vc): |
1444 | 1457 | ldargs=BLASLAPACK_LIB.split(), requires_zeroed_output_arguments=True) |
1445 | 1458 | return cache.setdefault(key, (prolong_kernel, restrict_kernel, coefficients)) |
1446 | 1459 |
|
1447 | | - def make_kernels(self, Vf, Vc): |
1448 | | - """ |
1449 | | - Interpolation and restriction kernels between arbitrary elements. |
1450 | | -
|
1451 | | - This is temporary while we wait for dual evaluation in FInAT. |
1452 | | - """ |
1453 | | - cache = self._cache_kernels |
1454 | | - key = (Vf.ufl_element(), Vc.ufl_element()) |
1455 | | - try: |
1456 | | - return cache[key] |
1457 | | - except KeyError: |
1458 | | - pass |
1459 | | - prolong_kernel, _ = prolongation_transfer_kernel_action(Vf, self.uc) |
1460 | | - matrix_kernel, coefficients = prolongation_transfer_kernel_action(Vf, firedrake.TrialFunction(Vc)) |
1461 | | - |
1462 | | - # The way we transpose the prolongation kernel is suboptimal. |
1463 | | - # A local matrix is generated each time the kernel is executed. |
1464 | | - element_kernel = cache_generate_code(matrix_kernel, Vf._comm) |
1465 | | - element_kernel = element_kernel.replace("void expression_kernel", "static void expression_kernel") |
1466 | | - coef_args = "".join([", c%d" % i for i in range(len(coefficients))]) |
1467 | | - coef_decl = "".join([", const %s *restrict c%d" % (ScalarType_c, i) for i in range(len(coefficients))]) |
1468 | | - dimc = Vc.finat_element.space_dimension() * Vc.block_size |
1469 | | - dimf = Vf.finat_element.space_dimension() * Vf.block_size |
1470 | | - restrict_code = f""" |
1471 | | - {element_kernel} |
1472 | | -
|
1473 | | - void restriction({ScalarType_c} *restrict Rc, const {ScalarType_c} *restrict Rf, const {ScalarType_c} *restrict w{coef_decl}) |
1474 | | - {{ |
1475 | | - {ScalarType_c} Afc[{dimf}*{dimc}] = {{0}}; |
1476 | | - expression_kernel(Afc{coef_args}); |
1477 | | - for ({IntType_c} i = 0; i < {dimf}; i++) |
1478 | | - for ({IntType_c} j = 0; j < {dimc}; j++) |
1479 | | - Rc[j] += Afc[i*{dimc} + j] * Rf[i] * w[i]; |
1480 | | - }} |
1481 | | - """ |
1482 | | - restrict_kernel = op2.Kernel( |
1483 | | - restrict_code, |
1484 | | - "restriction", |
1485 | | - requires_zeroed_output_arguments=True, |
1486 | | - events=matrix_kernel.events, |
1487 | | - ) |
1488 | | - return cache.setdefault(key, (prolong_kernel, restrict_kernel, coefficients)) |
1489 | | - |
1490 | 1460 | def multTranspose(self, mat, rf, rc): |
1491 | 1461 | """ |
1492 | 1462 | Implement restriction: restrict residual on fine grid rf to coarse grid rc. |
@@ -1566,61 +1536,15 @@ def getNestSubMatrix(self, i, j): |
1566 | 1536 | return None |
1567 | 1537 |
|
1568 | 1538 |
|
1569 | | -def prolongation_matrix_aij(P1, Pk, P1_bcs=[], Pk_bcs=[]): |
1570 | | - if isinstance(P1, firedrake.Function): |
1571 | | - P1 = P1.function_space() |
1572 | | - if isinstance(Pk, firedrake.Function): |
1573 | | - Pk = Pk.function_space() |
1574 | | - sp = op2.Sparsity((Pk.dof_dset, |
1575 | | - P1.dof_dset), |
1576 | | - {(i, j): [(rmap, cmap, None)] |
1577 | | - for i, rmap in enumerate(Pk.cell_node_map()) |
1578 | | - for j, cmap in enumerate(P1.cell_node_map()) |
1579 | | - if i == j}) |
1580 | | - mat = op2.Mat(sp, PETSc.ScalarType) |
1581 | | - mesh = Pk.mesh() |
1582 | | - |
1583 | | - fele = Pk.ufl_element() |
1584 | | - if type(fele) is finat.ufl.MixedElement: |
1585 | | - for i in range(fele.num_sub_elements): |
1586 | | - Pk_bcs_i = [bc for bc in Pk_bcs if bc.function_space().index == i] |
1587 | | - P1_bcs_i = [bc for bc in P1_bcs if bc.function_space().index == i] |
1588 | | - |
1589 | | - rlgmap, clgmap = mat[i, i].local_to_global_maps |
1590 | | - rlgmap = Pk.sub(i).local_to_global_map(Pk_bcs_i, lgmap=rlgmap) |
1591 | | - clgmap = P1.sub(i).local_to_global_map(P1_bcs_i, lgmap=clgmap) |
1592 | | - unroll = any(bc.function_space().component is not None |
1593 | | - for bc in chain(Pk_bcs_i, P1_bcs_i) if bc is not None) |
1594 | | - matarg = mat[i, i](op2.WRITE, (Pk.sub(i).cell_node_map(), P1.sub(i).cell_node_map()), |
1595 | | - lgmaps=((rlgmap, clgmap), ), unroll_map=unroll) |
1596 | | - expr = firedrake.TrialFunction(P1.sub(i)) |
1597 | | - kernel, coefficients = prolongation_transfer_kernel_action(Pk.sub(i), expr) |
1598 | | - parloop_args = [kernel, mesh.topology.unique().cell_set, matarg] |
1599 | | - for coefficient in coefficients: |
1600 | | - m_ = coefficient.cell_node_map() |
1601 | | - parloop_args.append(coefficient.dat(op2.READ, m_)) |
1602 | | - |
1603 | | - op2.par_loop(*parloop_args) |
1604 | | - |
1605 | | - else: |
1606 | | - rlgmap, clgmap = mat.local_to_global_maps |
1607 | | - rlgmap = Pk.local_to_global_map(Pk_bcs, lgmap=rlgmap) |
1608 | | - clgmap = P1.local_to_global_map(P1_bcs, lgmap=clgmap) |
1609 | | - unroll = any(bc.function_space().component is not None |
1610 | | - for bc in chain(Pk_bcs, P1_bcs) if bc is not None) |
1611 | | - matarg = mat(op2.WRITE, (Pk.cell_node_map(), P1.cell_node_map()), |
1612 | | - lgmaps=((rlgmap, clgmap), ), unroll_map=unroll) |
1613 | | - expr = firedrake.TrialFunction(P1) |
1614 | | - kernel, coefficients = prolongation_transfer_kernel_action(Pk, expr) |
1615 | | - parloop_args = [kernel, mesh.topology.unique().cell_set, matarg] |
1616 | | - for coefficient in coefficients: |
1617 | | - m_ = coefficient.cell_node_map() |
1618 | | - parloop_args.append(coefficient.dat(op2.READ, m_)) |
1619 | | - |
1620 | | - op2.par_loop(*parloop_args) |
1621 | | - |
1622 | | - mat.assemble() |
1623 | | - return mat.handle |
| 1539 | +def prolongation_matrix_aij(Vc, Vf, Vc_bcs=(), Vf_bcs=()): |
| 1540 | + if isinstance(Vf, firedrake.Function): |
| 1541 | + Vf = Vf.function_space() |
| 1542 | + if isinstance(Vc, firedrake.Function): |
| 1543 | + Vc = Vc.function_space() |
| 1544 | + bcs = Vc_bcs + Vf_bcs |
| 1545 | + interp = firedrake.interpolate(firedrake.TrialFunction(Vc), Vf) |
| 1546 | + mat = firedrake.assemble(interp, bcs=bcs) |
| 1547 | + return mat.petscmat |
1624 | 1548 |
|
1625 | 1549 |
|
1626 | 1550 | def prolongation_matrix_matfree(Vc, Vf, Vc_bcs=[], Vf_bcs=[]): |
|
0 commit comments