Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for *ELEMENT_TSHELL #4

Merged
merged 3 commits into from
Sep 9, 2024
Merged
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ PyVista. For example, you could plot the resulting mesh. Here's a full example u
>>> grid.plot(color="w", smooth_shading=True, show_edges=True)
```

![Yaris Static Suspension Mesh](https://github.com/akaszynski/lsdyna-mesh-reader/blob/main/docs/source/images/yaris-mesh.png)
![Yaris Static Suspension Mesh](https://github.com/akaszynski/lsdyna-mesh-reader/raw/main/docs/source/images/yaris-mesh.png)

### Caveats and Limitations

Expand All @@ -181,6 +181,7 @@ Additionally, this reader only supports the following keywords:
* `*NODE`
* `*ELEMENT_SHELL`
* `*ELEMENT_SOLID`
* `*ELEMENT_TSHELL` (note: sections encoded as solid sections)

The VTK UnstructuredGrid contains only the linear element conversion of the
underlying LS-DYNA elements, and only supports `VTK_QUAD`, `VTK_TRIANGLE`,
Expand Down
9 changes: 9 additions & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ API Reference

The following section contains the API reference for ``lsdyna-mesh-reader``.

**Reader**

.. autosummary::
:toctree: _autosummary
:template: custom-class-template.rst
Expand All @@ -11,3 +13,10 @@ The following section contains the API reference for ``lsdyna-mesh-reader``.
lsdyna_mesh_reader._deck.NodeSection
lsdyna_mesh_reader._deck.ElementShellSection
lsdyna_mesh_reader._deck.ElementSolidSection

**Examples**

.. autosummary::
:toctree: _autosummary

lsdyna_mesh_reader.examples
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Repository = "https://github.com/akaszynski/lsdyna-mesh-reader"
[tool.cibuildwheel]
archs = ["auto64"] # 64-bit only
skip = "cp38-* cp313-* pp* *musllinux*" # 3.9-3.12 and no PyPy and musl-based wheels
test-command = "pytest {project}/tests"
test-command = "pytest {project}/tests -v"
test-requires = "pytest pyvista"

[tool.cibuildwheel.macos]
Expand Down
61 changes: 34 additions & 27 deletions src/deck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,12 @@ class MemoryMappedFile {
}
}

// True when at end of file
bool eof() { return current >= start + size; }

// True when at end of line (DOS and UNIX EOF)
bool eol() { return *current == '\n' || *current == '\r'; }

bool read_line() {
line.clear();
if (current >= start + size) {
Expand Down Expand Up @@ -355,26 +359,21 @@ struct NodeSection {
NDArray<int, 1> tc;
NDArray<int, 1> rc;
int n_nodes = 0;
bool _has_constraints;

// Default constructor
NodeSection() {}

NodeSection(std::vector<int> nid_vec, std::vector<double> nodes_vec,
std::vector<int> tc_vec, std::vector<int> rc_vec,
bool has_constraints) {
_has_constraints = has_constraints;
std::vector<int> tc_vec, std::vector<int> rc_vec) {
n_nodes = nid_vec.size();
std::array<int, 1> nid_shape = {static_cast<int>(n_nodes)};
std::array<int, 2> coord_shape = {static_cast<int>(n_nodes), 3};

// Wrap vectors as NDArrays
nid = WrapVectorAsNDArray(std::move(nid_vec), nid_shape);
coord = WrapVectorAsNDArray(std::move(nodes_vec), coord_shape);
if (has_constraints) {
tc = WrapVectorAsNDArray(std::move(tc_vec), nid_shape);
rc = WrapVectorAsNDArray(std::move(rc_vec), nid_shape);
}
tc = WrapVectorAsNDArray(std::move(tc_vec), nid_shape);
rc = WrapVectorAsNDArray(std::move(rc_vec), nid_shape);
}

int Length() { return n_nodes; }
Expand Down Expand Up @@ -403,10 +402,9 @@ struct NodeSection {
<< std::setw(15) << std::scientific << std::setprecision(8)
<< coord(i, 2) << " "; // Z

if (_has_constraints) {
oss << std::setw(8) << tc(i) << " " // tc
<< std::setw(8) << rc(i); // rc
}
// constraints
oss << std::setw(8) << tc(i) << " " // tc
<< std::setw(8) << rc(i); // rc

oss << "\n";
}
Expand Down Expand Up @@ -669,8 +667,6 @@ class Deck {
std::cout << "Reading node section" << std::endl;
#endif

bool has_constraints = true; // assume true

// Since we don't know the total number of nodes, we'll use vectors here,
// even though a malloc would be more efficient. Seems they don't store the
// total number of nodes per section.
Expand Down Expand Up @@ -722,24 +718,32 @@ class Deck {
std::cout << "Done reading coordinates " << std::endl;
#endif

// constraints
if (memmap[0] == '\n') {
has_constraints = false;
}

if (has_constraints) {
// Populate constraints. These may be missing from the node section, and
// if they are, populate a zero.
if (memmap.eol()) {
#ifdef DEBUG
std::cout << "EOL on tc" << std::endl;
#endif
tc.push_back(0);
} else {
tc.push_back(fast_atoi(memmap.current, 8));
memmap += 8;
}

if (memmap.eol()) {
#ifdef DEBUG
std::cout << "EOL on rc" << std::endl;
#endif
rc.push_back(0);
} else {
rc.push_back(fast_atoi(memmap.current, 8));
memmap += 8;
}

// skip remainder of the line
memmap.seek_eol();
}

NodeSection *node_section =
new NodeSection(nid, coord, tc, rc, has_constraints);
NodeSection *node_section = new NodeSection(nid, coord, tc, rc);
node_sections.push_back(*node_section);

return;
Expand Down Expand Up @@ -831,10 +835,11 @@ class Deck {
}

first_char = memmap[0];
// #ifdef DEBUG
// std::cout << "Read character: " <<
// static_cast<char>(first_char) << std::endl;
// #endif
#ifdef DEBUG
std::cout << "Read character: " << static_cast<char>(first_char)
<< std::endl;
#endif

// Check if line contains a keyword
if (first_char != '*') {
memmap.seek_eol();
Expand All @@ -848,6 +853,8 @@ class Deck {
ReadElementSolidSection();
} else if (memmap.line.compare(0, 14, "*ELEMENT_SHELL") == 0) {
ReadElementShellSection();
} else if (memmap.line.compare(0, 15, "*ELEMENT_TSHELL") == 0) {
ReadElementSolidSection();
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/lsdyna_mesh_reader/deck.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@


class Deck:
"""LS-DYNA deck.
r"""LS-DYNA deck.

Parameters
----------
filename : str | pathlib.Path
Path to the keyword file (\*.k, \*.key, \*.dyn).
Path to the keyword file (`*.k`, `*.key`, `*.dyn`).

Examples
--------
Expand Down
100 changes: 98 additions & 2 deletions src/lsdyna_mesh_reader/examples/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""LS-DYNA examples module.
"""LS-DYNA Mesh Reader examples module.

Content reused based on the following implicit open to use license from
https://www.dynaexamples.com/
`LS-DYNA Examples <https://www.dynaexamples.com/>`_.

