Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@jcapriot
Copy link
Member

@jcapriot jcapriot commented Dec 10, 2024

Summary

Move physical properties to base classes meant for inheritance.

PR Checklist

  • If this is a work in progress PR, set as a Draft PR
  • Linted my code according to the style guides.
  • Added tests to verify changes to the code.
  • Added necessary documentation to any new functions/classes following the
    expect style.
  • Marked as ready for review (if this is was a draft PR), and converted
    to a Pull Request
  • Tagged @simpeg/simpeg-developers when ready for review.

Reference issue

Working towards #1429, and #1227

What does this implement/fix?

Moving the physical properties to base classes to reduce duplication, and planning ahead for their future rename.
The goal for doing this here is to have a single location to place deprecations on the rename.

Additional information

Better represent that the object passes is a class (and not an instance of it).
Allows to be more descriptive and catch better errors on the simulations that need specific mesh types.
Better represent that the object passes is a class (and not an instance of it).
@jcapriot jcapriot marked this pull request as ready for review December 16, 2024 22:21
@jcapriot jcapriot requested a review from santisoler December 16, 2024 22:57
self,
mesh,
survey=None,
*,
Copy link
Member Author

Choose a reason for hiding this comment

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

I've done this to several classes to make it more clear in the source code which parameters should only be set as keywords.

Copy link
Member

Choose a reason for hiding this comment

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

could we add comments throughout where we use * in the code to help developers understand why this is here and what keywords it is meant to catch? That would be helpful for contributors who are learning the codebase by reading it

@jcapriot
Copy link
Member Author

@santisoler I think this is about ready now, I'd appreciate some feedback. I'll add documentation for the classes soon.

One of the things I'm still unsure about is what to do with the one off physical properties that are in unique classes (that are not necessarily physical properties, but more like parameterizations of physical properties,)

@jcapriot
Copy link
Member Author

I decided to move the parameters I was suspicious of to the common physical properties, as more than one simulation used them.
However, there is not (at the moment) a way to change a physical property's invertibility, for the classes where should be reused.

@jcapriot jcapriot force-pushed the common_physical_props branch from 4627190 to 56361c3 Compare December 20, 2024 23:48
Copy link
Member

@santisoler santisoler left a comment

Choose a reason for hiding this comment

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

Looks good! I think we should include the physical properties as arguments for the constructor of simulations as well if we are still going to require them for the simulation to run, but I guess you are planning to tackle that in #1593, right?

The other thing that looks a little bit weird is having the simulation classes as childs of physical property classes. I understand the technicality of it (so they inherit the properties), but from an abstraction point of view it kind of looks weird. I'm nit picking, and I wouldn't block this PR because of that, but I wanted to mention it.


class BaseEM1DSimulation(BaseSimulation):
class BaseEM1DSimulation(
BaseSimulation, ElectricalConductivity, MagneticPermeability, LayerThickness
Copy link
Member

Choose a reason for hiding this comment

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

I am raising this as a point of conversation... inheriting 4 classes introduces a fair bit of complexity for someone to understand when learning the codebase. I appreciate that the physical property classes are lightweight, but none-the-less, it does create a fair bit to navigate through to understand that we are going through 4 classes to instantiate this. Is there any way we could simplify this?

Having physical properties be properties of the class makes conceptual sense. Having a simulation inherit a physical property is a bit odd. I realize that it brings with it the benefits of not having to duplicate documentation.

If you really don't see an alternative, then I understand. But I wanted to raise it as something to discuss, as part of the goal of SimPEG is as a learning tool, and this introduces a new layer of complexity.

@jcapriot
Copy link
Member Author

jcapriot commented Jan 13, 2025

I am raising this as a point of conversation... inheriting 4 classes introduces a fair bit of complexity for someone to understand when learning the codebase. I appreciate that the physical property classes are lightweight, but none-the-less, it does create a fair bit to navigate through to understand that we are going through 4 classes to instantiate this. Is there any way we could simplify this?

Having physical properties be properties of the class makes conceptual sense. Having a simulation inherit a physical property is a bit odd. I realize that it brings with it the benefits of not having to duplicate documentation.

If you really don't see an alternative, then I understand. But I wanted to raise it as something to discuss, as part of the goal of SimPEG is as a learning tool, and this introduces a new layer of complexity.

One of my overall goals is to "cleanup" the simulations.

Some Discussion

There's a few points to I think this highlights for discussion,

First on the level of complexity of the codebase. I feel it's worth discussing where we should aim for, and there are a few different levels of people who interact with the code. I see at least three:

  1. Someone who uses simpeg (should be easy and require hopefully basic understandings of python) I see this as the average user
  2. Someone who wants to extend simpeg to suit their own needs (Moderate knowledge of python). Should be clear (not necessarily "easy", but at least straightforward).
  3. Simpeg developers (Higher knowledge of python expected). We internally make use of many different aspects of python that require a higher level of understanding in the first place, things like: Multiple Inheritance, Metaclasses, Wrappers, etc.

I feel like the internals of simpeg should be straightforward to follow, but not necessarily simple. There are many great aspects of python that we get to take advantage of to reduce code duplication. Having less code to maintain is always helpful.

One of the biggest issues I currently see with our simulations is not that they have complicated inheritance, it's that they simply inherit too many properties from those parents that most people would never need to interact with. (sigmaDeriv? getRHSDeriv, MccSigma, etc.). All of those extra properties adds so much noise to the simulations making them hard to use, hard to read, and hard to extend.

Another issue is that the "base" items live all over the place. There are fundamental bits of Simulations, Physical Properties, Models, Sources, Receivers, Surveys, etc.) based items in multiple of the first level subpackages of simpeg. These are things that an average user would never interact with. I would be a proponent of these base classes into the base submodule and separating them a bit more than they already are.

