So far we have defined an interface in the class LinearSolver and then implemented it for different solvers: UMFPACK, TAUCS, MUMPS and PARDISO. The implementation in solver_*.cpp uses solvers.h but the application code actually needs almost nothing from these files. The word almost means that it is still necessary to instantiate a particular solver class and this will be achieved by means of a static function
LinearSolver::create. Let us consider its definition in solvers.cpp.
First there are declarations of functions
make_*(). These functions have been defined within the solver implementation. Then in the code of the function
LinearSolver* LinearSolver::create(const string &s);
the map between a string and a function is created and is employed to find the right function for the solver specified in the function argument. For example
LinearSolver *mumps = LinearSolver::create("MUMPS");
create a pointer that will be working with the MUMPS solver. This way the application code is completely independent from the solver definitions. Let us imagine that we add a new solver by deriving it from
LinearSolver and programming it in solver_new.cpp. We need to modify
LinearSolver::create indeed to be able to instantiate the new solver but we do not have to recompile the application code. It will be just enough to relink it for example with a new library.
Another feature of solvers.cpp is the use of preprocessor directives that check if macros USEUMFPACK, USETAUCS, USEMUMPS and USEPARDISO are defined. This allows us at compile time to use only part of solvers. Imagine that for a particular application it would be enough only TAUCS and MUMPS. Then
$ cc -DUSETAUCS -DUSEMUMPS -c solvers.cpp
does the trick and the application must be linked with TAUCS and MUMPS only.