-
I am trying to setup a simulation, yesterday somehow I got it working, now it fails and I don't understand why. All the files are here: fails.zip. This is how it looks like in AppCSXCAD (everything looks OK to the best of my understanding): When I look at the electric field with Paraview I only see this, no propagation along the line of PEC: This is the output of openEMS:
I am getting the warning # run_simulation.py
import math
import numpy
import os, tempfile, shutil
from pathlib import Path
from pylab import *
import csv
import CSXCAD
from openEMS import openEMS
from openEMS.physical_constants import *
import threading
import time
CSX = CSXCAD.ContinuousStructure()
FDTD = openEMS()
FDTD.SetCSX(CSX)
FDTD.SetBoundaryCond("PML_8","PML_8","PML_8","PML_8","PML_8","PML_8")
FDTD.SetStepExcite(1)
# MATERIALS AND GEOMETRY
air = CSX.AddMaterial('air')
air.SetMaterialProperty(epsilon=1, mue=1)
air.AddPolyhedronReader(Path(__file__).parent/'air.stl', priority=1).ReadFile()
FR4 = CSX.AddMaterial('FR4')
FR4.SetMaterialProperty(epsilon=4.5, mue=1)
FR4.AddPolyhedronReader(Path(__file__).parent/'substrate.stl', priority=2).ReadFile()
copper = CSX.AddMetal('PEC')
copper.AddPolyhedronReader(Path(__file__).parent/'copper.stl', priority=3).ReadFile()
# GRID LINES
CSX.grid.SetDeltaUnit(unit=1e-3) # Set unit to millimeter.
AIR_POSITION = numpy.array([-25,-17,-4]) # Position of bottom left cornrer.
AIR_SIZE = numpy.array([51,35,10]) # Cube size.
air_ends = AIR_POSITION + AIR_SIZE # Position of top right corner.
COPPER_TOP_BOTTOM_PART_Z = 1.6
COPPER_TOP_TOP_PART_Z = COPPER_TOP_BOTTOM_PART_Z + .035
COPPER_BOTTOM_TOP_PART_Z = 0
COPPER_BOTTOM_BOTTOM_PART_Z = COPPER_BOTTOM_TOP_PART_Z - .035
# Grid lines for the air:
for i,xyz in enumerate(['x','y','z']):
CSX.grid.AddLine(
xyz,
list(numpy.linspace(AIR_POSITION[i], air_ends[i], 33)),
)
# Grid lines for the track and the gaps with ground plane:
CSX.grid.AddLine(
'y',
list(numpy.linspace(-3,3,22)),
)
# Fine grid for copper top:
CSX.grid.AddLine(
'z',
list(numpy.linspace(COPPER_TOP_BOTTOM_PART_Z,COPPER_TOP_TOP_PART_Z,11)),
)
# Fine grid for copper bottom:
CSX.grid.AddLine(
'z',
list(numpy.linspace(COPPER_BOTTOM_BOTTOM_PART_Z,COPPER_BOTTOM_TOP_PART_Z,11)),
)
# Fine grid for substrate:
CSX.grid.AddLine(
'z',
list(numpy.linspace(0,1.6,11)),
)
# PORTS
port_in_start = numpy.array([-20,-.5,-.034])
port_out_start = numpy.array([20,-.5,-.034])
port_size = numpy.array([1,1,1.66])
# Port in:
FDTD.AddLumpedPort(
port_nr = 1,
R = 50, # Ohm
start = port_in_start, # mm
stop = port_in_start + port_size, # mm
p_dir = 'z',
excite = 5555, # V m⁻¹
)
# Port out:
# ~ FDTD.AddLumpedPort(
# ~ port_nr = 1,
# ~ R = 50, # Ohm
# ~ start = port_out_start, # mm
# ~ stop = port_out_start + port_size, # mm
# ~ p_dir = 'z',
# ~ excite = 0, # V m⁻¹
# ~ )
# Grid lines for the ports:
for i,xyz in enumerate(['x','y','z']):
CSX.grid.AddLine(
xyz,
list(numpy.linspace(port_in_start[i], (port_in_start+port_size)[i], 5)),
)
# ~ if xyz=='x': # Only the 'x' position is different for the port out.
# ~ CSX.grid.AddLine(
# ~ xyz,
# ~ list(numpy.linspace(port_out_start[i], (port_out_start+port_size)[i], 5)),
# ~ )
# PROBES
E_field_dump = CSX.AddDump(
name = 'E_field_probe',
dump_type = 'E_field_time_domain',
)
E_field_dump.AddBox(
list(AIR_POSITION)[0:2] + [0.8], # start
list(air_ends)[0:2] + [0.8], # stop
)
PATH_TO_SIMULATION_OUTPUT_FOLDER = Path(__file__).parent/'simulation_output'
CSX.Write2XML(PATH_TO_SIMULATION_OUTPUT_FOLDER/'CSX_model.xml')
OUTPUT_DATA_DIR = PATH_TO_SIMULATION_OUTPUT_FOLDER/'data'
simulation_ongoing = True
def delete_excess_of_files():
time.sleep(1)
while simulation_ongoing:
for p in sorted(OUTPUT_DATA_DIR.iterdir()):
if '.vtr' not in p.name:
continue
if int(p.name.split('_')[-1].replace('.vtr','')) % 1000 == 0:
continue
p.unlink()
remove_excess_of_files_thread = threading.Thread(target=delete_excess_of_files)
remove_excess_of_files_thread.start()
FDTD.Run(
sim_path = OUTPUT_DATA_DIR,
cleanup = True,
)
simulation_ongoing = False |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 17 replies
-
We can't reproduce your model because the STL files are missing. Some general FAQ on the "unused property or primitive" topic is is here: Have you fixed the "hollow STL object" issue discussed before? One other comment, unrealted to your question: did you also include the vias that connect top ground to bottom ground? |
Beta Was this translation helpful? Give feedback.
-
Hi, I checked your simulation and again it's due your STL files are hollow, have to reopen them in FreeCAD, import and make solid from them. It seems that application from which you are exporting them makes them hollow, actually long time ago with @0xCoto we figured that reason why STL files seems to be for openEMS hollow is that programs which are exporting them are not settings normal for each STL triangle face and therefore there are wrong normals defined and STL file is damaged. PrusaSlicer: https://www.prusa3d.com/page/prusaslicer_424/ I tried save it and it was probably ok but model was shifted outside of zour absolute defined coordinates :( Anyway your problem is that your original application is exporting damaged STL (it's not it's fault since to export STL model and have everythig OK on all possible models is quite hard) therefore you should use always FreeCAD or some other tool to repair your STL files before using them in simulation. Corrected simulation: pcb_transfer_signal_simulation.zip I went through your script and made some corrections, here is running version, also attaching my simulation. import numpy
from pathlib import Path
import CSXCAD
from openEMS import openEMS
import threading
import time
#LuboJ added to get current directory
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
CSX = CSXCAD.ContinuousStructure()
max_timesteps = 100e3
min_decrement = 1e-03 # 10*log10(min_decrement) dB (i.e. 1E-5 means -50 dB)
FDTD = openEMS(NrTS=max_timesteps, EndCriteria=min_decrement)
FDTD.SetCSX(CSX)
FDTD.SetBoundaryCond(["PML_8","PML_8","PML_8","PML_8","PML_8","PML_8"]) #LuboJ modified, changed to array
FDTD.SetStepExcite(1)
# MATERIALS AND GEOMETRY
air = CSX.AddMaterial('air')
air.SetMaterialProperty(epsilon=1, mue=1)
air.AddPolyhedronReader(os.path.join(dir_path, 'air.stl'), priority=1).ReadFile() #LuboJ modified path
FR4 = CSX.AddMaterial('FR4')
FR4.SetMaterialProperty(epsilon=4.5, mue=1)
FR4.AddPolyhedronReader(os.path.join(dir_path, 'substrate.stl'), priority=2).ReadFile() #LuboJ modified path
copper = CSX.AddMetal('PEC')
#original
#copper.AddPolyhedronReader(os.path.join(dir_path, 'copper.stl'), priority=3).ReadFile() #LuboJ modified path
#LuboJ corrected with FreeCAD
copper.AddPolyhedronReader(os.path.join(dir_path, 'topLayer.stl'), priority=3).ReadFile() #LuboJ modified path, make solids from object in FreeCAD, split to top and bottom to be able make solid
copper.AddPolyhedronReader(os.path.join(dir_path, 'bottomLayer.stl'), priority=3).ReadFile() #LuboJ modified path, make solids from object in FreeCAD, split to top and bottom to be able make solid
# GRID LINES
openEMS_grid = CSX.GetGrid() #LuboJ added
openEMS_grid.SetDeltaUnit(1e-3) # Set unit to millimeter. #LuboJ modified
AIR_POSITION = numpy.array([-25,-17,-4]) # Position of bottom left cornrer.
AIR_SIZE = numpy.array([51,35,10]) # Cube size.
air_ends = AIR_POSITION + AIR_SIZE # Position of top right corner.
COPPER_TOP_BOTTOM_PART_Z = 1.6
COPPER_TOP_TOP_PART_Z = COPPER_TOP_BOTTOM_PART_Z + .035
COPPER_BOTTOM_TOP_PART_Z = 0
COPPER_BOTTOM_BOTTOM_PART_Z = COPPER_BOTTOM_TOP_PART_Z - .035
def mesh():
x,y,z
mesh.x = numpy.array([]) # mesh variable initialization (Note: x y z implies type Cartesian).
mesh.y = numpy.array([])
mesh.z = numpy.array([])
# Grid lines for the air:
'''
for i,xyz in enumerate(['x','y','z']):
openEMS_grid.AddLine(
xyz,
list(numpy.linspace(AIR_POSITION[i], air_ends[i], 33)),
)
'''
mesh.x = numpy.linspace(AIR_POSITION[0], air_ends[0], 33)
mesh.y = numpy.linspace(AIR_POSITION[1], air_ends[1], 33)
mesh.z = numpy.linspace(AIR_POSITION[2], air_ends[2], 33)
#LuboJ remove all gridlines from AIR which are between top copper to bottom copper to not randomly generate two lines too close each other
mesh.z = numpy.delete(mesh.z, numpy.argwhere((mesh.z >= COPPER_BOTTOM_BOTTOM_PART_Z) & (mesh.z <= COPPER_TOP_TOP_PART_Z)))
# Grid lines for the track and the gaps with ground plane:
'''
openEMS_grid.AddLine(
'y',
list(numpy.linspace(-3,3,22)),
)
'''
mesh.y = numpy.delete(mesh.y, numpy.argwhere((mesh.y >= -3.2) & (mesh.y <= 3.2))) #LuboJ, first remove lines from area where is fine meshing
mesh.y = numpy.concatenate((mesh.y, numpy.linspace(-3,3,11)))
# Fine grid for copper top:
'''
openEMS_grid.AddLine(
'z',
list(numpy.linspace(COPPER_TOP_BOTTOM_PART_Z,COPPER_TOP_TOP_PART_Z,1)), #LuboJ line count changed 11 -> 1
)
'''
#mesh.z = numpy.concatenate((mesh.z, numpy.linspace(COPPER_TOP_BOTTOM_PART_Z, COPPER_TOP_TOP_PART_Z, 1)))
mesh.z = numpy.concatenate((mesh.z, [(COPPER_TOP_BOTTOM_PART_Z+COPPER_TOP_TOP_PART_Z)/2]))
# Fine grid for copper bottom:
'''
openEMS_grid.AddLine(
'z',
list(numpy.linspace(COPPER_BOTTOM_BOTTOM_PART_Z,COPPER_BOTTOM_TOP_PART_Z,1)), #LuboJ line count changed 11 -> 1
)
'''
#mesh.z = numpy.concatenate((mesh.z, numpy.linspace(COPPER_BOTTOM_BOTTOM_PART_Z, COPPER_BOTTOM_TOP_PART_Z, 1)))
mesh.z = numpy.concatenate((mesh.z, [(COPPER_BOTTOM_BOTTOM_PART_Z+COPPER_BOTTOM_TOP_PART_Z)/2]))
# Fine grid for substrate:
'''
openEMS_grid.AddLine(
'z',
list(numpy.linspace(0,1.6,11)),
)
'''
substrateZLittleShift = 0.35
mesh.z = numpy.concatenate((mesh.z, numpy.linspace(0+substrateZLittleShift, 1.6-substrateZLittleShift, 3)))
openEMS_grid.AddLine('x', mesh.x)
openEMS_grid.AddLine('y', mesh.y)
openEMS_grid.AddLine('z', mesh.z)
# PORTS
port_in_start = numpy.array([-20,-.5,-.034])
port_out_start = numpy.array([20,-.5,-.034])
port_size = numpy.array([1,1,1.66])
# Port in:
FDTD.AddLumpedPort(
port_nr = 1,
R = 50, # Ohm
start = port_in_start, # mm
stop = port_in_start + port_size, # mm
p_dir = 'z',
excite = 5555, # V m⁻¹
)
# Port out:
# ~ FDTD.AddLumpedPort(
# ~ port_nr = 1,
# ~ R = 50, # Ohm
# ~ start = port_out_start, # mm
# ~ stop = port_out_start + port_size, # mm
# ~ p_dir = 'z',
# ~ excite = 0, # V m⁻¹
# ~ )
FDTD.AddLumpedPort(
port_nr = 1,
R = 50, # Ohm
start = port_out_start, # mm
stop = port_out_start + port_size, # mm
p_dir = 'z',
excite = 0, # V m⁻¹
)
# Grid lines for the ports:
'''
for i,xyz in enumerate(['x','y','z']):
openEMS_grid.AddLine(
xyz,
list(numpy.linspace(port_in_start[i], (port_in_start+port_size)[i], 5)),
)
# ~ if xyz=='x': # Only the 'x' position is different for the port out.
# ~ CSX.grid.AddLine(
# ~ xyz,
# ~ list(numpy.linspace(port_out_start[i], (port_out_start+port_size)[i], 5)),
# ~ )
'''
openEMS_grid.AddLine('y', port_in_start[1]+port_size[1]/2)
openEMS_grid.AddLine('x', port_in_start[0]+port_size[0]/2)
openEMS_grid.AddLine('x', port_out_start[0]+port_size[0]/2) #LuboJ port out is not added now
# PROBES
E_field_dump = CSX.AddDump(
name = 'E_field_probe',
dump_type = 0, #LuboJ change to 0 = E-field probe
)
E_field_dump.AddBox(
list(AIR_POSITION)[0:2] + [0.8], # start
list(air_ends)[0:2] + [0.8], # stop
)
PATH_TO_SIMULATION_OUTPUT_FOLDER = os.path.join(dir_path, 'simulation_output') #LuboJ modified
if not os.path.exists(PATH_TO_SIMULATION_OUTPUT_FOLDER):
os.makedirs(PATH_TO_SIMULATION_OUTPUT_FOLDER)
CSX_file = os.path.join(PATH_TO_SIMULATION_OUTPUT_FOLDER, 'CSX_model.xml')
CSX.Write2XML(CSX_file)
[pcb_transfer_signal_simulation.zip](https://github.com/user-attachments/files/17611990/pcb_transfer_signal_simulation.zip)
OUTPUT_DATA_DIR = os.path.join(PATH_TO_SIMULATION_OUTPUT_FOLDER, 'data')
if not os.path.exists(OUTPUT_DATA_DIR):
os.makedirs(OUTPUT_DATA_DIR)
simulation_ongoing = True
'''
def delete_excess_of_files():
time.sleep(1)
while simulation_ongoing:
for p in sorted(OUTPUT_DATA_DIR.iterdir()):
if '.vtr' not in p.name:
continue
if int(p.name.split('_')[-1].replace('.vtr','')) % 1000 == 0:
continue
p.unlink()
remove_excess_of_files_thread = threading.Thread(target=delete_excess_of_files)
remove_excess_of_files_thread.start()
'''
from CSXCAD import AppCSXCAD_BIN
os.system(AppCSXCAD_BIN + ' "{}"'.format(CSX_file))
FDTD.Run(
sim_path = OUTPUT_DATA_DIR,
cleanup = True,
setup_only = True #LuboJ, if True it will not run simulation
)
simulation_ongoing = False |
Beta Was this translation helpful? Give feedback.
@LubomirJagos42 I found a (hopefully) reliable solution for the hollow STL issue after asking here in the FreeCAD forum. Summary:
For me in step 2 I have to select the option "Mefisto" and then up to now any "maximum edge length" is working. The default option "standard" produces a mesh that does not pass step 3, and when exported it fails with openEMS.
Step 3 can be …