My first C++-code I wrote was a finite-element-solver ( in short FE ) for my master-thesis. The task was complex: implement a non-linear algorithm to calculate the maximum possible load for user-defined 2D-steal structures by using the plastical capacity of steal-beams. You can use this algorithm to design much more filigree steel-structures than using only the elastic capacity. This helps a lot to save steel and money.
The task in short:
- You need to write a FE-solver for 2D-beam-elements
- Calculate the forces and moments for your model
- Increase the loads until they reaches the boundary of the elastic capacity
- Add a joint there
- Goto 1 until the model collapses
Seems to be easy! So I said yes to my professor when he asked me. But It took 10 months to complete this task.
The first thing you need for this are vectors and matrixes. So I started to implement a vector- and a matrix-class. I need to reserve the number of elements dynamically. I looked around how to do this and I found: a linked list. Easy to add new elements to the end of the matrix / vector. Of course I used my own implementation, no STL or another implementation. In 2000 I didn’t found any books about the STL. The only book I had about C++ showed me a how to implement a linked-list. Unfortunately I made some more mistakes:
- All my linked-list implementations leaked memory. I completly forgot to release the allocated memory or to add some kind of RAII.
- There was not last-pointer showing to the last item in the list. So when I wanted to add a new element to a vector the class iterated through all items until it found the end of the list
- Each element was allocated with a separated new-call. So for a matrix with 500 elements I allocated 500 small double-values.
- Caused by this the access operator needed to iterate through all elements until it found the correct location
- And last but not least I introduced an index starting with one instead of zero.
The performance of this was a desaster. The models I used to validate my algorithm were small and I was able to get my diploma. And I learned a lot about c++.
So here are my most important things I learned during this task:
- You need to think about your performance: Even if the task you want to acomplish is not time-critical, finding the right datastructure to the right job is important: Forget “Premature optimization is the root of all evil.” You need to take care about your performance. If you are using random read-write access to your data choose a data-structure which has a complexity of 0(1) ( constant access time ).
- Try to make you core-concepts reusable. I wrote my linked-list access multible times and this made the redesign afterward to a really hard task. I used different implemtation of same same linked-list-concept:
- One for the nodes
- One for the elements
- One for the loads
- One for my matrix class
- And last but not least one for my vector
- Decouble the core-algorithms from your UI-code. If you want to reuse the code later you have to refactor a lot. Normally UI-stuff ( in this special case MFC ) is hard to move out afterwards when the software-architecture does not support this. I recomment to learn something about the passive-view pattern for instance if you want to do something like this ( you can find it here: https://martinfowler.com/eaaDev/PassiveScreen.html )
If you are unterested in this peace of software: you can find it on github: https://github.com/kimkulling/traglast