7.4. Notes¶
Library Design
modular design with multiple submodules
plotting and TraceGUI are independent of the tracing backend
automation/scripting easily possible
platform independent and open source
importing only the backend tracing functionality does not import GUI and plotting libraries. This ensures better performance and enables us to use this functionality without ever needing to install this heavy libraries when they are never needed.
Dependencies
balance of minimizing dependencies while also trying not to implement too much manually
outsource GUI and plotting functionality/backend to external libraries
tracing, color conversion, geometry manipulations etc. are implemented in library itself
prefer python standard libraries
only use open source dependencies
Documentation Style
publication-like design
LaTeX equations (🠪 MathJax)
citations and bibliography (ideally per webpage)
clickable references to sections, table, equations, citations
keyword/topic index
no use of external images (so no copyright/licensing issues)
Graphical Outputs
professional, publication-like plots
prefer serif fonts (e.g. Times New Roman)
use LaTeX formatted equations/labels
highlight more important elements by colors, font size or boldness
axes, minor and major grid lines, titles and legend are a must
block
function allows for halting the rest of the program when plottingoptions for hiding some visual elements (labels, axes in GUI, legend entries)
prefer svg for self-created figures, png for screenshots and webp for rendered images
use tinypng to shrink pngs for the webpage, vecta.io for pyplot svgs
in some cases there are issues with webp output in chromatic channels, export in lossless webp in these cases
Multithreading and Multiprocessing
outsource heavy tasks onto multiple cores
- prefer threads over processes (no copying overhead). However we need to:
ensure there are no race conditions by using locks or by ensuring each thread writes on a different memory location
minimize python code (because of the GIL limitation while multithreading). Use lower level libraries with like numpy
all worker and background threads need to terminate immediately when the main thread has ended This is ensured by providing
daemon=True
while creating theThread
object.multithreading should be controlled with a
multithreading
global option- threading rules for
TraceGUI
, with some ideas from traits Futures GUI changes only in main thread
GUI must be responsive at all costs
simplified Read/Write access model: only one thread can read and write
no locks in the main thread, waiting for locks only in worker threads
- threading rules for
Performance and Memory
use of multithreading
numpy
where possibleavoid loops
work with object references when possible (instead of copies)
use masks on arrays instead of creating new ones
only do calculations on elements actually needed
pre-allocation instead of growing an array step by step
use
np.float32
orint
instead ofnp.float64
where high precision is not neededprefer analytical solutions instead of iterative numerical approximations
multi-dimensional array access can be accelerated by choosing a specific memory layout of the
numpy.ndarray
(order="F", order="C"
etc.)always keep the GUI responsive
range indexing (
array[52:79829]
) is faster than boolean indexing (array[[False, False, True, ..., True, False]]
, which is faster than indexing by index list (array[[52, 456, 897987, 0, 77, ...]]
)a reasonable amount of points and curves in plots
limit array sizes
File Input/Output
OS independent file names
store under a fallback path when files exists or can’t be written
write file in one go, don’t append iteratively
use external libraries for loading special files (images, spreadsheets etc.)
use compressed numpy archives (
.npz
) to save some spacetry to detect the correct text encoding before loading any clear text formats. Outsource this to chardet
Type and Value Checking
functions and classes that are exposed to the user should have type and value checking
- some people will tell you “this is not the pythonic way”, however:
clear error messages are more helpful than debugging for 20 minutes
some values produce results that are valid mathematically, but impossible according to physics (e.g. negative energies, zero sized geometries etc.).
even I as developer do not remember the types and value ranges for all parameters and the correct function usage
Object and Geometry Locks
- Class functions change parameters of the object itself, assigning parameters directly to the object can break things. Hard to debug, very frustrating.
e.g. the surface height depends on the surface parameters. Changing one without the other leads to very weird issues
This however depends on the parameters/variables and their roles.
Some parameters are even read-only.
a change is not propagated to the parent/child object
we can’t expect the user to know where assignments are possible without side effects and where not.
- ➜ restricting assignments
lock the geometry of an
Element
, surfaces can only be assigned by special functions, the position can only be changed with a dedicated methodlock objects like a
Surface
to avoid nasty side effectsallow assignments where possible
make numpy arrays read-only while locking
locking can still be turned off manually when knowing about the internal mechanism, but at that point the user should have noticed that changing the code in such a way was not intended by the library
Coding Style
CamelCase
class names,lower_case_with_underscores
for functions, filenames, parameters. Note that the latter this is not always possible for mathematical or physical quantities with standardized symbolsincreased line length of 120 characters
prefer writing out keyword arguments (
function(width=1026, height=4596)
) for readability and simpler documentationuse of docstrings for functions, classes and important variables
Standard Output
functions and classes output information and warnings to the terminal
warnings have an own type
OptraceWarning
and can be silenced with a global optionshow_warnings
the progressbar should only used for more time-intensive tasks and can be turned off with the
show_progressbar
option.
Responsiveness
- some actions need time, but the program should still appear active and responsive. Hence, we need to notify the user with:
a message that something has been started / processed/ approved
a progress bar indicating the progress and estimated remaining time. Also distracts the user, lowering the subjective waiting time
TraceGUI actions like tracing, focussing etc. need to run in background threads, so the scene and main UI thread are responsive