Repository: ansys/pydyna

Issue:
ansys.dyna.core.lib.deck.write fails writing keywords without fields
### 🔍 Before submitting the issue

- [x] I have searched among the existing issues
- [x] I am using a Python virtual environment

### 🐞 Description of the bug

There are keywords without fields e.g. *CONTROL_DEBUG. An error is raised when one tries to write a deck containing a keyword without fields. Function def _field_iterator is called even if there are no fields and it requires at least one field. 

     45 def _field_iterator(fields: typing.List[Field], long_format: bool) -> typing.Iterable[Field]:
---> 46     assert len(fields) > 0, "at least one field is needed"
     47     if fields[0].offset > 0:
     48         # insert a blank field in the beginning up to the offset
     49         blank_field = Field(name=None, type=None, offset=0, width=fields[0].offset)

AssertionError: at least one field is needed

### 📝 Steps to reproduce

```
from ansys.dyna.core.lib.deck import Deck
mydeck = Deck()
mystring = '*CONTROL_DEBUG'
mydeck.loads(mystring)
mydeck.write()
```

### 💻 Which operating system are you using?

Windows

### 📀 Which ANSYS version are you using?

..

### 🐍 Which Python version are you using?

3.12

### 📦 Installed packages

```shell
ansys-api-dyna==0.4.1
ansys-api-platform-instancemanagement==1.1.0
ansys-dpf-core==0.12.2
-e git+https://github.com/pyansys/pyDyna@11661b7119687e7d762847cff2d3d3643492dcf4#egg=ansys_dyna_core
ansys-platform-instancemanagement==1.1.2
ansys-tools-path==0.7.0
appdirs==1.4.4
asttokens==2.4.1
cachetools==5.5.0
certifi==2024.8.30
charset-normalizer==3.4.0
click==8.1.7
colorama==0.4.6
comm==0.2.2
contourpy==1.3.1
cycler==0.12.1
debugpy==1.8.8
decorator==5.1.1
executing==2.1.0
fonttools==4.54.1
google-api-core==2.23.0
google-api-python-client==2.152.0
google-auth==2.36.0
google-auth-httplib2==0.2.0
googleapis-common-protos==1.66.0
grpcio==1.67.1
hollerith==0.4.1
httplib2==0.22.0
idna==3.10
importlib_metadata==8.5.0
ipykernel==6.29.5
ipython==8.29.0
jedi==0.19.2
jupyter_client==8.6.3
jupyter_core==5.7.2
kiwisolver==1.4.7
matplotlib==3.9.2
matplotlib-inline==0.1.7
nest-asyncio==1.6.0
numpy==2.1.3
packaging==24.2
pandas==2.2.3
parso==0.8.4
pillow==11.0.0
platformdirs==4.3.6
pooch==1.8.2
prompt_toolkit==3.0.48
proto-plus==1.25.0
protobuf==5.28.3
psutil==6.1.0
pure_eval==0.2.3
pyasn1==0.6.1
pyasn1_modules==0.4.1
Pygments==2.18.0
pyparsing==3.2.0
python-dateutil==2.9.0.post0
pytz==2024.2
pyvista==0.44.1
pywin32==308
pyzmq==26.2.0
requests==2.32.3
rsa==4.9
scooby==0.10.0
setuptools==75.5.0
six==1.16.0
stack-data==0.6.3
tornado==6.4.1
tqdm==4.67.0
traitlets==5.14.3
typing_extensions==4.12.2
tzdata==2024.2
uritemplate==4.1.1
urllib3==2.2.3
vtk==9.3.1
wcwidth==0.2.13
zipp==3.21.0
```

Hints from issue comments:

Solution patch:
diff --git a/doc/changelog/643.fixed.md b/doc/changelog/643.fixed.md
new file mode 100644
index 00000000..ad380210
--- /dev/null
+++ b/doc/changelog/643.fixed.md
@@ -0,0 +1 @@
+fix: reading *CONTROL_DEBUG
\ No newline at end of file
diff --git a/src/ansys/dyna/core/lib/field_writer.py b/src/ansys/dyna/core/lib/field_writer.py
index c11048b8..f0b4a0fd 100644
--- a/src/ansys/dyna/core/lib/field_writer.py
+++ b/src/ansys/dyna/core/lib/field_writer.py
@@ -43,7 +43,8 @@ def _write_null(width):
 
 
 def _field_iterator(fields: typing.List[Field], long_format: bool) -> typing.Iterable[Field]:
-    assert len(fields) > 0, "at least one field is needed"
+    if len(fields) == 0:
+        return []
     if fields[0].offset > 0:
         # insert a blank field in the beginning up to the offset
         blank_field = Field(name=None, type=None, offset=0, width=fields[0].offset)


Test patch:
diff --git a/tests/test_deck.py b/tests/test_deck.py
index d715f49f..87263266 100644
--- a/tests/test_deck.py
+++ b/tests/test_deck.py
@@ -113,6 +113,14 @@ $#    ssid
     )
 
 
+@pytest.mark.keywords
+def test_control_debug():
+    from ansys.dyna.core.lib.deck import Deck
+    deck = Deck()
+    deck.loads('*CONTROL_DEBUG')
+    deck.write()
+
+
 @pytest.mark.keywords
 def test_deck_006(ref_string):
     """test adding two decks together"""