def df2ecl_pvto(dframe, comment=None): """Print PVTO-data from a dataframe Args: dframe (pd.DataFrame): Containing PVTO data comment (str): Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVTO\n" string += common.comment_formatter(comment) string += "-- {:^22} {:^22} {:^22} {:^22}\n".format( "RS", "PRESSURE", "VOLUMEFACTOR", "VISCOSITY" ) string += "-- {:^22} {:^22} {:^22} {:^22}\n".format( "*", "PRESSURE", "VOLUMEFACTOR", "VISCOSITY" ) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVTO"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical("If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() def _pvto_pvtnum(dframe): """Print PVTO-data for a specific PVTNUM""" string = "" dframe = dframe.set_index("RS").sort_index() for rs in dframe.index.unique(): string += _pvto_pvtnum_rs(dframe[dframe.index == rs]) return string + "/\n" def _pvto_pvtnum_rs(dframe): """Print PVTO-data for a particular RS""" string = "" assert len(dframe.index.unique()) == 1 rs = dframe.index.values[0] string += "{:20.7f} ".format(rs) for rowidx, row in dframe.reset_index().iterrows(): if rowidx > 0: indent = "\n" + " " * 22 else: indent = "" string += ( indent + "{PRESSURE:20.7f} {VOLUMEFACTOR:20.7f} {VISCOSITY:20.7f}".format( **(row.to_dict()) ) ) string += " /\n-- End RS={}\n".format(rs) return string for pvtnum in subset.index.unique(): string += _pvto_pvtnum(subset[subset.index == pvtnum]) return string + "\n"
def df2ecl_pvtw(dframe, comment=None): """Print PVTW keyword with data PVTW is one line/record with data for a reference pressure for each PVTNUM. Args: dframe (pd.DataFrame): Containing PVTW data comment (str): Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVTW\n" string += common.comment_formatter(comment) string += "-- {:^21} {:^21} {:^21} {:^21} {:^21} \n".format( "PRESSURE", "VOLUMEFACTOR", "COMPRESSIBILITY", "VISCOSITY", "VISCOSIBILITY" ) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVTW"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical("If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() for _, row in subset.iterrows(): string += " {PRESSURE:20.7f} {VOLUMEFACTOR:20.7f} ".format(**(row.to_dict())) string += "{COMPRESSIBILITY:20.7f} {VISCOSITY:20.7f} ".format(**(row.to_dict())) string += "{VISCOSIBILITY:20.7f}/\n".format(**(row.to_dict())) return string + "\n"
def df2ecl_pvtg(dframe, comment=None): """Print DENSITY keyword with data DENSITY is one line (one record) of data pr. PVTNUM Args: dframe (pd.DataFrame): Containing PVTG data comment (str): Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "DENSITY\n" string += common.comment_formatter(comment) string += "-- {:^21} {:^21} {:^21} \n".format( "OILDENSITY", "WATERDENSITY", "GASDENSITY" ) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "DENSITY"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical("If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() for _, row in subset.iterrows(): string += " {OILDENSITY:20.7f} {WATERDENSITY:20.7f} ".format(**(row.to_dict())) string += "{GASDENSITY:20.7f} /\n".format(**(row.to_dict())) return string + "\n"
def _df2ecl_satfuncs(keyword: str, dframe: pd.DataFrame, comment: Optional[str] = None) -> str: if dframe.empty: return "-- No data!\n" string = "{}\n".format(keyword) string += common.comment_formatter(comment) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == keyword] if "SATNUM" not in subset: subset["SATNUM"] = 1 subset = subset.set_index("SATNUM").sort_index() # Make a function that is to be called for each SATNUM def _df2ecl_satfuncs_satnum(keyword, dframe): """Print one saturation function for one specific SATNUM""" col_headers = RENAMERS[keyword]["DATA"] string = ("-- " + dframe[col_headers].to_string( float_format=" %g", header=True, index=False).strip()) return string + "\n/\n" # Loop over every SATNUM for satnum in subset.index.unique(): string += "-- SATNUM: {}\n".format(satnum) string += _df2ecl_satfuncs_satnum(keyword, subset[subset.index == satnum]) return string + "\n"
def df2ecl_rock(dframe, comment=None): """Print ROCK keyword with data Args: dframe (pd.DataFrame): Containing ROCK data comment (str): Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "ROCK\n" string += common.comment_formatter(comment) string += "-- {:^21} {:^21}\n".format("PRESSURE", "COMPRESSIBILITY") if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "ROCK"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical("If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() for _, row in subset.iterrows(): string += " {PRESSURE:20.7f} {COMPRESSIBILITY:20.7f} /\n".format( **(row.to_dict()) ) return string + "\n"
def df2ecl_pvtw(dframe: pd.DataFrame, comment: Optional[str] = None) -> str: """Print PVTW keyword with data PVTW is one line/record with data for a reference pressure for each PVTNUM. Args: dframe: Containing PVTW data comment: Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVTW\n" string += common.comment_formatter(comment) string += ( f"-- {'PRESSURE':^21} {'VOLUMEFACTOR':^21} {'COMPRESSIBILITY':^21} " f"{'VISCOSITY':^21} {'VISCOSIBILITY':^21}\n") if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVTW"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical( "If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() for _, row in subset.iterrows(): string += f" {row['PRESSURE']:20.7f} {row['VOLUMEFACTOR']:20.7f} " string += f"{row['COMPRESSIBILITY']:20.7f} {row['VISCOSITY']:20.7f} " string += f"{row['VISCOSIBILITY']:20.7f}/\n" return string + "\n"
def df2ecl_density(dframe: pd.DataFrame, comment: Optional[str] = None) -> str: """Print DENSITY keyword with data Args: dframe: Containing DENSITY data comment: Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "DENSITY\n" string += common.comment_formatter(comment) string += f"-- {'OILDENSITY':^21} {'WATERDENSITY':^21} {'GASDENSITY':^21}\n" if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "DENSITY"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical( "If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() for _, row in subset.iterrows(): string += f" {row['OILDENSITY']:20.7f} {row['WATERDENSITY']:20.7f}" string += f" {row['GASDENSITY']:20.7f} /\n" return string + "\n"
def df2ecl_equil(dframe, comment=None): """Print EQUIL keyword with data Args: dframe (pd.DataFrame): Containing EQUIL data comment (str): Text that will be included as a comment """ string = "EQUIL\n" string += common.comment_formatter(comment) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "EQUIL"] if "EQLNUM" not in subset: if len(subset) != 1: logger.critical("If EQLNUM is not supplied, only one row should be given") return "" subset["EQLNUM"] = 1 subset = subset.set_index("EQLNUM").sort_index() phases = phases_from_columns(subset.columns) # Make a copy as we are going to modify it in order to have Pandas # make a pretty txt table: equildf = subset.copy() # Column names are pr. ec2ldf standard, redo to opm.common in order # to use sorting from that: inv_renamer = {value: key for key, value in RENAMERS[phases].items()} # print(inv_renamer) equildf.rename(inv_renamer, axis="columns", inplace=True) col_headers = [item["name"] for item in common.OPMKEYWORDS["EQUIL"]["items"]] for colname in col_headers: # Add those that are missing, as Eclipse defaults if colname not in equildf: equildf[colname] = "1*" # Reorder columns: equildf = equildf[col_headers] # It is critical for opm.common, maybe also E100 to have integers printed # as integers, for correct parsing. Ensure integer types where # the json says integer: integer_cols = [ item["name"] for item in common.OPMKEYWORDS["EQUIL"]["items"] if item["value_type"] == "INT" ] for int_col in integer_cols: # But allow these columns to contain "1*" if set(equildf[int_col]) != {"1*"}: equildf[int_col] = equildf[int_col].astype(int) # Now rename again to have prettier column names: equildf.rename(RENAMERS[phases], axis="columns", inplace=True) # Add a final column with the end-slash, invisible header: equildf[" "] = "/" string += "-- " + equildf.to_string(header=True, index=False) return string + "\n\n"
def df2ecl_pvtg(dframe: pd.DataFrame, comment: Optional[str] = None) -> str: """Print PVTG keyword with data Args: dframe: Containing PVTG data comment: Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVTG\n" string += common.comment_formatter(comment) string += "-- {:^22} {:^22} {:^22} {:^22}\n".format( "PRESSURE", "OGR", "VOLUMEFACTOR", "VISCOSITY") string += "-- {:^22} {:^22} {:^22} {:^22}\n".format( "*", "OGR", "VOLUMEFACTOR", "VISCOSITY") if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVTG"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical( "If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() def _pvtg_pvtnum(dframe): """Print PVTG-data for a specific PVTNUM""" string = "" dframe = dframe.set_index("PRESSURE").sort_index() for p_gas in dframe.index.unique(): string += _pvtg_pvtnum_pg(dframe[dframe.index == p_gas]) return string + "/\n" def _pvtg_pvtnum_pg(dframe): """Print PVTG-data for a particular gas phase pressure""" string = "" assert len(dframe.index.unique()) == 1 p_gas = dframe.index.values[0] string += "{:20.7f} ".format(p_gas) for rowidx, row in dframe.reset_index().iterrows(): if rowidx > 0: indent = "\n" + " " * 22 else: indent = "" string += ( indent + "{OGR:20.7f} {VOLUMEFACTOR:20.7f} {VISCOSITY:20.7f}".format( **(row.to_dict()))) string += " /\n-- End PRESSURE={}\n".format(p_gas) return string for pvtnum in subset.index.unique(): string += _pvtg_pvtnum(subset[subset.index == pvtnum]) return string + "\n"
def df2ecl_pvto(dframe: pd.DataFrame, comment: Optional[str] = None) -> str: """Print PVTO-data from a dataframe Args: dframe: Containing PVTO data comment: Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVTO\n" string += common.comment_formatter(comment) string += "-- {'RS':^22} {'PRESSURE':^22} {'VOLUMEFACTOR':^22} {'VISCOSITY':^22}\n" string += "-- {'*':^22} {'PRESSURE':^22} {'VOLUMEFACTOR':^22} {'VISCOSITY':^22}\n" if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVTO"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical( "If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 subset = subset.set_index("PVTNUM").sort_index() def _pvto_pvtnum(dframe: pd.DataFrame) -> str: """Print PVTO-data for a specific PVTNUM""" string = "" dframe = dframe.set_index("RS").sort_index() for rs in dframe.index.unique(): string += _pvto_pvtnum_rs(dframe[dframe.index == rs]) return string + "/\n" def _pvto_pvtnum_rs(dframe: pd.DataFrame) -> str: """Print PVTO-data for a particular RS""" string = "" assert len(dframe.index.unique()) == 1 rs = dframe.index.values[0] string += f"{rs:20.7f} " for rowidx, row in dframe.reset_index().iterrows(): if rowidx > 0: indent = "\n" + " " * 22 else: indent = "" string += ( indent + f"{row['PRESSURE']:20.7f} {row['VOLUMEFACTOR']:20.7f} " + f"{row['VISCOSITY']:20.7f}") string += f" /\n-- End RS={rs}\n" return string for pvtnum in subset.index.unique(): string += _pvto_pvtnum(subset[subset.index == pvtnum]) return string + "\n"
def df2ecl_pvdo(dframe, comment=None): """Print PVDO keyword with data Args: dframe (pd.DataFrame): Containing PVDO data comment (str): Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVDO\n" string += common.comment_formatter(comment) string += "-- {:^21} {:^21} {:^21} \n".format( "PRESSURE", "VOLUMEFACTOR", "VISCOSITY" ) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVDO"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical("If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 def _pvdo_pvtnum(dframe): """Print PVDO-data for a specific PVTNUM Args: dframe (pd.DataFrame): Cropped to only contain the relevant data. Returns: string """ string = "" dframe = dframe.sort_values("PRESSURE") for _, row in dframe.iterrows(): string += " {PRESSURE:20.7f} {VOLUMEFACTOR:20.7f} ".format( **(row.to_dict()) ) string += "{VISCOSITY:20.7f}\n".format(**(row.to_dict())) return string + "/\n" subset = subset.set_index("PVTNUM").sort_index() for pvtnum in subset.index.unique(): string += "-- PVTNUM: {}\n".format(pvtnum) string += _pvdo_pvtnum(subset[subset.index == pvtnum]) return string + "\n"
def df2ecl_pvdg(dframe, comment=None): """Print PVDG keyword with data This data consists of one table (volumefactor and visosity as a function of pressure) pr. PVTNUM. Args: dframe (pd.DataFrame): Containing PVDG data comment (str): Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVDG\n" string += common.comment_formatter(comment) string += "-- {:^21} {:^21} {:^21} \n".format( "PRESSURE", "VOLUMEFACTOR", "VISCOSITY" ) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVDG"] if "PVTNUM" not in subset: subset["PVTNUM"] = 1 def _pvdg_pvtnum(dframe): """Print PVDG-data for a specific PVTNUM Args: dframe (pd.DataFrame): Cropped to only contain the relevant data. Returns: string """ string = "" dframe = dframe.sort_values("PRESSURE") for _, row in dframe.iterrows(): string += " {PRESSURE:20.7f} {VOLUMEFACTOR:20.7f} ".format( **(row.to_dict()) ) string += "{VISCOSITY:20.7f}\n".format(**(row.to_dict())) return string + "/\n" subset = subset.set_index("PVTNUM").sort_index() for pvtnum in subset.index.unique(): string += "-- PVTNUM: {}\n".format(pvtnum) string += _pvdg_pvtnum(subset[subset.index == pvtnum]) return string + "\n"
def df2ecl_pvdg(dframe: pd.DataFrame, comment: Optional[str] = None) -> str: """Print PVDG keyword with data This data consists of one table (volumefactor and visosity as a function of pressure) pr. PVTNUM. Args: dframe: Containing PVDG data comment: Text that will be included as a comment """ if dframe.empty: return "-- No data!" string = "PVDG\n" string += common.comment_formatter(comment) string += f"-- {'PRESSURE':^21} {'VOLUMEFACTOR':^21} {'VISCOSITY':^21} \n" if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == "PVDG"] if "PVTNUM" not in subset: if len(subset) != 1: logger.critical( "If PVTNUM is not supplied, only one row should be given") return "" subset["PVTNUM"] = 1 def _pvdg_pvtnum(dframe): """Print PVDG-data for a specific PVTNUM Args: dframe (pd.DataFrame): Cropped to only contain the relevant data. Returns: string """ string = "" dframe = dframe.sort_values("PRESSURE") for _, row in dframe.iterrows(): string += f" {row['PRESSURE']:20.7f} {row['VOLUMEFACTOR']:20.7f} " string += f"{row['VISCOSITY']:20.7f}\n" return string + "/\n" subset = subset.set_index("PVTNUM").sort_index() for pvtnum in subset.index.unique(): string += "-- PVTNUM: {pvtnum}\n" string += _pvdg_pvtnum(subset[subset.index == pvtnum]) return string + "\n"
def _df2ecl_equilfuncs(keyword: str, dframe: pd.DataFrame, comment: Optional[str] = None) -> str: """Internal function to be used by df2ecl_<keyword>() functions""" if dframe.empty: return "-- No data!" string = "{}\n".format(keyword) string += common.comment_formatter(comment) col_headers = RENAMERS[keyword]["DATA"] string += "-- {:^21} {:^21} \n".format("DEPTH", col_headers[1]) if "KEYWORD" not in dframe: # Use everything.. subset = dframe else: subset = dframe[dframe["KEYWORD"] == keyword] if "EQLNUM" not in subset: subset["EQLNUM"] = 1 def _df2ecl_equilfuncs_eqlnum(dframe: pd.DataFrame) -> str: """Print one equilibriation function table for a specific EQLNUM Args: dframe (pd.DataFrame): Cropped to only contain data for one EQLNUM Returns: string """ string = "" dframe = dframe.sort_values("Z") for _, row in dframe.iterrows(): string += " {:20.7f} {:20.7f}\n".format(row[col_headers[0]], row[col_headers[1]]) return string + "/\n" subset = subset.set_index("EQLNUM").sort_index() for eqlnum in subset.index.unique(): string += "-- EQLNUM: {}\n".format(eqlnum) string += _df2ecl_equilfuncs_eqlnum(subset[subset.index == eqlnum]) return string + "\n"
def df2ecl(grid_df, keywords, eclfiles=None, dtype=None, filename=None, nocomments=False): """ Write an include file with grid data keyword, like PERMX, PORO, FIPNUM etc, for the GRID section of the Eclipse deck. Output (returned as string and optionally written to file) will then contain f.ex:: PERMX 3.3 4.1 500.1 8543.0 1223.0 5022.0 411.455 4433.9 / if the grid contains 8 cells (inactive and active). Args: grid_df (pd.DataFrame). Dataframe with the keyword for which we want to export data, and also the a column with GLOBAL_INDEX. Without GLOBAL_INDEX, the output will likely be invalid. The grid can contain both active and inactive cells. keywords (str or list of str): The keyword(s) to export, with one value for every cell. eclfiles (EclFiles): If provided, the total cell count for the grid will be requested from this object. If not, it will be *guessed* from the maximum number of GLOBAL_INDEX, which can be under-estimated in the corner-case that the last cells are inactive. dtype (float or int-class): If provided, the columns which are outputted are converted to int or float. Dataframe columns read from CSV files easily gets the wrong type, while Eclipse might require some data to be strictly integer. filename (str): If provided, the string produced will also to be written to this filename. nocomments (bool): Set to True to avoid any comments being written. Defaults to False. """ if isinstance(keywords, str): keywords = [keywords] if isinstance(dtype, str): if dtype.startswith("int"): dtype = int elif dtype.startswith("float"): dtype = float else: raise ValueError("Wrong dtype argument {}".format(dtype)) # Figure out the total number of cells for which we need to export data for: global_size = None active_cells = None if eclfiles is not None: if eclfiles.get_egrid() is not None: global_size = eclfiles.get_egrid().get_global_size() active_cells = eclfiles.get_egrid().getNumActive() if "GLOBAL_INDEX" not in grid_df: logger.warning(("Global index not found in grid dataframe. " "Assumes all cells are active")) # Drop NaN rows for columns to be used (triggerd by stacked # dates and no global index, unlikely) # Also copy dataframe to avoid side-effects on incoming data. grid_df = grid_df.dropna( axis="rows", subset=[keyword for keyword in keywords if keyword in grid_df]) grid_df["GLOBAL_INDEX"] = grid_df.index if global_size is None: global_size = int(grid_df["GLOBAL_INDEX"].max() + 1) active_cells = len(grid_df[grid_df.index >= 0]) logger.warning("Global grid size estimated to %s", str(global_size)) ecl2df_header = ("Output file printed by " + "ecl2df.grid " + __version__ + "\n" + " at " + str(datetime.datetime.now())) string = "" if not nocomments: string += common.comment_formatter(ecl2df_header) string += "\n" # If we have NaNs in the dataframe, we will be more careful (costs memory) if grid_df.isna().any().any(): grid_df = grid_df.dropna( axis="rows", subset=[keyword for keyword in keywords if keyword in grid_df]) for keyword in keywords: if keyword not in grid_df.columns: raise ValueError( "Keyword {} not found in grid dataframe".format(keyword)) vector = np.zeros(global_size) vector[grid_df["GLOBAL_INDEX"].astype(int).values] = grid_df[keyword] if dtype == int: vector = vector.astype(int) if dtype == float: vector = vector.astype(float) if len(vector) != global_size: logger.warning( ("Mismatch between dumped vector length " "%d from df2ecl and assumed grid size %d"), len(vector), global_size, ) logger.warning("Data will be dumped, but may error in simulator") strvector = " ".join([str(x) for x in vector]) strvector = common.runlength_eclcompress(strvector) string += keyword + "\n" indent = " " * 5 string += "\n".join( textwrap.wrap(strvector, initial_indent=indent, subsequent_indent=indent, width=70)) string += "\n/" if not nocomments: string += " -- {}: {} active cells, {} total cell count\n".format( keyword, active_cells, global_size) string += "\n" if filename is not None: # Make directory if not present: filenamedir = os.path.dirname(filename) if filenamedir and not os.path.exists(filenamedir): os.makedirs(filenamedir) with open(filename, "w") as file_handle: file_handle.write(string) return string
def df2ecl_editnnc(nnc_df, filename=None, nocomments=False): """Write an EDITNNC keyword This will write EDITNNC IX IY IZ JX JY JZ TRANM / ... / and return as string and/or dump to filename. The column TRANM must be in the incoming dataframe and it should be the multiplier to be written for each connection. If you want to edit only a subset of the non-neighbour connections, filter the dataframe upfront. Only rows where the column "DIR" is "NNC" will be considered. Args: nnc_df (pd.DataFrame): Dataframe with I1, J1, K1, I2, J2, K2 and a TRANM column, where the multiplier to be written is in TRANM. If the DIR column is present, only the rows with 'NNC' in the DIR column are included. filename (str): Filename to write to nocomments (bool): Set to True if you don't want any comments in the produced string/file Returns: string with the EDITNNC keyword. """ string = "" ecl2df_header = ("Output file printed by ecl2df.nnc" + " " + __version__ + "\n" + " at " + str(datetime.datetime.now())) if not nocomments: string += common.comment_formatter(ecl2df_header) string += "\n" if "DIR" in nnc_df: nnc_df = nnc_df[nnc_df["DIR"] == "NNC"] if "TRANM" not in nnc_df: raise ValueError("TRANM not supplied in nnc_df") string += "EDITNNC" + os.linesep table_str = nnc_df[["I1", "J1", "K1", "I2", "J2", "K2", "TRANM"]].to_string(header=True, index=False) lines = table_str.rstrip().split(os.linesep) indent = " " string += "-- " + lines[0] + os.linesep string += os.linesep.join([indent + line + " /" for line in lines[1:]]) string += os.linesep string += "/" if not nocomments: string += " " string += common.comment_formatter( " {} nnc connections, avg multiplier {}".format( len(nnc_df), nnc_df["TRANM"].mean())) string += "\n\n" if filename is not None: # Make directory if not present: filenamedir = os.path.dirname(filename) if filenamedir and not os.path.exists(filenamedir): os.makedirs(filenamedir) with open(filename, "w") as file_handle: file_handle.write(string) return string