Skip to content

Conversation

@kle96
Copy link
Contributor

@kle96 kle96 commented Dec 8, 2025

What type of PR is this? (check all applicable)

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Example
  • Documentation

Description

I noticed that the backward Euler method was not implemented correctly. It is currently solving the ODE explicitly. The y at each iteration should be updated after each iteration instead. I also corrected some typos in the documentation.

Related Issues & Documents

examples/cpp/backward_euler.cpp
doc/sphinx/source/examples/Time-Integrators/backward_euler.md

QA Instructions, Screenshots, Recordings

Please replace this line with instructions on how to test your changes, a note
on the devices and browsers this has been tested on, as well as any relevant
images for UI changes.

Added/updated tests?

_We encourage you to test all code included with MOLE, including examples.

  • Yes
  • No, and this is why: please replace this line with details on why tests
    have not been included
  • I need help with writing tests

Read Contributing Guide and Code of Conduct

[optional] Are there any post deployment tasks we need to perform?

[optional] What gif best describes this PR or how it makes you feel?

@valeriabarra
Copy link
Collaborator

Hi @kle96 , thank you for this follow-up PR! I have left a few suggestions in your Issue #248

Copy link
Collaborator

@jbrzensk jbrzensk left a comment

Choose a reason for hiding this comment

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

Good catch! missed the "fzero" in Matlab/Octave, thats the solve for that method.
The output also matches very well:

4.85 24.5469
4.86 24.7894
4.87 25.0336
4.88 25.2793
4.89 25.5266
4.9 25.7754
4.91 26.0256
4.92 26.2772
4.93 26.5302
4.94 26.7844
4.95 27.0398
4.96 27.2964
4.97 27.554
4.98 27.8127
4.99 28.0723
5 28.3329

versus from matlab:

Time: 4.850, Val: 24.547
Time: 4.860, Val: 24.789
Time: 4.870, Val: 25.034
Time: 4.880, Val: 25.279
Time: 4.890, Val: 25.527
Time: 4.900, Val: 25.775
Time: 4.910, Val: 26.026
Time: 4.920, Val: 26.277
Time: 4.930, Val: 26.530
Time: 4.940, Val: 26.784
Time: 4.950, Val: 27.040
Time: 4.960, Val: 27.296
Time: 4.970, Val: 27.554
Time: 4.980, Val: 27.813
Time: 4.990, Val: 28.072
Time: 5.000, Val: 28.333

@jbrzensk
Copy link
Collaborator

jbrzensk commented Dec 9, 2025

Note that I have not checked the documentation. The approval is for the C++ code.

@kle96
Copy link
Contributor Author

kle96 commented Dec 10, 2025

Thank you Dr. Barra and @jbrzensk for checking my PR. The figure is now showing in the documentation. I also added the documentation to the index file as recommended.

Copy link
Collaborator

@aboada aboada left a comment

Choose a reason for hiding this comment

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

Thank you for the changes, left some minor suggestions and an open question. Let me know if you have any questions!

arma::mat y = arma::mat(1, t.size(), arma::fill::zeros);
constexpr double tol = 1e-6; // tolerance for fixed-point iteration

Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: I suggest removing introduced extra space. For formatting, I recommend clang-format though I'm not sure if that's well accepted within the library.

break;
}
xn = xnp1;
// std::cout << k <<std::endl; // Print number of iterations until convergence
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: I suggest removing unneeded commented line.

if (std::abs(y(i+1) - y_old) < tol) { // Stopping criteria for approximate relative error
double xn = y_old; // Initial input for fixed-point iteration
double xnp1; // x at iteration n+1
for (int n = 0; n < 100; n++) { // fixed-point iteration for rootfinding
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the readability/maintainability of the code can improve by using a constant for the number of iterations (100). The constant can be declared as constexpr following the example of other constants in this file.

double xnp1; // x at iteration n+1
for (int n = 0; n < 100; n++) { // fixed-point iteration for rootfinding
xnp1 = y_old + h*f(t(i+1), xn); // Backward Euler
if (std::abs(xnp1 - xn) < tol) { // Stopping criteria for approximate relative error
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens if we don't achieve the desired tolerance? Is that scenario handled in the current implementation? Should we inform the user?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi Angel. The tolerance would be problem dependent (on the scale of the numbers in their problem) and needs to be specified by the user. If the tolerance isn't met, we can reduce the step-size of h or increase the tolerance. It's currently not handled in this implementation. However, I'll add a message to the user for situations where it does not converge.

arma::vec t = arma::regspace(0, h, 5); // Calculates up to y(5) at step-size h
arma::mat y = arma::mat(1, t.size(), arma::fill::zeros);
constexpr double tol = 1e-6; // Tolerance for fixed-point iteration
constexpr int iter = 100; // Max iterations for fixed-point iteration
Copy link
Collaborator

@aboada aboada Dec 11, 2025

Choose a reason for hiding this comment

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

nit: very minor but maybe max_iter can convey better the purpose of this variable.

Copy link
Collaborator

@aboada aboada left a comment

Choose a reason for hiding this comment

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

Thank you for applying clang-format! I noticed the comments at the top of the file were reformatted, likely because they were not marked as Doxygen comments (//!).

@jbrzensk
Copy link
Collaborator

@valeriabarra Does the image integration work? I get an error ( missing image ).
image

Do we need to add to the Makefile in the doc/sphinx in this section like we did for the MOLE OSE images?

.PHONY: copy-images
copy-images:

@valeriabarra
Copy link
Collaborator

Do we need to add to the Makefile in the doc/sphinx in this section like we did for the MOLE OSE images?

.PHONY: copy-images
copy-images:

@jbrzensk , I think so, yes. Although now that I look more closely, it does not look like the approach we took in the Makefile is actually robust and scalable if we need to add more images to other sections of the docs (likely, in the Mathematical Framework section, for instance). If I look at libCEED's doc/sphinx/Makefile (which was our reference) I do not see any of this being needed at all. Does @pritkc perhaps recall why we ended up having to deal with images in the docs this way?

@pritkc
Copy link
Collaborator

pritkc commented Dec 17, 2025

Do we need to add to the Makefile in the doc/sphinx in this section like we did for the MOLE OSE images?

.PHONY: copy-images
copy-images:

@jbrzensk , I think so, yes. Although now that I look more closely, it does not look like the approach we took in the Makefile is actually robust and scalable if we need to add more images to other sections of the docs (likely, in the Mathematical Framework section, for instance). If I look at libCEED's doc/sphinx/Makefile (which was our reference) I do not see any of this being needed at all. Does @pritkc perhaps recall why we ended up having to deal with images in the docs this way?

Off the top of my head, MyST's {include} directive: when we include markdown files from outside the Sphinx source directory (like OSE_ORGANIZATION.md at repo root), MyST resolves image paths relative to the including file rather than the included file, which was breaking paths either locally or post hosting. libCEED likely doesn't encounter this since they don't include files from outside their Sphinx source tree.

I've just published a PR (#260) that fixes this generically using Sphinx event hooks. It automatically collects images from multiple locations and fixes paths at both source and doctree levels. Originally I planned this for our long overdue of main branch RTD image invisibility, but it should serve dual purpose. I've tested it well on existing images, I'll keep in an eye on this PR to make sure it picks the untested images.

@jbrzensk jbrzensk merged commit d09eb07 into csrc-sdsu:main Dec 22, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Correction to Backward Euler C++ Example and Adding Images into Documentation

5 participants