Skip to content
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

Add forward models as plugins #7743

Merged
merged 12 commits into from
Jun 3, 2024
Merged

Conversation

yngve-sk
Copy link
Contributor

@yngve-sk yngve-sk commented Apr 23, 2024

Not about preinstalled forward model steps "bleeding" into other tests causing failure
The preinstalled forward model steps are added as a global singleton ClassVar to ErtConfig, since plugins installed from imported system modules are inherently global. This does have some pitfalls when it comes to running tests, if a test context imports and thus also installs some plugin forward models to the ErtConfig, these will persist as classvars of the ErtConfig for subsequent test runs. So for example if we run

pm = ErtPluginManager(plugins=[dummy_plugins])
    run_cli_with_plugin_manager(
        [TEST_RUN_MODE, "--disable-monitor", str(tmp_path / "test.ert")], pm
    )

in one test, then the installed plugins will "show up" in subsequent tests, so this test would fail:

def test_that_include_take_into_account_path():
    ...
    assert list(ert_config.installed_forward_model_steps.keys()) == [
        "job1",
        "job2",
    ]

because the DummyForwardModel installed in the previous step would also show up. However when we run ert, we only create one config and don't care about creating multiple configs with separate sets of extensions within the same python context.

Issue
Resolves #7409

@yngve-sk yngve-sk self-assigned this Apr 23, 2024
@yngve-sk yngve-sk marked this pull request as draft April 23, 2024 13:00
@yngve-sk yngve-sk force-pushed the plugin-forward-model branch 2 times, most recently from 278a961 to 49e1756 Compare April 26, 2024 13:22
@yngve-sk yngve-sk force-pushed the plugin-forward-model branch 3 times, most recently from b3c863a to bb22569 Compare May 13, 2024 08:39
@yngve-sk yngve-sk mentioned this pull request May 13, 2024
@yngve-sk yngve-sk force-pushed the plugin-forward-model branch 5 times, most recently from 9734629 to 5d85938 Compare May 14, 2024 08:46
@yngve-sk yngve-sk marked this pull request as ready for review May 14, 2024 08:46
@codecov-commenter
Copy link

codecov-commenter commented May 14, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 86.01%. Comparing base (36c89fb) to head (8295f62).

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #7743       +/-   ##
===========================================
+ Coverage   68.61%   86.01%   +17.40%     
===========================================
  Files         381      382        +1     
  Lines       23482    23586      +104     
  Branches      633      629        -4     
===========================================
+ Hits        16112    20288     +4176     
+ Misses       7291     3225     -4066     
+ Partials       79       73        -6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@yngve-sk yngve-sk marked this pull request as draft May 14, 2024 09:47
@yngve-sk yngve-sk force-pushed the plugin-forward-model branch 11 times, most recently from ef4d6e2 to f190186 Compare May 21, 2024 10:00
@yngve-sk yngve-sk marked this pull request as ready for review May 21, 2024 10:23
try:
if not skip_pre_experiment_validation:
fm_step_json = fm_step.validate_pre_realization_run(fm_step_json)
except BaseException as exc:
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of BaseException I think we should create a specific exception that forward model validation can raise to indicate invalid json. This is in order to avoid catching things like keyboard interrupt (Ctrl-C) or AttributeError (something is wrong with the plugin implementation):

class InvalidForwardModelCall(Exception):
    """ Thrown when the user calls the forward model incorrectly.
          
          Can be subtyped by the implementation of ForwardModelStepPlugin and
          thrown from `validate_pre_realization_run` or `validate_pre_experiment`.
    """

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added it to ert, called it ForwardModelInvalidStepCall, if you insist I will go with InvalidForwardModelCall but it is nice to be able to just type Fo.., in the IDE and get up all the forwardmodel stuff on autocomplete.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍 You also need to just catch that exception when you call validate_pre_realization_run.

on the queue.

Attributes:
name: A string representing the name of the job
Copy link
Contributor

