eulumdat-py 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eulumdat_py-0.1.0/LICENSE +21 -0
- eulumdat_py-0.1.0/PKG-INFO +185 -0
- eulumdat_py-0.1.0/README.md +138 -0
- eulumdat_py-0.1.0/eulumdat_py.egg-info/PKG-INFO +185 -0
- eulumdat_py-0.1.0/eulumdat_py.egg-info/SOURCES.txt +13 -0
- eulumdat_py-0.1.0/eulumdat_py.egg-info/dependency_links.txt +1 -0
- eulumdat_py-0.1.0/eulumdat_py.egg-info/requires.txt +3 -0
- eulumdat_py-0.1.0/eulumdat_py.egg-info/top_level.txt +1 -0
- eulumdat_py-0.1.0/pyldt/__init__.py +33 -0
- eulumdat_py-0.1.0/pyldt/model.py +83 -0
- eulumdat_py-0.1.0/pyldt/parser.py +252 -0
- eulumdat_py-0.1.0/pyldt/writer.py +247 -0
- eulumdat_py-0.1.0/pyproject.toml +38 -0
- eulumdat_py-0.1.0/setup.cfg +4 -0
- eulumdat_py-0.1.0/tests/test_parser.py +302 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 123VincentB
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: eulumdat-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python library for reading and writing EULUMDAT (.ldt) photometric files
|
|
5
|
+
Author: 123VincentB
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 123VincentB
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/123VincentB/pyldt
|
|
29
|
+
Project-URL: Repository, https://github.com/123VincentB/pyldt
|
|
30
|
+
Project-URL: Changelog, https://github.com/123VincentB/pyldt/blob/main/CHANGELOG.md
|
|
31
|
+
Keywords: photometry,eulumdat,ldt,lighting,luminaire,ies
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Intended Audience :: Science/Research
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
41
|
+
Requires-Python: >=3.9
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
License-File: LICENSE
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
# pyldt
|
|
49
|
+
|
|
50
|
+
A Python library for reading and writing **EULUMDAT** (`.ldt`) photometric files — the standard format for luminaire intensity distribution data used in lighting design and photometric testing.
|
|
51
|
+
|
|
52
|
+
Developed in an ISO 17025 accredited photometry laboratory.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
- Parse any valid EULUMDAT file into a clean Python object model
|
|
59
|
+
- Full symmetry expansion (ISYM 0–4) into a complete `[mc × ng]` intensity matrix
|
|
60
|
+
- Edit header fields (luminaire name, lamp data, photometric factors, geometry, …)
|
|
61
|
+
- Save back to a valid EULUMDAT file with correct ISO-8859-1 encoding
|
|
62
|
+
- Optional symmetry compression on write
|
|
63
|
+
- Safe file naming: auto-increments filename (`_1`, `_2`, …) if destination exists
|
|
64
|
+
- No dependencies beyond the Python standard library
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install pyldt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> Not yet published on PyPI. Clone the repository and install locally:
|
|
75
|
+
>
|
|
76
|
+
> ```bash
|
|
77
|
+
> git clone https://github.com/123VincentB/pyldt.git
|
|
78
|
+
> cd pyldt
|
|
79
|
+
> pip install -e .
|
|
80
|
+
> ```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quick start
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from pyldt import LdtReader, LdtWriter
|
|
88
|
+
|
|
89
|
+
# Read
|
|
90
|
+
ldt = LdtReader.read("luminaire.ldt")
|
|
91
|
+
print(ldt.header.luminaire_name)
|
|
92
|
+
print(f"I(C=0°, γ=0°) = {ldt.intensities[0][0]:.1f} cd/klm")
|
|
93
|
+
|
|
94
|
+
# Edit a header field
|
|
95
|
+
ldt.header.date_user = "2026-01-01 / modified"
|
|
96
|
+
|
|
97
|
+
# Save (adds _1 suffix if file already exists)
|
|
98
|
+
saved = LdtWriter.write(ldt, "luminaire_modified.ldt")
|
|
99
|
+
print(f"Saved to: {saved}")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Examples
|
|
105
|
+
|
|
106
|
+
| File | Description |
|
|
107
|
+
|------|-------------|
|
|
108
|
+
| [`examples/01_basic_usage.md`](examples/01_basic_usage.md) | Accessing header fields, lamp data and intensity values |
|
|
109
|
+
| [`examples/01_basic_usage.py`](examples/01_basic_usage.py) | Runnable script for the above |
|
|
110
|
+
| [`examples/02_polar_diagram.md`](examples/02_polar_diagram.md) | Plotting the polar intensity diagram (4 C-planes) |
|
|
111
|
+
| [`examples/02_polar_diagram.py`](examples/02_polar_diagram.py) | Runnable script for the above (requires matplotlib) |
|
|
112
|
+
|
|
113
|
+
Run any example from the repository root:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
python examples/01_basic_usage.py
|
|
117
|
+
python examples/02_polar_diagram.py
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Project structure
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
pyldt/
|
|
126
|
+
├── pyldt/
|
|
127
|
+
│ ├── __init__.py ← Public API
|
|
128
|
+
│ ├── model.py ← LdtHeader, Ldt dataclasses
|
|
129
|
+
│ ├── parser.py ← LdtReader
|
|
130
|
+
│ └── writer.py ← LdtWriter
|
|
131
|
+
├── examples/
|
|
132
|
+
│ ├── 01_basic_usage.md
|
|
133
|
+
│ ├── 01_basic_usage.py
|
|
134
|
+
│ ├── 02_polar_diagram.md
|
|
135
|
+
│ └── 02_polar_diagram.py
|
|
136
|
+
├── tests/
|
|
137
|
+
│ ├── test_parser.py
|
|
138
|
+
│ └── samples/ ← .ldt test files (10 real manufacturer files)
|
|
139
|
+
├── docs/
|
|
140
|
+
│ └── eulumdat_format.md
|
|
141
|
+
├── CHANGELOG.md
|
|
142
|
+
├── LICENSE
|
|
143
|
+
└── README.md
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## EULUMDAT format
|
|
149
|
+
|
|
150
|
+
EULUMDAT is the standard file format for luminaire photometric data, defined by the LiTG (Deutsche Lichttechnische Gesellschaft, 1990). It is widely used in Europe alongside IES files (North America).
|
|
151
|
+
|
|
152
|
+
Key concepts:
|
|
153
|
+
|
|
154
|
+
- **C-planes**: vertical planes through the luminaire vertical axis (azimuth, 0–360°)
|
|
155
|
+
- **γ-angles**: elevation angles within each C-plane (0° = nadir, 90° = horizontal, 180° = zenith)
|
|
156
|
+
- **ISYM**: symmetry code that allows the file to store only a subset of C-planes
|
|
157
|
+
- **Intensities**: tabulated in cd/klm (candela per kilolumen of lamp flux)
|
|
158
|
+
|
|
159
|
+
See [`docs/eulumdat_format.md`](docs/eulumdat_format.md) for a detailed field-by-field description.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Symmetry types (ISYM)
|
|
164
|
+
|
|
165
|
+
| ISYM | Description | C-planes stored |
|
|
166
|
+
|------|-------------|-----------------|
|
|
167
|
+
| 0 | No symmetry | All mc planes |
|
|
168
|
+
| 1 | Full rotational symmetry | 1 plane |
|
|
169
|
+
| 2 | Symmetry about C0–C180 | mc/2 + 1 planes |
|
|
170
|
+
| 3 | Symmetry about C90–C270 | mc/2 + 1 planes |
|
|
171
|
+
| 4 | Quadrant symmetry | mc/4 + 1 planes |
|
|
172
|
+
|
|
173
|
+
`LdtReader.read()` always returns a fully expanded matrix regardless of ISYM.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT — see [LICENSE](LICENSE).
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Context
|
|
184
|
+
|
|
185
|
+
This library was developed as a practical tool in the context of ISO 17025 accredited photometric testing. It is shared as open-source in the hope that it will be useful to others working with EULUMDAT files in Python.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# pyldt
|
|
2
|
+
|
|
3
|
+
A Python library for reading and writing **EULUMDAT** (`.ldt`) photometric files — the standard format for luminaire intensity distribution data used in lighting design and photometric testing.
|
|
4
|
+
|
|
5
|
+
Developed in an ISO 17025 accredited photometry laboratory.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Parse any valid EULUMDAT file into a clean Python object model
|
|
12
|
+
- Full symmetry expansion (ISYM 0–4) into a complete `[mc × ng]` intensity matrix
|
|
13
|
+
- Edit header fields (luminaire name, lamp data, photometric factors, geometry, …)
|
|
14
|
+
- Save back to a valid EULUMDAT file with correct ISO-8859-1 encoding
|
|
15
|
+
- Optional symmetry compression on write
|
|
16
|
+
- Safe file naming: auto-increments filename (`_1`, `_2`, …) if destination exists
|
|
17
|
+
- No dependencies beyond the Python standard library
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install pyldt
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> Not yet published on PyPI. Clone the repository and install locally:
|
|
28
|
+
>
|
|
29
|
+
> ```bash
|
|
30
|
+
> git clone https://github.com/123VincentB/pyldt.git
|
|
31
|
+
> cd pyldt
|
|
32
|
+
> pip install -e .
|
|
33
|
+
> ```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from pyldt import LdtReader, LdtWriter
|
|
41
|
+
|
|
42
|
+
# Read
|
|
43
|
+
ldt = LdtReader.read("luminaire.ldt")
|
|
44
|
+
print(ldt.header.luminaire_name)
|
|
45
|
+
print(f"I(C=0°, γ=0°) = {ldt.intensities[0][0]:.1f} cd/klm")
|
|
46
|
+
|
|
47
|
+
# Edit a header field
|
|
48
|
+
ldt.header.date_user = "2026-01-01 / modified"
|
|
49
|
+
|
|
50
|
+
# Save (adds _1 suffix if file already exists)
|
|
51
|
+
saved = LdtWriter.write(ldt, "luminaire_modified.ldt")
|
|
52
|
+
print(f"Saved to: {saved}")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Examples
|
|
58
|
+
|
|
59
|
+
| File | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| [`examples/01_basic_usage.md`](examples/01_basic_usage.md) | Accessing header fields, lamp data and intensity values |
|
|
62
|
+
| [`examples/01_basic_usage.py`](examples/01_basic_usage.py) | Runnable script for the above |
|
|
63
|
+
| [`examples/02_polar_diagram.md`](examples/02_polar_diagram.md) | Plotting the polar intensity diagram (4 C-planes) |
|
|
64
|
+
| [`examples/02_polar_diagram.py`](examples/02_polar_diagram.py) | Runnable script for the above (requires matplotlib) |
|
|
65
|
+
|
|
66
|
+
Run any example from the repository root:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
python examples/01_basic_usage.py
|
|
70
|
+
python examples/02_polar_diagram.py
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Project structure
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
pyldt/
|
|
79
|
+
├── pyldt/
|
|
80
|
+
│ ├── __init__.py ← Public API
|
|
81
|
+
│ ├── model.py ← LdtHeader, Ldt dataclasses
|
|
82
|
+
│ ├── parser.py ← LdtReader
|
|
83
|
+
│ └── writer.py ← LdtWriter
|
|
84
|
+
├── examples/
|
|
85
|
+
│ ├── 01_basic_usage.md
|
|
86
|
+
│ ├── 01_basic_usage.py
|
|
87
|
+
│ ├── 02_polar_diagram.md
|
|
88
|
+
│ └── 02_polar_diagram.py
|
|
89
|
+
├── tests/
|
|
90
|
+
│ ├── test_parser.py
|
|
91
|
+
│ └── samples/ ← .ldt test files (10 real manufacturer files)
|
|
92
|
+
├── docs/
|
|
93
|
+
│ └── eulumdat_format.md
|
|
94
|
+
├── CHANGELOG.md
|
|
95
|
+
├── LICENSE
|
|
96
|
+
└── README.md
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## EULUMDAT format
|
|
102
|
+
|
|
103
|
+
EULUMDAT is the standard file format for luminaire photometric data, defined by the LiTG (Deutsche Lichttechnische Gesellschaft, 1990). It is widely used in Europe alongside IES files (North America).
|
|
104
|
+
|
|
105
|
+
Key concepts:
|
|
106
|
+
|
|
107
|
+
- **C-planes**: vertical planes through the luminaire vertical axis (azimuth, 0–360°)
|
|
108
|
+
- **γ-angles**: elevation angles within each C-plane (0° = nadir, 90° = horizontal, 180° = zenith)
|
|
109
|
+
- **ISYM**: symmetry code that allows the file to store only a subset of C-planes
|
|
110
|
+
- **Intensities**: tabulated in cd/klm (candela per kilolumen of lamp flux)
|
|
111
|
+
|
|
112
|
+
See [`docs/eulumdat_format.md`](docs/eulumdat_format.md) for a detailed field-by-field description.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Symmetry types (ISYM)
|
|
117
|
+
|
|
118
|
+
| ISYM | Description | C-planes stored |
|
|
119
|
+
|------|-------------|-----------------|
|
|
120
|
+
| 0 | No symmetry | All mc planes |
|
|
121
|
+
| 1 | Full rotational symmetry | 1 plane |
|
|
122
|
+
| 2 | Symmetry about C0–C180 | mc/2 + 1 planes |
|
|
123
|
+
| 3 | Symmetry about C90–C270 | mc/2 + 1 planes |
|
|
124
|
+
| 4 | Quadrant symmetry | mc/4 + 1 planes |
|
|
125
|
+
|
|
126
|
+
`LdtReader.read()` always returns a fully expanded matrix regardless of ISYM.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT — see [LICENSE](LICENSE).
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Context
|
|
137
|
+
|
|
138
|
+
This library was developed as a practical tool in the context of ISO 17025 accredited photometric testing. It is shared as open-source in the hope that it will be useful to others working with EULUMDAT files in Python.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: eulumdat-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python library for reading and writing EULUMDAT (.ldt) photometric files
|
|
5
|
+
Author: 123VincentB
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 123VincentB
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/123VincentB/pyldt
|
|
29
|
+
Project-URL: Repository, https://github.com/123VincentB/pyldt
|
|
30
|
+
Project-URL: Changelog, https://github.com/123VincentB/pyldt/blob/main/CHANGELOG.md
|
|
31
|
+
Keywords: photometry,eulumdat,ldt,lighting,luminaire,ies
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Intended Audience :: Science/Research
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
41
|
+
Requires-Python: >=3.9
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
License-File: LICENSE
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
# pyldt
|
|
49
|
+
|
|
50
|
+
A Python library for reading and writing **EULUMDAT** (`.ldt`) photometric files — the standard format for luminaire intensity distribution data used in lighting design and photometric testing.
|
|
51
|
+
|
|
52
|
+
Developed in an ISO 17025 accredited photometry laboratory.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
- Parse any valid EULUMDAT file into a clean Python object model
|
|
59
|
+
- Full symmetry expansion (ISYM 0–4) into a complete `[mc × ng]` intensity matrix
|
|
60
|
+
- Edit header fields (luminaire name, lamp data, photometric factors, geometry, …)
|
|
61
|
+
- Save back to a valid EULUMDAT file with correct ISO-8859-1 encoding
|
|
62
|
+
- Optional symmetry compression on write
|
|
63
|
+
- Safe file naming: auto-increments filename (`_1`, `_2`, …) if destination exists
|
|
64
|
+
- No dependencies beyond the Python standard library
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install pyldt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> Not yet published on PyPI. Clone the repository and install locally:
|
|
75
|
+
>
|
|
76
|
+
> ```bash
|
|
77
|
+
> git clone https://github.com/123VincentB/pyldt.git
|
|
78
|
+
> cd pyldt
|
|
79
|
+
> pip install -e .
|
|
80
|
+
> ```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quick start
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from pyldt import LdtReader, LdtWriter
|
|
88
|
+
|
|
89
|
+
# Read
|
|
90
|
+
ldt = LdtReader.read("luminaire.ldt")
|
|
91
|
+
print(ldt.header.luminaire_name)
|
|
92
|
+
print(f"I(C=0°, γ=0°) = {ldt.intensities[0][0]:.1f} cd/klm")
|
|
93
|
+
|
|
94
|
+
# Edit a header field
|
|
95
|
+
ldt.header.date_user = "2026-01-01 / modified"
|
|
96
|
+
|
|
97
|
+
# Save (adds _1 suffix if file already exists)
|
|
98
|
+
saved = LdtWriter.write(ldt, "luminaire_modified.ldt")
|
|
99
|
+
print(f"Saved to: {saved}")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Examples
|
|
105
|
+
|
|
106
|
+
| File | Description |
|
|
107
|
+
|------|-------------|
|
|
108
|
+
| [`examples/01_basic_usage.md`](examples/01_basic_usage.md) | Accessing header fields, lamp data and intensity values |
|
|
109
|
+
| [`examples/01_basic_usage.py`](examples/01_basic_usage.py) | Runnable script for the above |
|
|
110
|
+
| [`examples/02_polar_diagram.md`](examples/02_polar_diagram.md) | Plotting the polar intensity diagram (4 C-planes) |
|
|
111
|
+
| [`examples/02_polar_diagram.py`](examples/02_polar_diagram.py) | Runnable script for the above (requires matplotlib) |
|
|
112
|
+
|
|
113
|
+
Run any example from the repository root:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
python examples/01_basic_usage.py
|
|
117
|
+
python examples/02_polar_diagram.py
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Project structure
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
pyldt/
|
|
126
|
+
├── pyldt/
|
|
127
|
+
│ ├── __init__.py ← Public API
|
|
128
|
+
│ ├── model.py ← LdtHeader, Ldt dataclasses
|
|
129
|
+
│ ├── parser.py ← LdtReader
|
|
130
|
+
│ └── writer.py ← LdtWriter
|
|
131
|
+
├── examples/
|
|
132
|
+
│ ├── 01_basic_usage.md
|
|
133
|
+
│ ├── 01_basic_usage.py
|
|
134
|
+
│ ├── 02_polar_diagram.md
|
|
135
|
+
│ └── 02_polar_diagram.py
|
|
136
|
+
├── tests/
|
|
137
|
+
│ ├── test_parser.py
|
|
138
|
+
│ └── samples/ ← .ldt test files (10 real manufacturer files)
|
|
139
|
+
├── docs/
|
|
140
|
+
│ └── eulumdat_format.md
|
|
141
|
+
├── CHANGELOG.md
|
|
142
|
+
├── LICENSE
|
|
143
|
+
└── README.md
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## EULUMDAT format
|
|
149
|
+
|
|
150
|
+
EULUMDAT is the standard file format for luminaire photometric data, defined by the LiTG (Deutsche Lichttechnische Gesellschaft, 1990). It is widely used in Europe alongside IES files (North America).
|
|
151
|
+
|
|
152
|
+
Key concepts:
|
|
153
|
+
|
|
154
|
+
- **C-planes**: vertical planes through the luminaire vertical axis (azimuth, 0–360°)
|
|
155
|
+
- **γ-angles**: elevation angles within each C-plane (0° = nadir, 90° = horizontal, 180° = zenith)
|
|
156
|
+
- **ISYM**: symmetry code that allows the file to store only a subset of C-planes
|
|
157
|
+
- **Intensities**: tabulated in cd/klm (candela per kilolumen of lamp flux)
|
|
158
|
+
|
|
159
|
+
See [`docs/eulumdat_format.md`](docs/eulumdat_format.md) for a detailed field-by-field description.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Symmetry types (ISYM)
|
|
164
|
+
|
|
165
|
+
| ISYM | Description | C-planes stored |
|
|
166
|
+
|------|-------------|-----------------|
|
|
167
|
+
| 0 | No symmetry | All mc planes |
|
|
168
|
+
| 1 | Full rotational symmetry | 1 plane |
|
|
169
|
+
| 2 | Symmetry about C0–C180 | mc/2 + 1 planes |
|
|
170
|
+
| 3 | Symmetry about C90–C270 | mc/2 + 1 planes |
|
|
171
|
+
| 4 | Quadrant symmetry | mc/4 + 1 planes |
|
|
172
|
+
|
|
173
|
+
`LdtReader.read()` always returns a fully expanded matrix regardless of ISYM.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT — see [LICENSE](LICENSE).
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Context
|
|
184
|
+
|
|
185
|
+
This library was developed as a practical tool in the context of ISO 17025 accredited photometric testing. It is shared as open-source in the hope that it will be useful to others working with EULUMDAT files in Python.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
eulumdat_py.egg-info/PKG-INFO
|
|
5
|
+
eulumdat_py.egg-info/SOURCES.txt
|
|
6
|
+
eulumdat_py.egg-info/dependency_links.txt
|
|
7
|
+
eulumdat_py.egg-info/requires.txt
|
|
8
|
+
eulumdat_py.egg-info/top_level.txt
|
|
9
|
+
pyldt/__init__.py
|
|
10
|
+
pyldt/model.py
|
|
11
|
+
pyldt/parser.py
|
|
12
|
+
pyldt/writer.py
|
|
13
|
+
tests/test_parser.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyldt
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyldt - Python library for reading and writing EULUMDAT (.ldt) photometric files.
|
|
3
|
+
|
|
4
|
+
Basic usage::
|
|
5
|
+
|
|
6
|
+
from pyldt import LdtReader, LdtWriter
|
|
7
|
+
|
|
8
|
+
# Read
|
|
9
|
+
ldt = LdtReader.read("luminaire.ldt")
|
|
10
|
+
print(ldt.header.luminaire_name)
|
|
11
|
+
print(ldt.intensities[0][0]) # cd/klm at C=0°, γ=0°
|
|
12
|
+
|
|
13
|
+
# Edit
|
|
14
|
+
ldt.header.luminaire_name = "Modified"
|
|
15
|
+
|
|
16
|
+
# Save
|
|
17
|
+
LdtWriter.write(ldt, "output.ldt")
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .model import Ldt, LdtHeader
|
|
21
|
+
from .parser import LdtReader
|
|
22
|
+
from .writer import LdtWriter
|
|
23
|
+
|
|
24
|
+
__version__ = "0.1.0"
|
|
25
|
+
__author__ = "123VincentB"
|
|
26
|
+
__license__ = "MIT"
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"Ldt",
|
|
30
|
+
"LdtHeader",
|
|
31
|
+
"LdtReader",
|
|
32
|
+
"LdtWriter",
|
|
33
|
+
]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data model for EULUMDAT (.ldt) photometric files.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class LdtHeader:
|
|
13
|
+
"""
|
|
14
|
+
EULUMDAT file header (lines 1-42 + direct ratios + angles).
|
|
15
|
+
|
|
16
|
+
References:
|
|
17
|
+
EULUMDAT Format Description, LiTG (Deutsche Lichttechnische Gesellschaft), 1990.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# Lines 1-12 : Identification
|
|
21
|
+
company: str = ""
|
|
22
|
+
ityp: int = 0 # Luminaire type (0=point, 1=linear, 2=area)
|
|
23
|
+
isym: int = 0 # Symmetry (0=none, 1=full, 2=C0-C180, 3=C90-C270, 4=quadrant)
|
|
24
|
+
mc: int = 0 # Number of C-planes
|
|
25
|
+
dc: float = 0.0 # Angular step between C-planes (degrees)
|
|
26
|
+
ng: int = 0 # Number of gamma angles per C-plane
|
|
27
|
+
dg: float = 0.0 # Angular step between gamma angles (degrees)
|
|
28
|
+
report_number: str = ""
|
|
29
|
+
luminaire_name: str = ""
|
|
30
|
+
luminaire_number: str = ""
|
|
31
|
+
file_name: str = ""
|
|
32
|
+
date_user: str = ""
|
|
33
|
+
|
|
34
|
+
# Lines 13-22 : Geometry (mm)
|
|
35
|
+
length: float = 0.0
|
|
36
|
+
width: float = 0.0
|
|
37
|
+
height: float = 0.0
|
|
38
|
+
length_lum_area: float = 0.0
|
|
39
|
+
width_lum_area: float = 0.0
|
|
40
|
+
h_lum_c0: float = 0.0
|
|
41
|
+
h_lum_c90: float = 0.0
|
|
42
|
+
h_lum_c180: float = 0.0
|
|
43
|
+
h_lum_c270: float = 0.0
|
|
44
|
+
|
|
45
|
+
# Lines 23-26 : Photometric factors
|
|
46
|
+
dff: float = 0.0 # Downward flux fraction (%)
|
|
47
|
+
lorl: float = 0.0 # Light output ratio luminaire (%)
|
|
48
|
+
conv_factor: float = 1.0
|
|
49
|
+
tilt: float = 0.0
|
|
50
|
+
|
|
51
|
+
# Line 26 : Number of lamp sets
|
|
52
|
+
n_sets: int = 0
|
|
53
|
+
|
|
54
|
+
# Lines 26a-26f : Lamp data (one entry per set)
|
|
55
|
+
num_lamps: List[int] = field(default_factory=list)
|
|
56
|
+
lamp_types: List[str] = field(default_factory=list)
|
|
57
|
+
lamp_flux: List[float] = field(default_factory=list)
|
|
58
|
+
lamp_cct: List[str] = field(default_factory=list)
|
|
59
|
+
lamp_cri: List[str] = field(default_factory=list)
|
|
60
|
+
lamp_watt: List[float] = field(default_factory=list)
|
|
61
|
+
|
|
62
|
+
# Direct ratios (10 values, lines after lamp data)
|
|
63
|
+
direct_ratios: List[float] = field(default_factory=list)
|
|
64
|
+
|
|
65
|
+
# Angular grids
|
|
66
|
+
c_angles: List[float] = field(default_factory=list)
|
|
67
|
+
g_angles: List[float] = field(default_factory=list)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class Ldt:
|
|
72
|
+
"""
|
|
73
|
+
Complete EULUMDAT file representation.
|
|
74
|
+
|
|
75
|
+
Attributes:
|
|
76
|
+
header: Parsed header with all metadata and lamp data.
|
|
77
|
+
intensities: Full intensity matrix [mc x ng], in cd/klm.
|
|
78
|
+
Always expanded to the full angular range regardless of file symmetry.
|
|
79
|
+
filepath: Source file path (None if not loaded from disk).
|
|
80
|
+
"""
|
|
81
|
+
header: LdtHeader
|
|
82
|
+
intensities: List[List[float]]
|
|
83
|
+
filepath: Optional[Path] = None
|