-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement the Poynting vector calculation #115
Implement the Poynting vector calculation #115
Conversation
Looks amazing! Two small ideas:
What do you think? |
Thanks for the comments/ideas :)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great progress!
femwell/maxwell/waveguide.py
Outdated
|
||
# New basis will be the discontinuous variant used by the solved Ez-field | ||
(Et, Et_basis), (En, En_basis) = self.basis.split(self.E) | ||
poynting_basis = self.basis.with_element(ElementDG(ElementTriP1())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant as this line we should reuse the element for Ez of the basis, i.e.
poynting_basis = self.basis.with_element(ElementDG(ElementTriP1())) | |
poynting_basis = self.basis.with_element(ElementDG(self.basis.elems[1])) |
would brobably do it.
Even better would be to have here a
poynting_basis = self.basis.with_element(ElementDG(ElementTriP1())) | |
poynting_basis = self.basis.with_element(ElementDG(ElementVector(self.basis.elems[1],3))) |
as this way we could directly project using just one basis. This way we'd just have one field to return.
Some background:
ElementDG converts Elements in their discontinous counterpart. For example, ElementTriP1 has its degrees of freedom (DOFs) on the nodes around (Tri->Triangles->3 nodes/dofs).
As those nodes are shared with the neighboring triangles, DOFs are shared with the neighbors (just imagine the triangles's node-heights being the values and the triangles the surfaces in-between the nodes. A continuous element would lead to a continuous surface as the values at the nodes are reused.)
Here, we don't expect it to be continuous as epsilon
makes discrete jumps as the boundaries, thus we have to consider that in how we choose the element.
For maxwell's equations we know that the tangential component of the field is continuous while the normal component is not -> best choice for Ex/Ey is a H(curl)-conforming element like the Nedelec-element. For Ez we know it's continuous so we're best of with a Lagrange element.
For the pointing vector, i'd guess it's save to use a vector of Lagrangian elements. As we see in the plots that it's discontinuous at boundaries, we need the discontinuous version of it.
Here, the question would be if there's any continuity across boundaries of the poynting vector which we could have in our choice of element as that would reduce the needed number of DOFs and would probably also be a bit more precise. (@DorisReiter do you know if there's any component of the pointing vector continuous across boundaries?)
For now I think we can just get it in with the Vector of Lagrangian elements, as we don't do a solve using those elements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see for the use of basis.elem.elems
.
(In the beginning I wanted/was thinking to use split()
and get the elements from En_basis
, but this way is much cleaner!)
(Corrected on 98cb853)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation! :)
I don't get the second part of your message to use a function like self.basis.with_element(ElementDG(ElementVector(self.basis.elems[1],3)))
. Why will we be allowed to project using one basis? Don't we already make that with the poynting_basis.project()
?
For the Poynting vector, from what I remember, you have the Poynting theorem which is an expression for the conservation of energy:
with
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at the moment, we have three sets of DOFs as the element is a scalar element.
if we use a vector-element we can have all three components in one set of DOFs (which we can split if we need)
something like
poynting_basis = self.basis.with_element(ElementDG(ElementVector(self.basis.elems[1],3)))
... = poynting_basis.project(np.stack([Px,Py,Pz]))
should do it (I always forget if stack/hstack/vstack, it should be stacked as a new last axis)
alternatively, there should also be a way to combine the DOFs into one set and use it with the vector basis, but I think it's better readable if we treat it directly as a vector.
About the continuity: that equation doesn't tell us about the interface-conditions of a single component (as a discrete change in one component can be compensated in another one)
So I guess it's better to assume it's discontinuous (the pictures you posted/in the paper also show that it's not continuous across interfaces)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also wondering if treating it as a vector makes sense at all 🤔
we're calculating eigenmodes, which should mean that the mode propagates only in z
direction...
That lead to
Or is it only the integral over the whole domain which needs to be zero for those two components?
Edit: seems like it can be non-zero https://doi.org/10.1364/OE.472148
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also wondering if treating it as a vector makes sense at all 🤔 we're calculating eigenmodes, which should mean that the mode propagates only in
z
direction... That lead to Sx=$S_y$=0? Or is it only the integral over the whole domain which needs to be zero for those two components?
Honestly that's a good question... I also found an article which states about that. So I think it is safer to keep the 3 components :)
use vectorbasis instead of three individual bases for the poynting vector
Regarding the issue #106:
calculate_poynting()
for the classMode()
to calculate the Poynting vector of a mode