Closed Marco-Pellegrino closed 3 years ago
I'm not sure, off the top of my head, how to create the Coordinate class in IronPython, but perhaps it's doable using clrtype
. So I cheated in injected the class into the scope (alternatively you could import it from your DLL on the Python side).
using HDF5CSharp.DataTypes;
using IronPython.Hosting;
var engine = Python.CreateEngine();
var paths = engine.GetSearchPaths();
paths.Add(@"C:\Program Files\IronPython 2.7\Lib");
engine.SetSearchPaths(paths);
var scope = engine.CreateScope();
scope.SetVariable("Coordinate", typeof(Coordinate));
engine.ExecuteFile("test.py", scope);
public class Coordinate
{
[Hdf5EntryName("COORDINATES")] public double[,] COORDINATES { get; set; }
}
test.py:
import clr
clr.AddReference(r"HDF5CSharp")
from HDF5CSharp import Hdf5
fileId = 0
try:
fileId = Hdf5.OpenFile(r"recorder.hdf5", True)
result = Hdf5.ReadObject[Coordinate](fileId, "/MODEL_STAGE[1]/MODEL/NODES")
print(result.COORDINATES[0,0])
except:
if fileId > 0:
Hdf5.CloseFile(fileId)
thanks @slozier ! It is an interesting solution but I am not able to make it working. How can I run all the code in IronPython? I am a structural engineer who try to code but it seems a pretty advance topic to me :/
Ok, looks like the Hdf5EntryName
attribute is not necessary if the name of the property already matches, this simplifies things a bit:
import System
import clr
import clrtype
clr.AddReference(r"HDF5CSharp")
from HDF5CSharp import Hdf5
type_2d = type(System.Array.CreateInstance(float, 1, 1))
class Coordinate(object):
__metaclass__ = clrtype.ClrClass
@property
@clrtype.accepts()
@clrtype.returns(type_2d)
def COORDINATES(self): return self.__coords
@COORDINATES.setter
@clrtype.accepts(type_2d)
@clrtype.returns()
def COORDINATES(self, value): self.__coords = value
fileId = 0
try:
fileId = Hdf5.OpenFile(r"recorder.hdf5", True)
result = Hdf5.ReadObject[Coordinate](fileId, "/MODEL_STAGE[1]/MODEL/NODES")
print(result.COORDINATES[0,0])
finally:
if fileId > 0:
Hdf5.CloseFile(fileId)
@slozier Marvellous! It is really good stuff. I would never get close to this solution.
There is only a small issue with this approach. If we try to run the script twice time, we get an error.
Message: Duplicate type name within an assembly.
Traceback:
line 537, in __clrtype__, "C:\Program Files\Rhino 6\Plug-ins\IronPython\Lib\clrtype.py"
line 12, in <module>, "C:\Users\FORMAT\Desktop\hdf5Test\test.py"
do you have a solution for this? I can use my brute-force approach and change the name in order to have a different one every time I run the script.
Is there anyway to offer you a beer by paypal? I appreciate your help
You could extract the type definitions into a module, however that would require the module load path to be set up correctly. As an in-code workaround, you could check if the class is already defined:
import System import clr import clrtype
clr.AddReference(r"HDF5CSharp")
from HDF5CSharp import Hdf5
if "Coordinate" not in globals(): type_2d = type(System.Array.CreateInstance(float, 1, 1))
class Coordinate(object):
__metaclass__ = clrtype.ClrClass
@property
@clrtype.accepts()
@clrtype.returns(type_2d)
def COORDINATES(self): return self.__coords
@COORDINATES.setter
@clrtype.accepts(type_2d)
@clrtype.returns()
def COORDINATES(self, value): self.__coords = value
fileId = 0 try: fileId = Hdf5.OpenFile(r"recorder.hdf5", True) result = Hdf5.ReadObjectCoordinate print(result.COORDINATES[0,0]) finally: if fileId > 0: Hdf5.CloseFile(fileId)
Hi @thimolangbehn ! Thanks for your help but I am still getting the same error as per @slozier approach.
have you tested your script in your application?
I have no idea how Rhino uses IronPython, but assuming it's just reusing the same engine you could maybe stash it away in a module:
my_module_name = "some_unique_name" # replace this with something unique that doesn't collide with a real module!
my_module = sys.modules.setdefault(my_module_name, type(sys)(my_module_name))
try:
Coordinate = my_module.Coordinate
except AttributeError:
type_2d = type(System.Array.CreateInstance(float, 1, 1))
class Coordinate(object):
__metaclass__ = clrtype.ClrClass
@property
@clrtype.accepts()
@clrtype.returns(type_2d)
def COORDINATES(self): return self.__coords
@COORDINATES.setter
@clrtype.accepts(type_2d)
@clrtype.returns()
def COORDINATES(self, value): self.__coords = value
my_module.Coordinate = Coordinate
You could also put it in an existing module (like clrtype
).
@slozier , you are my hero! It is finally working and I should be able to read also the other "attributes" from the data base. Thanks you so much! You made me happy!
The tool that I am trying to use is called "Alpaca4d". The aim is to allow user to design for earthquake within a parametric environment. https://github.com/Alpaca4d/Alpaca
Hi @slozier , I wanted to give you a little update and show you what it has been possible with your help! I can finally read the coordinates and displacement from a HDF5 file and it looks great! Do you have any idea on how can I read different "attribute"? I would like to select a specific STEP_X as input.
the number of Step are different from each analyses. Do you have any idea or suggestion?
For example: n = number of step
result.STEP_n
result = Hdf5.ReadObject[Displacementss](fileId, "/MODEL_STAGE[1]/RESULTS/ON_NODES/DISPLACEMENT/DATA")
try:
for i in range(1000):
a.append( result.STEP_n[i,0])
b.append( result.STEP_n[i,1])
c.append( result.STEP_n[i,2])
Hdf5.CloseFile(fileId)
except:
pass
They have suggest me something like this but I am not sure that it can work with ItonPython
public class Steps
{
[Hdf5EntryName("STEP_0")] public double[,] STEP0 { get; set; }
[Hdf5EntryName("STEP_1")] public double[,] STEP1 { get; set; }
}
fileId = Hdf5.OpenFile(filename, true);
Assert.IsTrue(fileId > 0);
var step = "/MODEL_STAGE[1]/RESULTS/ON_NODES/DISPLACEMENT/DATA";
var result2 = Hdf5.ReadObject<
It seems you want to build attribute-names in code.
step_n = getattr(result, 'STEP_{}'.format(n))
Using this, the following examples are equivalent:
# manual:
a = []
a.append(result.STEP_0)
a.append(result.STEP_1)
a.append(result.STEP_2)
# in a loop:
a = []
for i in range(3):
step_i = getattr(result, 'STEP_{}'.format(i))
a.append(step_i)
This is common python, not an IronPython specific process,
It looks like HDF5CSharp
might work on fields too. Here's a simplification of my previous code:
try:
Coordinate = my_module.Coordinate
except AttributeError:
type_2d = type(System.Array.CreateInstance(float, 1, 1))
class Coordinate(object):
__metaclass__ = clrtype.ClrClass
_clrfields = {"COORDINATES": type_2d}
my_module.Coordinate = Coordinate
and then by extension, you could do:
try:
Steps = my_module.Steps
except AttributeError:
type_2d = type(System.Array.CreateInstance(float, 1, 1))
class Steps(object):
__metaclass__ = clrtype.ClrClass
_clrfields = {"STEP_{}".format(i): type_2d for i in range(100)} # change 100 to your max
my_module.Steps = Steps
@slozier @thimolangbehn you are rock stars! I should be able to extend your concept for also the other values (Forces, Stress, ect ect) I need to study a little bit what it is happening with clr, clrtype and what happen to the module with a unique name but I am happy.
I share my latest code and a .gif Thanks a lot!
import sys
import System
import clr
import clrtype
import Rhino.Geometry as rg
my_module_name = "aaa_one_other_unique_name" # replace this with something unique that doesn't collide with a real module!
my_module = sys.modules.setdefault(my_module_name, type(sys)(my_module_name))
clr.AddReferenceToFileAndPath(r"C:\Users\FORMAT\Desktop\hdf5Test\HDF5CSharp.dll")
from HDF5CSharp import Hdf5
try:
Steps = my_module.Steps
except AttributeError:
type_2d = type(System.Array.CreateInstance(float, 1, 1))
class Steps(object):
__metaclass__ = clrtype.ClrClass
_clrfields = {"STEP_{}".format(i): type_2d for i in range(1000)} # it will work for model with less than 1000 steps
my_module.Steps = Steps
fileId = Hdf5.OpenFile(r"C:\Users\FORMAT\Desktop\hdf5Test\recorder.hdf5", True)
numberOfPoints = 304 #
displacementResult = Hdf5.ReadObject[Steps](fileId, "/MODEL_STAGE[1]/RESULTS/ON_NODES/DISPLACEMENT/DATA")
displacement = []
for i in range(numberOfPoints):
x = getattr(displacementResult, 'STEP_{}'.format(step))[i,0]
y = getattr(displacementResult, 'STEP_{}'.format(step))[i,1]
z = getattr(displacementResult, 'STEP_{}'.format(step))[i,2]
displacement.append(rg.Vector3d(x,y,z))
rotationResult = Hdf5.ReadObject[Steps](fileId, "/MODEL_STAGE[1]/RESULTS/ON_NODES/ROTATION/DATA")
rotation = []
for i in range(numberOfPoints):
x = getattr(rotationResult, 'STEP_{}'.format(step))[i,0]
y = getattr(rotationResult, 'STEP_{}'.format(step))[i,1]
z = getattr(rotationResult, 'STEP_{}'.format(step))[i,2]
rotation.append(rg.Vector3d(x,y,z))
Hi guys, is anyone able to help translating this C# piece of code for IronPython? Is it even possible?
I am developing a .NET application that requires the use of Iron Python to read an HDF5 file format and I have found a piece of code written in C# that solve my problem. I have tried to translate the code in Iron Python but with no luck.
I attached a "recorder.hdf5" in case it is helpful. Download: https://drive.google.com/file/d/1SAKkZf0VGHRfbdPKabyiEPzpEXie4VzC/view?usp=sharing I am using the HDF5-CSharp library https://github.com/LiorBanai/HDF5-CSharp but I am struggling to find a solution.
Best, Marco