**Usage Notice from LS-DYNA**

The input files and several class notes are available for download. The
download is free of charge, a login is not required. All examples are
Expand All @@ -11,6 +13,96 @@
The content is prepared for educational purposes. Hence, material
properties and other parameters might be non-physic for simplification.

Copyright (c) 2014 DYNAmore GmbH (www.dynamore.de)
Copying for non-commercial usage allowed, if this notice is included.


Example Files
^^^^^^^^^^^^^

.. py:data:: lsdyna_mesh_reader.examples.birdball
:annotation: = str

Path to the `Contact Eroding I <https://www.dynaexamples.com/introduction/intro-by-a.-tabiei/contact/contact-eroding-i>`_ example file. Usage:

.. code:: pycon

>>> from lsdyna_mesh_reader import examples
>>> import lsdyna_mesh_reader
>>> deck = lsdyna_mesh_reader.Deck(examples.birdball)
>>> deck
LSDYNA Deck with:
Node sections: 1
Element Solid sections: 1
Element Shell sections: 1

.. py:data:: lsdyna_mesh_reader.examples.joint_screw
:annotation: = str

Path to the `Joint Screw <https://www.dynaexamples.com/show-cases/joint-screw/>`_ example file. Usage:

.. code:: pycon

>>> from lsdyna_mesh_reader import examples
>>> import lsdyna_mesh_reader
>>> deck = lsdyna_mesh_reader.Deck(examples.joint_screw)
>>> deck
LSDYNA Deck with:
Node sections: 1
Element Solid sections: 1
Element Shell sections: 1


.. py:data:: lsdyna_mesh_reader.examples.wheel
:annotation: = str

Path to the `SSD with a wheel rim <https://www.dynaexamples.com/nvh/example-05-03>`_ example file. Usage:

.. code:: pycon

>>> from lsdyna_mesh_reader import examples
>>> import lsdyna_mesh_reader
>>> deck = lsdyna_mesh_reader.Deck(examples.wheel)
>>> deck
LSDYNA Deck with:
Node sections: 1
Element Solid sections: 0
Element Shell sections: 1


.. py:data:: lsdyna_mesh_reader.examples.bracket
:annotation: = str

Path to `An aluminium bracket <https://www.dynaexamples.com/nvh/example-05-03>`_ example file. Usage:

.. code:: pycon

>>> from lsdyna_mesh_reader import examples
>>> import lsdyna_mesh_reader
>>> deck = lsdyna_mesh_reader.Deck(examples.bracket)
>>> deck
LSDYNA Deck with:
Node sections: 1
Element Solid sections: 0
Element Shell sections: 1


.. py:data:: lsdyna_mesh_reader.examples.simple_plate
:annotation: = str

Path to the `Square Plate Out-of-Plane Vibration (thick shell mesh) <https://www.dynaexamples.com/nvh/example-05-03>`_ example file. Usage:

.. code:: pycon

>>> from lsdyna_mesh_reader import examples
>>> import lsdyna_mesh_reader
>>> deck = lsdyna_mesh_reader.Deck(examples.simple_plate)
>>> deck
LSDYNA Deck with:
Node sections: 1
Element Solid sections: 0
Element Shell sections: 1

"""

import os
Expand All @@ -29,9 +121,13 @@
# https://www.dynaexamples.com/nvh/example-07-01
bracket = os.path.join(dir_path, "bracket.k")

# https://www.dynaexamples.com/introduction/Introduction/example-13
simple_plate = os.path.join(dir_path, "ex_13_thick_shell_elform_2.k")

__all__ = [
"birdball",
"joint_screw",
"wheel",
"bracket",
"simple_plate",
]
Loading
Loading