Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 115 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,100 +1,138 @@
## python-mvdxml

A mvdXML checker and w3c SPARQL converter, as an IfcOpenShell submodule or stand-alone.
An mvdXML parser, checker, and W3C SPARQL converter provided as an
IfcOpenShell submodule.

WARNING: While this repository has many useful building blocks to build software around mvdXML and IFC, there are many mvdXML dialects and not all variants are likely to be fully supported.
> [!WARNING]
> While this package has useful building blocks for mvdXML and IFC, there are
> many mvdXML dialects and not all variants are fully supported.

### Quickstart

#### Extraction
### Parsing

Parsed documents are immutable dataclasses. Templates and template references
are resolved while parsing, so repeated access returns the same parsed object.

```python
import ifcopenshell
from ifcopenshell.mvd import mvd
from ifcopenshell.mvd import parse

concept_roots = parse("mvd_examples/wall_extraction.mvdxml")
concept_root = concept_roots[0]

print(concept_root.name)
print(concept_root.entity)
print([concept.name for concept in concept_root.concepts()])
```

`parse()` returns a tuple of `concept_root` objects. A document containing only
concept templates returns a tuple of `template` objects instead. Invalid XML
and missing template references raise `ValueError` with the relevant document
or template identifier. Recursive template branches are expanded once.

mvd_concept = mvd.open_mvd("examples/wall_extraction.mvdxml")
file = ifcopenshell.open("Duplex_A_20110505.ifc")
### Graphviz concept templates

all_data = mvd.get_data(mvd_concept, file, spreadsheet_export=True)
The lightweight concept graphs used by the buildingSMART IFC4.x documentation
can be read directly into the same immutable `template` representation:

non_respecting_entities = mvd.get_non_respecting_entities(file, all_data[1])
respecting_entities = mvd.get_respecting_entities(file, all_data[1])
~~~python
from ifcopenshell.mvd import template

source = """
This prose is ignored.

```
concept {
IfcObject:ObjectType -> IfcLabel
IfcObject:ObjectType[binding="UserDefinedType"]
}
```
"""

parsed_template = template.from_graphviz(
source,
name="Object Predefined Type",
)
~~~

Only `concept {}` declarations inside triple-backtick fences are read; the
surrounding Markdown is not parsed. Edges, attribute bindings, constraint nodes,
and named template references follow the syntax used by buildingSMART's
`templates_to_mvdxml.py`. Referenced templates must already be parsed and
provided by name:

~~~python
parent = template.from_graphviz(
parent_source,
references={"Surface Color Style": surface_color_style},
)
~~~

Reference names are matched without spaces or underscores. Graph parsing uses
`networkx`, available through IfcOpenShell's `advanced` optional dependencies.

### Extraction

Extraction returns native Python containers and IFC values.

```python
# Create a new file
new_file = ifcopenshell.file(schema=file.schema)
proj = file.by_type("IfcProject")[0]
new_file.add(proj)
import ifcopenshell

from ifcopenshell.mvd import concept_root, parse

for e in respecting_entities:
new_file.add(e)
parsed = parse("mvd_examples/wall_extraction.mvdxml")
root = parsed[0]
assert isinstance(root, concept_root)
ifc_file = ifcopenshell.open("Duplex_A_20110505.ifc")

new_file.write("new_file.ifc")
all_data, verification = root.get_data(ifc_file)
non_respecting = root.get_non_respecting_entities(ifc_file, verification)
respecting = root.get_respecting_entities(ifc_file, verification)
```

The result is:

```python
# Visualize results
mvd.visualize(file, non_respecting_entities)
tuple[
list[dict[str, object]], # one GlobalId-to-value mapping per concept
dict[str, dict[str, int]], # GlobalId-to-concept verification matrix
]
```

##### Validation
Individual structures also expose their own behavior:

~~~py
import ifcopenshell
```python
concept = next(root.concepts())
parsed_template = concept.template()
entity = ifc_file.by_type(root.entity)[0]

from ifcopenshell.mvd import mvd
from colorama import Fore
from colorama import Style

concept_roots = list(ifcopenshell.mvd.concept_root.parse(MVDXML_FILENAME))
file = ifcopenshell.open(IFC_FILENAME)

tt = 0 # total number of tests
ts = 0 # total number of successful tests

for concept_root in concept_roots:
print("ConceptRoot: ", concept_root.entity)
for concept in concept_root.concepts():
tt = tt + 1
print("Concept: ", concept.name)
try:

if len(concept.template().rules) > 1:
attribute_rules = []
for rule in concept.template().rules:
attribute_rules.append(rule)
rules_root = ifcopenshell.mvd.rule("EntityRule", concept_root.entity, attribute_rules)
else:
rules_root = concept.template().rules[0]
ts = ts + 1
finst = 0 #failed instances

for inst in file.by_type(concept_root.entity):
try:
data = mvd.extract_data(rules_root, inst)
valid, output = mvd.validate_data(concept, data)
if not valid:
finst = finst + 1
print("[VALID]" if valid else Fore.RED +"[failure]"+Style.RESET_ALL, inst)
print(output)
except Exception as e:
print(Fore.RED+"EXCEPTION: ", e, Style.RESET_ALL,inst)
print ()
print (int(finst), "out of", int(len(file.by_type(concept_root.entity))), "instances failed the check")
print ("---------------------------------")
except Exception as e:
print("EXCEPTION: "+Fore.RED,e,Style.RESET_ALL)
print("---------------------------------")
print("---------------------------------")
print("---------------------------------")

tf = tt-ts # total number of failed tests

print ("\nRESULTS OVERVIEW")
print ("Total number of tests: ",tt)
print ("Total number of executed tests: ", ts)
print ("Total number of failed tests: ", tf)
~~~
extracted = parsed_template.extract(entity)
valid, report = concept.validate(extracted)
```

`extracted` is a list of dictionaries mapping immutable `rule` objects to IFC
values. `valid` is a boolean and `report` is a string; validation itself does
not print.

### Visualization and export

Visualization and spreadsheet generation are deliberately outside this
package. Use the returned GlobalIds to select or colour entities in the caller's
viewer. For CSV, JSON, dataframe, or spreadsheet output, transform `all_data`
and `verification` with the corresponding Python library. Keeping those
operations at the application boundary means importing this package does not
initialize a geometry backend or require a spreadsheet dependency.

### Command line

Inspect a document:

```console
python -m ifcopenshell.mvd mvd_examples/wall_extraction.mvdxml
```

Generate and execute SPARQL against an IFC-OWL Turtle file:

```console
python -m ifcopenshell.mvd model.mvdxml model.ttl
```

Use `python -m ifcopenshell.mvd --help` for argument details.
Loading