def test_parser_deckItems(self): parser = Parser() error_recovery = [("PARSE_RANDOM_SLASH", opm.io.action.ignore), ("PARSE_EXTRA_RECORDS", opm.io.action.ignore)] context = ParseContext(error_recovery) self.deck_spe1case1 = parser.parse(test_path("data/SPE1CASE1.DATA"), context) dkw_compdate = self.deck_spe1case1["COMPDAT"] self.assertTrue(dkw_compdate[0][0].is_string()) self.assertFalse(dkw_compdate[0][1].is_string()) self.assertTrue(dkw_compdate[0][1].is_int()) self.assertFalse(dkw_compdate[0][1].is_double()) self.assertTrue(dkw_compdate[0][8].is_double()) self.assertTrue(dkw_compdate[0][0].value == "PROD") conI = dkw_compdate[0][1].value conJ = dkw_compdate[0][2].value conK = dkw_compdate[0][3].value self.assertEqual(dkw_compdate[0][5].value, "OPEN") self.assertTrue((conI, conJ, conK) == (10, 10, 3)) self.assertFalse(dkw_compdate[0][7].valid) self.assertTrue(dkw_compdate[0][7].defaulted) self.assertEqual(dkw_compdate[0][6].value, 0) self.assertEqual(dkw_compdate[0][8].value, 0.5) dkw_wconprod = self.deck_spe1case1["WCONPROD"] welln = dkw_wconprod[0][0].value self.assertEqual(dkw_wconprod[0][2].value, "ORAT") self.assertEqual(dkw_wconprod[0][3].value, "WUOPRL") self.assertEqual(dkw_wconprod[0][5].value, 1.5e5) dkw_permx = self.deck_spe1case1["PERMX"] permx = dkw_permx.get_raw_array() self.assertEqual(len(permx), 300) self.assertTrue(isinstance(permx, np.ndarray)) self.assertEqual(permx.dtype, "float64") dkw_eqlnum = self.deck_spe1case1["EQLNUM"] eqlnum = dkw_eqlnum.get_int_array() self.assertEqual(len(eqlnum), 300) self.assertTrue(isinstance(eqlnum, np.ndarray)) self.assertEqual(eqlnum.dtype, "int32")
def setUpClass(cls): parser = Parser() cls.deck_cpa = parser.parse(test_path('data/CORNERPOINT_ACTNUM.DATA')) cls.cp_state = EclipseState(cls.deck_cpa) cls.deck_spe3 = parser.parse(test_path('spe3/SPE3CASE1.DATA')) cls.state = EclipseState(cls.deck_spe3) cls.schedule = Schedule(cls.deck_spe3, cls.state) cls.summary_config = SummaryConfig(cls.deck_spe3, cls.state, cls.schedule)
def test_throw_on_invalid_recovery(self): recoveries = [("PARSE_RANDOM_SLASH", 3.14)] with self.assertRaises(TypeError): parse_context = ParseContext(recoveries) deck = Parser().parse(self.spe3fn, parse_context) with self.assertRaises(TypeError): parse_context = ParseContext("PARSE_RANDOM_SLASH") deck = Parser().parse(self.spe3fn, parse_context)
def test_faults(self): self.assertEquals([], self.state.faultNames()) parser = Parser() faultdeck = parser.parse_string(self.FAULTS_DECK) faultstate = EclipseState(faultdeck) self.assertEqual(['F1', 'F2'], faultstate.faultNames()) # 'F2' 5 5 1 4 1 4 'X-' / \n" f2 = faultstate.faultFaces('F2') self.assertTrue((4, 0, 0, 'X-') in f2) self.assertFalse((3, 0, 0, 'X-') in f2)
def test_dynamic_parser2(self): parser = Parser(add_default=False) builtin = Builtin() kw_list = [ "START", "RUNSPEC", "FIELD", "REGIONS", "DIMENS", "GRID", "DX", "DY", "DZ", "TOPS", "OPERNUM", "FIPNUM" ] for kw in kw_list: parser.add_keyword(builtin[kw]) deck = parser.parse_string(self.REGIONDATA)
def test_jfunc(self): # jf["FLAG"] = WATER; # set in deck # jf["DIRECTION"] = XY; # default # jf["ALPHA_FACTOR"] = 0.5 # default # jf["BETA_FACTOR"] = 0.5 # default # jf["OIL_WATER"] = 21.0 # set in deck # jf["GAS_OIL"] = -1.0 # N/A parser = Parser() deck = parser.parse(test_path('data/JFUNC.DATA')) js = EclipseState(deck) self.assertEqual('JFUNC TEST', js.title) jf = js.jfunc() print(jf) self.assertEqual(jf['FLAG'], 'WATER') self.assertEqual(jf['DIRECTION'], 'XY') self.assertFalse('GAS_OIL' in jf) self.assertTrue('OIL_WATER' in jf) self.assertEqual(jf['OIL_WATER'], 21.0) self.assertEqual(jf["ALPHA_FACTOR"], 0.5) # default self.assertEqual(jf["BETA_FACTOR"], 0.5) # default jfunc_gas = """ DIMENS 10 10 10 / ENDSCALE / GRID DX 1000*0.25 / DY 1000*0.25 / DZ 1000*0.25 / TOPS 100*0.25 / PORO 1000*0.15 / JFUNC GAS * 13.0 0.6 0.7 Z / PROPS\nREGIONS """ deck2 = parser.parse_string(jfunc_gas) js_gas = EclipseState(deck2) jf = js_gas.jfunc() self.assertEqual(jf['FLAG'], 'GAS') self.assertEqual(jf['DIRECTION'], 'Z') self.assertTrue('GAS_OIL' in jf) self.assertFalse('OIL_WATER' in jf) self.assertEqual(jf['GAS_OIL'], 13.0) self.assertEqual(jf["ALPHA_FACTOR"], 0.6) # default self.assertEqual(jf["BETA_FACTOR"], 0.7) # default
def test_parse_ignore_keyword(self): deck_string = """ FIPNUM 100*1 100*2 / KEYWORD 1 2 3 / """ parse_context = ParseContext() parser = Parser() parse_context.ignore_keyword("KEYWORD") deck = parser.parse_string(deck_string, parse_context) self.assertEqual(len(deck), 1)
def test_parser_extension(self): error_recovery = [("PARSE_RANDOM_SLASH", opm.io.action.ignore)] parse_context = ParseContext(error_recovery) parser = Parser() for kw in self.KEYWORDS: parser.add_keyword(json.dumps(kw)) deck = parser.parse_string(self.DECK_ADDITIONAL_KEYWORDS, parse_context) self.assertIn('TESTKEY0', deck) self.assertIn('TESTKEY1', deck) self.assertIn('TESTKEY2', deck)
def setUpClass(cls): deck = Parser().parse(test_path('spe3/SPE3CASE1.DATA')) print("Creating state") cls.state = EclipseState(deck) print("State OK") cls.sch = Schedule(deck, cls.state) cls.timesteps = cls.sch.timesteps
def test_well_names(self): deck = Parser().parse(test_path('spe3/SPE3CASE1.DATA')) state = EclipseState(deck) sch = Schedule(deck, state) wnames = sch.well_names("*") self.assertTrue("PROD" in wnames) self.assertTrue("INJ" in wnames) self.assertEqual(len(wnames), 2)
def test_parse_with_multiple_recoveries(self): recoveries = [("PARSE_RANDOM_SLASH", opm.io.action.ignore), ("FOO", opm.io.action.warn), ("PARSE_RANDOM_TEXT", opm.io.action.throw)] parse_context = ParseContext(recoveries) deck = Parser().parse(self.spe3fn, parse_context) state = EclipseState(deck)
def test_parse_norne(self): parse_context = ParseContext( [('PARSE_RANDOM_SLASH', opm.io.action.ignore)] ) deck = Parser().parse(self.norne_fname, parse_context) es = EclipseState( deck ) self.assertEqual(46, es.grid().nx) self.assertEqual(112, es.grid().ny) self.assertEqual(22, es.grid().nz)
def test_raw_string_output(self): deck_string = """ UDQ DEFINE WUOPR2 WOPR '*' * WOPR '*' / DEFINE WUGASRA 3 - WGLIR '*' / / """ parse_context = ParseContext( ) parser = Parser() parse_context.ignore_keyword("KEYWORD") deck = parser.parse_string( deck_string ) udq = deck[0] s = "" for rec in udq: for item in rec: s += item.get_str(0)
def test_deck_kw_vector(self): parser = Parser() deck = parser.parse_string(self.REGIONDATA) active_unit_system = deck.active_unit_system() default_unit_system = deck.default_unit_system() self.assertEqual(active_unit_system.name, "Field") int_array = np.array([0, 1, 2, 3]) hbnum_kw = DeckKeyword( parser["HBNUM"], int_array) assert( np.array_equal(hbnum_kw.get_int_array(), int_array) ) raw_array = np.array([1.1, 2.2, 3.3]) zcorn_kw = DeckKeyword( parser["ZCORN"], raw_array, active_unit_system, default_unit_system) assert( np.array_equal(zcorn_kw.get_raw_array(), raw_array) ) si_array = zcorn_kw.get_SI_array() self.assertAlmostEqual( si_array[0], 1.1 * unit_foot ) self.assertAlmostEqual( si_array[2], 3.3 * unit_foot )
def parse(fname): s = dt.now() ps = ParseContext([('PARSE_RANDOM_SLASH', opm.io.action.ignore)]) deck = Parser().parse(fname, ps) es = EclipseState(deck) e = dt.now() print('Parsing took %s sec' % (e - s).seconds) return es
def test_deck_kw_records_uda(self): parser = Parser() deck = parser.parse_string(self.REGIONDATA) active_unit_system = deck.active_unit_system() default_unit_system = deck.default_unit_system() oil_target = 30000 # stb/day well_name = "PROD" well_status = "OPEN" control_mode = "ORAT" bhp_limit = 1000 # psia wconprod = DeckKeyword(parser["WCONPROD"], [[ well_name, well_status, control_mode, oil_target, "4*", bhp_limit ]], active_unit_system, default_unit_system) self.assertEqual(len(wconprod), 1) record = wconprod[0] self.assertEqual(record[0].name(), "WELL") self.assertTrue(record[0].is_string()) self.assertEqual(record[0].get_str(0), "PROD") self.assertEqual(record[1].name(), "STATUS") self.assertTrue(record[1].is_string()) self.assertEqual(record[1].get_str(0), "OPEN") self.assertEqual(record[2].name(), "CMODE") self.assertTrue(record[2].is_string()) self.assertEqual(record[2].get_str(0), "ORAT") self.assertEqual(record[3].name(), "ORAT") self.assertTrue(record[3].is_uda()) self.assertEqual(record[3].value, 30000) self.assertEqual(record[4].name(), "WRAT") self.assertTrue(record[4].is_uda()) self.assertEqual(record[4].value, 0) self.assertEqual(record[5].name(), "GRAT") self.assertTrue(record[5].is_uda()) self.assertEqual(record[5].value, 0) self.assertEqual(record[6].name(), "LRAT") self.assertTrue(record[6].is_uda()) self.assertEqual(record[6].value, 0) self.assertEqual(record[7].name(), "RESV") self.assertTrue(record[7].is_uda()) self.assertEqual(record[7].value, 0) self.assertEqual(record[8].name(), "BHP") self.assertTrue(record[8].is_uda()) self.assertEqual(record[8].value, 1000)
def test_no_leading_DATES(self): tv = TimeVector(datetime.date(1997, 11, 6), base_file=test_path("data/schedule/part1.sch")) s = str(tv) d = Parser().parse_string(s) kw0 = d[0] self.assertEqual(kw0.name, "WELSPECS") tv2 = TimeVector(datetime.date(2000, 1, 1)) self.assertEqual("", str(tv2))
def test_getitem(self): deck = Parser().parse(test_path('spe3/SPE3CASE1.DATA')) state = EclipseState(deck) sch = Schedule(deck, state) self.assertEqual(len(sch), 176) with self.assertRaises(IndexError): a = sch[200] st100 = sch[100] nupcol = st100.nupcol
def test_open_shut(self): deck = Parser().parse(test_path('spe3/SPE3CASE1.DATA')) state = EclipseState(deck) sch = Schedule(deck, state) prod = sch.get_well("PROD", 1) self.assertEqual(prod.status(), "OPEN") sch.shut_well("PROD", 10) prod = sch.get_well("PROD", 10) self.assertEqual(prod.status(), "SHUT")
def test_parser_section_deckItems(self): all_spe1case1 = [ "RUNSPEC", "TITLE", "DIMENS", "EQLDIMS", "TABDIMS", "REGDIMS", "OIL", "GAS", "WATER", "DISGAS", "FIELD", "START", "WELLDIMS", "UNIFOUT", "UDQDIMS", "UDADIMS", "GRID", "INIT", "NOECHO", "DX", "DY", "DZ", "TOPS", "PORO", "PERMX", "PERMY", "PERMZ", "ECHO", "PROPS", "PVTW", "ROCK", "SWOF", "SGOF", "DENSITY", "PVDG", "PVTO", "REGIONS", "EQLNUM", "FIPNUM", "SOLUTION", "EQUIL", "RSVD", "SUMMARY", "FOPR", "WGOR", "FGOR", "BPR", "BGSAT", "WBHP", "WGIR", "WGIT", "WGPR", "WGPT", "WOIR", "WOIT", "WOPR", "WOPT", "WWIR", "WWIT", "WWPR", "WWPT", "WUOPRL", "SCHEDULE", "UDQ", "RPTSCHED", "RPTRST", "DRSDT", "WELSPECS", "COMPDAT", "WCONPROD", "WCONINJE", "TSTEP" ] # notice that RUNSPEC keywords will always be parsed since these properties from these keyword # are needed to parse following sections. props_spe1case1 = [ "RUNSPEC", "TITLE", "DIMENS", "EQLDIMS", "TABDIMS", "REGDIMS", "OIL", "GAS", "WATER", "DISGAS", "FIELD", "START", "WELLDIMS", "UNIFOUT", "UDQDIMS", "UDADIMS", "GRID", "PVTW", "ROCK", "SWOF", "SGOF", "DENSITY", "PVDG", "PVTO" ] parser = Parser() error_recovery = [("PARSE_RANDOM_SLASH", opm.io.action.ignore), ("PARSE_EXTRA_RECORDS", opm.io.action.ignore)] context = ParseContext(error_recovery) deck1 = parser.parse(test_path("data/SPE1CASE1.DATA"), context) self.assertEqual(len(deck1), len(all_spe1case1)) test_1 = [dkw.name for dkw in deck1] for test, ref in zip(test_1, all_spe1case1): self.assertEqual(test, ref) section_list = [eclSectionType.PROPS] deck2 = parser.parse(test_path("data/SPE1CASE1.DATA"), context, section_list) self.assertEqual(len(deck2), len(props_spe1case1)) test_2 = [dkw.name for dkw in deck2] for test, ref in zip(test_2, props_spe1case1): self.assertEqual(test, ref) # props section keyword located in include file for this deck (SPE1CASE1B.DATA) # not possible to parse individual sections with self.assertRaises(RuntimeError): parser.parse(test_path("data/SPE1CASE1B.DATA"), context, section_list)
def test_injection_properties(self): deck = Parser().parse(test_path('spe3/SPE3CASE1.DATA')) state = EclipseState(deck) sch = Schedule(deck, state) report_step = 4 well_name = 'INJ' prop = sch.get_injection_properties(well_name, report_step) self.assertEqual(prop['surf_inj_rate'], 4700.0) # Mscf/day self.assertEqual(prop['resv_inj_rate'], 0.0) # rb/day self.assertEqual(prop['bhp_target'], 4000.0) # psi self.assertEqual(prop['thp_target'], 0.0) with self.assertRaises(IndexError): prop = sch.get_injection_properties("UNDEF", report_step) with self.assertRaises(KeyError): prop = sch.get_injection_properties("PROD", report_step)
def main(): deck = Parser().parse('../tests/spe3/SPE3CASE1.DATA') es = EclipseState(deck) sc = Schedule(deck, es) wp = sc.get_wells(0)[0] # producer wi = sc.get_wells(0)[1] # injector print('state: %s' % es) print('schedule: %s' % sc) print('prod well: %s' % wp) print('inj well: %s' % wi) for i in range(len(sc.timesteps)): if not sc.get_wells(i)[0].isproducer() or sc.get_wells(i)[0].isinjector(): print('wp is not producer in step %s' % sc.timesteps[i]) if not sc.get_wells(i)[1].isinjector() or sc.get_wells(i)[1].isproducer(): print('wi is not injector in step %s' % sc.timesteps[i])
def test_production_properties(self): deck = Parser().parse(test_path('spe3/SPE3CASE1.DATA')) state = EclipseState(deck) sch = Schedule(deck, state) report_step = 4 well_name = 'PROD' prop = sch.get_production_properties(well_name, report_step) self.assertEqual(prop['alq_value'], 0.0) self.assertEqual(prop['bhp_target'], 500.0) self.assertEqual(prop['gas_rate'], 6200.0) self.assertEqual(prop['liquid_rate'], 0.0) self.assertEqual(prop['oil_rate'], 0.0) self.assertEqual(prop['resv_rate'], 0.0) self.assertEqual(prop['thp_target'], 0.0) self.assertEqual(prop['water_rate'], 0.0)
def test_create(self): parser = Parser() deck = parser.parse(self.spe3fn) context = ParseContext() deck = parser.parse(self.spe3fn, context) with open(self.spe3fn) as f: string = f.read() deck = parser.parse_string(string) deck = parser.parse_string(string, context)
def test_create(self): parser = Parser() deck = parser.parse(self.spe3fn) active_unit_system = deck.active_unit_system() default_unit_system = deck.default_unit_system() self.assertEqual(active_unit_system.name, "Field") context = ParseContext() deck = parser.parse(self.spe3fn, context) with open(self.spe3fn) as f: string = f.read() deck = parser.parse_string(string) deck = parser.parse_string(string, context)
def load(self, filename, date=None): """Will parse a Schedule file and add the keywords to the current TimeVector. You can call the load() method repeatedly, the different timesteps will be ordered chronologically. If a timestep is already present the keywords will be appended. The optional date argument can be used to insert schedule file fragments which do not have any DATES / TSTEP keywords. Assuming you have a base file 'base.sch' and a small fragment 'well.sch' with the WELSPECS and COMPDAT keywords to create one well, then the new well can be added 1.st of April 2017 as this: tv = TimeVector( start ) tv.load("base.sch") tv.load("well.sch", date = datetime.datetime(2017, 4, 1)) """ deck = Parser().parse(filename) self._add_deck(deck, date)
def test_all(self): with pushd(self.data_dir): deck = Parser().parse('SPE1CASE1.DATA') state = EclipseState(deck) schedule = Schedule(deck, state) summary_config = SummaryConfig(deck, state, schedule) self.assertTrue('PROD' in schedule) self.assertTrue('INJ' in schedule) self.assertEqual(dt.datetime(2015, 1, 1), schedule.start) self.assertEqual(dt.datetime(2016, 1, 1), schedule.end) sim = BlackOilSimulator(deck, state, schedule, summary_config) sim.step_init() sim.step() prod = schedule.get_well("PROD", 2) self.assertEqual(prod.status(), "OPEN") #schedule.shut_well("PROD", 3) #prod = schedule.get_well("PROD", 3) #self.assertEqual(prod.status(), "SHUT") sim.step() sim.step()
def load_string(self, deck_string, date=None): """ Like load() - but load from a string literal instead of file. """ deck = Parser().parse_string(deck_string) self._add_deck(deck, date)
def __init__(self, start_date, base_string=None, base_file=None): """The TimeVector class is a simple vector class with DATES/TSTEP blocks. The TimeVector class is a basic building block for tools designed to update schedule files. A schedule file consists of a list of keywords related to the dynamic properties of the field, like opening and closing wells, specifiying rates and so on. The temporal advancement of the simulator is controlled by DATES and TSTEP keywords. A typical schedule section can look like this: --- Step 1 ----------------------- WELSPECS 'C1' 'G1' 10 10 10 'OIL' / / COMPDAT 'C1' 15 20 10 16 'OPEN' / 'C1' 15 21 16 16 'OPEN' / / WCONHIST 'C1' 'OPEN' 'ORAT' 1000 / / --- Step 2 ---------------------- DATES 10 'MAY' 2016 / / WCONHIST 'C1' 'OPEN' 'ORAT' 2000 / / --- Step 3 ---------------------- TSTEP 10 / WELSPECS 'W2' 'G1' 5 5 5 'OIL' / / COMPDAT 'W2' 10 10 7 10 'OPEN' / / WCONHIST 'C1' 'OPEN' 'ORAT' 3000 / 'W2' 'OPEN' 'ORAT' 1500 / / --- Step 4 ---------------------- DATES 30 'MAY' 2016 / / As indicated above the DATES and TSTEP keywords act as delimiters in the schedule file. In the TimeVector class the fundamental unit is TimeStep instance which consists of a list of keywords, and a terminating DATES or TSTEP keyword, the example above would correspond to a TimeVector with three TimeStep instances. Basic usage example: #!/usr/bin/env python from opm.tools import TimeVector # Create vector and load history. tv = TimeVector( start ) tv.load("history.sch") # Load predictions from another file tv.load("prediction.sch") # Insert the definition of one particular well at # a specifed date. tv.load("extra_wll.sch", date = datetime.datetime(2018,10,1)) # Check if we have a certain timestep: if datetime.datetime(2017,1,1) in tv: print("We have it!") else: print("No such date") # Dump the updated schedule content to a file: with open("schedule","w") as f: f.write(str(tv)) """ if base_string and base_file: raise ValueError( "Can only supply one of base_string and base_file arguments") self.start_date = datetime.datetime(start_date.year, start_date.month, start_date.day) self.time_steps_dict = {} self.time_steps_list = [] ts = TimeStep.create_first(self.start_date) self._add_dates_block(ts) start_dt = datetime.datetime(start_date.year, start_date.month, start_date.day) if base_file: deck = Parser().parse(base_file) self._add_deck(deck, start_dt) if base_string: deck = Parser().parse_string(base_string) self._add_deck(deck, start_dt)
class TestBasic(unittest.TestCase): @classmethod def setUpClass(cls): # NOTE: See comment in test_basic.py for the reason why we are # only using a single test_all() function instead of splitting # it up in multiple test functions test_dir = Path(os.path.dirname(__file__)) cls.data_dir = test_dir.parent.joinpath("test_data/SPE1CASE1b") def test_all(self): with pushd(self.data_dir): self.deck = Parser().parse('SPE1CASE1.DATA') state = EclipseState(self.deck) self.schedule = Schedule(self.deck, state) summary_config = SummaryConfig(self.deck, state, self.schedule) self.unit_system = self.deck.active_unit_system() self.assertTrue('PROD' in self.schedule) self.assertTrue('INJ' in self.schedule) self.assertEqual(dt.datetime(2015, 1, 1), self.schedule.start) self.assertEqual(dt.datetime(2016, 1, 1), self.schedule.end) self.sim = BlackOilSimulator(self.deck, state, self.schedule, summary_config) tsteps = self.schedule.timesteps self.assertEqual(dt.datetime(2015, 1, 1), tsteps[0]) last_step = len(tsteps) - 1 self.assertEqual(dt.datetime(2016, 1, 1), tsteps[last_step]) self.sim.step_init() report_step = 4 self.sim.advance(report_step=report_step) well_name = "PROD" prod = self.schedule.get_well(well_name, 2) self.assertEqual(prod.status(), "OPEN") #schedule.shut_well("PROD", 3) #prod = schedule.get_well("PROD", 3) #self.assertEqual(prod.status(), "SHUT") self.subtest_modify_prod_weltarg_dynamically( well_name, report_step) self.sim.step() report_step = self.sim.current_step() well_name = "INJ" self.subtest_modify_inj_weltarg_dynamically(well_name, report_step) self.sim.advance(report_step=last_step) self.sim.step_cleanup() def subtest_modify_inj_weltarg_dynamically(self, well_name, report_step): prop = self.schedule.get_injection_properties(well_name, report_step) self.assertEqual(prop['surf_inj_rate'], 100000.0) # Mscf/day self.assertEqual(prop['resv_inj_rate'], 0.0) # rb/day self.assertEqual(prop['bhp_target'], 9014.0) # psi self.assertEqual(prop['thp_target'], 0.0) new_grat_target = prop['surf_inj_rate'] - 100 # stb/day self.update_inj_grat_target_wconinje(well_name, new_grat_target) self.sim.step() prop2 = self.schedule.get_injection_properties(well_name, report_step + 1) self.assertEqual(prop2['surf_inj_rate'], new_grat_target) new_grat_target += 200 self.update_inj_grat_target_weltarg(well_name, new_grat_target) self.sim.step() prop3 = self.schedule.get_injection_properties(well_name, report_step + 2) self.assertEqual(prop3['surf_inj_rate'], new_grat_target) def subtest_modify_prod_weltarg_dynamically(self, well_name, report_step): prop = self.schedule.get_production_properties(well_name, report_step) self.assertEqual(prop['alq_value'], 0.0) self.assertEqual(prop['bhp_target'], 1000.0) self.assertEqual(prop['gas_rate'], 0.0) self.assertEqual(prop['liquid_rate'], 0.0) self.assertEqual(prop['oil_rate'], 20000.0) self.assertEqual(prop['resv_rate'], 0.0) self.assertEqual(prop['thp_target'], 0.0) self.assertEqual(prop['water_rate'], 0.0) new_oil_target = prop['oil_rate'] + 10000 # stb/day self.update_prod_orat_target_wconprod(well_name, new_oil_target) self.sim.step() prop2 = self.schedule.get_production_properties( well_name, report_step + 1) self.assertEqual(prop2['oil_rate'], new_oil_target) new_oil_target += 1000 self.update_prod_orat_target_weltarg(well_name, new_oil_target) self.sim.step() prop3 = self.schedule.get_production_properties( well_name, report_step + 2) self.assertEqual(prop3['oil_rate'], new_oil_target) # This is an alternative to using WELTARG def update_inj_grat_target_wconinje(self, well_name, new_surf_flow_rate): data = self.deck["WCONINJE"] # assumes data looks like this: # WCONINJE # 'INJ' 'GAS' 'OPEN' 'RATE' 100000 1* 9014 / # / # The initial rate can also be obtained from data[0][4].get_uda(0).get_double() data = re.sub(pattern='100000', repl=str(new_surf_flow_rate), string=str(data), count=1) report_step = self.sim.current_step() self.schedule.insert_keywords(data, step=report_step, unit_system=self.unit_system) # This is an alternative to using WCONINJE to modify injection properties def update_inj_grat_target_weltarg(self, well_name, net_surf_flow_rate): data = """ WELTARG '{}' GRAT {} / / """.format(well_name, net_surf_flow_rate) report_step = self.sim.current_step() self.schedule.insert_keywords(data, step=report_step, unit_system=self.unit_system) # This is an alternative to using WCONPROD to modify production properties def update_prod_orat_target_weltarg(self, well_name, oil_target): data = """ WELTARG '{}' ORAT {} / / """.format(well_name, oil_target) report_step = self.sim.current_step() self.schedule.insert_keywords(data, step=report_step, unit_system=self.unit_system) # This is an alternative to using WELTARG to modify production properties def update_prod_orat_target_wconprod(self, well_name, oil_target): well_status = "OPEN" control_mode = "ORAT" bhp_limit = 1000 # psia data = """ WCONPROD '{}' '{}' '{}' {} 4* {} / / """.format(well_name, well_status, control_mode, oil_target, bhp_limit) report_step = self.sim.current_step() self.schedule.insert_keywords(data, step=report_step, unit_system=self.unit_system)