This PR

Now moving onto this PR and my overall goals for unifying them here.
The biggest purpose of this is to reduce code and documentation duplication, things that would need to be duplicated if this wasn't in a common place:

  • Many classes implement the same physical properties, and having them defined in one place makes it a little easier to document them throughout
  • Any extra bits that would be common (like issuing the same warning on all simulations that would use permittivity).
  • We should also issue errors on instantiation if a user passes both sigma and sigmaMap (or if two reciprocal properties are passed).
  • More forward looking
    • If we want to change the names of the properties on the classes to not be symbol based (e.g. sigma $\rightarrow$
      conductivity), it's much easier to do if those properties are only defined in one location. I believe it will be easier to
      deprecate it this way and then easier to test the deprecations this way.

Then this last bit is more of a suspicion of mine, but I hope it also makes sense. I would trust someone who wants to make their own simulation to inherit a class rather than to make sure they use the correct combination of PhysicalProperty, Mapping, Derivatives, and Invertible classes internally.

Some other alternatives:

  • It might work to just have some predefined PhysicalProperty, Mapping and Derivative objects here instead that developers could grab.
    • That would get us some removal of code duplications, (Users could be a little more sure of themselves using a correct combination of PhysicalProperty, Mapping etc.) and make the attributes on the classes have the same documentation.
    • Don't get to re-use code for checking any other aspects about them though (Deprecations, errors, etc.).

So basically I believe moving them to common classes will reduce the overhead in the future.

Copy link
Member

@lheagy lheagy left a comment

Choose a reason for hiding this comment

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

Thanks for pushing this forwards @jcapriot and apologies for taking soooo long to get back to you on this! I like the idea and I can see how this will simplify name changes in the future. My main comment is that if we could add a few comments for where the * is in the init to just explain what is happening, that would be helpful. A lot of folks learn SimPEG by reading the code, and it might not be obvious to all what is happening, so if we could help provide some guidance through comments, I think that would be helpful

self,
mesh,
survey=None,
*,
Copy link
Member

Choose a reason for hiding this comment

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

could we add comments throughout where we use * in the code to help developers understand why this is here and what keywords it is meant to catch? That would be helpful for contributors who are learning the codebase by reading it

def __init__(
self,
mesh,
*args,
Copy link
Member

Choose a reason for hiding this comment

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

similarly here, could we add a comment to help developers who are learning by reading the code?

@jcapriot
Copy link
Member Author

Thanks for pushing this forwards @jcapriot and apologies for taking soooo long to get back to you on this! I like the idea and I can see how this will simplify name changes in the future. My main comment is that if we could add a few comments for where the * is in the init to just explain what is happening, that would be helpful. A lot of folks learn SimPEG by reading the code, and it might not be obvious to all what is happening, so if we could help provide some guidance through comments, I think that would be helpful

* on its own in a function definition actually blocks things, it doesn’t capture anything. It means that any keyword arguments that come after it in the function definition are only accepted as keyword arguments.

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.

3 participants