| 81 // // assert(adj->num_links(i) == 3); // Should not need this |
81 // // assert(adj->num_links(i) == 3); // Should not need this |
| 82 // auto d = fp->dofmap()->cell_dofs(i); |
82 // auto d = fp->dofmap()->cell_dofs(i); |
| 83 // printf("%zd\n", d.size()); |
83 // printf("%zd\n", d.size()); |
| 84 // } |
84 // } |
| 85 |
85 |
| 86 // DOF coordinates (may be more than nodes, e.g., intermediate points) |
86 // DOF coordinates and dofmap for the function space itself (not the mesh geometry). |
| 87 auto gx = geom.x(); |
87 // For a scalar P2 space this gives us, per cell, the 6 nodal points (3 corners + 3 edge |
| 88 // auto num_points = gx.size() / 3; |
88 // midpoints) directly in basix's local ordering, so we no longer need to reconstruct |
| 89 // Map from cells to DOF indices |
89 // edge midpoints via f->eval. |
| 90 auto geom_dofmap = geom.dofmap(); |
|
| 91 assert(geom_dofmap.extent(0) == (size_t)n_cells); |
|
| 92 assert(geom_dofmap.extent(1) == 3); |
|
| 93 auto fp_dofmap = fp->dofmap(); |
90 auto fp_dofmap = fp->dofmap(); |
| 94 |
91 // transpose=false gives a flat vector laid out as (num_dofs, 3) row-major, i.e. |
| 95 // auto dof_coords = fp->tabulate_dof_coordinates(); |
92 // dof_coords[3*d + component]. |
| |
93 auto dof_coords = fp->tabulate_dof_coordinates(false); |
| |
94 auto v_array = v->array(); // local coefficient vector |
| 96 |
95 |
| 97 CoordValuePair res{{{0.0, 0.0}}, INFINITY}; |
96 CoordValuePair res{{{0.0, 0.0}}, INFINITY}; |
| 98 |
97 |
| 99 // printf("%zd %zd\n", v->array().size(), gx.size()); |
98 for (auto i = 0; i < n_cells; i++) { |
| |
99 auto dofs = fp_dofmap->cell_dofs(i); |
| |
100 assert(dofs.size() == 6); |
| 100 |
101 |
| 101 for (auto i = 0; i < n_cells; i++) { |
102 // Coordinates of all 6 P2 nodes for this cell, in Fenics' hard-coded 3D layout. |
| 102 // Cell corners |
103 std::array<double, 18> x{}; |
| 103 auto j0 = geom_dofmap(i, 0); |
104 // Nodal values of f at those same 6 points. |
| 104 auto j1 = geom_dofmap(i, 1); |
105 std::array<double, 6> vals{}; |
| 105 auto j2 = geom_dofmap(i, 2); |
|
| 106 |
106 |
| 107 // Construct list of coordinates. Due to f->eval, we construct this is a single list |
107 for (std::size_t k = 0; k < 6; k++) { |
| 108 // with all the Fenics weirdness of hard-coded 3D. |
108 auto d = dofs[k]; |
| 109 std::array<double, 9> x = {gx[3 * j0], gx[3 * j0 + 1], 0, |
109 vals[k] = v_array[d]; |
| 110 gx[3 * j1], gx[3 * j1 + 1], 0, |
110 x[3 * k] = dof_coords[3 * d]; |
| 111 gx[3 * j2], gx[3 * j2 + 1], 0}; |
111 x[3 * k + 1] = dof_coords[3 * d + 1]; |
| |
112 x[3 * k + 2] = 0.0; |
| |
113 } |
| 112 |
114 |
| 113 // Find the solution on the simplex. |
115 // Find the solution on the simplex. |
| 114 auto newres = minmax_dolfinx_p2_cell(f, x, i, max); |
116 auto newres = minmax_dolfinx_p2(x, vals, max); |
| 115 |
117 |
| 116 // printf("%f [%f, %f] [%f %f %f %f %f %f] <%f, %f> <%f, %f> <‸%f, %f>\n", newres.v, |
|
| 117 // newres.x[0], newres.x[1], values[0], values[1], values[2], values[3], |
|
| 118 // values[4], values[5], x[0], x[1], x[3], x[4], x[6], x[7]); |
|
| 119 if (newres.v < res.v) { |
118 if (newres.v < res.v) { |
| 120 res = newres; |
119 res = newres; |
| 121 } |
120 } |
| 122 |
|
| 123 // // Full DOF data |
|
| 124 // auto d = fp_dofmap->cell_dofs(i); |
|
| 125 // // TODO: array() gives just local part of vector |
|
| 126 // assert(d.size() == 6); |
|
| 127 // for (auto k = 0; k < d.size(); k++) { |
|
| 128 // auto j = d[k]; |
|
| 129 // // printf("%d %d\n", 3 * j + 1, nodes.size()); |
|
| 130 // assert(2 * j + 1 <= nodes.size()); |
|
| 131 // auto x = {nodes[3 * j], nodes[3 * j + 1]}; |
|
| 132 // } |
|
| 133 } |
121 } |
| 134 |
122 |
| 135 // Negate result if maximising. |
123 // Negate result if maximising. |
| 136 if (max) { |
124 if (max) { |
| 137 res.v = -res.v; |
125 res.v = -res.v; |
| 138 } |
126 } |
| 139 return res; |
127 return res; |
| |
128 } |
| |
129 |
| |
130 void cell_dofs_Function_f64_p2(Function<double> const* f, int32_t cell, |
| |
131 std::array<double, 18>& x, std::array<double, 6>& vals) { |
| |
132 auto fp = f->function_space(); |
| |
133 auto fp_dofmap = fp->dofmap(); |
| |
134 auto dofs = fp_dofmap->cell_dofs(cell); |
| |
135 assert(dofs.size() == 6); |
| |
136 auto dof_coords = fp->tabulate_dof_coordinates(false); |
| |
137 auto v = f->x(); |
| |
138 auto v_array = v->array(); // local coefficient vector |
| |
139 |
| |
140 for (std::size_t k = 0; k < 6; k++) { |
| |
141 auto d = dofs[k]; |
| |
142 vals[k] = v_array[d]; |
| |
143 x[3 * k] = dof_coords[3 * d]; |
| |
144 x[3 * k + 1] = dof_coords[3 * d + 1]; |
| |
145 x[3 * k + 2] = 0.0; |
| |
146 } |
| 140 } |
147 } |
| 141 |
148 |
| 142 CoordValuePair min_Function_f64_p2(Function<double> const* f) { |
149 CoordValuePair min_Function_f64_p2(Function<double> const* f) { |
| 143 return minmax_Function_f64_p2(f, false); |
150 return minmax_Function_f64_p2(f, false); |
| 144 } |
151 } |
| 152 m.def("min_Function_f64_p2", &min_Function_f64_p2); |
159 m.def("min_Function_f64_p2", &min_Function_f64_p2); |
| 153 m.def("max_Function_f64_p2", &max_Function_f64_p2); |
160 m.def("max_Function_f64_p2", &max_Function_f64_p2); |
| 154 m.def("minmax_Function_f64_p2", &minmax_Function_f64_p2); |
161 m.def("minmax_Function_f64_p2", &minmax_Function_f64_p2); |
| 155 m.def("eval_Function_f64", &eval_Function_f64); |
162 m.def("eval_Function_f64", &eval_Function_f64); |
| 156 m.def("cell_Function_f64", &cell_Function_f64); |
163 m.def("cell_Function_f64", &cell_Function_f64); |
| |
164 m.def("cell_dofs_Function_f64_p2", &cell_dofs_Function_f64_p2); |
| 157 // m.def("cell_Mesh_f64", &cell_Mesh_f64); |
165 // m.def("cell_Mesh_f64", &cell_Mesh_f64); |
| 158 m.def("cell_FunctionSpace_f64", &cell_FunctionSpace_f64); |
166 m.def("cell_FunctionSpace_f64", &cell_FunctionSpace_f64); |
| 159 nanobind::class_<CoordValuePair>(m, "CoordValuePair") |
167 nanobind::class_<CoordValuePair>(m, "CoordValuePair") |
| 160 .def_rw("x", &CoordValuePair::x) |
168 .def_rw("x", &CoordValuePair::x) |
| 161 .def_rw("v", &CoordValuePair::v); |
169 .def_rw("v", &CoordValuePair::v); |