Task 448: .NEU File Format
Task 448: .NEU File Format
1. List of all the properties of this file format intrinsic to its file system
The .NEU file format is the Gambit Neutral File Format, an ASCII format for mesh data used in computational fluid dynamics (CFD) applications like Gambit and Fluent. The properties intrinsic to the format include the following sections and their contents (based on the format specifications). These are the core elements that define the file's structure and data:
Control Information:
- Neutral File Header (e.g., "** GAMBIT NEUTRAL FILE")
- User-Defined Title (80-character string)
- Program Name and Version (e.g., "GAMBIT" and revision level)
- Date and Time of creation
- Problem Size Parameters:
- NUMNP: Total number of nodal points
- NELEM: Total number of elements
- NGRPS: Number of element groups
- NBSETS: Number of boundary condition sets
- NDFCD: Number of coordinate directions (2 or 3)
- NDFVL: Number of velocity components (2 or 3)
Nodal Coordinates:
- List of nodes, each with:
- Node ID (integer)
- Coordinates (up to 3 real numbers: X, Y, Z)
Elements/Cells Connectivity:
- List of elements, each with:
- Element ID (integer)
- Element Type (integer: 1=Edge, 2=Quadrilateral, 3=Triangle, 4=Brick, 5=Wedge, 6=Tetrahedron, 7=Pyramid)
- Number of Nodes (integer)
- List of Node IDs defining the element (variable length based on type)
Element Groups (one section per group, repeated NGRPS times):
- Group Number (integer)
- Number of Elements in Group (NELGP)
- Material Type (integer: 0=Undefined, 1=Conjugate, 2=Fluid, 3=Porous, 4=Solid, 5=Deformable)
- Number of Flags (NFLAGS)
- Entity Name (string, e.g., "fluid")
- Solver-Dependent Flags (list of integers)
- List of Element IDs in the group
Boundary Condition Sets (optional, repeated NBSETS times):
- Set Name (string)
- Type (ITYPE: 0=node-based, 1=element-based)
- Number of Entries (NENTRY)
- Number of Values per Entry (NVALUES)
- IBCODE1-5 (optional codes for boundary types, e.g., 1=AXIS, 6=WALL)
- Data Entries (depending on ITYPE):
- For node-based: Node ID, values (real numbers)
- For element-based: Element ID, Element Type, Face Number, values (real numbers)
Optional Sections (not always present, but intrinsic if included):
- Application Data: Application ID, version, solver-dependent flags (integers, reals, strings)
- Face Connectivity: Number of face records, master/abutting element and face data for non-conformal meshes
- Solution Vectors: Time step info, vector/tensor/scalar data (node- or cell-based, e.g., velocity, temperature)
The file is ASCII with fixed-field formatting, sections separated by headers and "ENDOFSECTION".
2. Two direct download links for files of format .NEU
I was unable to find direct download links to .NEU files during my search, as they are typically generated by software like Gambit and not commonly hosted for public download. However, here is a direct link to a related archive from a CFD forum that contains code for generating .NEU files and may include examples inside the tar.gz (you can extract it to check):
For another resource, the Stanford handout PDF contains snippets of .NEU file content that can be copied to create a sample file:
If you need more, I recommend searching CFD repositories or forums like CFD Online for user-uploaded meshes.
3. Ghost blog embedded html javascript that allows a user to drag n drop a file of format .NEU and it will dump to screen all these properties
Here is a self-contained HTML page with embedded JavaScript that can be embedded in a Ghost blog post (e.g., via the HTML card). It creates a drag-and-drop area, reads the .NEU file using FileReader, parses it according to the spec, and dumps the properties to the screen in a readable format.
Note: This parser is basic and assumes a standard structure without optional sections or wrapped lines. For full robustness, expand the parsing logic.
4. Python class that can open any file of format .NEU and decode read and write and print to console all the properties from the above list
Here is a Python class for handling .NEU files. It has methods to read from file, print properties, and write to a new file.
import re
class NEUFile:
def __init__(self):
self.control = {}
self.nodal_coords = []
self.elements = []
self.groups = []
self.boundary_sets = []
self.optional_sections = {} # For optional like application data
def read(self, filename):
with open(filename, 'r') as f:
lines = f.readlines()
lines = [line.strip() for line in lines if line.strip() and not line.startswith('/')]
i = 0
# Parse Control Info
if lines[i].startsWith('CONTROL INFO'):
i += 1
self.control['header'] = lines[i]
i += 1
self.control['title'] = lines[i]
i += 1
self.control['program_version'] = lines[i]
i += 1
self.control['date_time'] = lines[i]
i += 1
i += 1 # Skip headings
sizes = list(map(int, lines[i].split()))
self.control['num_np'] = sizes[0]
self.control['nelem'] = sizes[1]
self.control['ngrps'] = sizes[2]
self.control['nbsets'] = sizes[3]
self.control['ndfcd'] = sizes[4]
self.control['ndfvl'] = sizes[5]
i += 1 # ENDOFSECTION
i += 1
# Parse Nodal Coordinates
if lines[i].startswith('NODAL COORDINATES'):
i += 1
for _ in range(self.control['num_np']):
data = lines[i].split()
node_id = int(data[0])
coords = list(map(float, data[1:]))
self.nodal_coords.append((node_id, coords))
i += 1
i += 1 # ENDOFSECTION
# Parse Elements
if lines[i].startswith('ELEMENTS/CELLS'):
i += 1
for _ in range(self.control['nelem']):
data = lines[i].split()
elem_id = int(data[0])
elem_type = int(data[1])
ndp = int(data[2])
nodes = list(map(int, data[3:]))
self.elements.append((elem_id, elem_type, ndp, nodes))
i += 1
i += 1 # ENDOFSECTION
# Parse Groups
for _ in range(self.control['ngrps']):
if lines[i].startswith('ELEMENT GROUP'):
i += 1
group_line = re.match(r'GROUP:\s*(\d+)\s*ELEMENTS:\s*(\d+)\s*MATERIAL:\s*(\d+)\s*NFLAGS:\s*(\d+)', lines[i])
group = {
'group': int(group_line.group(1)),
'nelgp': int(group_line.group(2)),
'mtyp': int(group_line.group(3)),
'nflags': int(group_line.group(4)),
}
i += 1
group['name'] = lines[i]
i += 1
group['flags'] = list(map(int, lines[i].split()))
i += 1
group['elements'] = []
while not lines[i].startswith('ENDOFSECTION'):
group['elements'].extend(map(int, lines[i].split()))
i += 1
self.groups.append(group)
i += 1
# Parse Boundary Sets
for _ in range(self.control['nbsets']):
if lines[i].startswith('BOUNDARY CONDITIONS'):
i += 1
data = lines[i].split()
bc = {
'name': data[0],
'itype': int(data[1]),
'nentry': int(data[2]),
'nvalues': int(data[3]),
'ibcodes': list(map(int, data[4:])),
'entries': []
}
i += 1
for _ in range(bc['nentry']):
entry_data = lines[i].split()
if bc['itype'] == 0:
node = int(entry_data[0])
values = list(map(float, entry_data[1:]))
bc['entries'].append((node, values))
else:
elem = int(entry_data[0])
e_type = int(entry_data[1])
face = int(entry_data[2])
values = list(map(float, entry_data[3:]))
bc['entries'].append((elem, e_type, face, values))
i += 1
self.boundary_sets.append(bc)
i += 1
# Optional sections can be parsed similarly if needed
def print_properties(self):
print('Control Information:')
for k, v in self.control.items():
print(f' {k}: {v}')
print('\nNodal Coordinates:')
for node in self.nodal_coords:
print(node)
print('\nElements:')
for elem in self.elements:
print(elem)
print('\nGroups:')
for group in self.groups:
print(group)
print('\nBoundary Sets:')
for bc in self.boundary_sets:
print(bc)
# Print optional if present
def write(self, filename):
with open(filename, 'w') as f:
# Write Control Info
f.write('CONTROL INFO 1.2.1\n')
f.write(self.control['header'] + '\n')
f.write(self.control['title'] + '\n')
f.write(self.control['program_version'] + '\n')
f.write(self.control['date_time'] + '\n')
f.write(' NUMNP NELEM NGRPS NBSETS NDFCD NDFVL\n')
f.write(f"{self.control['num_np']:10}{self.control['nelem']:10}{self.control['ngrps']:10}{self.control['nbsets']:10}{self.control['ndfcd']:10}{self.control['ndfvl']:10}\n")
f.write('ENDOFSECTION\n')
# Write Nodal Coordinates
f.write('NODAL COORDINATES 1.2.1\n')
for node, coords in self.nodal_coords:
coord_str = ' '.join(f'{c:20.11e}' for c in coords)
f.write(f'{node:10} {coord_str}\n')
f.write('ENDOFSECTION\n')
# Write Elements
f.write('ELEMENTS/CELLS 1.2.1\n')
for elem, type_, ndp, nodes in self.elements:
nodes_str = ' '.join(f'{n:8}' for n in nodes)
f.write(f'{elem:8} {type_:2} {ndp:2} {nodes_str}\n')
f.write('ENDOFSECTION\n')
# Write Groups
for group in self.groups:
f.write('ELEMENT GROUP 1.2.1\n')
f.write(f"GROUP: {group['group']:10} ELEMENTS: {group['nelgp']:10} MATERIAL: {group['mtyp']:10} NFLAGS: {group['nflags']:10}\n")
f.write(group['name'] + '\n')
f.write(' '.join(str(fl) for fl in group['flags']) + '\n')
elem_lines = [group['elements'][j:j+10] for j in range(0, len(group['elements']), 10)]
for line in elem_lines:
f.write(' '.join(f'{e:8}' for e in line) + '\n')
f.write('ENDOFSECTION\n')
# Write Boundary Sets
for bc in self.boundary_sets:
f.write('BOUNDARY CONDITIONS 1.2.1\n')
ibcodes_str = ' '.join(str(c) for c in bc['ibcodes'])
f.write(f"{bc['name']:32} {bc['itype']:8} {bc['nentry']:8} {bc['nvalues']:8} {ibcodes_str}\n")
for entry in bc['entries']:
if bc['itype'] == 0:
node, values = entry
values_str = ' '.join(f'{v:20.12e}' for v in values)
f.write(f'{node:10} {values_str}\n')
else:
elem, e_type, face, values = entry
values_str = ' '.join(f'{v:20.12e}' for v in values)
f.write(f'{elem:10} {e_type:5} {face:5} {values_str}\n')
f.write('ENDOFSECTION\n')
# Example usage
# neu = NEUFile()
# neu.read('input.neu')
# neu.print_properties()
# neu.write('output.neu')
Note: This is a basic implementation. For wrapped lines or optional sections, extend the class.
5. Java class that can open any file of format .NEU and decode read and write and print to console all the properties from the above list
Here is a Java class for handling .NEU files.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NEUFile {
private class Control {
String header;
String title;
String programVersion;
String dateTime;
int numNP;
int nelem;
int ngrps;
int nbsets;
int ndfcd;
int ndfvl;
}
private class Node {
int id;
double[] coords;
}
private class Element {
int id;
int type;
int ndp;
int[] nodes;
}
private class Group {
int group;
int nelgp;
int mtyp;
int nflags;
String name;
int[] flags;
int[] elements;
}
private class BoundarySet {
String name;
int itype;
int nentry;
int nvalues;
int[] ibcodes;
List<Object[]> entries;
}
private Control control = new Control();
private List<Node> nodalCoords = new ArrayList<>();
private List<Element> elements = new ArrayList<>();
private List<Group> groups = new ArrayList<>();
private List<BoundarySet> boundarySets = new ArrayList<>();
public void read(String filename) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(filename));
List<String> lines = new ArrayList<>();
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (!line.isEmpty() && !line.startsWith("/")) {
lines.add(line);
}
}
br.close();
int i = 0;
// Parse Control
if (lines.get(i).startsWith("CONTROL INFO")) {
i++;
control.header = lines.get(i++);
control.title = lines.get(i++);
control.programVersion = lines.get(i++);
control.dateTime = lines.get(i++);
i++; // Headings
String[] sizes = lines.get(i++).split("\\s+");
control.numNP = Integer.parseInt(sizes[0]);
control.nelem = Integer.parseInt(sizes[1]);
control.ngrps = Integer.parseInt(sizes[2]);
control.nbsets = Integer.parseInt(sizes[3]);
control.ndfcd = Integer.parseInt(sizes[4]);
control.ndfvl = Integer.parseInt(sizes[5]);
i++; // ENDOFSECTION
}
// Parse Nodal Coords
if (lines.get(i).startsWith("NODAL COORDINATES")) {
i++;
for (int j = 0; j < control.numNP; j++) {
String[] data = lines.get(i++).split("\\s+");
Node node = new Node();
node.id = Integer.parseInt(data[0]);
node.coords = new double[data.length - 1];
for (int k = 1; k < data.length; k++) {
node.coords[k - 1] = Double.parseDouble(data[k]);
}
nodalCoords.add(node);
}
i++; // ENDOFSECTION
}
// Parse Elements
if (lines.get(i).startsWith("ELEMENTS/CELLS")) {
i++;
for (int j = 0; j < control.nelem; j++) {
String[] data = lines.get(i++).split("\\s+");
Element elem = new Element();
elem.id = Integer.parseInt(data[0]);
elem.type = Integer.parseInt(data[1]);
elem.ndp = Integer.parseInt(data[2]);
elem.nodes = new int[elem.ndp];
for (int k = 0; k < elem.ndp; k++) {
elem.nodes[k] = Integer.parseInt(data[3 + k]);
}
elements.add(elem);
}
i++; // ENDOFSECTION
}
// Parse Groups
for (int g = 0; g < control.ngrps; g++) {
if (lines.get(i).startsWith("ELEMENT GROUP")) {
i++;
Pattern p = Pattern.compile("GROUP: (\\d+) ELEMENTS: (\\d+) MATERIAL: (\\d+) NFLAGS: (\\d+)");
Matcher m = p.matcher(lines.get(i++));
if (m.find()) {
Group group = new Group();
group.group = Integer.parseInt(m.group(1));
group.nelgp = Integer.parseInt(m.group(2));
group.mtyp = Integer.parseInt(m.group(3));
group.nflags = Integer.parseInt(m.group(4));
group.name = lines.get(i++);
String[] flagStr = lines.get(i++).split("\\s+");
group.flags = new int[flagStr.length];
for (int k = 0; k < flagStr.length; k++) {
group.flags[k] = Integer.parseInt(flagStr[k]);
}
List<Integer> elemList = new ArrayList<>();
while (!lines.get(i).startsWith("ENDOFSECTION")) {
String[] elemStr = lines.get(i++).split("\\s+");
for (String s : elemStr) {
if (!s.isEmpty()) {
elemList.add(Integer.parseInt(s));
}
}
}
group.elements = new int[elemList.size()];
for (int k = 0; k < elemList.size(); k++) {
group.elements[k] = elemList.get(k);
}
groups.add(group);
i++; // ENDOFSECTION
}
}
}
// Parse Boundary Sets
for (int b = 0; b < control.nbsets; b++) {
if (lines.get(i).startsWith("BOUNDARY CONDITIONS")) {
i++;
String[] data = lines.get(i++).split("\\s+");
BoundarySet bc = new BoundarySet();
bc.name = data[0];
bc.itype = Integer.parseInt(data[1]);
bc.nentry = Integer.parseInt(data[2]);
bc.nvalues = Integer.parseInt(data[3]);
bc.ibcodes = new int[data.length - 4];
for (int k = 4; k < data.length; k++) {
bc.ibcodes[k - 4] = Integer.parseInt(data[k]);
}
bc.entries = new List<>();
for (int e = 0; e < bc.nentry; e++) {
String[] entryData = lines.get(i++).split("\\s+");
if (bc.itype == 0) {
int node = Integer.parseInt(entryData[0]);
double[] values = new double[entryData.length - 1];
for (int k = 1; k < entryData.length; k++) {
values[k - 1] = Double.parseDouble(entryData[k]);
}
bc.entries.add(new Object[]{node, values});
} else {
int elem = Integer.parseInt(entryData[0]);
int eType = Integer.parseInt(entryData[1]);
int face = Integer.parseInt(entryData[2]);
double[] values = new double[entryData.length - 3];
for (int k = 3; k < entryData.length; k++) {
values[k - 3] = Double.parseDouble(entryData[k]);
}
bc.entries.add(new Object[]{elem, eType, face, values});
}
}
boundarySets.add(bc);
i++; // ENDOFSECTION
}
}
}
public void printProperties() {
System.out.println("Control Information:");
System.out.println(" Header: " + control.header);
System.out.println(" Title: " + control.title);
System.out.println(" Program Version: " + control.programVersion);
System.out.println(" Date Time: " + control.dateTime);
System.out.println(" NUMNP: " + control.numNP);
System.out.println(" NELEM: " + control.nelem);
System.out.println(" NGRPS: " + control.ngrps);
System.out.println(" NBSETS: " + control.nbsets);
System.out.println(" NDFCD: " + control.ndfcd);
System.out.println(" NDFVL: " + control.ndfvl);
System.out.println("\nNodal Coordinates:");
for (Node node : nodalCoords) {
System.out.print(" Node " + node.id + ": ");
for (double c : node.coords) {
System.out.print(c + " ");
}
System.out.println();
}
System.out.println("\nElements:");
for (Element elem : elements) {
System.out.print(" Element " + elem.id + " (Type " + elem.type + ", NDP " + elem.ndp + "): ");
for (int n : elem.nodes) {
System.out.print(n + " ");
}
System.out.println();
}
System.out.println("\nGroups:");
for (Group group : groups) {
System.out.println(" Group " + group.group + ", Elements " + group.nelgp + ", Material " + group.mtyp + ", NFlags " + group.nflags);
System.out.println(" Name: " + group.name);
System.out.print(" Flags: ");
for (int f : group.flags) {
System.out.print(f + " ");
}
System.out.println();
System.out.print(" Elements: ");
for (int e : group.elements) {
System.out.print(e + " ");
}
System.out.println();
}
System.out.println("\nBoundary Sets:");
for (BoundarySet bc : boundarySets) {
System.out.println(" Name: " + bc.name + ", Type: " + bc.itype + ", Entries: " + bc.nentry + ", Values: " + bc.nvalues);
System.out.print(" IBCodes: ");
for (int c : bc.ibcodes) {
System.out.print(c + " ");
}
System.out.println();
for (Object[] entry : bc.entries) {
System.out.print(" Entry: ");
for (Object o : entry) {
if (o instanceof Integer) {
System.out.print((Integer) o + " ");
} else if (o instanceof double[]) {
for (double v : (double[]) o) {
System.out.print(v + " ");
}
}
}
System.out.println();
}
}
}
public void write(String filename) throws Exception {
PrintWriter pw = new PrintWriter(filename);
// Write Control
pw.println("CONTROL INFO 1.2.1");
pw.println(control.header);
pw.println(control.title);
pw.println(control.programVersion);
pw.println(control.dateTime);
pw.println(" NUMNP NELEM NGRPS NBSETS NDFCD NDFVL");
pw.printf("%10d%10d%10d%10d%10d%10d%n", control.numNP, control.nelem, control.ngrps, control.nbsets, control.ndfcd, control.ndfvl);
pw.println("ENDOFSECTION");
// Write Nodal Coords
pw.println("NODAL COORDINATES 1.2.1");
for (Node node : nodalCoords) {
pw.printf("%10d", node.id);
for (double c : node.coords) {
pw.printf(" %20.11e", c);
}
pw.println();
}
pw.println("ENDOFSECTION");
// Write Elements
pw.println("ELEMENTS/CELLS 1.2.1");
for (Element elem : elements) {
pw.printf("%8d %2d %2d", elem.id, elem.type, elem.ndp);
for (int n : elem.nodes) {
pw.printf(" %8d", n);
}
pw.println();
}
pw.println("ENDOFSECTION");
// Write Groups
for (Group group : groups) {
pw.println("ELEMENT GROUP 1.2.1");
pw.printf("GROUP: %10d ELEMENTS: %10d MATERIAL: %10d NFLAGS: %10d%n", group.group, group.nelgp, group.mtyp, group.nflags);
pw.println(group.name);
for (int f = 0; f < group.flags.length; f++) {
pw.print(group.flags[f] + " ");
}
pw.println();
for (int e = 0; e < group.elements.length; e++) {
pw.print(String.format("%8d", group.elements[e]));
if ((e + 1) % 10 == 0) pw.println();
}
pw.println();
pw.println("ENDOFSECTION");
}
// Write Boundary Sets
for (BoundarySet bc : boundarySets) {
pw.println("BOUNDARY CONDITIONS 1.2.1");
pw.print(bc.name + " ");
pw.print(bc.itype + " ");
pw.print(bc.nentry + " ");
pw.print(bc.nvalues + " ");
for (int c : bc.ibcodes) {
pw.print(c + " ");
}
pw.println();
for (Object[] entry : bc.entries) {
if (bc.itype == 0) {
int node = (Integer) entry[0];
double[] values = (double[]) entry[1];
pw.printf("%10d", node);
for (double v : values) {
pw.printf(" %20.12e", v);
}
pw.println();
} else {
int elem = (Integer) entry[0];
int eType = (Integer) entry[1];
int face = (Integer) entry[2];
double[] values = (double[]) entry[3];
pw.printf("%10d %5d %5d", elem, eType, face);
for (double v : values) {
pw.printf(" %20.12e", v);
}
pw.println();
}
}
pw.println("ENDOFSECTION");
}
pw.close();
}
// Example usage
// public static void main(String[] args) throws Exception {
// NEUFile neu = new NEUFile();
// neu.read("input.neu");
// neu.printProperties();
// neu.write("output.neu");
// }
}
Note: This is a basic implementation; handle wrapped lines and exceptions as needed.
6. Javascript class that can open any file of format .NEU and decode read and write and print to console all the properties from the above list
Here is a JavaScript class for handling .NEU files (node.js, using fs for read/write).
const fs = require('fs');
class NEUFile {
constructor() {
this.control = {};
this.nodalCoords = [];
this.elements = [];
this.groups = [];
this.boundarySets = [];
}
read(filename) {
const content = fs.readFileSync(filename, 'utf8');
const lines = content.split('\n').map(line => line.trim()).filter(line => line && !line.startsWith('/'));
let i = 0;
// Parse Control
if (lines[i].startsWith('CONTROL INFO')) {
i++;
this.control.header = lines[i++];
this.control.title = lines[i++];
this.control.programVersion = lines[i++];
this.control.dateTime = lines[i++];
i++; // Headings
const sizes = lines[i++].split(/\s+/).map(Number);
this.control.numNP = sizes[0];
this.control.nelem = sizes[1];
this.control.ngrps = sizes[2];
this.control.nbsets = sizes[3];
this.control.ndfcd = sizes[4];
this.control.ndfvl = sizes[5];
i++; // ENDOFSECTION
}
// Parse Nodal Coords
if (lines[i].startsWith('NODAL COORDINATES')) {
i++;
for (let j = 0; j < this.control.numNP; j++) {
const data = lines[i++].split(/\s+/);
const nodeId = Number(data[0]);
const coords = data.slice(1).map(Number);
this.nodalCoords.push({id: nodeId, coords});
}
i++; // ENDOFSECTION
}
// Parse Elements
if (lines[i].startsWith('ELEMENTS/CELLS')) {
i++;
for (let j = 0; j < this.control.nelem; j++) {
const data = lines[i++].split(/\s+/);
const elemId = Number(data[0]);
const type = Number(data[1]);
const ndp = Number(data[2]);
const nodes = data.slice(3).map(Number);
this.elements.push({id: elemId, type, ndp, nodes});
}
i++; // ENDOFSECTION
}
// Parse Groups
for (let g = 0; g < this.control.ngrps; g++) {
if (lines[i].startsWith('ELEMENT GROUP')) {
i++;
const groupMatch = lines[i++].match(/GROUP:\s*(\d+)\s*ELEMENTS:\s*(\d+)\s*MATERIAL:\s*(\d+)\s*NFLAGS:\s*(\d+)/);
const group = {
group: Number(groupMatch[1]),
nelgp: Number(groupMatch[2]),
mtyp: Number(groupMatch[3]),
nflags: Number(groupMatch[4]),
name: lines[i++],
flags: lines[i++].split(/\s+/).map(Number),
elements: []
};
while (!lines[i].startsWith('ENDOFSECTION')) {
group.elements.push(...lines[i++].split(/\s+/).map(Number).filter(Boolean));
}
this.groups.push(group);
i++;
}
}
// Parse Boundary Sets
for (let b = 0; b < this.control.nbsets; b++) {
if (lines[i].startsWith('BOUNDARY CONDITIONS')) {
i++;
const data = lines[i++].split(/\s+/);
const bc = {
name: data[0],
itype: Number(data[1]),
nentry: Number(data[2]),
nvalues: Number(data[3]),
ibcodes: data.slice(4).map(Number),
entries: []
};
for (let e = 0; e < bc.nentry; e++) {
const entryData = lines[i++].split(/\s+/).map(str => isNaN(Number(str)) ? str : Number(str));
if (bc.itype === 0) {
bc.entries.push({node: entryData[0], values: entryData.slice(1)});
} else {
bc.entries.push({elem: entryData[0], type: entryData[1], face: entryData[2], values: entryData.slice(3)});
}
}
this.boundarySets.push(bc);
i++;
}
}
}
printProperties() {
console.log('Control Information:', this.control);
console.log('\nNodal Coordinates:');
this.nodalCoords.forEach(node => console.log(node));
console.log('\nElements:');
this.elements.forEach(elem => console.log(elem));
console.log('\nGroups:');
this.groups.forEach(group => console.log(group));
console.log('\nBoundary Sets:');
this.boundarySets.forEach(bc => console.log(bc));
}
write(filename) {
let output = '';
// Write Control
output += 'CONTROL INFO 1.2.1\n';
output += this.control.header + '\n';
output += this.control.title + '\n';
output += this.control.programVersion + '\n';
output += this.control.dateTime + '\n';
output += ' NUMNP NELEM NGRPS NBSETS NDFCD NDFVL\n';
output += `${this.control.numNP.toString().padStart(10)}${this.control.nelem.toString().padStart(10)}${this.control.ngrps.toString().padStart(10)}${this.control.nbsets.toString().padStart(10)}${this.control.ndfcd.toString().padStart(10)}${this.control.ndfvl.toString().padStart(10)}\n`;
output += 'ENDOFSECTION\n';
// Write Nodal Coords
output += 'NODAL COORDINATES 1.2.1\n';
this.nodalCoords.forEach(node => {
output += node.id.toString().padStart(10) + ' ';
output += node.coords.map(c => c.toExponential(11).padStart(20)).join(' ') + '\n';
});
output += 'ENDOFSECTION\n';
// Write Elements
output += 'ELEMENTS/CELLS 1.2.1\n';
this.elements.forEach(elem => {
output += elem.id.toString().padStart(8) + ' ' + elem.type.toString().padStart(2) + ' ' + elem.ndp.toString().padStart(2) + ' ';
output += elem.nodes.map(n => n.toString().padStart(8)).join(' ') + '\n';
});
output += 'ENDOFSECTION\n';
// Write Groups
this.groups.forEach(group => {
output += 'ELEMENT GROUP 1.2.1\n';
output += `GROUP: ${group.group.toString().padStart(10)} ELEMENTS: ${group.nelgp.toString().padStart(10)} MATERIAL: ${group.mtyp.toString().padStart(10)} NFLAGS: ${group.nflags.toString().padStart(10)}\n`;
output += group.name + '\n';
output += group.flags.map(f => f.toString()).join(' ') + '\n';
let elemStr = group.elements.map(e => e.toString().padStart(8)).join(' ');
output += elemStr.match(/.{1,80}/g).join('\n') + '\n';
output += 'ENDOFSECTION\n';
});
// Write Boundary Sets
this.boundarySets.forEach(bc => {
output += 'BOUNDARY CONDITIONS 1.2.1\n';
output += bc.name.padEnd(32) + bc.itype.toString().padStart(8) + bc.nentry.toString().padStart(8) + bc.nvalues.toString().padStart(8) + ' ';
output += bc.ibcodes.map(c => c.toString()).join(' ') + '\n';
bc.entries.forEach(entry => {
if (bc.itype === 0) {
output += entry.node.toString().padStart(10) + ' ';
output += entry.values.map(v => v.toExponential(12).padStart(20)).join(' ') + '\n';
} else {
output += entry.elem.toString().padStart(10) + ' ' + entry.type.toString().padStart(5) + ' ' + entry.face.toString().padStart(5) + ' ';
output += entry.values.map(v => v.toExponential(12).padStart(20)).join(' ') + '\n';
}
});
output += 'ENDOFSECTION\n';
});
fs.writeFileSync(filename, output);
}
}
// Example usage
// const neu = new NEUFile();
// neu.read('input.neu');
// neu.printProperties();
// neu.write('output.neu');
Note: Run with node.js. Basic implementation; extend for edge cases.
7. C class that can open any file of format .NEU and decode read and write and print to console all the properties from the above list
In C, we use structs instead of classes. Here is a C implementation with structs and functions for read, print, write.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE 1024
#define MAX_NODES 27 // Max nodes per element
struct Control {
char header[100];
char title[81];
char programVersion[50];
char dateTime[30];
int numNP;
int nelem;
int ngrps;
int nbsets;
int ndfcd;
int ndfvl;
};
struct Node {
int id;
double coords[3];
};
struct Element {
int id;
int type;
int ndp;
int nodes[MAX_NODES];
};
struct Group {
int group;
int nelgp;
int mtyp;
int nflags;
char name[33];
int *flags;
int *elements;
};
struct BoundaryEntry {
int elem_or_node;
int type; // for element
int face; // for element
double *values;
};
struct BoundarySet {
char name[33];
int itype;
int nentry;
int nvalues;
int ibcodes[5];
struct BoundaryEntry *entries;
};
struct NEUFile {
struct Control control;
struct Node *nodalCoords;
struct Element *elements;
struct Group *groups;
struct BoundarySet *boundarySets;
};
void readNEU(struct NEUFile *neu, const char *filename) {
FILE *fp = fopen(filename, "r");
if (!fp) {
perror("fopen");
exit(1);
}
char line[MAX_LINE];
int lineNum = 0;
// Read lines, skip comments
char **lines = NULL;
int numLines = 0;
while (fgets(line, MAX_LINE, fp)) {
lineNum++;
char *trimmed = line;
while (isspace(*trimmed)) trimmed++;
if (*trimmed == 0 || *trimmed == '/') continue;
lines = realloc(lines, (numLines + 1) * sizeof(char*));
lines[numLines] = strdup(trimmed);
numLines++;
}
fclose(fp);
int i = 0;
// Parse Control
if (strstr(lines[i], "CONTROL INFO")) {
i++;
strcpy(neu->control.header, lines[i++]);
strcpy(neu->control.title, lines[i++]);
strcpy(neu->control.programVersion, lines[i++]);
strcpy(neu->control.dateTime, lines[i++]);
i++; // Headings
sscanf(lines[i++], "%d %d %d %d %d %d", &neu->control.numNP, &neu->control.nelem, &neu->control.ngrps, &neu->control.nbsets, &neu->control.ndfcd, &neu->control.ndfvl);
i++; // ENDOFSECTION
}
// Allocate arrays
neu->nodalCoords = malloc(neu->control.numNP * sizeof(struct Node));
neu->elements = malloc(neu->control.nelem * sizeof(struct Element));
neu->groups = malloc(neu->control.ngrps * sizeof(struct Group));
neu->boundarySets = malloc(neu->control.nbsets * sizeof(struct BoundarySet));
// Parse Nodal Coords
if (strstr(lines[i], "NODAL COORDINATES")) {
i++;
for (int j = 0; j < neu->control.numNP; j++) {
sscanf(lines[i++], "%d %lf %lf %lf", &neu->nodalCoords[j].id, &neu->nodalCoords[j].coords[0], &neu->nodalCoords[j].coords[1], &neu->nodalCoords[j].coords[2]);
}
i++; // ENDOFSECTION
}
// Parse Elements
if (strstr(lines[i], "ELEMENTS/CELLS")) {
i++;
for (int j = 0; j < neu->control.nelem; j++) {
char *tok = lines[i++];
neu->elements[j].id = strtol(tok, &tok, 10);
neu->elements[j].type = strtol(tok, &tok, 10);
neu->elements[j].ndp = strtol(tok, &tok, 10);
for (int k = 0; k < neu->elements[j].ndp; k++) {
neu->elements[j].nodes[k] = strtol(tok, &tok, 10);
}
}
i++; // ENDOFSECTION
}
// Parse Groups
for (int g = 0; g < neu->control.ngrps; g++) {
if (strstr(lines[i], "ELEMENT GROUP")) {
i++;
sscanf(lines[i++], "GROUP: %d ELEMENTS: %d MATERIAL: %d NFLAGS: %d", &neu->groups[g].group, &neu->groups[g].nelgp, &neu->groups[g].mtyp, &neu->groups[g].nflags);
strcpy(neu->groups[g].name, lines[i++]);
neu->groups[g].flags = malloc(neu->groups[g].nflags * sizeof(int));
char *tok = lines[i++];
for (int f = 0; f < neu->groups[g].nflags; f++) {
neu->groups[g].flags[f] = strtol(tok, &tok, 10);
}
neu->groups[g].elements = malloc(neu->groups[g].nelgp * sizeof(int));
int elemIdx = 0;
while (!strstr(lines[i], "ENDOFSECTION")) {
tok = lines[i++];
while (*tok) {
neu->groups[g].elements[elemIdx++] = strtol(tok, &tok, 10);
}
}
i++;
}
}
// Parse Boundary Sets
for (int b = 0; b < neu->control.nbsets; b++) {
if (strstr(lines[i], "BOUNDARY CONDITIONS")) {
i++;
char *tok = lines[i++];
strncpy(neu->boundarySets[b].name, tok, 32);
tok += 32;
neu->boundarySets[b].itype = strtol(tok, &tok, 10);
neu->boundarySets[b].nentry = strtol(tok, &tok, 10);
neu->boundarySets[b].nvalues = strtol(tok, &tok, 10);
for (int c = 0; c < 5; c++) {
neu->boundarySets[b].ibcodes[c] = strtol(tok, &tok, 10);
}
neu->boundarySets[b].entries = malloc(neu->boundarySets[b].nentry * sizeof(struct BoundaryEntry));
for (int e = 0; e < neu->boundarySets[b].nentry; e++) {
tok = lines[i++];
if (neu->boundarySets[b].itype == 0) {
neu->boundarySets[b].entries[e].elem_or_node = strtol(tok, &tok, 10);
neu->boundarySets[b].entries[e].values = malloc(neu->boundarySets[b].nvalues * sizeof(double));
for (int v = 0; v < neu->boundarySets[b].nvalues; v++) {
neu->boundarySets[b].entries[e].values[v] = strtod(tok, &tok);
}
} else {
neu->boundarySets[b].entries[e].elem_or_node = strtol(tok, &tok, 10);
neu->boundarySets[b].entries[e].type = strtol(tok, &tok, 10);
neu->boundarySets[b].entries[e].face = strtol(tok, &tok, 10);
neu->boundarySets[b].entries[e].values = malloc(neu->boundarySets[b].nvalues * sizeof(double));
for (int v = 0; v < neu->boundarySets[b].nvalues; v++) {
neu->boundarySets[b].entries[e].values[v] = strtod(tok, &tok);
}
}
}
i++;
}
}
// Free lines
for (int j = 0; j < numLines; j++) free(lines[j]);
free(lines);
}
void printNEUProperties(const struct NEUFile *neu) {
printf("Control Information:\n");
printf(" Header: %s\n", neu->control.header);
printf(" Title: %s\n", neu->control.title);
printf(" Program Version: %s\n", neu->control.programVersion);
printf(" Date Time: %s\n", neu->control.dateTime);
printf(" NUMNP: %d, NELEM: %d, NGRPS: %d, NBSETS: %d, NDFCD: %d, NDFVL: %d\n", neu->control.numNP, neu->control.nelem, neu->control.ngrps, neu->control.nbsets, neu->control.ndfcd, neu->control.ndfvl);
printf("\nNodal Coordinates:\n");
for (int j = 0; j < neu->control.numNP; j++) {
printf(" Node %d: %e %e %e\n", neu->nodalCoords[j].id, neu->nodalCoords[j].coords[0], neu->nodalCoords[j].coords[1], neu->nodalCoords[j].coords[2]);
}
printf("\nElements:\n");
for (int j = 0; j < neu->control.nelem; j++) {
printf(" Element %d (Type %d, NDP %d): ", neu->elements[j].id, neu->elements[j].type, neu->elements[j].ndp);
for (int k = 0; k < neu->elements[j].ndp; k++) {
printf("%d ", neu->elements[j].nodes[k]);
}
printf("\n");
}
printf("\nGroups:\n");
for (int g = 0; g < neu->control.ngrps; g++) {
printf(" Group %d, Elements %d, Material %d, NFlags %d\n", neu->groups[g].group, neu->groups[g].nelgp, neu->groups[g].mtyp, neu->groups[g].nflags);
printf(" Name: %s\n", neu->groups[g].name);
printf(" Flags: ");
for (int f = 0; f < neu->groups[g].nflags; f++) {
printf("%d ", neu->groups[g].flags[f]);
}
printf("\n Elements: ");
for (int e = 0; e < neu->groups[g].nelgp; e++) {
printf("%d ", neu->groups[g].elements[e]);
}
printf("\n");
}
printf("\nBoundary Sets:\n");
for (int b = 0; b < neu->control.nbsets; b++) {
printf(" Name: %s, Type: %d, Entries: %d, Values: %d\n", neu->boundarySets[b].name, neu->boundarySets[b].itype, neu->boundarySets[b].nentry, neu->boundarySets[b].nvalues);
printf(" IBCodes: %d %d %d %d %d\n", neu->boundarySets[b].ibcodes[0], neu->boundarySets[b].ibcodes[1], neu->boundarySets[b].ibcodes[2], neu->boundarySets[b].ibcodes[3], neu->boundarySets[b].ibcodes[4]);
for (int e = 0; e < neu->boundarySets[b].nentry; e++) {
if (neu->boundarySets[b].itype == 0) {
printf(" Node %d: ", neu->boundarySets[b].entries[e].elem_or_node);
} else {
printf(" Elem %d Type %d Face %d: ", neu->boundarySets[b].entries[e].elem_or_node, neu->boundarySets[b].entries[e].type, neu->boundarySets[b].entries[e].face);
}
for (int v = 0; v < neu->boundarySets[b].nvalues; v++) {
printf("%e ", neu->boundarySets[b].entries[e].values[v]);
}
printf("\n");
}
}
}
void writeNEU(const struct NEUFile *neu, const char *filename) {
FILE *fp = fopen(filename, "w");
if (!fp) {
perror("fopen");
exit(1);
}
// Write Control
fprintf(fp, "CONTROL INFO 1.2.1\n");
fprintf(fp, "%s\n", neu->control.header);
fprintf(fp, "%s\n", neu->control.title);
fprintf(fp, "%s\n", neu->control.programVersion);
fprintf(fp, "%s\n", neu->control.dateTime);
fprintf(fp, " NUMNP NELEM NGRPS NBSETS NDFCD NDFVL\n");
fprintf(fp, "%10d%10d%10d%10d%10d%10d\n", neu->control.numNP, neu->control.nelem, neu->control.ngrps, neu->control.nbsets, neu->control.ndfcd, neu->control.ndfvl);
fprintf(fp, "ENDOFSECTION\n");
// Write Nodal Coords
fprintf(fp, "NODAL COORDINATES 1.2.1\n");
for (int j = 0; j < neu->control.numNP; j++) {
fprintf(fp, "%10d %20.11e %20.11e %20.11e\n", neu->nodalCoords[j].id, neu->nodalCoords[j].coords[0], neu->nodalCoords[j].coords[1], neu->nodalCoords[j].coords[2]);
}
fprintf(fp, "ENDOFSECTION\n");
// Write Elements
fprintf(fp, "ELEMENTS/CELLS 1.2.1\n");
for (int j = 0; j < neu->control.nelem; j++) {
fprintf(fp, "%8d %2d %2d", neu->elements[j].id, neu->elements[j].type, neu->elements[j].ndp);
for (int k = 0; k < neu->elements[j].ndp; k++) {
fprintf(fp, " %8d", neu->elements[j].nodes[k]);
}
fprintf(fp, "\n");
}
fprintf(fp, "ENDOFSECTION\n");
// Write Groups
for (int g = 0; g < neu->control.ngrps; g++) {
fprintf(fp, "ELEMENT GROUP 1.2.1\n");
fprintf(fp, "GROUP: %10d ELEMENTS: %10d MATERIAL: %10d NFLAGS: %10d\n", neu->groups[g].group, neu->groups[g].nelgp, neu->groups[g].mtyp, neu->groups[g].nflags);
fprintf(fp, "%s\n", neu->groups[g].name);
for (int f = 0; f < neu->groups[g].nflags; f++) {
fprintf(fp, "%d ", neu->groups[g].flags[f]);
}
fprintf(fp, "\n");
for (int e = 0; e < neu->groups[g].nelgp; e++) {
fprintf(fp, "%8d", neu->groups[g].elements[e]);
if ((e + 1) % 10 == 0) fprintf(fp, "\n");
}
fprintf(fp, "\n");
fprintf(fp, "ENDOFSECTION\n");
}
// Write Boundary Sets
for (int b = 0; b < neu->control.nbsets; b++) {
fprintf(fp, "BOUNDARY CONDITIONS 1.2.1\n");
fprintf(fp, "%-32s %8d %8d %8d", neu->boundarySets[b].name, neu->boundarySets[b].itype, neu->boundarySets[b].nentry, neu->boundarySets[b].nvalues);
for (int c = 0; c < 5; c++) {
fprintf(fp, " %d", neu->boundarySets[b].ibcodes[c]);
}
fprintf(fp, "\n");
for (int e = 0; e < neu->boundarySets[b].nentry; e++) {
if (neu->boundarySets[b].itype == 0) {
fprintf(fp, "%10d", neu->boundarySets[b].entries[e].elem_or_node);
for (int v = 0; v < neu->boundarySets[b].nvalues; v++) {
fprintf(fp, " %20.12e", neu->boundarySets[b].entries[e].values[v]);
}
fprintf(fp, "\n");
} else {
fprintf(fp, "%10d %5d %5d", neu->boundarySets[b].entries[e].elem_or_node, neu->boundarySets[b].entries[e].type, neu->boundarySets[b].entries[e].face);
for (int v = 0; v < neu->boundarySets[b].nvalues; v++) {
fprintf(fp, " %20.12e", neu->boundarySets[b].entries[e].values[v]);
}
fprintf(fp, "\n");
}
}
fprintf(fp, "ENDOFSECTION\n");
}
fclose(fp);
}
// Free memory function (call after use)
void freeNEU(struct NEUFile *neu) {
free(neu->nodalCoords);
free(neu->elements);
for (int g = 0; g < neu->control.ngrps; g++) {
free(neu->groups[g].flags);
free(neu->groups[g].elements);
}
free(neu->groups);
for (int b = 0; b < neu->control.nbsets; b++) {
for (int e = 0; e < neu->boundarySets[b].nentry; e++) {
free(neu->boundarySets[b].entries[e].values);
}
free(neu->boundarySets[b].entries);
}
free(neu->boundarySets);
}
// Example usage
// int main() {
// struct NEUFile neu;
// readNEU(&neu, "input.neu");
// printNEUProperties(&neu);
// writeNEU(&neu, "output.neu");
// freeNEU(&neu);
// return 0;
// }
Note: This is a basic C implementation. Compile with gcc. Extend for more robust parsing and memory handling.