def test_post_update_data(client): data = pd.DataFrame(np.random.rand(4, 2), index=[2, 4, 6, 8]) builder = ErtConfigBuilder() builder.add_general_observation("OBS", "RES", data) ert = builder.build() # Post two ensembles parent_ensemble_id = extraction.post_ensemble_data(ert, builder.ensemble_size) update_id = extraction.post_update_data(ert, parent_ensemble_id, "boruvka") child_ensemble_id = extraction.post_ensemble_data(ert, builder.ensemble_size, update_id) # Experiment should have two ensembles experiment_id = client.fetch_experiment() ensembles = client.get(f"/experiments/{experiment_id}/ensembles").json() assert len(ensembles) == 2 # Parent ensemble should have a child assert ensembles[0]["child_ensemble_ids"] == [child_ensemble_id] assert ensembles[0]["parent_ensemble_id"] is None # Child ensemble should have a parent assert ensembles[1]["child_ensemble_ids"] == [] assert ensembles[1]["parent_ensemble_id"] == parent_ensemble_id
def test_observation_transformation(client): data = pd.DataFrame([[1, 0.1], [2, 0.2], [3, 0.3], [4, 0.4]], index=[0, 1, 2, 3]) builder = ErtConfigBuilder() builder.ensemble_size = 5 builder.add_general_observation("OBS", "RES", data) builder.job_script = dedent("""\ #!/usr/bin/python3 import re from pathlib import Path # Obtain realization index by looking at the name of current directory real = int(re.match("^realization([0-9]+)$", Path.cwd().name)[1]) outlier = 1000 + real # Large number, ERT disables active_a = 1 + real active_b = 2 + real small_var = 3 # Small variation between responses, ERT disables output = [outlier, active_a, active_b, small_var] with open("poly_0.out", "w") as f: f.write("\\n".join(str(x) for x in output)) """) ert = builder.build() # Post first ensemble parent_ensemble_id = extraction.post_ensemble_data(ert, builder.ensemble_size) # Create runpath and run ERT run_context = _create_runpath(ert) _evaluate_ensemble(ert, run_context) _run_update(ert, run_context) # Post second ensemble update_id = extraction.post_update_data(ert, parent_ensemble_id, "boruvka") child_ensemble_id = extraction.post_ensemble_data(ert, builder.ensemble_size, update_id) # Ensemble should have 1 observation with transformation observations = client.get( f"/ensembles/{child_ensemble_id}/observations").json() assert len(observations) == 1 # Validate data obs = observations[0] assert obs["name"] == "OBS" assert obs["values"] == data[0].tolist() assert obs["errors"] == data[1].tolist() trans = obs["transformation"] assert trans["name"] == "OBS" assert trans["active"] == [False, True, True, False] assert trans["scale"] == [1.0] * 4 assert trans["observation_id"] == obs["id"]
def test_parameters(client): priors = _make_priors() # Add priors to ERT config builder = ErtConfigBuilder() builder.ensemble_size = 10 for name, conf, _ in priors: builder.add_prior(name, conf) ert = builder.build() # Start ERT _create_runpath(ert) # Post initial ensemble extraction.post_ensemble_data(ert, -1) # Get ensemble_id experiment_id = client.fetch_experiment() ensembles = client.get(f"/experiments/{experiment_id}/ensembles").json() ensemble_id = ensembles[0]["id"] # Compare parameters (+ 2 due to the two log10_ coeffs) parameters = client.get(f"/ensembles/{ensemble_id}/parameters").json() parameter_names = [entry["name"] for entry in parameters] assert len(parameters) == len(parameter_names) assert len(parameters) == len(priors) + 2 for name, _, prior in priors: assert f"COEFFS:{name}" in parameter_names if prior["function"] in ("lognormal", "loguniform"): assert f"LOG10_COEFFS:{name}" in parameter_names # Compare records (+ 2 due to the two log10_ coeffs) records = client.get(f"/ensembles/{ensemble_id}/records").json() assert len(records) == len(priors) + 2 for name, _, prior in priors: assert f"COEFFS:{name}" in records if prior["function"] in ("lognormal", "loguniform"): assert f"LOG10_COEFFS:{name}" in records parameters_df = _get_parameters() assert len(parameters_df) == builder.ensemble_size for col in parameters_df: record_data = client.get( f"/ensembles/{ensemble_id}/records/COEFFS:{col}", headers={ "accept": "application/x-parquet" }, ).content stream = io.BytesIO(record_data) df = pd.read_parquet(stream) # ERT produces a low-quality version assert_almost_equal(parameters_df[col].values, df.values.flatten(), decimal=4)
def test_empty_ensemble(client): ert = ErtConfigBuilder().build() extraction.post_ensemble_data(ert, -1) id = client.fetch_experiment() # Name is "default" for ens in client.get(f"/experiments/{id}/ensembles").json(): assert (client.get(f"/ensembles/{ens['id']}/userdata").json()["name"] == "default") # No priors exist assert client.get(f"/experiments/{id}").json()["priors"] == {}
def test_empty_ensemble_with_name(client): name = _rand_name() # Create case with given name ert = ErtConfigBuilder().build() ert.select_or_create_new_case(name) # Post initial ensemble extraction.post_ensemble_data(ert, -1) # Compare results id = client.fetch_experiment() for ens in client.get(f"/experiments/{id}/ensembles").json(): assert client.get(f"/ensembles/{ens['id']}/userdata").json()["name"] == name
def _runAndPostProcess(self, run_context, arguments, update_id=None): phase_msg = "Running iteration %d of %d simulation iterations..." % ( run_context.get_iter(), self.phaseCount() - 1, ) self.setPhase(run_context.get_iter(), phase_msg, indeterminate=False) self.setPhaseName("Pre processing...", indeterminate=True) self.ert().getEnkfSimulationRunner().createRunPath(run_context) EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_SIMULATION, ert=ERT.ert) # create ensemble ensemble_id = post_ensemble_data(update_id=update_id) self.setPhaseName("Running forecast...", indeterminate=False) if FeatureToggling.is_enabled("ensemble-evaluator"): ee_config = arguments["ee_config"] num_successful_realizations = self.run_ensemble_evaluator( run_context, ee_config) else: self._job_queue = self._queue_config.create_job_queue() num_successful_realizations = ( self.ert().getEnkfSimulationRunner().runSimpleStep( self._job_queue, run_context)) self.checkHaveSufficientRealizations(num_successful_realizations) self.setPhaseName("Post processing...", indeterminate=True) EnkfSimulationRunner.runWorkflows(HookRuntime.POST_SIMULATION, ert=ERT.ert) post_ensemble_results(ensemble_id) return ensemble_id
def _post_ensemble_data(self, update_id: Optional[str] = None) -> str: self.setPhaseName("Uploading data...") ensemble_id = post_ensemble_data(ert=ERT.enkf_facade, ensemble_size=self._ensemble_size, update_id=update_id) self.setPhaseName("Uploading done") return ensemble_id
def _post_ensemble_data(self, update_id: Optional[str] = None) -> str: self.setPhaseName("Uploading data...") ensemble_id = post_ensemble_data( ert=self.facade, ensemble_size=self._ensemble_size, update_id=update_id, active_realizations=self._active_realizations, ) self.setPhaseName("Uploading done") return ensemble_id
def test_priors(client): priors = _make_priors() # Add priors to ERT config builder = ErtConfigBuilder() for name, conf, _ in priors: builder.add_prior(name, conf) ert = builder.build() # Start ERT _create_runpath(ert) # Post initial ensemble extraction.post_ensemble_data(ert, -1) # Compare results id = client.fetch_experiment() actual_priors = client.get(f"/experiments/{id}").json()["priors"] assert len(priors) == len(actual_priors) for name, _, resp in priors: assert actual_priors[f"COEFFS:{name}"] == resp
def test_observations(client): data = pd.DataFrame([[1, 0.1], [2, 0.2], [3, 0.3], [4, 0.4]], index=[2, 4, 6, 8]) builder = ErtConfigBuilder() builder.add_general_observation("OBS", "RES", data) ert = builder.build() # Post ensemble extraction.post_ensemble_data(ert, builder.ensemble_size) # Experiment should have 1 observation experiment_id = client.fetch_experiment() observations = client.get(f"/experiments/{experiment_id}/observations").json() assert len(observations) == 1 # Validate data obs = observations[0] assert obs["name"] == "OBS" assert obs["values"] == data[0].tolist() assert obs["errors"] == data[1].tolist() assert obs["x_axis"] == data.index.astype(str).tolist() assert obs["transformation"] is None
def test_post_ensemble_results(client): data = pd.DataFrame([[1, 0.1], [2, 0.2], [3, 0.3], [4, 0.4]], index=[2, 4, 6, 8]) response_name = "RES" # Add priors to ERT config builder = ErtConfigBuilder() builder.ensemble_size = 2 builder.add_general_observation("OBS", response_name, data) data = [0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9] df = pd.DataFrame(data) # Create job script = dedent(f"""\ #!/usr/bin/python3 if __name__ == "__main__": output = {str(data)} with open("poly_0.out", "w") as f: f.write("\\n".join(map(str, output))) """) builder.job_script = script ert = builder.build() # Create runpath and run ERT run_context = _create_runpath(ert) _evaluate_ensemble(ert, run_context) # Post initial ensemble ensemble_id = extraction.post_ensemble_data(ert, builder.ensemble_size) # Post ensemble results extraction.post_ensemble_results(ert, ensemble_id) # Retrieve response data data = client.get( f"/ensembles/{ensemble_id}/responses/{response_name}/data") stream = io.BytesIO(data.content) response_df = pd.read_csv(stream, index_col=0, float_precision="round_trip") for realization in range(0, builder.ensemble_size): assert_array_equal(response_df.loc[realization].values, df.values.flatten())
def _simulateAndPostProcess(self, run_context, arguments, update_id: int = None): iteration = run_context.get_iter() phase_string = "Running simulation for iteration: %d" % iteration self.setPhaseName(phase_string, indeterminate=True) self.ert().getEnkfSimulationRunner().createRunPath(run_context) phase_string = "Pre processing for iteration: %d" % iteration self.setPhaseName(phase_string) EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_SIMULATION, ert=ERT.ert) # Push ensemble, parameters, observations to new storage new_ensemble_id = post_ensemble_data(update_id=update_id, ensemble_size=self._ensemble_size) phase_string = "Running forecast for iteration: %d" % iteration self.setPhaseName(phase_string, indeterminate=False) if FeatureToggling.is_enabled("ensemble-evaluator"): ee_config = arguments["ee_config"] num_successful_realizations = self.run_ensemble_evaluator( run_context, ee_config) else: self._job_queue = self._queue_config.create_job_queue() num_successful_realizations = ( self.ert().getEnkfSimulationRunner().runSimpleStep( self._job_queue, run_context)) # Push simulation results to storage post_ensemble_results(new_ensemble_id) num_successful_realizations += arguments.get( "prev_successful_realizations", 0) self.checkHaveSufficientRealizations(num_successful_realizations) phase_string = "Post processing for iteration: %d" % iteration self.setPhaseName(phase_string, indeterminate=True) EnkfSimulationRunner.runWorkflows(HookRuntime.POST_SIMULATION, ert=ERT.ert) return num_successful_realizations, new_ensemble_id
def runSimulations__(self, arguments, run_msg): run_context = self.create_context(arguments) self.setPhase(0, "Running simulations...", indeterminate=False) self.setPhaseName("Pre processing...", indeterminate=True) self.ert().getEnkfSimulationRunner().createRunPath(run_context) # Push ensemble, parameters, observations to new storage ensemble_id = post_ensemble_data(ensemble_size=self._ensemble_size) EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_SIMULATION, ERT.ert) self.setPhaseName(run_msg, indeterminate=False) if FeatureToggling.is_enabled("ensemble-evaluator"): ee_config = arguments["ee_config"] num_successful_realizations = self.run_ensemble_evaluator( run_context, ee_config ) else: self._job_queue = self._queue_config.create_job_queue() num_successful_realizations = ( self.ert() .getEnkfSimulationRunner() .runEnsembleExperiment(self._job_queue, run_context) ) num_successful_realizations += arguments.get("prev_successful_realizations", 0) self.checkHaveSufficientRealizations(num_successful_realizations) self.setPhaseName("Post processing...", indeterminate=True) EnkfSimulationRunner.runWorkflows(HookRuntime.POST_SIMULATION, ERT.ert) self.setPhase(1, "Simulations completed.") # done... # Push simulation results to storage post_ensemble_results(ensemble_id) return run_context
def runSimulations(self, arguments): prior_context = self.create_context(arguments) self.checkMinimumActiveRealizations(prior_context) self.setPhase(0, "Running simulations...", indeterminate=False) # self.setAnalysisModule(arguments["analysis_module"]) self.setPhaseName("Pre processing...", indeterminate=True) self.ert().getEnkfSimulationRunner().createRunPath(prior_context) # Push ensemble, parameters, observations to new storage ensemble_id = post_ensemble_data() EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_SIMULATION, ert=ERT.ert) self.setPhaseName("Running forecast...", indeterminate=False) if FeatureToggling.is_enabled("ensemble-evaluator"): ee_config = arguments["ee_config"] num_successful_realizations = self.run_ensemble_evaluator( prior_context, ee_config) else: self._job_queue = self._queue_config.create_job_queue() num_successful_realizations = self.ert().getEnkfSimulationRunner( ).runSimpleStep(self._job_queue, prior_context) self.checkHaveSufficientRealizations(num_successful_realizations) self.setPhaseName("Post processing...", indeterminate=True) EnkfSimulationRunner.runWorkflows(HookRuntime.POST_SIMULATION, ert=ERT.ert) self.setPhaseName("Analyzing...") EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_FIRST_UPDATE, ert=ERT.ert) EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_UPDATE, ert=ERT.ert) es_update = self.ert().getESUpdate() success = es_update.smootherUpdate(prior_context) if not success: raise ErtRunError("Analysis of simulation failed!") EnkfSimulationRunner.runWorkflows(HookRuntime.POST_UPDATE, ert=ERT.ert) # Push simulation results to storage post_ensemble_results(ensemble_id) self.setPhase(1, "Running simulations...") self.ert().getEnkfFsManager().switchFileSystem( prior_context.get_target_fs()) self.setPhaseName("Pre processing...") rerun_context = self.create_context(arguments, prior_context=prior_context) self.ert().getEnkfSimulationRunner().createRunPath(rerun_context) # Push ensemble, parameters, observations to new storage analysis_module_name = self.ert().analysisConfig().activeModuleName() ensemble_id = post_ensemble_data((ensemble_id, analysis_module_name)) EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_SIMULATION, ert=ERT.ert) self.setPhaseName("Running forecast...", indeterminate=False) if FeatureToggling.is_enabled("ensemble-evaluator"): ee_config = arguments["ee_config"] num_successful_realizations = self.run_ensemble_evaluator( rerun_context, ee_config) else: self._job_queue = self._queue_config.create_job_queue() num_successful_realizations = self.ert().getEnkfSimulationRunner( ).runSimpleStep(self._job_queue, rerun_context) self.checkHaveSufficientRealizations(num_successful_realizations) self.setPhaseName("Post processing...", indeterminate=True) EnkfSimulationRunner.runWorkflows(HookRuntime.POST_SIMULATION, ert=ERT.ert) self.setPhase(2, "Simulations completed.") # Push simulation results to storage post_ensemble_results(ensemble_id) return prior_context
def runSimulations(self, arguments): phase_count = ERT.enkf_facade.get_number_of_iterations() + 1 self.setPhaseCount(phase_count) analysis_module = self.setAnalysisModule(arguments["analysis_module"]) target_case_format = arguments["target_case"] run_context = self.create_context(arguments, 0) self.ert().analysisConfig().getAnalysisIterConfig().setCaseFormat( target_case_format) self._runAndPostProcess(run_context, arguments) analysis_config = self.ert().analysisConfig() analysis_iter_config = analysis_config.getAnalysisIterConfig() num_retries_per_iteration = analysis_iter_config.getNumRetries() num_retries = 0 current_iter = 0 previous_ensemble_id = None while current_iter < ERT.enkf_facade.get_number_of_iterations( ) and num_retries < num_retries_per_iteration: pre_analysis_iter_num = analysis_module.getInt("ITER") # We run the PRE_FIRST_UPDATE hook here because the current_iter is explicitly available, versus # in the run_context inside analyzeStep if current_iter == 0: EnkfSimulationRunner.runWorkflows(HookRuntime.PRE_FIRST_UPDATE, ert=ERT.ert) self.analyzeStep(run_context) current_iter = analysis_module.getInt("ITER") analysis_success = current_iter > pre_analysis_iter_num if analysis_success: # Push ensemble, parameters, observations to new storage analysis_module_name = self.ert().analysisConfig( ).activeModuleName() previous_ensemble_id = post_ensemble_data(( previous_ensemble_id, analysis_module_name ) if previous_ensemble_id is not None else None) post_ensemble_results(previous_ensemble_id) run_context = self.create_context(arguments, current_iter, prior_context=run_context) self._runAndPostProcess(run_context, arguments) num_retries = 0 else: run_context = self.create_context(arguments, current_iter, prior_context=run_context, rerun=True) self._runAndPostProcess(run_context, arguments) num_retries += 1 analysis_module_name = self.ert().analysisConfig().activeModuleName() previous_ensemble_id = post_ensemble_data(( previous_ensemble_id, analysis_module_name ) if previous_ensemble_id is not None else None) post_ensemble_results(previous_ensemble_id) if current_iter == (phase_count - 1): self.setPhase(phase_count, "Simulations completed.") else: raise ErtRunError( "Iterated Ensemble Smoother stopped: maximum number of iteration retries (%d retries) reached for iteration %d" % (num_retries_per_iteration, current_iter)) return run_context