Choose a reason for hiding this comment

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

name is obvious so maybe just omit or at least make the description shorter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removing

self,
name: str,
command: List[str],
options: Optional[ForwardModelStepOptions] = None,
Copy link
Contributor

Choose a reason for hiding this comment

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

options here seems like a typical use case for https://typing.readthedocs.io/en/latest/spec/callables.html#unpack-kwargs . I suggest we put in **kwargs: Unpack[ForwardModelStepOptions] instead. If a plugin wants to use type the call to their ForwardModelStepPlugin we also need to expose ForwardModelStepOptions through ert/__init__.py.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did not know about Unpack, so nice, updated semeio plugins accordingly equinor/semeio@055f28c


# It is in the command, but not in the forward model(...) entry in the
# ert config. Thus it is not a "private" arg in that sense.
# Note2reviewer: We COULD include references to variables in the
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe remove Note2reviewer and put that in github comments instead :D. I didn't understand exactly what you ment by this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ohh, I was trying to say that private_args will only include substituted args that are declared in the ert config, but not necessarily all the args in arglist.

So if arglist (in the fm step specification) is [x,y,z], but the forward model invocation in the ert config is this FORWARD_MODEL FM(<x>=2), then self.private_args will only contain <x>, and the concern was whether developers implementing a forward model would be interested in what y and z would be substituted to, even though it isn't specified in the forward model step invocation in the ert config.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So my question/concern was whether it was important to tweak the substitution logic to somehow make the substituted args from the entire arglist available, for validation purposes. If a developer implementing a fm step plugin says that X is in the arglist, and in the pre-experiment / pre-realization hook wants to know what it would be substituted with, regardless of whether it is invoked in the ert config fm step. I would assume this is never the case but am not completely sure.

Copy link
Contributor

Choose a reason for hiding this comment

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

We looked into this a while ago and we are pretty much unable to check the entire arglist because it seems that some user scripts handle unsubstituted arguments on their own.

stderr_file: Optional[str]
start_file: Optional[str]
target_file: Optional[str]
error_file: Optional[str]
Copy link
Contributor

Choose a reason for hiding this comment

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

With TypedDict you need to use `NotRequired to indicate that the dictionary does not need to contain the keyword: https://typing.readthedocs.io/en/latest/spec/callables.html#required-and-non-required-keys .

@yngve-sk yngve-sk requested a review from sondreso May 31, 2024 12:44
@@ -52,6 +57,9 @@
"ExternalErtScript",
"Field",
"ForwardModelStep",
"ForwardModelStepPlugin",
"ForwardModelStepJSON",
"ForwardModelInvalidCallError",
Copy link
Contributor

Choose a reason for hiding this comment

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

The -Error is a common postfix for Exceptions, so is -Exception. I would rather we either just called it InvalidForwardModelCall which is a more descriptive name without any postfix, or we go with ForwardModelValidationError which has the postfix and otherwise is better gramatically.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, I think ForwardModelValidationError is nice and more in-tune with other naming we currently have in ert, and is easier to find/lookup when looking for stuff related to ForwardModel. Also personal preference but I think having Error postfix is nice, esp for just looking up stuff when developing. Just typing in something like fmer would find a fuzzy match on this, but on InvalidForwardModelCall it'd be a bit further away from forward model in a fuzzy-textual manner.

Also the errors we raise in the validation steps pre_experiment and pre_realization_run are per definition validation errors. What exactly they validate (state or input arguments to the forward model) is arbitrary, but they are still distinct from errors that arise during the run of the forward model.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I actually think it should be ForwardModelStepValidationError just to be explicit about the forward model vs forward model step, in spite of it being a bit more verbose

Copy link
Contributor

@eivindjahren eivindjahren left a comment

Choose a reason for hiding this comment

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

👍

@yngve-sk yngve-sk merged commit ceda74f into equinor:main Jun 3, 2024
38 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.

Make it possible for plugins to subtype ForwardModel
3 participants