#!/usr/bin/env python3
"""
This file is part of the PAFFrontendSim.
The PAFFrontendSim is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3 as published by the Free Software Foundation.
The PAFFrontendSim is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with the PAFFrontendSim. If not, see https://www.gnu.org/licenses/.
"""
#############################################################################
#
# including c-code library for fast calculation of electromagnetic wave propagation from surface to surface
# and providing all necessay data-typed to operate it
#
#
#############################################################################
# ToDo
#############################################################################
# - clean-up code (frequently and regularly, please)
# - improve readability and add more comments (frequently and regularly)
#
# single task-changes / add-ons
# - add geometric trace
#
#############################################################################
# import libs
#############################################################################
from ctypes import *
import subprocess
from copy import copy, deepcopy
import LogClass
from Simulation.constants import _pythonPath
#############################################################################
# constants
#############################################################################
_CLASSNAME = "UFO-CCode"
# import c-code (and compile it if necessary)
log = LogClass.LogClass(_CLASSNAME) # documentation class used for all in and output messages
try:
libCalc = CDLL(_pythonPath + "/src/Libs/Simulation/UFO/C-includes/libUFO.so")
except:
log.printOut(" C-library not found, try to compile it", log.WARNING_TYPE, False)
try:
x = subprocess.call("gcc -Wall -Ofast -shared -o %s/src/Libs/Simulation/UFO/C-includes/libUFO.so -fPIC -fopenmp -lm -lc %s/src/Libs/Simulation/UFO/C-includes/UFO_calc.c" %(_pythonPath, _pythonPath), shell = True)
libCalc = CDLL(_pythonPath + "/src/Libs/Simulation/UFO/C-includes/libUFO.so")
except:
libCalc = None
if libCalc == None :
log.printOut(" C-library not available (can't be compiled and included", log.ERROR_TYPE, False)
else :
log.printOut(" C-library sucessfully included", log.FLOW_TYPE, False)
def _cCalc_setLog ( newlog ) :
global log
log = deepcopy(newlog) # logging class used for all in and output messages
log.addLabel( _CLASSNAME )
#############################################################################
# classes
#############################################################################
class _UFOVector(Structure) :
_fields_ = [("x", c_double), ("y", c_double), ("z", c_double)]
class _UFOMatrix(Structure) :
_fields_ = [("vx", _UFOVector), ("vy", _UFOVector), ("vz", _UFOVector)]
[docs]
class UFODataPoint(Structure) :
_fields_ =[
("v", _UFOVector),
("n", _UFOVector),
("Jr", _UFOVector),
("Ji", _UFOVector),
("Er", _UFOVector),
("Ei", _UFOVector),
("Jtr", _UFOVector),
("Jti", _UFOVector),
("df", c_double),
("I", c_double)
]
#############################################################################
# setup method calls on c-library
#############################################################################
# for calculating a current distribution
cCalc_CurrentDist = libCalc.Calc_CurrentDist
cCalc_CurrentDist.argtypes = [
POINTER(UFODataPoint), # Surface 1
POINTER(UFODataPoint), # Surface 2
c_int, # number of points in Surface 1
c_int, # number of points in Surface 2
c_double, # wavelength of the calculation
c_double, # e_r of the material on the incomming ray
c_double, # tangens Delta of the material
c_int # adding up to previous data (< 0) or not
]
cCalc_CurrentDist.restype = None
# full simulation for transmission and reflection
cCalc_CurrentDistFull = libCalc.Calc_CurrentDistFull
cCalc_CurrentDistFull.argtypes = [
POINTER(UFODataPoint), # Surface 1
POINTER(UFODataPoint), # Surface 2
c_int, # number of points in Surface 1
c_int, # number of points in Surface 2
c_double, # wavelength of the calculation
c_double, # e_r of the material on the incomming ray,
c_double, # e_r of the material on the outgoing ray,
c_double, # tangens Delta of the material
c_int # adding up to previous data (< 0) or not
]
cCalc_CurrentDistFull.restype = None
# for moving a surface
cMove = libCalc.move
cMove.argtypes = [
POINTER(UFODataPoint), # Surface
c_int, # number of points in Surface
_UFOVector # vector to add
]
cMove.restype = None
# for matrix transforming a surface (e.g. rotation)
cTransform = libCalc.transform
cTransform.argtypes = [
POINTER(UFODataPoint), # Surface
c_int, # number of points in Surface
_UFOMatrix # transformation matrix
]
cTransform.restype = None
def _cCalc_CurrentDist(Data, new, points, wavelength, er, tanD, number):
cCalc_CurrentDist(Data, new.Data, points, new.points , wavelength, er, tanD, number) # for calculating a current distribution
return new
def _cMove(Data, points, UFOVector):
cMove(Data, points, UFOVector) # for moving a surface
return Data, points
def _cTransform(Data, points, UFOMatrix):
cTransform(Data, points, UFOMatrix) # for matrix transforming a surface (e.g. rotation)
return Data, points
def _cCalc_CurrentDistFull(obj, new, wavelength = -1, add = False, trans = False):
"""
Calculate a current distribution on object new, starting with the current distribution on object obj
Parameters:
obj (UFODataClass) : Object to start with
new (UFODataClass) : Object to calculate the current distribution on
wavelength (float) : simulation wavelength; if negative, wavelength of object obj is used
add (bool) : if true, the new currents and fields will be added to the fields and currents existing on object new already.
trans (bool) : if true, using transmittance data of object 'obj' for the simulation
"""
erIn = 1.
tanD = 0.
if isinstance(obj.er, (float, int, complex) ) :
erIn = obj.er
if isinstance(obj.tanD, (float, int, complex) ) :
tanD = obj.tanD
if isinstance(new.er, (float, int, complex) ) :
erOut = new.er
else:
erOut = erIn
# check if transmitted field should be used
if trans :
# and rearange data and invert normal vector if so
obj = deepcopy( obj )
for idx, d in enumerate( obj.Data ) :
obj.Data[idx].Jr = d.Jtr
obj.Data[idx].Ji = d.Jti
obj.Data[idx].n.x *= -1.
obj.Data[idx].n.y *= -1.
obj.Data[idx].n.z *= -1.
number = 0
if add:
number = 1
if wavelength < 0 :
wavelength = obj.Wavelength
if True : #erOut == erIn :
log.printOut("Using reflection simulation only", log.FLOW_TYPE, False)
cCalc_CurrentDist ( obj.Data, new.Data, obj.points, new.points , wavelength, erIn, tanD, number )
else :
log.printOut("Using full simulation", log.FLOW_TYPE, False)
cCalc_CurrentDistFull( obj.Data, new.Data, obj.points, new.points , wavelength, erIn, erOut, tanD, number )
if not trans : # das ist falsch, man braucht zwei Speicherplätze für Permittivity bei Current-Files
new.er = erIn
return new