diff --git a/.gitignore b/.gitignore index b835bff007..11ac897324 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ python/lib64 /libenkf/src/.faultlist /develbranch/libenkf/src/.faultlist /build +/temp-build /libert_util/tests/data/latex_OK.pdf /test-data/Statoil /python/python/ert/ecl/ecl_local.py diff --git a/README.md b/README.md index 07d72dec3a..6a53539df1 100644 --- a/README.md +++ b/README.md @@ -78,5 +78,6 @@ fopt = summary.numpy_vector("FOPT") ``` +The installation with Python enabled is described in a [YouTube video](https://www.youtube.com/watch?v=Qqy1vA1PSk8) by Carlf Fredrik Berg. [1]: The exact paths here will depend on your system and Python version. The example given is for a RedHat system with Python version 2.7. diff --git a/WINDOWS.md b/WINDOWS.md new file mode 100644 index 0000000000..2bfb46b95b --- /dev/null +++ b/WINDOWS.md @@ -0,0 +1,27 @@ +# Compiling and Installing **_libecl_** on Windows + +## Prerequisits: +* Python 2.7 or 3.x https://www.python.org/ or https://anaconda.org/ +* Microsoft Visual Studio https://visualstudio.microsoft.com/downloads/ +* Local copy of **_libecl_** + +## Instructions: +1. Download or clone the **_libecl_** Github repository to your local disk. + +2. Python 2.7 or 3.x installation + - Download a python instalation or a python environment solution such as Anaconda. + +3. Download and install Microsoft Visual Studio . At a minimum **_libecl_** requires the VS Studio packages for cmake, msbuild, c and c++ compilers (CL.exe). + +4. Open a MSVC command prompt such as _x64 Native Tools Command Prompt for VS 2017_ from your start menu. In the open prompt, navigate to the **_libecl_** source directory you created in step 1. Use the Python package manager **pip** to install **_libecl_** requirements via `pip install -r requirements.txt`. If Python is not accessible from the prompt it may be necessary to add the Python environment location to your system path variable `PATH`. + +5. Execute the build commands with the desired CMAKE parameters from `README.md`. The cmake generator can be _`NMake Makefiles`_ , _`Ninja`_ or an appropriate version of _`MSVC`_. For the availble options type `cmake -G` in the MSVC command prompt. + + An example build and install is provided below where %VARIABLE% are user defined directory paths: +~~~~ + cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX=%INSTALLPATH% -DBUILD_SHARED_LIBS="ON" -DENABLE_PYTHON="ON" -DCMAKE_BUILD_TYPE="Release" %SOURCEPATH% + cmake --build %BUILDPATH% --config Release --target install +~~~~ +6. For **_libecl_** to be accessible in Python the `%INSTALLPATH%\lib\pythonX.Y\site-package` and Python subdirectories must be added to the `PATH` and `PYTHONPATH` variables. Where `pythonx.y` is the current Python version _e.g._ (`python2.7`, `python3.6` _etc._) . + +8. Open a Python interactive session and run `import ecl` to check that the install and paths are now set. \ No newline at end of file diff --git a/Windows.txt b/Windows.txt deleted file mode 100644 index 7eda76b091..0000000000 --- a/Windows.txt +++ /dev/null @@ -1,90 +0,0 @@ -Preparations: -------------- - -1. Install the CMake build system from www.cmake.org - -2. Install the MinGW and MSYS packages from www.mingw.org - this a - collection of gnu tools built for windows. Observe that these tools - behave like they do on linux, but they are native windows - applications and the compilers produce native windows binaries, not - like Cygwin which is based on a portability layer. - - Make sure to install at least the C and Fortran compilers. - -3. Install lapack; download and install instructions can be found on - http://icl.cs.utk.edu/lapack-for-windows/ The text says that you - will need the Intel Fortran compiler, but the Fortran compiler from - MinGW works fine. The distribution contains a cmake CMakeLists.txt - file, and build with Cmake is easy altough time consuming. - - To make sure the system can find your libraries you should update - the windows PATH variable to include the location of your - libblas.dll and liblapack.dll files; if you fail to do this CMake - will fail to generate a valid set of makefiles for building libutil - and libecl. - - -Building libecl / libutil -------------------------- - -1. Go to the root directory of the ert distribution and create a - directory to hold the files created by the build - - e.g. 'tmp-build'. - -2. Open the cmake gui and give the path to the source (i.e. the root - of the ert distribution) and the path to the build directory. - -3. Press the [Configure] button and select the "MSys Makefiles" - option. Cmake will inspect your system and set build configuration - variables accordingly. Cmake will fail with a beep and large red - warnings. Scroll down to the variables: - - USE_LSF - USE_PTHREAD - USE_ZLIB - - and uncheck them. In addition you might want to modify some other - variables? Press the [Configure] button again, and then finally the - [Generate] button to create makefiles. - -4. Start up the MSys shell, go to the build directory, - e.g. 'tmp-build', and type: - - make ; make install - - :-) - - -Using from VisualStudio ------------------------ -The ERT code itself can unfortunately not be compiled with the -VisualStudio C++ compiler, however you can link against the ert -libraries. In that case you will need the dummy header file -VisualStudio/stdbool.h - - - -About the portabaility and features ------------------------------------ - -The libecl library is virtually unmodified for compiling on windows, -but the libutil library (in particular the util.c file) has quite many - - #ifdef HAVE_FEATUREXX - - #endif - -codeblocks. The symbols HAVE_FEATUREXX are defined during the CMake -configure process. The system inspection is linux centric in the sense -that the features it is checked for are mostly present/defined on -linux. If FEATUREXX is not present it is sometimes completely ignore, -e.g. pthreads, or a windows alternative is compiled in. In the case of -windows alternative it is just assumed that the feature in question is -present on the other (i.e. Windows) platform. - - - - - - - diff --git a/python/ecl/summary/ecl_sum.py b/python/ecl/summary/ecl_sum.py index a00c209d67..a0f851f835 100644 --- a/python/ecl/summary/ecl_sum.py +++ b/python/ecl/summary/ecl_sum.py @@ -26,6 +26,8 @@ import datetime import os.path import ctypes +import pandas +import re # Observe that there is some convention conflict with the C code # regarding order of arguments: The C code generally takes the time @@ -500,7 +502,6 @@ def pandas_frame(self, time_index = None, column_keys = None): .... """ from ecl.summary import EclSumKeyWordVector - import pandas if column_keys is None: keywords = EclSumKeyWordVector(self, add_keywords = True) else: @@ -524,6 +525,61 @@ def pandas_frame(self, time_index = None, column_keys = None): frame = pandas.DataFrame(index = time_index, columns=list(keywords), data=data) return frame + @staticmethod + def _compile_headers_list(headers, dims): + var_list = [] + for key in headers: + lst = re.split(':', key) + kw = lst[0] + wgname = None + num = 0; + unit = "UNIT" + if len(lst) > 1: + nums = [] + if lst[1][0].isdigit(): + nums = re.split(',', lst[1]) + else: + wgname = lst[1] + if len(lst) == 3: + nums = re.split(",", lst[2]) + if len(nums) == 3: + i = int(nums[0])-1 + j = int(nums[1])-1 + k = int(nums[2])-1 + if dims is None: + raise ValueError("For key %s When using indexing i,j,k you must supply a valid value for the dims argument" % key) + num = i + j * dims[0] + k * dims[0]*dims[1] + 1 + elif len(nums) == 1: + num = int(nums[0]) + + var_list.append( [kw, wgname, num, unit] ) + return var_list + + @classmethod + def from_pandas(cls, case, frame, dims = None, headers = None): + start_time = frame.index[0] + var_list = [] + if headers is None: + header_list = EclSum._compile_headers_list( frame.columns.values, dims ) + else: + header_list = EclSum._compile_headers_list( headers, dims ) + if dims is None: + dims = [1,1,1]; + ecl_sum = EclSum.writer(case, + start_time.to_pydatetime(), + dims[0], dims[1], dims[2]) + for kw, wgname, num, unit in header_list: + var_list.append( ecl_sum.addVariable( kw , wgname = wgname , num = num, unit =unit).getKey1() ) + + for i, time in enumerate(frame.index): + days = (time - start_time).days + t_step = ecl_sum.addTStep( i+1 , days ) + + for var in var_list: + t_step[var] = frame.iloc[i][var] + + return ecl_sum + def get_key_index(self, key): """ diff --git a/python/tests/ecl_tests/test_sum.py b/python/tests/ecl_tests/test_sum.py index 8394def5b7..4f2a28b85a 100644 --- a/python/tests/ecl_tests/test_sum.py +++ b/python/tests/ecl_tests/test_sum.py @@ -22,6 +22,8 @@ import shutil import cwrap import stat +import pandas +from pandas.testing import assert_frame_equal from contextlib import contextmanager from unittest import skipIf, skipUnless, skipIf @@ -78,6 +80,21 @@ def create_case(case = "CSV", restart_case = None, restart_step = -1, data_start restart_case = restart_case, restart_step = restart_step) +def create_case2(case = "CSV", restart_case = None, restart_step = -1, data_start = None): + length = 100 + return createEclSum(case , [("WOPT", "OPX" , 0, "SM3") , ("FOPR" , None , 0, "SM3/DAY"), ("BPR" , None , 10, "SM3"), ("RPR", None, 3, "BARS"), ("COPR", "OPX", 421, "BARS")], + sim_length_days = length, + num_report_step = 10, + num_mini_step = 10, + data_start = data_start, + func_table = {"FOPT" : fopt, + "FOPR" : fopr , + "FGPT" : fgpt }, + restart_case = restart_case, + restart_step = restart_step) + + + class SumTest(EclTest): @@ -549,6 +566,24 @@ def test_pandas(self): self.assertEqual(len(case), rows) + def test_csv_load(self): + case = create_case2() + frame = case.pandas_frame() + ecl_sum = EclSum.from_pandas("PANDAS", frame, dims=[20,10,5]) + + for key in frame.columns: + self.assertTrue(key in ecl_sum) + + df = ecl_sum.pandas_frame() + assert_frame_equal(frame, df) + + ecl_sum_less = EclSum.from_pandas("PANDAS", frame, dims=[20,10,5], headers=['BPR:10', 'RPR:3,1,1', 'COPR:OPX:1,2,3']) + del frame['WOPT:OPX'] + del frame['FOPR'] + df_less = ecl_sum_less.pandas_frame() + assert_frame_equal(frame, df_less) + + def test_total_and_rate(self): self.assertTrue( EclSum.is_total("FOPT")) self.assertTrue( EclSum.is_total("WWPT:OP_3"))