The main objective is to comply with the Software Requirements Specification. Within this goal, there are three levels of importance:
See the compilation instructions.
linux-x86_64
.Rule of Simplicity: Design for simplicity; add complexity only where you must.
C++ is a great language when used to solve problems it solves naturally well without being forced to solve it (see LibreBlackjack). C++ is a terrible language whenever else. It is messy, overwhelming, complicated, not robust and hard to debug (especially when using templates and this nightmare called smart pointers). The cons are far more than the pros. There is no need to add complexity.
Fortran is a terrible language. Fortran90+ is a patched FORTRAN 77. The assumptions that the language had over the kind of computers it has to run on worked in the early days but are now widely outdated. That’s it.
Go & Rust, I think still nobody knows for sure right now. But Rust’s automatic memory handling is not a point strong enough for CAE/DAE/FEA software.
C is the best language for FeenoX. Its assumptions still hold, especially in
In the late 1990s, Gerrit Blaauw and Fred Brooks observed in Computer Architecture: Concepts and Evolution [BlaauwBrooks] that the architectures in every generation of computers, from early mainframes through minicomputers through workstations through PCs, had tended to converge. The later a design was in its technology generation, the more closely it approximated what Blaauw & Brooks called the “classical architecture”: binary representation, flat address space, a distinction between memory and working store (registers), general-purpose registers, address resolution to fixed-length bytes, two-address instructions, big-endianness,[46] and data types a consistent set with sizes a multiple of either 4 or 6 bits (the 6-bit families are now extinct).
Thompson and Ritchie designed C to be a sort of structured assembler for an idealized processor and memory architecture that they expected could be efficiently modeled on most conventional computers. By happy accident, their model for the idealized processor was the PDP-11, a particularly mature and elegant minicomputer design that closely approximated Blaauw & Brooks’s classical architecture. By good judgment, Thompson and Ritchie declined to wire into their language most of the few traits (such as little-endian byte order) where the PDP-11 didn’t match it.[47]
The PDP-11 became an important model for the following generations of microprocessor architectures. The basic abstractions of C turned out to capture the classical architecture rather neatly. Thus, C started out as a good fit for microprocessors and, rather than becoming irrelevant as its assumptions fell out of date, actually became a better fit as hardware converged more closely on the classical architecture. One notable example of this convergence was when Intel’s 386, with its large flat memory-address space, replaced the 286’s awkward segmented-memory addressing after 1985; pure C was actually a better fit for the 386 than it had been for the 286.
It is not a coincidence that the experimental era in computer architectures ended in the mid-1980s at the same time that C (and its close descendant C++) were sweeping all before them as general-purpose programming languages. C, designed as a thin but flexible layer over the classical architecture, looks with two decades’ additional perspective like almost the best possible design for the structured-assembler niche it was intended to fill. In addition to compactness, orthogonality, and detachment (from the machine architecture on which it was originally designed), it also has the important quality of transparency that we will discuss in Chapter 6. The few language designs since that are arguably better have needed to make large changes (like introducing garbage collection) in order to get enough functional distance from C not to be swamped by it.
This history is worth recalling and understanding because C shows us how powerful a clean, minimalist design can be. If Thompson and Ritchie had been less wise, they would have designed a language that did much more, relied on stronger assumptions, never ported satisfactorily off its original hardware platform, and withered away as the world changed out from under it. Instead, C has flourished — and the example Thompson and Ritchie set has influenced the style of Unix development ever since. As the writer, adventurer, artist, and aeronautical engineer Antoine de Saint-Exupéry once put it, writing about the design of airplanes: «La perfection est atteinte non quand il ne reste rien à ajouter, mais quand il ne reste rien à enlever». (“Perfection is attained not when there is nothing more to add, but when there is nothing more to remove”.)
Therefore:
Stick to plain C.
C enables us to build data structures for storing sparse matrices, solver information, etc. in ways that Fortran simply does not allow. ANSI C is a complete standard that all modern C compilers support. The language is identical on all machines. C++ is still evolving and compilers on different machines are not identical. Using C function pointers to provide data encapsulation and polymorphism allows us to get many of the advantages of C++ without using such a large and more complicated language.
PETSc FAQs
https://www.mcs.anl.gov/petsc/documentation/faq.html#why-c
Keep C++ away.
C++ is a horrible language. It’s made more horrible by the fact that a lot of substandard programmers use it, to the point where it’s much much easier to generate total and utter crap with it. Quite frankly, even if the choice of C were to do nothing but keep the C++ programmers out, that in itself would be a huge reason to use C.
Linus Torvalds about why Git is written in C
http://harmful.cat-v.org/software/c++/linus
Libraries written in C++ are allowed as long as they provide C wrappers and do not meddle with stuff we do not need nor want.
Keep Fortran even farther away. It is allowed only for existing libraries dating from ancient well-tested and optimized code, but for nothing else.
Modern high-level languages like Python or Julia are targets and not sources of FeenoX.
For documentation and comments within the code, American English should be used.
To work on FeenoX using NetBeans, first make sure you have the C/C++ module working. If you don’t, do this:
In Netbeans go to Tools->Plugins->Settings. Entry NetBeans 8.2 Plugin Portal is already present. Click the checkbox next to this entry. Switch to Available Plugins tab, click Check for Newest. C/C++ is now on the list.
Then create a new C/C++ project File->New Project… choose C/C++
Project with Existing Sources click Next, browse to find the root
directory of your local FeenoX sources. It is important to have the
configure
script already created there, so make sure you
have run ./autogen.sh
. Make sure the configuration mode is
set to Automatic and that NetBeans detected the configure script by
adding “using configure” next to “Automatic.” Click to create the
project. This will create a directory nbproject
which will
be ignored by .gitignore
.
./configure && make
still works.The directory tests
contains the test suite with
shell scripts that return appropriate errorlevels according to Automake’s
generic test scripts. In a nutshell:
When no test protocol is in use, an exit status of 0 from a test script will denote a success, an exit status of 77 a skipped test, an exit status of 99 a hard error, and any other exit status will denote a failure.
If you add a new feature please also write a test script not just to check your feature works but to prevent further changes by other people (or even by yourself) from breaking the feature.
Try to make the check results meaningful and not just check for random results. Try to create tests cases with analytical solution or use benchmarks with known results.
We will eventually add some code coverage tools to have as most lines covered by at least one test.
K&R 1TBS with no tabs and two spaces per indent https://en.wikipedia.org/wiki/Indentation_style#Variant:_1TBS_(OTBS)
void checknegative(x) {
if (x < 0) {
("Negative");
puts} else {
(x);
nonnegative}
}
Do not worry about long lines. Only wrap lines when it makes sense to from a logic point of view not because “it looks bad on screen” because “screen” can be anything from a mobile phone to a desktop with many 24” LED monitors.
Make sure you understand and follow the 17 rules of Unix philosophy https://en.wikipedia.org/wiki/Unix_philosophy
Even though we use C, we can still have some “virtual methods” by using function pointers. So in a FEM formulation, the routines that build the stiffness matrix are mostly independent of the problem type (for the same family, say elliptic problems) but in the integrands. So a good practice is to have a common set of routines that loop over elements and over gauss points and then at the inner loop a virtual method is called which depends on the particular problem (thermal, mechanical, etc). This is accomplished by using function pointers so all problems have to provide more or less the same sets of routines: initialization, integrands, BCs, etc. See the basic problems to see how this idea works.
Reading and writing mesh/post-processing files work the same way. Each format has to provide a virtual reader/writer method.
Check all malloc()
calls for NULL
. You
can use the feenox_check_alloc()/feenox_check_alloc_null()
macros.
Use the macro feenox_free()
instead of plain
free()
. The former explicitly makes the pointer equal to
NULL
after freeing it, which is handy.
Use valgrind
to check for invalid memory access and
leaks
Memory analysis tools such as valgrind can be useful, but don’t complicate a program merely to avoid their false alarms. For example, if memory is used until just before a process exits, don’t free it simply to silence such a tool.
GNU Coding Standards
https://www.gnu.org/prep/standards/html_node/Memory-Usage.html
Mind that FeenoX might be used in parametric or minimization mode which would re-allocate some stuff so make sure you know which alarms you ignore.
Use snake case such as in
this_is_a_long_name
.
All functions ought to start with feenox_
. This is
the small price we need to pay in order to keep a magnificent beast like
C++ away from our lives (those who can). The names of functions should
go from general to particular such as
feenox_expression_parse()
and
feenox_expression_eval()
(and not
feenox_parse_expression()
/feenox_eval_expression()
)
so all function related with expressions can be easily found. There are
exceptions, like functions which do similar tasks such as
feenox_add_assignemnt()
and
feenox_add_instructions()
. Here the add
part
is the common one.
In a similar way, “virtual” methods should add the particularity at the end, like
feenox_build_element_volumetric_gauss_point()
—the
function pointer which is invoked in the codefeenox_build_element_volumetric_gauss_point_thermal()
—the
particular function the pointer will point to and which is actually
calledUse single-line comments //
to add comments to the
code so we can easily comment out certain parts of code using
multi-line comments /*
—*/
while developing new
features.
Explain any non-trivial block or flag that needs to be set. Example
switch (c = fgetc(file_ptr)) {
case '"':
// if there's an escaped quote, we take away the escape char
// and put a magic marker 0x1e, afterwards in get_next_token()
// we change back the 0x1e with the unescaped quote
.line[i++] = 0x1e; feenox_parser
Focus on the why and not on the how, except for very complex loops.
All nice-to-have things that are welcome to be done should be written as
// TODO: allow refreshing file data before each transit step
Features that might or might not be added should be written as questions
// TODO: should we allow unquoted names in the $PhysicalNames section?
Index | Loop over… |
---|---|
i |
elements or cells |
j |
nodes, either global or local. If there
are loops which need both, use j_local and
j_global . |
k |
dummy index |
d |
dimensions |
g |
degree of freedoms (from groups of energy actually) |
q |
Gauss (quadrature) points |
git
. This may seem obvious but
predecessors of this project have used Subversion, Bazaar and Mercurial
in that order. I have myself used CVS (in the past century).doc
directory.