Reading CDB Values with Python

Hi!

I’m new to reading values out of the CDB using python, so I have what might be a simple question.

In the following code, I’m trying to read out the quad numbers, their respective nodes, and their group numbers. There doesn’t seem to be a record under CQUAD for group number, so my plan was to simply determine the group numbers by dividing the quad element numbers by the group divisor. To do this I also need to get the group divisor from the database, which I found under CSYST. The problem I’m having is that my code is returning two group divisors, so I’m curious what I’m doing wrong. I’m pretty sure it’s just outputting a duplicate of the group divisor, so I must have an indexing problem.

Any help on this would be greatly appreciated.

Thanks,

Grant

# import all types from sofistik_daten.py, original file can be found by following
# --> examples/python/sofistik_daten.py

sofistikFolderPath = r"C:\Program Files\SOFiSTiK\2024\SOFiSTiK 2024\"
CDBFilePath = r"C:\Users\PC01\Desktop\Local_Copy\V1_Balcony.cdb"

import sys
sys.path.append(sofistikFolderPath + r"interfaces\examples\python")
from sofistik_daten import *
import os  # for the environment variable necessary
import platform  # checks the python platform
import string
from ctypes import *  # read the functions from the cdb

# This example has been tested with Python 3.7 (64-bit)
print("The path variable=", os.environ["Path"])

# Check the python platform (32bit or 64bit)
print("Python architecture=", platform.architecture())
sofPlatform = str(platform.architecture())

# Get the DLL (32bit or 64bit DLL)
if sofPlatform.find("32Bit") < 0:
    # Set environment variable for the DLL files
    print("Hint: 64bit DLLs are used")

    # Set DLL dir path - new in PY 3.8 for ctypes
    # See: https://docs.python.org/3/whatsnew/3.8.html#ctypes
    os.add_dll_directory(sofistikFolderPath + r"interfaces\64bit")
    os.add_dll_directory(sofistikFolderPath[:-1])

    # Get the DLL functions
    myDLL = cdll.LoadLibrary("sof_cdb_w-2024.dll")
    py_sof_cdb_get = cdll.LoadLibrary("sof_cdb_w-2024.dll").sof_cdb_get
    py_sof_cdb_get.restype = c_int

    py_sof_cdb_kenq = cdll.LoadLibrary("sof_cdb_w-2024.dll").sof_cdb_kenq_ex
else:
    # Set environment variable for the dll files
    print("Hint: 32bit DLLs are used")

    # Set DLL dir path - new in PY 3.8 for ctypes
    # See: https://docs.python.org/3/whatsnew/3.8.html#ctypes
    os.add_dll_directory(sofistikFolderPath + r"interfaces\32bit")
    os.add_dll_directory(sofistikFolderPath[:-1])

    # Get the DLL functions
    myDLL = cdll.LoadLibrary("cdb_w31.dll")
    py_sof_cdb_get = cdll.LoadLibrary("cdb_w31.dll").sof_cdb_get
    py_sof_cdb_get.restype = c_int

    py_sof_cdb_kenq = cdll.LoadLibrary("cdb_w31.dll").sof_cdb_kenq_ex

# Connect to CDB
Index = c_int()
cdbIndex = 99

# Set the CDB Path
# e.g. fileName = "S:\\test\\read_nodes.cdb"
# fileName = r"S:\test\read_nodes.cdb"
fileName = CDBFilePath

# important: Unicode call!
Index.value = myDLL.sof_cdb_init(fileName.encode("utf-8"), cdbIndex)
if Index.value == 0:
    print("A database with the given file name does not exist and was created.")

cdbStat = c_int()  # get the CDB status
cdbStat.value = myDLL.sof_cdb_status(Index.value)

# Print the Status of the CDB
print("CDB Status:", cdbStat.value)

grpDiv = []
qNr = []
qN1 = []
qN2 = []
qN3 = []
qN4 = []

pos = c_int(0)
datalen = c_int(0)

# Get system group divisor
# a = c_int()
ie = c_int(0)
datalen.value = sizeof(CSYST)
RecLen = c_int(sizeof(csyst))

"""
do while ie == 0, see cdbase.chm, Returnvalue.
   = 0 -> No error
   = 1 -> Item is longer than Data
   = 2 -> End of file reached
   = 3 -> Key does not exist
"""

