3

I want to implement a simplified version of what I have suggested here to import some vertices from an OpenFOAM blockMeshDict file and then visualize them with FreeCAD.

the part of the file I'm interested in is a list of tuples (xi yi zi)s of floats, between parentheses after the vertices keyword. the file looks like this:

vertices
(
    (1 2 3)
    (3 4 5)
    ...
)

I'm able to read the file from the same folder as the python script with:

import os
os.chdir(os.path.dirname(__file__))
with open("blockMeshDict", "r") as f:
    s=f.read()

But then when I try to extract the content between the parentheses after the vertices with:

import re
r1=re.search(r'vertices\n\((.*?)\)', s)
print r1.group(1)

I get the error:

type 'exceptions.IndexError: no such group

and I don't know how to solve it. What I want to have in the end is a list of tuples like [(x1,y1,z1),(x2,y2,z2)...] I would appreciate it if you could help me know how I can implement this in Python 2.7.

P.S. A summary of this effort can be found in this GitHub Gist

Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193

3 Answers3

1

This will be the main regex to find the outter structure: \bvertices\s*\((\s*(?:\([^)]+\)\s*)+)\)

Before that, we will remove all the comments.

And then an extra regex to extract all content inside the vertices structure: \([^)]+\)

See demo here.

The code:

import re

test_str = """
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  5                                     |
|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

convertToMeters 0.001;

vertices
(
    (-20.6 0 -0.5)
    (-20.6 25.4 -0.5)  /* Some comment */
    (0 -25.4 -0.5)
    (0 0 -0.5)
    (0 25.4 -0.5)
    (206 -25.4 -0.5)
    (206 0 -0.5)
    (206 25.4 -0.5)
    (290 -16.6 -0.5)
    (290 0 -0.5)
    (290 16.6 -0.5)

    (-20.6 0 0.5)
    (-20.6 25.4 0.5)
    (0 -25.4 0.5)
    (0 0 0.5)
    (0 25.4 0.5)
    (206 -25.4 0.5)
    (206 0 0.5)
    (206 25.4 0.5)
    (290 -16.6 0.5)
    (290 0 0.5)
    (290 16.6 0.5)
  /*(1 2 3 4)*/ // Commented tuple
  //(1 2 3 4)
);

/* vertices commented
vertices
(
    (-20.6 0 -0.5)
    (-20.6 25.4 -0.5)
    (0 -25.4 -0.5)
    (0 0 -0.5)
    (0 25.4 -0.5)
    (206 -25.4 -0.5)
    (206 0 -0.5)
    (206 25.4 -0.5)
    (290 -16.6 -0.5)
    (290 0 -0.5)
    (290 16.6 -0.5)
)
*/

negY
(
    (2 4 1)
    (1 3 0.3)
);

posY
(
    (1 4 2)
    (2 3 4)
    (2 4 0.25)
);

posYR
(
    (2 1 1)
    (1 1 0.25)
);


blocks
(
    hex (0 3 4 1 11 14 15 12)
    (18 30 1)
    simpleGrading (0.5 $posY 1)

    hex (2 5 6 3 13 16 17 14)
    (180 27 1)
    edgeGrading (4 4 4 4 $negY 1 1 $negY 1 1 1 1)

    hex (3 6 7 4 14 17 18 15)
    (180 30 1)
    edgeGrading (4 4 4 4 $posY $posYR $posYR $posY 1 1 1 1)

    hex (5 8 9 6 16 19 20 17)
    (25 27 1)
    simpleGrading (2.5 1 1)

    hex (6 9 10 7 17 20 21 18)
    (25 30 1)
    simpleGrading (2.5 $posYR 1)
);

edges
(
);

boundary
(
    inlet
    {
        type patch;
        faces
        (
            (0 1 12 11)
        );
    }
    outlet
    {
        type patch;
        faces
        (
            (8 9 20 19)
            (9 10 21 20)
        );
    }
    upperWall
    {
        type wall;
        faces
        (
            (1 4 15 12)
            (4 7 18 15)
            (7 10 21 18)
        );
    }
    lowerWall
    {
        type wall;
        faces
        (
            (0 3 14 11)
            (3 2 13 14)
            (2 5 16 13)
            (5 8 19 16)
        );
    }
    frontAndBack
    {
        type empty;
        faces
        (
            (0 3 4 1)
            (2 5 6 3)
            (3 6 7 4)
            (5 8 9 6)
            (6 9 10 7)
            (11 14 15 12)
            (13 16 17 14)
            (14 17 18 15)
            (16 19 20 17)
            (17 20 21 18)
        );
    }
);
// ************************************************************************* //
"""

# Clean comments:
test_str = re.sub(r"//.*", '', test_str)
test_str = re.sub(r"/\*.*?\*/", '', test_str, 0, re.DOTALL)

# Match main group
matches = re.findall(r"\bvertices\s*\((\s*(?:\([^)]+\)\s*)+)\)", test_str, re.MULTILINE | re.DOTALL)

# Fetch tuples
matches2 = re.findall(r"\([^)]+\)", matches[0], re.MULTILINE | re.DOTALL)
print matches2

Explained:

