Skip to content

Extend derivative block to derive residuals from functionals#4118

Open
Joseabcd wants to merge 27 commits intoFEniCS:mainfrom
Joseabcd:extend-derivative_block-to-derive-residuals-from-functionals
Open

Extend derivative block to derive residuals from functionals#4118
Joseabcd wants to merge 27 commits intoFEniCS:mainfrom
Joseabcd:extend-derivative_block-to-derive-residuals-from-functionals

Conversation

@Joseabcd
Copy link
Copy Markdown

@Joseabcd Joseabcd commented Mar 4, 2026

Make fem.forms.derivative_block work on functionals to derive residuals, as described in #3766.

The following notes could be useful for the review:

  1. The new logic is in a new code paragraph, independent of the original code. Not sure if a different style is preferred
  2. I have used ValueError exceptions as opposed to asserts, assuming that the checks are on user input (as opposed to checks against bugs). The original code however has some asserts, so I’m not sure which is their right intent
  3. I have not covered the case where F is a list of functionals
  4. The original code creates a list of trial functions independently. Perhaps it should be updated to use ufl.TrialFunctions(ufl.MixedFunctionSpace(…))?
  5. As in the original code, I have not checked that du is the correct type of argument (test vs trial), but possibly this might be helpful

CLOSES: #3766

@schnellerhase
Copy link
Copy Markdown
Contributor

schnellerhase commented Mar 5, 2026

Looks like a good start.

  • Your case switching check is identical for rank 0 to 1 and 1 to 2. A dependency on the rank will be necessary to differentiate. For a ufl form a you can access the rank as a.rank. I now saw the arguments check.
  • To ensure your code works and to simplify development unit tests would be good to add, for example in test_forms.py. (The rank 1 to 2 case seems to be only unit tested through the assembler at the moment, would be good to also add a small unit test for this case)

Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
@Joseabcd
Copy link
Copy Markdown
Author

Joseabcd commented Mar 9, 2026

thanks @schnellerhase and @jorgensd

I found no rank() method, so I used the more cumbersome check with len(F.arguments())

While adding tests, I realized there were more situations where the user can supply bad inputs and get obscure errors (or unintended results silently), so I have been more comprehensive when checking the inputs.

For example, before you could wrongly pass trial functions to derive functionals, and it would still return a form (or Nones) without complaining, asufl.derivative seems quite silent. I’ve also made sure that incorrect arguments don't exit derivative_block with an unhelpful error. After this,derivative_block grew, so its body is now grouped in small functions to make it more readable.

For consistency, I’ve also replaced the asserts with ValueError. And I’ve used ValueError even in cases when the strictly correct exception should be TypeError, in order to avoid more extra conditions (assuming that users won’t care and that they won't be dealing with these exceptions at such level of detail). I was not quite sure about the preference on this point though

Could you let me know how it looks, if the new checks do indeed belong here, or any other feedback or thoughts?

Comment thread python/test/unit/fem/test_forms.py Outdated
Comment thread python/test/unit/fem/test_forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py Outdated
Comment thread python/dolfinx/fem/forms.py
@jhale
Copy link
Copy Markdown
Member

jhale commented Mar 10, 2026

This looks pretty good but I think it's a bit 'strongly typed/overly checked' with if statements - shouldn't a lot of these already be picked up lower down in UFL?

…, and rename to 'F' variables holding residuals.
@schnellerhase
Copy link
Copy Markdown
Contributor

I found no rank() method, so I used the more cumbersome check with len(F.arguments())

My bad - the rank functionality is only available for expressions. Should be added to the UFL maybe as form.arity property. len(F.arguments()) is good here.

For example, before you could wrongly pass trial functions to derive functionals, and it would still return a form (or Nones) without complaining, asufl.derivative seems quite silent.

I agree this is a problematic interface. The underlying reason for this is that the only difference between a trial and test function in UFL is an index denoting the placement https://github.com/FEniCS/ufl/blob/61ea6299409a61d9e90e94d0b34f14ed269fa745/ufl/argument.py#L297-L312, however no input checks are performed on 2 only showing up if 1 is provided. This causes also other surprising behaviour #3721.

Comment thread python/test/unit/fem/test_forms.py
…ence of them. Remove the corresponding tests from test_derivative_block..
… Remove the corresponding test from test_derivative_block.
@Joseabcd
Copy link
Copy Markdown
Author

Joseabcd commented Mar 12, 2026

This looks pretty good but I think it's a bit 'strongly typed/overly checked' with if statements - shouldn't a lot of these already be picked up lower down in UFL?

I've removed now some of the checks as suggested above. I'm happy to remove the rest of those suggested, but I left a question in an inline comment that I think needs to be resolved first

I marked as "resolved" the comments that I believe require no further action, but please let me know if anything doesn't look good

@Joseabcd Joseabcd force-pushed the extend-derivative_block-to-derive-residuals-from-functionals branch from 14b082d to 30ef1a9 Compare March 13, 2026 20:03
@Joseabcd
Copy link
Copy Markdown
Author

Joseabcd commented Apr 12, 2026

I think all comments above have been addressed now. The stringent checks on the inputs have mostly been removed, letting inputs reach UFL in most cases. Some checks remain inside _derive_block_jacobian (see comment), to prevent from breaking the code that here calculates the component-wise Jacobian.

Could you please have another look at it when you have time, and let me know if there are still any concerns?

…bad second argument. Clean up import no longer needed.
@Joseabcd Joseabcd force-pushed the extend-derivative_block-to-derive-residuals-from-functionals branch from c7808da to c94308d Compare April 12, 2026 18:06
Copy link
Copy Markdown
Member

@jhale jhale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks this looks very nice, and super useful for people working with energy minimization principles.

@schnellerhase schnellerhase added the enhancement New feature or request label Apr 18, 2026
Comment thread python/test/unit/fem/test_forms.py Outdated
@schnellerhase
Copy link
Copy Markdown
Contributor

Could you link the issue so it auto closes/links to the PR?

@Joseabcd
Copy link
Copy Markdown
Author

Could you link the issue so it auto closes/links to the PR?

done now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extend derivative_block() to derive residuals from functionals

4 participants