-
Notifications
You must be signed in to change notification settings - Fork 707
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
Integrators for DG face integrals with tests. #5870
Conversation
/run-tests |
The evaluator part of face integrals |
I'd like to review this patch but it will probably take me a couple of days to get to it. |
I'm glad @Rombur wants to do it, because 3800 new lines would have blown a substantial hole into one of my next days :-) |
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 only skimmed it and I hope somebody else does a thorough review, but I have a few comments...
} | ||
else | ||
{ | ||
evaluator.template values<2,false,false>(t0, t2); |
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.
can you please leave a comment to explain this reverse ordering? (also above)
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.
It is because the EvaluatorTensorProduct
kernels have gained the possibility to do in-place operations, which necessitated a change in the hardcoded strides/offsets in the generalized matrix-matrix multiplication to make sure it does not overwrite things. In particular, we need to start with the outermost dimension in the no-transpose path with more columns than rows (second false
template argument). By the way, this reminds me that we could now do all this in a single array t0
without temporary arrays t1,t2
.
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.
We have replaced the whole function by the new FEEvaluationImplBasisChange::do_forward/do_backward
call.
Utilities::fixed_power<dim>(shape_info.fe_degree+1) : shape_info.dofs_per_component_on_cell; | ||
Number *values_dofs = (type == MatrixFreeFunctions::truncated_tensor) ? | ||
scratch_data+2*(std::max(shape_info.dofs_per_component_on_cell, shape_info.n_q_points)) : | ||
const_cast<Number *> (values_dofs_actual); |
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 don't like the const cast, wouldn't it be cleaner to move this variable below the if and make it const and operate on a different (non-const) variable inside the if? (this assumes this is the only place you modify it)
note: I hope I understood the code correctly.
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.
We need to check this carefully. I agree that it is not pretty right now.
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.
Fixed.
* evaluation, spectral collocation or simply collocation, meaning the same | ||
* location for shape functions and evaluation space (quadrature points). | ||
* | ||
* @author Katharina Kormann, 2012 |
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.
you have been sitting on this since 2012? ;-)
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.
No, it is just github that gets confused by moving this class FEEvaluationImplCollocation
above FEEvaluationImplTransformToCollocation
- the latter now uses the former after having changed the basis, as promised by the name.
And just as a side note, the changes in that file are actually mostly 2017.
EvalGeneric::dofs_per_cell : EvalGeneric::n_q_points; | ||
static_assert(temp_size > 0, "temp_size should not be zero"); | ||
|
||
Number temp_data[temp_size < 100 ? temp_size : 1]; |
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.
can you use boost::container::small_vector here instead?
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.
Fixed (with using the provided scratch_data
array rather than a separate one).
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 am not done reviewing this PR yet. This only the first part.
if (evaluate_hessians == true) | ||
eval.template hessians<0,true,false> (values_dofs[c], hessians_quad[c][0]); | ||
eval.template hessians<0,true,false> (values_dofs, hessians_quad); | ||
values_dofs += dofs_per_comp; |
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.
Can you add a comment that we are moving in the 1D array. This was confusing at first.
|
||
switch (dim) | ||
{ | ||
case 1: | ||
for (unsigned int c=0; c<n_components; c++) | ||
{ | ||
if (integrate_values == true) | ||
eval.template values<0,false,false> (values_quad[c], values_dofs[c]); | ||
{ | ||
if (overwrite_values == true) |
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.
Is overwrite_values
the appropriate name? Is it just the opposite of the add
template parameters in the tensor product kernels? If so, I think that it would makes sense to rename the variable because it is unclear what overwrite_values==false
means.
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.
Also you may want to make overwrite_values
a template parameter. I feel that it would simplify the code quite a bit here.
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.
Changed the name to add_into_values_array
which better reflects the purpose. We decided not to have a function template within the already templated class for now because it is shorter to write at the call.
::do_forward(transformation_matrix, | ||
values_in + (q-1)*Utilities::fixed_int_power<n_points_1,next_dim>::value, | ||
values_out + (q-1)*Utilities::fixed_int_power<n_points_2,next_dim>::value); | ||
if (n_points_2 == n_points_1 && dim == 2) |
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.
So if I understand this correctly, the end of the recursion is for dim==1
except if n_points_2==n_points_1 && dim==2
where we stop early.
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.
Commented.
const unsigned int d3 = d1+d2; | ||
const unsigned int d4 = dim>2?4:d3; | ||
const unsigned int d5 = dim>2?5:d4; | ||
Assert(n_q_points_1d > fe_degree, |
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.
Shouldn't this be a static assert?
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.
The compiler does not like the static assert because the function where we select the different paths sees the struct also in the invalid case - even though the code then does not enter the function.
// gradients_quad[2] only for dim==3. | ||
const unsigned int d1 = dim>1?1:0; | ||
const unsigned int d2 = dim>2?2:0; | ||
Assert(n_q_points_1d > fe_degree, |
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.
static assert?
const Number *input, | ||
Number *output, | ||
const bool do_gradients, | ||
const unsigned int face_no) |
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.
The indentation is pretty strange here
::evaluate(shape_info, values_dofs_actual, values_quad, | ||
gradients_quad, hessians_quad, scratch_data, | ||
evaluate_values, evaluate_gradients, evaluate_hessians); | ||
else if (degree < n_q_points_1d) |
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.
Is this the same condition as before or is it more general?
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.
Before we only did it for degree+1==n_q_points_1d
but now we do it for degree<n_q_points_1d
. It works because a lower polynomial degree can be exactly embedded into a space of a higher degree.
4c45d17
to
296a914
Compare
Assert(shape_values.size() == 0 || | ||
shape_values.size() == n_rows*n_columns || | ||
shape_values.size() % n_rows == 0, | ||
ExcDimensionMismatch(shape_values.size(), n_rows*n_columns)); |
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.
Assert
can be reduced to shape_values.size() % n_rows == 0
?
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.
Can you elaborate on shape_values.size() % n_rows == 0
?
static const unsigned int dofs_per_cell = Utilities::fixed_int_power<fe_degree+1,dim>::value; | ||
static const unsigned int n_q_points = Utilities::fixed_int_power<n_q_points_1d,dim>::value; | ||
static const unsigned int dofs_per_cell = Utilities::fixed_int_power<n_rows,dim>::value; | ||
static const unsigned int n_q_points = Utilities::fixed_int_power<n_columns,dim>::value; |
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.
Do we need dofs_per_cell
and n_q_points
only in the context of FEEvaluation
?
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.
Right now it's only used there, but again it is a general concept. It would probably make sense to give the variables more descriptive names now that we don't use fe_degree
any more. How about n_rows_of_product
and n_columns_of_product
to indicate that it is the size accumulated over all dimensions, n_rows^dim
?
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 like that! It generically describes the size of the resulting matrix with respect to the underlying Kronecker product.
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.
Do you want to change the name of the variables in this PR? If not, I'll merge.
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.
It is fixed now. The PR should be ready for merging.
Assert(shape_values.size() == 0 || | ||
shape_values.size() == n_rows*n_columns || | ||
shape_values.size() % n_rows == 0, | ||
ExcDimensionMismatch(shape_values.size(), n_rows*n_columns)); |
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.
Can you elaborate on shape_values.size() % n_rows == 0
?
* not correct. | ||
* | ||
* @tparam direction Direction that is evaluated | ||
* @tparam contract_over_rows If true, the tensor contraction goes sums |
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.
typo goes
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.
Fixed.
* the one currently applied. In other words, apply_face() must be called | ||
* before calling any interpolation within the face. | ||
* | ||
* @tparam direction Direction of the normal vector (0=x, 1=y, etc) |
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.
is it better to call it face_direction
?
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.
Fixed. (This was a typo in the comment, the actual parameter was already named this way.)
* @tparam contract_onto_face If true, the input vector is of size n_rows^dim | ||
* and interpolation into n_rows^(dim-1) points | ||
* is performed. This is a typical scenario in | ||
* FEEvaluation::evaluate() calls. If false, the |
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.
Do you mean FEFaceEvaluation::evaluate()
here?
template <int dim, int fe_degree, int n_q_points_1d, typename Number> | ||
struct EvaluatorTensorProduct<evaluate_general,dim,fe_degree,n_q_points_1d,Number> | ||
template <int dim, int n_rows, int n_columns, typename Number, typename Number2> | ||
struct EvaluatorTensorProduct<evaluate_general,dim,n_rows,n_columns,Number,Number2> |
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! I like the generalization to n_rows
and n_columns
.
779cf96
to
8dc3978
Compare
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.
Looks good. Next time please split the patch in more PR/commits it's really hard to review such a large PR
* @tparam variant Variant of evaluation used for creating template | ||
* specializations | ||
* @tparam dim Dimension of the function | ||
* @tparam n_rows Number rows in the transformation matrix, which corresponds |
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.
Number of rows
* tensor product form of the basis functions. | ||
* | ||
* @tparam dim Space dimension in which this class is applied | ||
* @tparam n_rows Number rows in the transformation matrix, which corresponds |
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.
Number of rows
* together | ||
* @tparam add If true, the result is added to the output vector, else | ||
* the computed values overwrite the content in the output | ||
* @tparam max_derivatve Sets the number of derivatives that should be |
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.
typo max_derivative
@@ -456,48 +799,70 @@ namespace internal | |||
* tensor-product based elements for "symmetric" finite elements, i.e., when | |||
* the shape functions are symmetric about 0.5 and the quadrature points | |||
* are, too. | |||
* | |||
* @tparam dim Space dimension in which this class is applied | |||
* @tparam n_rows Number rows in the transformation matrix, which corresponds |
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.
Number of rows
@@ -1032,99 +1340,200 @@ namespace internal | |||
* experiments in the book say that the method is not efficient for N<20, it | |||
* is more efficient in the context where the loop bounds are compile-time | |||
* constants (templates). | |||
* | |||
* @tparam dim Space dimension in which this class is applied | |||
* @tparam n_rows Number rows in the transformation matrix, which corresponds |
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.
typo
shape_gradients (nullptr), | ||
shape_hessians (nullptr) | ||
{ | ||
AssertDimension(shape_values.size(), n_rows*((n_columns+1)/2)); |
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.
Does this assert work if shape_values
is empty? You check that it is not empty below.
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.
In this case, it makes no sense if shape_values
is empty since it is the only argument.
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, this function is internal right? If it is then it's fine otherwise we should check that shape_values
is not empty, so that user get a nicer error message.
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.
Yes, the function is internal (at least for now). We might think about making some of those generally usable at some point in the future but certainly not for the 9.0 release.
* difference is in the way the input and output quantities are symmetrized. | ||
* | ||
* @tparam dim Space dimension in which this class is applied | ||
* @tparam n_rows Number rows in the transformation matrix, which corresponds |
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.
typo
* Empty constructor. Does nothing. Be careful when using 'values' and | ||
* related methods because they need to be filled with the other | ||
* constructor passing in at least an array for the values. | ||
*/ |
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.
Does this mean that the object constructed is never usable?
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.
You can only use the (static) function apply
.
8dc3978
to
34609c3
Compare
This PR was already split out from the overall matrix-free DG support as laid out in #5667 and it would have been difficult to split this up further without considerably re-working on the code. I think we have a few smaller patches ahead though. On the plus side, I would argue that pulling in code from a development branch that we have worked on for more than three years has the advantage that the master branch has skipped a lot of initially bad decisions that we made under the way and thus reduced the noise so far. |
I understand but for example replacing |
34609c3
to
13fc76d
Compare
Integrator part of #5667.
EvaluatorTensorProduct::apply_face
providing face integrals. Introduces structsFEFaceEvaluationImpl
for operations within the face andFEFaceNormalEvaluationImpl
for interpolation from the cell to the face.EvaluatorTensorProduct
fromfe_degree
andn_q_points_1d
ton_rows
andn_columns
because the kernels are a linear algebra abstraction and do not necessarily need to be associated to quadrature and elements.EvaluatorTensorProduct
for dimension-independent case (dim>3
).DEAL_II_RESTRICT
to main worker kernels where appropriate.EvaluatorTensorProduct::apply
also works whenin
andout
point to same data.EvaluatorTensorProduct
.FEEvaluationImpl
a true abstract typeNumber
, rather than constructingVectorizedArray<Number>
. This removes the hardcoding ofVectorizedArray
in this class.FEEvaluationImplTransformToCollocation
forn_q_points_1d > fe_degree+1
.Since all changes are in the
internal
namespace, breaking the old interface is uncritical.