Skip to main content
24 events
when toggle format what by license comment
Jan 8, 2022 at 23:30 comment added bob_bill Thanks a lot @knl, for the mathematical side I was already using those classics, while I have to say FEniCS book was new to me, but really cool (I already saw most of Bangerth's lectures notes). Your suggestions are really precious, thanks again :-)
Jan 7, 2022 at 7:13 comment added knl I read so many books that I've lost count. There isn't a single source I used. However, reading books by people who have developed codes themselves and comparing them to some of the more mathematical texts have helped me a lot. Some examples are Demkowicz' books, Larson book is very nice although the codes are not very fast, Wolfgang Bangerth's lecture notes, FEniCS book is quite good overview of modern thinking. The mathematical side is: Braess, Johnson, Ern-Guermond books, Brenner-Scott, and Boffi-Brezzi-Fortin. However, I also learn a lot from colleagues in academia so hard to say.
Jan 5, 2022 at 12:12 vote accept bob_bill
Jan 5, 2022 at 12:12 history bounty ended bob_bill
Jan 5, 2022 at 12:12 comment added bob_bill You're right. Thanks so much @knl, you've been really helpful. I accepted your answer. I've seen you're developing a python library. Is there any reference/book that describes FEM implementations from the Mathematical perspective (i.e. by thinking in terms of DoFs, not like engineers) that you've used to develop it, or is it "only experience"?
Jan 5, 2022 at 7:34 comment added knl Note that even in standard $H^1$ FEM we are doing two transformations, the other one is just so trivial that you never think about it as a transformation. ($\psi(x) = \hat{\psi}(\hat{x})$)
Jan 5, 2022 at 7:31 comment added knl Yes, we are applying two transformations. $F_K$ defines the shape of the global triangle. Piola makes sure that the derivative DOFs are preserved through the transformation. You can think about it in 1D. If you have $f(u) = u(a)$ as a DOF we can transform basis function as $\psi(x) = \hat{\psi}(\hat{x})$ and, as a consequence, $f(\hat{\psi}) = f(\psi)$. However, if you have $g(u) = u^\prime(a)$ as a DOF we would have $g(\hat{\psi}) \not= g(\psi)$. Hence, we cannot do $\psi(x) = \hat{\psi}(\hat{x})$ and need to invent something else. (Piola preserves normal derivatives in 2D and 3D).
Jan 5, 2022 at 0:37 comment added bob_bill Sorry for asking again, but the "dx" term with $\det(B_K)$ (which simplifies with the $\det(B_K)$ in the divergence term) then will appear because we're still using the transformation $x = B_K \hat{x} + b_K$, i.e. $x=F_K(\hat{x})$ when we come back to $\hat{K}$, right? What is puzzling me is that is seems that we're applying two transformations: Piola and $F_K$. I understand the definition of Piola transformation, but I don't see how the change of variable from $K$ to $\hat{K}$ is working in this case. @knl
Jan 4, 2022 at 21:24 comment added knl I'm not sure what is going on. The contravariant Piola transformation is defined as $$\frac{1}{\det(B_K)} B_K \hat{\Psi}(\hat{x}) = \Psi(x).$$ This implies that the divergence transforms as $$\frac{1}{\det(B_K)} \hat{\mathrm{div}}\hat{\Psi} = \mathrm{div}\Psi.$$
Jan 4, 2022 at 19:19 comment added bob_bill So basically we have $\int_K \operatorname{div}(\Phi)p(x) dx$ and since $x = F_K(\hat{x})$ and we $$\int_{\hat{K}} \operatorname{div}(\frac{1}{\det(B_K))} \hat{\Phi}(\hat{x})) \hat{q_j}(\hat{x}) |\det(B_K)| d \hat{x}$$ What is not clear to me is why we're allowed to put that $\frac{1}{\det(B_K)}$ inside the divergence, instead of the usual affine map. This is not mathematically correct, right? @knl
Jan 4, 2022 at 14:48 comment added knl The code in your reference is a bit unreadable due to the unnecessarily complicated vectorization. However, it seems in the first snippet they multiply by detJ and in the second snippet they divide by detJ so the end result should be the same. The equation (9) is really confusing because the divergence has no "hat" implying that it would be in the global coordinates. Somehow I feel that shouldn't be the case so I assume they have a typo somewhere in the formulae.
Jan 4, 2022 at 14:40 comment added knl Usually you multiply by detJ because of the integral transformation. The integral is transformed to the reference element and, as a consequence, we multiply by detJ. However, Piola transformation requires dividing by detJ so those two cancel out and that's why your approach works.
Jan 4, 2022 at 10:58 comment added bob_bill You spotted the biggest typo. Thanks a lot. I edited my question with my results and the new code. It seems to work (see solution and EOC w.r.t DoFs), even if I do not understand what should be the local contribution to the matrix $B$, since in the paper I am using it's not clear to me what's going on. If you could clarify this last aspect, then I have no other questions (I opened a bounty so to give you more credits, as you looked also the code)
Jan 2, 2022 at 22:09 history edited knl CC BY-SA 4.0
added 331 characters in body
Jan 2, 2022 at 22:05 comment added knl Looking at your code, that could explain the error. What you need to do is to uniquely index all edges in your mesh and then use those instead of the vertex indices when assembling. I edited the answer to reflect this.
Jan 2, 2022 at 22:05 comment added knl RT0 basis functions are one per edge, not one per vertex. The indexing is different.
Jan 2, 2022 at 19:47 comment added bob_bill Uhm, then there must be an error in my assembly routine. I have, in each triangle $K$, three DoFs for the velocity $\boldsymbol{u}$ whose global index is given by the l2g vector, and one for the pressure. On each velocity DoF (corresponding to the vertex of the triangle) I am assuming to have a RT basis function, so the "divergence" matrix is a 3 by 1 in each $K$, while the mass matrix is a 3by3. That's correct, right? @knl
Jan 2, 2022 at 11:22 comment added knl No postprocessing unless you want to do Neumann boundary condition.
Jan 2, 2022 at 10:26 comment added bob_bill So, correct me if I'm wrong, in my case I shouldn't post process the matrices $A,B$ after the assembly, right? The problem then must be in how I assemble $B$, since its nullspace is not made by a multiple of the vector $1$. Maybe the problem is in how I considered the DoFs for $B$ in the snippet @knl
Jan 2, 2022 at 8:15 comment added knl Zero Dirichlet is a natural BC and automatically satisfied.
Jan 1, 2022 at 16:37 comment added bob_bill Okay. For what concerns the homogeneous Dirichlet BC, how should I impose them? In my code, I just assembled the global block matrix and solved using that matrix, without any postprocess, because the term with the Dirichlet BC in the weak form is identically $0$. @knl
Jan 1, 2022 at 15:27 comment added knl Alright, in the DOF you are dividing by the length of the edge. Then it's fine I guess.
Jan 1, 2022 at 10:59 comment added bob_bill Honestly, I just found the expression for those functions and used them. I took them from siam.org/Portals/0/Publications/SIURO/Vol12/S01743.pdf (page 250)
Jan 1, 2022 at 7:28 history answered knl CC BY-SA 4.0