-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #65 from DHI/feature/mikenet
Initial implementation of the MIKE.NET module
- Loading branch information
Showing
7 changed files
with
280 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
""" | ||
MIKE.NET: Module for loading MIKE software .NET libraries | ||
========================================================= | ||
MIKE.NET is a module which creates helper methods for loading and referencing | ||
MIKE software .NET libraries. To use the module on an existing MIKE installation | ||
one needs before loading MIKE IO 1D to define `MIKE_INSTALL_PATH` environment | ||
variable which points to desired installation: | ||
```python | ||
>>> import os | ||
>>> os.environ["MIKE_INSTALL_PATH"] = "C:/Program File (x86)/DHI/MIKE+/2023/" | ||
``` | ||
If this variable is not defined the MIKE IO 1D bin folder will be used per | ||
default. This MIKE IO 1D bin folder contains very small subset of MIKE software | ||
libraries. | ||
Usage example | ||
------------- | ||
MIKE.NET can be imported as: | ||
```python | ||
>>> from mikeio1d import mikenet | ||
``` | ||
When used within Jupyter `mikenet` has a list of methods starting with `load_` | ||
which can load the relevant MIKE software libraries. For example, we can load a | ||
`DHI.Mike1D.Generic` library as: | ||
```python | ||
>>> mikenet.load_Mike1D_Generic() | ||
``` | ||
This makes a `Mike1D_Generic` reference to the `DHI.Mike1D.Generic`, which also | ||
can be auto-completed in Jupyter. As an example, now we can create an instance | ||
of `Quantity` class as: | ||
```python | ||
>>> quantity = mikenet.Mike1D_Generic.Quantity() | ||
``` | ||
To load all MIKE software libraries one can use: | ||
```python | ||
>>> mikenet.load_all() | ||
``` | ||
""" | ||
|
||
import sys | ||
|
||
from .library_loaders import LibraryLoaders | ||
|
||
mikenet_module = sys.modules[__name__] | ||
library_loaders = LibraryLoaders(mikenet_module) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import clr | ||
from pathlib import Path | ||
from warnings import warn | ||
|
||
|
||
class LibraryLoader: | ||
""" | ||
Helper class which assigns 'load_[LIRABRY_NAME]' to MIKE.NET module. | ||
Parameters | ||
---------- | ||
file_name: str | ||
Library file_name to load. Typically this is a full path to the library (dll). | ||
mikenet_module: module | ||
Reference to MIKET.NET module | ||
""" | ||
|
||
def __init__(self, file_name, mikenet_module): | ||
self.file_name = file_name | ||
self.mikenet_module = mikenet_module | ||
|
||
self.file_path = Path(file_name) | ||
self.library_name = self.file_path.stem | ||
self.library_alias = self.library_name.replace("DHI.", "") | ||
self.library_alias = self.library_alias.replace(".", "_") | ||
|
||
load_function_name = "load_" + self.library_alias | ||
|
||
setattr(mikenet_module, load_function_name, self.load) | ||
|
||
def load(self): | ||
""" | ||
A method which adds a reference of a relevant library to Python.NET (CLR) | ||
and also adds a reference to the MIKE.NET. | ||
""" | ||
clr.AddReference(self.library_name) | ||
|
||
try: | ||
mikenet_dict = self.mikenet_module.__dict__ | ||
exec(f"import {self.library_name} as {self.library_alias}", mikenet_dict) | ||
except Exception as e: | ||
warn(f"Could not import .NET library {self.library_name}: {e}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import os | ||
import sys | ||
from glob import glob | ||
|
||
from ..mikepath import MikePath | ||
|
||
from .library_loader import LibraryLoader | ||
|
||
|
||
class LibraryLoaders: | ||
""" | ||
Helper class which finds all MIKE software .NET libraries | ||
and assigns references to those libraries in MIKE.NET module. | ||
Parameters | ||
---------- | ||
mikenet_module: module | ||
Reference to MIKE.NET module | ||
""" | ||
|
||
def __init__(self, mikenet_module): | ||
self.mikenet_module = mikenet_module | ||
self.library_loader_list = [] | ||
self.library_loader_dict = {} | ||
|
||
MikePath.setup_mike_installation(sys.path) | ||
self.create_loaders() | ||
|
||
def create_loaders(self): | ||
""" | ||
Creates .NET library loaders and assigns relevant `load` methods | ||
to MIKE.NET module. | ||
""" | ||
mikenet_module = self.mikenet_module | ||
|
||
for pattern in MikePath.library_patterns: | ||
file_candidates = glob(os.path.join(MikePath.mike_bin_path, pattern)) | ||
for file_name in file_candidates: | ||
library_loader = LibraryLoader(file_name, mikenet_module) | ||
self.library_loader_list.append(library_loader) | ||
self.library_loader_dict[library_loader.library_name] = library_loader | ||
self.library_loader_dict[library_loader.library_alias] = library_loader | ||
|
||
setattr(mikenet_module, "load_all", self.load_all) | ||
setattr(mikenet_module, "load", self.load) | ||
|
||
def load_all(self): | ||
""" | ||
Loads all libraries present in library_loader_list. | ||
""" | ||
for library_loader in self.library_loader_list: | ||
library_loader.load() | ||
|
||
def load(self, libraries=[]): | ||
""" | ||
Loads all libraries specified by the list `libraries`. | ||
Parameters | ||
---------- | ||
libraries: list of str | ||
List of strings specifying what .NET libraries to load. | ||
This can also be set as a string having the name of the | ||
library to load. | ||
""" | ||
if isinstance(libraries, str): | ||
libraries = [libraries] | ||
|
||
for library in libraries: | ||
self.library_loader_dict[library].load() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import os | ||
|
||
|
||
class MikePath: | ||
""" | ||
Class for handling MIKE binary paths. | ||
Attributes | ||
---------- | ||
mikeio1d_bin_path: string | ||
Path to binaries contained in MIKE IO 1D Python package. | ||
mike_install_path: string | ||
Environment variable MIKE_INSTALL_PATH specifying location of MIKE installation. | ||
skip_bin_x64: string | ||
Environment variable specifying not to append 'bin/x64' for binary location. | ||
bin_x64: string | ||
String which will be appended to mike_install_path for full location of binaries. | ||
mike_bin_path: string | ||
Actual path for MIKE binaries, which is either mikeio1d_bin_path or mike_install_path/bin/x64. | ||
""" | ||
|
||
mikeio1d_bin_path = os.path.join(os.path.dirname(__file__), "bin") | ||
|
||
mike_install_path = os.environ.get("MIKE_INSTALL_PATH", None) | ||
|
||
skip_bin_x64 = os.environ.get("MIKE_SKIP_BIN_X64", None) | ||
bin_x64 = os.path.join("bin", "x64") if skip_bin_x64 is None else "" | ||
|
||
mike_bin_path = ( | ||
os.path.join(mike_install_path, bin_x64) | ||
if mike_install_path is not None | ||
else mikeio1d_bin_path | ||
) | ||
|
||
library_patterns = ["DHI.*.dll"] | ||
|
||
@staticmethod | ||
def setup_mike_installation(syspath): | ||
""" | ||
Adds MIKE installation bin path and MIKE IO 1D bin path to the | ||
given PATH variable. | ||
Parameters | ||
---------- | ||
syspath: list of str | ||
List of strings defining PATH variable. | ||
""" | ||
mike_bin_path = MikePath.mike_bin_path | ||
mikeio1d_bin_path = MikePath.mikeio1d_bin_path | ||
mike_install_path = MikePath.mike_install_path | ||
|
||
syspath.append(mike_bin_path) | ||
if mikeio1d_bin_path != mike_bin_path: | ||
syspath.append(mikeio1d_bin_path) | ||
|
||
# Some of the MIKE libraries will need to be resolved by DHI.Mike.Install, | ||
# so set it up here. | ||
import clr | ||
|
||
clr.AddReference( | ||
"DHI.Mike.Install, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c513450b5d0bf0bf" | ||
) | ||
from DHI.Mike.Install import MikeImport | ||
|
||
MikeImport.SetupInstallDir(mike_install_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from mikeio1d import mikenet | ||
|
||
|
||
def test_load_mike1d_generic(): | ||
mikenet.load_Mike1D_Generic() | ||
quantity = mikenet.Mike1D_Generic.Quantity() | ||
|
||
|
||
def test_load_projections(): | ||
mikenet.load("DHI.Projections") | ||
map_projection = mikenet.Projections.MapProjection( | ||
'PROJCS["UTM-33",GEOGCS["Unused",DATUM["UTM Projections",SPHEROID["WGS 1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000],PARAMETER["False_Northing",0],PARAMETER["Central_Meridian",15],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0],UNIT["Meter",1]]' | ||
) | ||
|
||
|
||
def test_load_all(): | ||
mikenet.load_all() | ||
result_data = mikenet.PFS.PFSBuilder() | ||
|
||
|
||
def test_libraries_loaded_to_clr(): | ||
# Libraries already loaded to CLR by mikeio1d.__init__.py | ||
import System | ||
import System.Runtime | ||
import System.Runtime.InteropServices | ||
import DHI.Generic.MikeZero.DFS | ||
import DHI.Generic.MikeZero | ||
import DHI.Mike1D.Generic | ||
import DHI.Mike1D.ResultDataAccess | ||
import DHI.Mike1D.CrossSectionModule | ||
import DHI.Mike1D.MikeIO | ||
|
||
# Libraries loaded inside test_mikenet.py | ||
import DHI.PFS | ||
import DHI.Projections |