while ie.value < 2:
    ie.value = py_sof_cdb_get(Index, 10, 0, byref(csyst), byref(RecLen), 1)

    print(csyst.m_igdiv)
    grpDiv.append(csyst.m_igdiv)

    # Always read the length of record before sof_cdb_get is called
    RecLen = c_int(sizeof(csyst))

# Get Quad element numbers and node numbers
# a = c_int()
ie = c_int(0)
datalen.value = sizeof(CQUAD)
RecLen = c_int(sizeof(cquad))

while ie.value < 2:
    ie.value = py_sof_cdb_get(Index, 200, 0, byref(cquad), byref(RecLen), 1)

    qNr.append(cquad.m_nr)
    qN1.append(cquad.m_node[0])
    qN2.append(cquad.m_node[1])
    qN3.append(cquad.m_node[2])
    qN4.append(cquad.m_node[3])

    # Always read the length of record before sof_cdb_get is called
    RecLen = c_int(sizeof(cquad))

# Close the CDB, 0 - will close all the files
myDLL.sof_cdb_close(0)

# Print again the status of the CDB, if status = 0 -> CDB Closed successfully
cdbStat.value = myDLL.sof_cdb_status(Index.value)
if cdbStat.value == 0:
    print("CDB closed successfully, status = 0")

You’re probably also checking the next record,

The while condition (while ie.value < 2) is enforced before reading the record (py_sof_cdb_get).
So the error return value of a faulty read (ie.value = py_sof_cdb_get) doesn’t prevent printing/appending → you’re adding junk.

You might want to change the while for an if, since you’re only checking one record.

Also you shouldn’t check groups with the group divisor manually. Sometimes the divisor can be “flexible” for large systems.
It’s better to read the group information (record 11/0).
The “trick” with this record is to differentiate between the types (quads/beams/…)

Thanks for the reply!

I updated the code to read the first instance of the record before the while loop so that the while loop would append the correct number of elements.

I also implemented record 11/0 as you suggested and successfully read the group numbers for the quad elements. However, this only gives me a list of all the groups in the system, not a list of the group numbers for each quad. What I’m trying to do is get a list of the group numbers similar to if you were to read the results out of the result viewer (see the second column in the screenshot below).

Updated Code: (Beginning at the while loops)

qGr = []
qNr = []
qN1 = []
qN2 = []
qN3 = []
qN4 = []

pos = c_int(0)
datalen = c_int(0)

# Get quad group numbers ----------------------------------------------------------
# a = c_int()
ie = c_int(0)
datalen.value = sizeof(CGRP)
RecLen = c_int(sizeof(cgrp))
ie.value = py_sof_cdb_get(Index, 11, 0, byref(cgrp), byref(RecLen), 1)

"""
do while ie == 0, see cdbase.chm, Returnvalue.
   = 0 -> No error
   = 1 -> Item is longer than Data
   = 2 -> End of file reached
   = 3 -> Key does not exist
"""

while ie.value < 2:
    # Read and save database information
    if cgrp.m_typ == 200:
        qGr.append(cgrp.m_ng)

    # Always read the length of record before sof_cdb_get is called
    RecLen = c_int(sizeof(cgrp))
    ie.value = py_sof_cdb_get(Index, 11, 0, byref(cgrp), byref(RecLen), 1)

# Get Quad element numbers and node numbers ----------------------------------------
# a = c_int()
ie = c_int(0)
datalen.value = sizeof(CQUAD)
RecLen = c_int(sizeof(cquad))
ie.value = py_sof_cdb_get(Index, 200, 0, byref(cquad), byref(RecLen), 1)

while ie.value < 2:
    # Read and save database information
    qNr.append(cquad.m_nr)
    qN1.append(cquad.m_node[0])
    qN2.append(cquad.m_node[1])
    qN3.append(cquad.m_node[2])
    qN4.append(cquad.m_node[3])

    # Always read the length of record before sof_cdb_get is called
    RecLen = c_int(sizeof(cquad))
    ie.value = py_sof_cdb_get(Index, 200, 0, byref(cquad), byref(RecLen), 1)

# Close the CDB, 0 - will close all the files
myDLL.sof_cdb_close(0)

# Print again the status of the CDB, if status = 0 -> CDB Closed successfully
cdbStat.value = myDLL.sof_cdb_status(Index.value)
if cdbStat.value == 0:
    print("CDB closed successfully, status = 0")

11/0 gives you:

  • Group number
  • Max and min element number

So if you store all the three values above, you can check if the element is within the boundaries of each group.

Perfect. Thanks for the help!