1515
1616import anyio
1717import httpx
18+ from httpx import AsyncClient
1819from resfo_utilities import SummaryKeyType
1920
2021from ert .cli .main import ErtCliError
@@ -122,28 +123,21 @@ async def path_exists() -> None:
122123 return proc , config_path
123124
124125
125- async def extract_summary_observations (
126- client : httpx .AsyncClient ,
127- experiment : str ,
128- experiments : list [Any ],
129- ) -> dict [str , list [Any ]]:
130- experiment_match = next (filter (lambda x : x ["id" ] == experiment , experiments ), None )
131- if experiment_match is None :
132- raise ErtCliError (f"Provided experiment id { experiment } not found in storage" )
133- if "summary" not in experiment_match ["observations" ]:
134- raise ErtCliError (
135- f"No summary observations found for experiment '{ experiment } '"
136- )
137- summary_observations = experiment_match ["observations" ]["summary" ]
138- response_key = {v : k for k , vs in summary_observations .items () for v in vs }
126+ async def extract_observations (
127+ obs_type : str , experiment : dict [str , Any ], experiment_id : str , client : AsyncClient
128+ ) -> dict [str , Any ]:
129+ if obs_type not in experiment ["observations" ]:
130+ return {}
131+ observations = experiment ["observations" ][obs_type ]
132+ obs_name_to_summary_key = {
133+ obs_name : summary_key
134+ for summary_key , obs_names in observations .items ()
135+ for obs_name in obs_names
136+ }
139137 result : dict [str , list [Any ]] = defaultdict (list )
140- for obs in await get_observations (experiment , client ):
141- if obs ["name" ] in response_key :
142- result [response_key [obs ["name" ]]].append (obs )
143- if len (result ) == 0 :
144- raise ErtCliError (
145- f"No summary observations found for experiment '{ experiment } '"
146- )
138+ for obs in await get_observations (experiment_id , client ):
139+ if obs ["name" ] in obs_name_to_summary_key :
140+ result [obs_name_to_summary_key [obs ["name" ]]].append (obs )
147141 return result
148142
149143
@@ -157,9 +151,10 @@ def non_empty_fields(skds: list[SummaryKeyData]) -> list[str]:
157151 ]
158152
159153
160- def localization_to_string (
161- east : float | None , north : float | None , radius : float | None
162- ) -> str | None :
154+ def obs_to_localization_str (obs : list [Any ]) -> str | None :
155+ east = get_first_loc_value ("east" , obs )
156+ north = get_first_loc_value ("north" , obs )
157+ radius = get_first_loc_value ("radius" , obs )
163158 if east is None or north is None :
164159 return None
165160 lines = [
@@ -170,34 +165,41 @@ def localization_to_string(
170165 if radius is not None :
171166 lines .append (f"{ INDENT6 } RADIUS={ radius } ;" )
172167 lines .append (f"{ INDENT4 } }};" )
173- return "\n " .join (lines )
168+ return "\n " .join (lines ) + " \n "
174169
175170
176- def get_first_loc_value (loc_key : str , summary_obs : list [Any ]) -> float | None :
177- for obs in summary_obs :
178- key_value = obs .get (loc_key , [None ])[0 ]
171+ def get_first_loc_value (loc_key : str , obs : list [dict [ str , Any ]] ) -> float | int | None :
172+ for o in obs :
173+ key_value = o .get (loc_key , [None ])[0 ]
179174 if key_value is not None :
180175 return key_value
181176 return None
182177
183178
179+ def breakthrough_to_string (obss : list [dict [str , Any ]], key : str ) -> str :
180+ obs = obss [0 ]
181+ lines = [
182+ f"{ INDENT4 } BREAKTHROUGH {{" ,
183+ f"{ INDENT6 } THRESHOLD={ obs ['values' ][0 ]} ;" ,
184+ f"{ INDENT6 } DATE={ obs ['x_axis' ][0 ]} ;" ,
185+ f"{ INDENT6 } ERROR={ obs ['errors' ][0 ]} ;" ,
186+ f"{ INDENT6 } KEY={ key } ;" ,
187+ f"{ INDENT4 } }};" ,
188+ ]
189+ return "\n " .join (lines ) + "\n "
190+
191+
184192def convert_summary_observations (
185- summary_observations : dict [str , list [Any ]], csv_file_name : str
193+ summary_observations : dict [str , list [Any ]],
194+ breakthrough_observations : dict [str , list [Any ]],
195+ csv_file_name : str ,
186196) -> None :
187- skds = []
188-
189- localization = {}
190- for key in summary_observations : # noqa: PLC0206
197+ summary_keys = []
198+ for key in summary_observations :
191199 summary_key = make_summary_key_data (key )
192- skds .append (summary_key )
193- east = get_first_loc_value ("east" , summary_observations [key ])
194- north = get_first_loc_value ("north" , summary_observations [key ])
195- radius = get_first_loc_value ("radius" , summary_observations [key ])
196- loc_string = localization_to_string (east , north , radius )
197- if loc_string is not None and (well := summary_key .well ) is not None :
198- localization [well ] = loc_string
200+ summary_keys .append (summary_key )
199201
200- header_fields = non_empty_fields (skds )
202+ header_fields = non_empty_fields (summary_keys )
201203 with Path (csv_file_name ).open (mode = "w" , encoding = "utf-8" ) as fout :
202204 fout .write (", " .join ([* header_fields , "value" , "error" , "date" ]))
203205 fout .write ("\n " )
@@ -215,10 +217,27 @@ def convert_summary_observations(
215217 fout .write (f"{ observation ['errors' ][0 ]:.3g} , " )
216218 fout .write (f"{ date .isoformat ()} \n " )
217219
220+ breakthrough = {}
221+ for brt_key , obs in breakthrough_observations .items ():
222+ key = brt_key .removeprefix ("BREAKTHROUGH:" )
223+ summary_key = make_summary_key_data (key )
224+ if (well := summary_key .well ) is not None :
225+ breakthrough [well ] = breakthrough_to_string (obs , summary_key .keyword )
226+
227+ localization = {}
228+ for key in summary_observations | breakthrough_observations :
229+ summary_key = make_summary_key_data (key .removeprefix ("BREAKTHROUGH:" ))
230+ loc_string = obs_to_localization_str (
231+ summary_observations .get (key , []) + breakthrough_observations .get (key , [])
232+ )
233+ if loc_string is not None and (well := summary_key .well ) is not None :
234+ localization [well ] = loc_string
235+
218236 print (f"SUMMARY {{\n VALUES = { csv_file_name } ;" )
219- for well , loc in localization .items ( ):
237+ for well in sorted ( localization .keys () | breakthrough . keys () ):
220238 print (f"{ INDENT2 } WELL { well } {{" )
221- print (loc )
239+ print (localization .get (well , "" ), end = "" )
240+ print (breakthrough .get (well , "" ), end = "" )
222241 print (f"{ INDENT2 } }};" )
223242 print ("};" )
224243
@@ -312,11 +331,11 @@ async def _run_with_client(
312331
313332 assert isinstance (all_experiments , list )
314333 if args .experiment is not None :
315- experiment = args .experiment
334+ experiment_id = args .experiment
316335 experiment_ids = [ex ["id" ] for ex in all_experiments ]
317- if experiment not in experiment_ids :
336+ if experiment_id not in experiment_ids :
318337 raise ErtCliError (
319- f"An experiment with id '{ experiment } ' does not exist.\n "
338+ f"An experiment with id '{ experiment_id } ' does not exist.\n "
320339 f"Available experiments:\n "
321340 + "\n " .join (
322341 [
@@ -326,13 +345,29 @@ async def _run_with_client(
326345 )
327346 )
328347 else :
329- experiment = query_user_for_experiment (all_experiments )
348+ experiment_id = query_user_for_experiment (all_experiments )
330349
331- summary_observations = await extract_summary_observations (
332- client , experiment , all_experiments
350+ experiment = next (
351+ filter (lambda x : x ["id" ] == experiment_id , all_experiments ), None
352+ )
353+ if experiment is None :
354+ raise ErtCliError (
355+ f"Provided experiment id { experiment_id } not found in storage"
356+ )
357+ if "summary" not in experiment ["observations" ]:
358+ raise ErtCliError (
359+ f"No summary observations found for experiment '{ experiment_id } '"
360+ )
361+ summary_observations = await extract_observations (
362+ "summary" , experiment , experiment_id , client
363+ )
364+ breakthrough_observations = await extract_observations (
365+ "breakthrough" , experiment , experiment_id , client
333366 )
334367
335- convert_summary_observations (summary_observations , args .output_csv_file )
368+ convert_summary_observations (
369+ summary_observations , breakthrough_observations , args .output_csv_file
370+ )
336371
337372
338373async def _async_main (args : Namespace ) -> None :
0 commit comments