\b        # word boundary
vertices  # literal 'vertices'
\s*       # 0 or more spaces (includes line feed/carriage return)
\(        # literal '('
  (       # First capturing group
    \s*   # Som spaces
    (?:   # Group
       \([^)]+\)   # literal '(' + any non-')' character 1 or more times + literal ')'
       \s*         # extra spaces
    )+    # repeated one or more times
  )
\)        # literal ')'

Then you get that captured group and search for \([^)]+\). That will find instances of vertices.

Julio
  • 5,208
  • 1
  • 13
  • 42
  • awesome. this works fine. the output is now a list of strings. how can you turn it into tuples? `(1 2 3 )` --> `(1, 2, 3)` – Foad S. Farimani Aug 22 '18 at 12:23
  • I edited the post, there are no `,`s between the numbers. just spaces. but your code works perfectly fine! – Foad S. Farimani Aug 22 '18 at 12:29
  • 1
    @Foad I changed my answer to allow comments. Also I tested it with the example file (plus extra comments). Please, note that the accepted answer will fail with the example file. See: https://ideone.com/9FzKVY this is because it matches tuples from other sections like `negY`, `posY`, `posYR` and `blocks`. If you are not supposed to match those, you may use this solution instead. – Julio Aug 22 '18 at 15:18
  • I just saw your edit. I will try it and come back here. – Foad S. Farimani Aug 22 '18 at 15:18
  • I was wondering if I could invite you to help us continue this? – Foad S. Farimani Aug 22 '18 at 21:07
  • 1
    Hi, how do you want to go on? Did you try with my last edit? Is there something missing? – Julio Aug 22 '18 at 21:14
  • Yes we indeed want to continue this to make a nice import package for FreeCAD. you may see it over [here](https://forum.freecadweb.org/viewtopic.php?f=37&t=30426&start=10#p251946). I haven't integrated your edits yet, but I will. – Foad S. Farimani Aug 22 '18 at 21:25
  • 1
    Oh, glad to hear that code from this question will be added to such a big opensource project. If you need something, just tell me – Julio Aug 22 '18 at 22:18
  • I will tell here the next steps if you don't mind: read the 8 integers inside the `()` after all `hex` keywords. put 4 points as a tuple `p1 , p2, p3 ,p4` so every hex ends up as two faces. `hex (1 2 3 4 5 6 7 8)` --> `[(1,2,3,4),(5,6,7,8)]` – Foad S. Farimani Aug 22 '18 at 22:31
1
vertices
(
    (1 2 3)
    (3 4 5)
    ...
)

add a re.DOTALL as in

r1 = re.search(r'(?:vertices\s+)?(\([\w\s]+\))', s, re.DOTALL)
print r1.group(1)

>>> (1 2 3)

you may need to use re.findall if you want all results stored as a list as in

r1 = re.findall(r'(?:vertices\s+)?(\([\w\s]+\))', s, re.DOTALL)
print r1

>>> ['(1 2 3)', '(3 4 5)']
Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193
tushortz
  • 3,697
  • 2
  • 18
  • 31
  • First regex does not seem to work. See here: https://regex101.com/r/VbE8RY/2/. Second regex could match things like `foobar ((1,2,3)(3))` instead of just `vertices ((1,2,3)(3))`. See: https://regex101.com/r/VbE8RY/3. Not sure if that could be a problem for OP, although – Julio Aug 22 '18 at 12:18
  • @Julio that is not the format OP is asking for. OP question is relating to tuples separated by a `,` hence the answer is still valid – tushortz Aug 22 '18 at 12:24
  • @Tushortz my mistake. the format in the file has no `,`. edited the post. my apologies. – Foad S. Farimani Aug 22 '18 at 12:27
  • there are only spaces between the numbers – Foad S. Farimani Aug 22 '18 at 12:31
  • 1
    well, he said: *"I'm interested in is a list of tuples (xi yi zi)s of floats, between parentheses **after the vertices keyword**"* Anyways if there are no other possible keywords different than "vertices" on the file, then It is not necessary to check the vertices keyword anyways – Julio Aug 22 '18 at 14:21
1

My test data file blockMeshDict:

vertices // comment 1
(
          (1 2 3) // comment 2
/* :) */  (3 4 5) /* multi line...
...comment */

          (65.71 72.8 2.0)
)

Code:

import re

with open("blockMeshDict", "r") as f:
    s=f.read()

# Remove comments like "//" until end of line
s = re.sub(r'//.*', '', s)

# Remove comments between /* and */
s = re.sub(r'/\*(.|\s)*?\*/', '', s, re.DOTALL)

r1 = re.search(r'vertices\s*\(\s*(.*)\s*\)', s, re.DOTALL)
vertices = [(float(v[0]),float(v[1]),float(v[2]))
        for v in re.findall(r'\(\s*([-0-9.]+)\s+([-0-9.]+)\s+([-0-9.]+)\s*\)', r1.group(1))]

print(vertices)

Output is the list of tuples (of float's):

[(1.0, 2.0, 3.0), (3.0, 4.0, 5.0), (65.71, 72.8, 2.0)]
Hkoof
  • 756
  • 5
  • 14