diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4d46632e99820cc85b44076780142a6303686a10..1290ed98787377eea7d54f12d05b94eff0aeaf2f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,14 +18,15 @@ workflow:
     - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
 
 stages:
+   - compatibility
    - build
    - run
    - test
 
-building_stage:
-   stage: build
+compatibility_stage:
+   stage: compatibility
    tags: ["np-tmcode"]
-   allow_failure: false
+   allow_failure: true
    artifacts:
       paths:
          - build/cluster/*
@@ -33,7 +34,6 @@ building_stage:
          - build/testing/*
          - build/trapping/*
          - build/libnptm/*
-         - doc/build/*
       exclude:
          - ".git*"
          - ".git/**/*"
@@ -52,18 +52,44 @@ building_stage:
       - echo "Running make with gnu compilers version 12..."
       - make clean && BUILDDIR=$PWD/../build_gnu12 CXX=g++-12 FC=gfortran-12 make -j
       - echo "Running make with flang version 16 and clang version 13..."
-      - make clean && BUILDDIR=$PWD/../build_clang13-flang16 CXX="clang++-13 -stdlib=libc++" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS=-L/usr/lib/llvm-16/lib make -j
+      - make clean && BUILDDIR=$PWD/../build_clang13-flang16 CXX="clang++-13 -stdlib=libstdc++ -I/usr/include/c++/12 -I/usr/include/x86_64-linux-gnu/c++/12" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS="-L/usr/lib/llvm-16/lib -L/usr/lib/gcc/x86_64-linux-gnu/12" make -j
       - echo "Running make with flang version 16 and clang version 14..."
-      - make clean && BUILDDIR=$PWD/../build_clang14-flang16 CXX="clang++-14 -stdlib=libc++" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS=-L/usr/lib/llvm-16/lib make -j
+      - make clean && BUILDDIR=$PWD/../build_clang14-flang16 CXX="clang++-14 -stdlib=libstdc++ -I/usr/include/c++/12 -I/usr/include/x86_64-linux-gnu/c++/12" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS="-L/usr/lib/llvm-16/lib -L/usr/lib/gcc/x86_64-linux-gnu/12" make -j
       - echo "Running make with flang version 16 and clang version 15..."
-      - make clean && BUILDDIR=$PWD/../build_clang15-flang16 CXX="clang++-15 -stdlib=libc++" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS=-L/usr/lib/llvm-16/lib make -j
+      - make clean && BUILDDIR=$PWD/../build_clang15-flang16 CXX="clang++-15 -stdlib=libstdc++ -I/usr/include/c++/12 -I/usr/include/x86_64-linux-gnu/c++/12" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS="-L/usr/lib/llvm-16/lib -L/usr/lib/gcc/x86_64-linux-gnu/12" make -j
       - echo "Running make with flang version 16 and clang version 16..."
-      - make clean && BUILDDIR=$PWD/../build_clang16-flang16 CXX="clang++-16 -stdlib=libc++" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS=-L/usr/lib/llvm-16/lib make -j
+      - make clean && BUILDDIR=$PWD/../build_clang16-flang16 CXX="clang++-16 -stdlib=libstdc++ -I/usr/include/c++/12 -I/usr/include/x86_64-linux-gnu/c++/12" FC=flang-new-16 FCFLAGS=-O3 LDFLAGS="-L/usr/lib/llvm-16/lib -L/usr/lib/gcc/x86_64-linux-gnu/12" make -j
       - echo "Running make with Intel ifort and Intel icpx..."
       - make clean && PATH=/opt/intel/oneapi/compiler/latest/bin:$PATH BUILDDIR=$PWD/../build_ifort-icpx CXX=icpx FC=ifort FCFLAGS="-O3 -diag-disable=10448" make -j
       - echo "Running make with Intel ifx and Intel icpx..."
       - make clean && LD_LIBRARY_PATH=/opt/intel/oneapi/compiler/latest/lib PATH=/opt/intel/oneapi/compiler/latest/bin:$PATH BUILDDIR=$PWD/../build_ifx-icpx CXX=icpx FC=ifx FCFLAGS=-O3 make -j
-      - echo "Finally running make with default compilers..."
+   
+building_stage:
+   stage: build
+   tags: ["np-tmcode"]
+   allow_failure: false
+   artifacts:
+      paths:
+         - build/cluster/*
+         - build/sphere/*
+         - build/testing/*
+         - build/trapping/*
+         - build/libnptm/*
+         - doc/build/*
+      exclude:
+         - ".git*"
+         - ".git/**/*"
+      expire_in: 2 hours
+   script:
+      # bash commands to be executed
+      - pwd
+      - hostname
+      - echo $CI_COMMIT_SHA
+      - echo $CI_COMMIT_BRANCH
+      - echo "Getting system info ..."
+      - cat /etc/os-release
+      - cd src
+      - echo "Running make with default compilers..."
       - make clean && make -j
       - make docs -j && make -C ../doc/build/latex -j
 
@@ -135,6 +161,9 @@ testing_stage:
       - python3 ../../src/scripts/pycompare.py --ffile=$FFILE --cfile=c_OCLU --html
       - echo "Testing cluster with 24 spheres"
       - ./np_cluster ../../test_data/cluster/DEDFB_24 ../../test_data/cluster/DCLU_24 .
+      - echo "Comparing output of CLUSTER with 24 spheres"
+      - export FFILE=../../test_data/cluster/OCLU_24
+      - python3 ../../src/scripts/pycompare.py --ffile=$FFILE --cfile=c_OCLU --html
       - echo "Checking consistency among legacy and HDF5 configuration files"
       - ../testing/test_TEDF ../../test_data/cluster/DEDFB_24 c_TEDF c_TEDF.hd5
       - echo "Checking consistency among legacy and HDF5 TM files"
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..f288702d2fa16d3cdf0035b15a9fcbc552cd88e7
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/README.md b/README.md
index 15766ce3810b67aaa98dd64ac920233c06b0e1ee..cef20a5bc75eb48a494148946e1c6f438e2b86c6 100644
--- a/README.md
+++ b/README.md
@@ -7,3 +7,7 @@ The aim of the project, funded by PNRR-CNS, is to refactor the original, very ol
 The current implementation offers a set of elementary tests to check that the original FORTRAN code can be compiled and executed on a limited set of pre-defined input data. The functionality of this initial stage can be verified by cloning the gitLab repository on a local machine and building the binaries from the `src` folder.
 
 *NOTE:* The building process requires a working installation of the GNU Compiler Collection (`gcc`), of the GNU FORTRAN compiler (`gfortran`) and of the GNU `make` builder.
+
+# License
+
+This project is distributed under the terms of the *GNU General Public License V3.0 or later* (GPL-3.0-or-later). Check the contents of the *COPYING* file for further details.
\ No newline at end of file
diff --git a/build/README.md b/build/README.md
index 2596e698074726fbfbb035f1f95fe7a13d44335a..bd4fe07fd2a7db8b7b645a23a001180531071154 100644
--- a/build/README.md
+++ b/build/README.md
@@ -1,3 +1,5 @@
+Distributed under the terms of *GNU GPL-3.0-or-later*
+
 # Folder instructions
 
 This directory collects all the output of make builds.
diff --git a/containers/docker/Dockerfile b/containers/docker/Dockerfile
index 0d11a3db77d31a6b386bd70f968cd038efb82a6e..2f528d227e1881262a3297663a697b13d9ef5ffe 100644
--- a/containers/docker/Dockerfile
+++ b/containers/docker/Dockerfile
@@ -18,6 +18,8 @@ COPY --chown=root:root containers/docker/dockerstuff/intelcomps/oneapi-archive-k
 COPY --chown=root:root containers/docker/dockerstuff/intelcomps/oneAPI.list /etc/apt/sources.list.d/
 RUN apt update
 RUN DEBIAN_FRONTEND=noninteractive apt -y install intel-oneapi-compiler-fortran intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic intel-oneapi-compiler-dpcpp-cpp
+# install lapacke and its dependencies, both standard and the version with 64 bit integers
+RUN DEBIAN_FRONTEND=noninteractive apt -y install liblapacke-dev liblapacke64-dev libopenblas-dev libopenblas-openmp-dev libopenblas64-dev libopenblas64-openmp-dev
 # install packages needed to run python scripts for checks
 RUN DEBIAN_FRONTEND=noninteractive apt -y install python3 python-is-python3 python3-regex
 # install packages needed to run doxygen to create html docs
@@ -51,7 +53,7 @@ FROM  debian:bookworm-slim AS np-tmcode-run-minimal
 WORKDIR /root
 # install the strictly needed runtime libraries needed to run the executables
 # and the python check scripts
-RUN DEBIAN_FRONTEND=noninteractive apt update && DEBIAN_FRONTEND=noninteractive apt upgrade && DEBIAN_FRONTEND=noninteractive apt -y install libgfortran5 libgcc-s1 libhdf5-103-1 libstdc++6 libssl3 libcurl4 libsz2 zlib1g libnghttp2-14 libidn2-0 librtmp1 libssh2-1 libpsl5 libgssapi-krb5-2 libldap-2.5-0 libzstd1 libbrotli1 libaec0 libunistring2 libgmp10 libkrb5-3 libk5crypto3 libcom-err2 libkrb5support0 libsasl2-2 libp11-kit0 libtasn1-6 libkeyutils1 libffi8 python3 python-is-python3 python3-regex hdf5-tools && rm -rf /var/lib/apt/lists/*
+RUN DEBIAN_FRONTEND=noninteractive apt update && DEBIAN_FRONTEND=noninteractive apt upgrade && DEBIAN_FRONTEND=noninteractive apt -y install libgfortran5 libgcc-s1 libhdf5-103-1 libstdc++6 libssl3 libcurl4 libsz2 zlib1g libnghttp2-14 libidn2-0 librtmp1 libssh2-1 libpsl5 libgssapi-krb5-2 libldap-2.5-0 libzstd1 libbrotli1 libaec0 libunistring2 libgmp10 libkrb5-3 libk5crypto3 libcom-err2 libkrb5support0 libsasl2-2 libp11-kit0 libtasn1-6 libkeyutils1 libffi8 liblapacke64 libopenblas64-0-openmp python3 python-is-python3 python3-regex hdf5-tools && rm -rf /var/lib/apt/lists/*
 COPY --from=np-tmcode-run-dev /root /root
 # remove everything which is not needed to run the codes
 RUN cd /root/np-tmcode && find build -name "*.o" -exec rm -v \{\} \; && find build -name "*.gcno" -exec rm -v \{\} \; && cd src && rm -rvf cluster libnptm trapping include sphere Makefile make.inc README.md && cd .. && rm -rvf containers && cd doc && rm -rvf src && cd build/latex && rm -rvf *.tex *.out *.sty *.ind *.log *.toc *.ilg *.idx *.aux *.eps Makefile class*.pdf
diff --git a/containers/docker/README.md b/containers/docker/README.md
index c6bf1c9e9fc5bfbab6156a968259e6c0f66c386a..555a487d89a97d85acd42a412e535e3ba6e383ff 100644
--- a/containers/docker/README.md
+++ b/containers/docker/README.md
@@ -1,3 +1,5 @@
+Distributed under the terms of *GNU GPL-3.0-or-later*
+
 # Docker support for the NP-TMcode project
 
 This Dockerfile allows to create mainly:
diff --git a/containers/singularity/README.md b/containers/singularity/README.md
index 04cfdfe1108d63f93ebe707d6f35a5eb1956d580..20e9767c4df0e96126e41ef74e1b3b4b941dda42 100644
--- a/containers/singularity/README.md
+++ b/containers/singularity/README.md
@@ -1,3 +1,5 @@
+Distributed under the terms of *GNU GPL-3.0-or-later*
+
 # Singularity support for the NP-TMcode project
 
 This `np-tmcode-run.def` file allows to create a np-tmcode-run image, that contains only the pre-built executables, python test scripts, compiled documentation, and the minimal runtime to run them
diff --git a/containers/singularity/np-tmcode-run.def b/containers/singularity/np-tmcode-run.def
index da7025e0dd6899c8bf0698ec4615cb923bcc01ad..b9e3736ac27ea223c99de20775bbc7b739cc0a32 100644
--- a/containers/singularity/np-tmcode-run.def
+++ b/containers/singularity/np-tmcode-run.def
@@ -11,7 +11,7 @@ Stage: np-tmcode-run-dev
 %post
 	apt update
 	apt -y upgrade
-	apt -y install g++ gfortran make gcc-offload-nvptx libhdf5-dev
+	apt -y install g++ gfortran make gcc-offload-nvptx libhdf5-dev liblapacke-dev liblapacke64-dev libopenblas-dev libopenblas-openmp-dev libopenblas64-dev libopenblas64-openmp-dev
 	apt -y install python3 python-is-python3 python3-regex
 	apt -y install doxygen
 	apt -y install texlive-latex-base texlive-latex-recommended texlive-latex-extra texlive-font-utils
@@ -32,7 +32,7 @@ Stage: np-tmcode-run-minimal
 %post
 	apt update
 	apt -y upgrade
-	apt -y install libgfortran5 libgcc-s1 libhdf5-103-1 libstdc++6 libssl3 libcurl4 libsz2 zlib1g libnghttp2-14 libidn2-0 librtmp1 libssh2-1 libpsl5 libgssapi-krb5-2 libldap-2.5-0 libzstd1 libbrotli1 libaec0 libunistring2 libgmp10 libkrb5-3 libk5crypto3 libcom-err2 libkrb5support0 libsasl2-2 libp11-kit0 libtasn1-6 libkeyutils1 libffi8 python3 python-is-python3 python3-regex hdf5-tools
+	apt -y install libgfortran5 libgcc-s1 libhdf5-103-1 libstdc++6 libssl3 libcurl4 libsz2 zlib1g libnghttp2-14 libidn2-0 librtmp1 libssh2-1 libpsl5 libgssapi-krb5-2 libldap-2.5-0 libzstd1 libbrotli1 libaec0 libunistring2 libgmp10 libkrb5-3 libk5crypto3 libcom-err2 libkrb5support0 libsasl2-2 libp11-kit0 libtasn1-6 libkeyutils1 libffi8 liblapacke64 libopenblas64-0-openmp python3 python-is-python3 python3-regex hdf5-tools
 	rm -rf /var/lib/apt/lists/*
 	cd /usr/local/np-tmcode
 	find build -name "*.o" -exec rm -v \{\} \;
diff --git a/containers/singularity/np-tmcode-run.sif b/containers/singularity/np-tmcode-run.sif
index dd5129f356ed91f9477b7ee0c981b5b62cf6523d..d6fdf38eb04f927a4c9d721c1cab608f00b089c6 100755
Binary files a/containers/singularity/np-tmcode-run.sif and b/containers/singularity/np-tmcode-run.sif differ
diff --git a/doc/src/README.md b/doc/src/README.md
index 94056c1801324d3dcb85fffea980b27a26181a20..40ca9e988adb0865d58cb2011fb40b4bda0e3244 100644
--- a/doc/src/README.md
+++ b/doc/src/README.md
@@ -1,3 +1,5 @@
+Distributed under the terms of *GNU GPL-3.0-or-later*
+
 # Folder instructions
 
 This directory contains the material to build the project documentation with *doxygen*.
diff --git a/src/Makefile b/src/Makefile
index 61a13c6fe594c97d704dc0d1efaf62cc19a658cf..dd65769a321c70e4883df53b2e981f74936ee568 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -9,8 +9,8 @@ override BUILDDIR_NPTM=$(BUILDDIR)/libnptm
 endif
 ifndef LIBNPTM
 # choose one of the two following lines, depending on whether a static or dynamic libnptm is wanted
-override LIBNPTM=$(BUILDDIR_NPTM)/libnptm.a
-#override LIBNPTM=$(BUILDDIR_NPTM)/libnptm.so
+#override LIBNPTM=$(BUILDDIR_NPTM)/libnptm.a
+override LIBNPTM=$(BUILDDIR_NPTM)/libnptm.so
 endif
 DOCSDIR=$(SRCDIR)/../doc
 
diff --git a/src/README.md b/src/README.md
index c345b3895299ffb296e3df970e74dcf92b3aca33..803470ee896cabebd92f61f297f971030136e1d4 100644
--- a/src/README.md
+++ b/src/README.md
@@ -1,3 +1,5 @@
+Distributed under the terms of *GNU GPL-3.0-or-later*
+
 # Folder instructions
 
 This directory collects the source code of the original programs and the development folders.
diff --git a/src/cluster/Makefile b/src/cluster/Makefile
index 22bc637a66fc67ed87f40b4355315a0e34ba87c8..c13c9680436ae9621e5b861ba2b7198138f20a1d 100644
--- a/src/cluster/Makefile
+++ b/src/cluster/Makefile
@@ -12,8 +12,8 @@ override BUILDDIR_NPTM=$(BUILDDIR)/libnptm
 endif
 ifndef LIBNPTM
 # choose one of the two following lines, depending on whether a static or dynamic libnptm is wanted
-override LIBNPTM=$(BUILDDIR_NPTM)/libnptm.a
-#override LIBNPTM=$(BUILDDIR_NPTM)/libnpTm.so
+#override LIBNPTM=$(BUILDDIR_NPTM)/libnptm.a
+override LIBNPTM=$(BUILDDIR_NPTM)/libnptm.so
 endif
 
 include ../make.inc
@@ -46,7 +46,7 @@ $(BUILDDIR_CLU)/edfb_clu: $(OBJDIR) $(OBJDIR)/edfb_clu.o $(BUILDDIR_CLU)
 
 # We put $(LIBNPTM) as an object to link in directly, so that it will be found at runtime even if it is a shared object library. May change in the future when we have an install: target
 $(BUILDDIR_CLU)/np_cluster: $(OBJDIR) $(CXX_CLU_OBJS) $(BUILDDIR_CLU) $(LIBNPTM)
-	$(CXX) $(CXXFLAGS) -o $(BUILDDIR_CLU)/np_cluster $(CXX_CLU_OBJS) $(LIBNPTM) $(CXXLDFLAGS) 
+	$(CXX) $(CXXFLAGS) -o $(BUILDDIR_CLU)/np_cluster $(CXX_CLU_OBJS) $(LIBNPTM) $(CXXLDFLAGS)
 
 clean:
 	rm -f $(F_CLU_OBJS) $(CXX_CLU_OBJS) $(CXX_CLU_DEBUG)
diff --git a/src/cluster/cluster.cpp b/src/cluster/cluster.cpp
index 4591b28aa6bda3f1483f0e0190af7bea94d934f2..e2debd9055ca0faf7a9711f360a7bd7d8f5637bd 100644
--- a/src/cluster/cluster.cpp
+++ b/src/cluster/cluster.cpp
@@ -1,13 +1,18 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file cluster.cpp
  *
  * \brief Implementation of the calculation for a cluster of spheres.
  */
-#include <complex>
 #include <cstdio>
 #include <exception>
 #include <fstream>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_ERRORS_H_
 #include "../include/errors.h"
 #endif
@@ -32,6 +37,21 @@
 #include "../include/TransitionMatrix.h"
 #endif
 
+#ifdef USE_LAPACK
+#ifdef USE_MKL
+#include <mkl_lapacke.h>
+#else
+#include <lapacke.h>
+#endif
+#ifndef INCLUDE_LAPACK_CALLS_H_
+#include "../include/lapack_calls.h"
+#endif
+#endif
+
+#ifndef INCLUDE_ALGEBRAIC_H_
+#include "../include/algebraic.h"
+#endif
+
 using namespace std;
 
 /*! \brief C++ implementation of CLU
@@ -66,7 +86,7 @@ void cluster(string config_file, string data_file, string output_path) {
   if (sconf->number_of_spheres == gconf->number_of_spheres) {
     // Shortcuts to variables stored in configuration objects
     int nsph = gconf->number_of_spheres;
-    int mxndm = gconf->mxndm;
+    lapack_int mxndm = (lapack_int)gconf->mxndm;
     int inpol = gconf->in_pol;
     int npnt = gconf->npnt;
     int npntts = gconf->npntts;
@@ -117,49 +137,54 @@ void cluster(string config_file, string data_file, string output_path) {
     C6 *c6 = new C6(c4->lmtpo);
     FILE *output = fopen((output_path + "/c_OCLU").c_str(), "w");
     int jer = 0, lcalc = 0;
-    complex<double> arg(0.0, 0.0), ccsam(0.0, 0.0);
+    dcomplex arg = 0.0 + 0.0 * I;
+    dcomplex ccsam = 0.0 + 0.0 * I;
     int configurations = 0;
     for (int ci = 1; ci <= nsph; ci++) {
       if (sconf->iog_vec[ci -1] >= ci) configurations++;
     }
     C2 *c2 = new C2(nsph, configurations, npnt, npntts);
-    complex<double> **am = new complex<double>*[mxndm];
-    for (int ai = 0; ai < mxndm; ai++) am[ai] = new complex<double>[mxndm]();
+    lapack_int ndit = 2 * nsph * c4->nlim;
+    dcomplex *am_vector = new dcomplex[ndit * ndit]();
+    dcomplex **am = new dcomplex*[ndit];
+    for (int ai = 0; ai < ndit; ai++) {
+      am[ai] = (am_vector + ai * ndit);
+    }
     const int ndi = c4->nsph * c4->nlim;
     C9 *c9 = new C9(ndi, c4->nlem, 2 * ndi, 2 * c4->nlem);
     double *gaps = new double[nsph]();
     double *tqev = new double[3]();
     double *tqsv = new double[3]();
     double **tqse, **tqss, **tqce, **tqcs;
-    complex<double> **tqspe, **tqsps, **tqcpe, **tqcps;
+    dcomplex **tqspe, **tqsps, **tqcpe, **tqcps;
     tqse = new double*[2];
-    tqspe = new complex<double>*[2];
+    tqspe = new dcomplex*[2];
     tqss = new double*[2];
-    tqsps = new complex<double>*[2];
+    tqsps = new dcomplex*[2];
     tqce = new double*[2];
-    tqcpe = new complex<double>*[2];
+    tqcpe = new dcomplex*[2];
     tqcs = new double*[2];
-    tqcps = new complex<double>*[2];
+    tqcps = new dcomplex*[2];
     for (int ti = 0; ti < 2; ti++) {
       tqse[ti] = new double[nsph]();
-      tqspe[ti] = new complex<double>[nsph]();
+      tqspe[ti] = new dcomplex[nsph]();
       tqss[ti] = new double[nsph]();
-      tqsps[ti] = new complex<double>[nsph]();
+      tqsps[ti] = new dcomplex[nsph]();
       tqce[ti] = new double[3]();
-      tqcpe[ti] = new complex<double>[3]();
+      tqcpe[ti] = new dcomplex[3]();
       tqcs[ti] = new double[3]();
-      tqcps[ti] = new complex<double>[3]();
+      tqcps[ti] = new dcomplex[3]();
     }
     double *gapv = new double[3]();
-    complex<double> **gapp, **gappm;
+    dcomplex **gapp, **gappm;
     double **gap, **gapm;
-    gapp = new complex<double>*[3];
-    gappm = new complex<double>*[3];
+    gapp = new dcomplex*[3];
+    gappm = new dcomplex*[3];
     gap = new double*[3];
     gapm = new double*[3];
     for (int gi = 0; gi < 3; gi++) {
-      gapp[gi] = new complex<double>[2]();
-      gappm[gi] = new complex<double>[2]();
+      gapp[gi] = new dcomplex[2]();
+      gappm[gi] = new dcomplex[2]();
       gap[gi] = new double[2]();
       gapm[gi] = new double[2]();
     }
@@ -192,7 +217,7 @@ void cluster(string config_file, string data_file, string output_path) {
     double scan, cfmp, sfmp, cfsp, sfsp;
     // End of global variables for CLU
     fprintf(output, " READ(IR,*)NSPH,LI,LE,MXNDM,INPOL,NPNT,NPNTTS,IAVM,ISAM\n");
-    fprintf(output, " %5d%5d%5d%5d%5d%5d%5d%5d%5d\n",
+    fprintf(output, " %5d%5d%5d%5ld%5d%5d%5d%5d%5d\n",
 	    nsph, c4->li, c4->le, mxndm, inpol, npnt, npntts, iavm, isam
 	    );
     fprintf(output, " READ(IR,*)RXX(I),RYY(I),RZZ(I)\n");
@@ -264,6 +289,11 @@ void cluster(string config_file, string data_file, string output_path) {
     string tppoan_name = output_path + "/c_TPPOAN";
     tppoan.open(tppoan_name.c_str(), ios::out | ios::binary);
     if (tppoan.is_open()) {
+#ifdef USE_LAPACK
+      printf("INFO: using LAPACK calls.\n");
+#else
+      printf("INFO: using fall-back lucin() calls.\n");
+#endif
       tppoan.write(reinterpret_cast<char *>(&iavm), sizeof(int));
       tppoan.write(reinterpret_cast<char *>(&isam), sizeof(int));
       tppoan.write(reinterpret_cast<char *>(&inpol), sizeof(int));
@@ -331,8 +361,7 @@ void cluster(string config_file, string data_file, string output_path) {
 	  if (jer != 0) break;
 	} // i132 loop
 	cms(am, c1, c1ao, c4, c6);
-	int ndit = 2 * nsph * c4->nlim;
-	lucin(am, mxndm, ndit, jer);
+	invert_matrix(am, ndit, jer, mxndm);
 	if (jer != 0) break; // jxi488 loop: goes to memory clean
 	ztm(am, c1, c1ao, c4, c6, c9);
 	if (sconf->idfc >= 0) {
@@ -354,9 +383,8 @@ void cluster(string config_file, string data_file, string output_path) {
 	// label 160
 	double cs0 = 0.25 * vk * vk * vk / acos(0.0);
 	double csch = 0.0, qschu = 0.0, pschu = 0.0, s0mag = 0.0;
-	std::complex<double> s0(0.0, 0.0);
+	dcomplex s0 = 0.0 + 0.0 * I;
 	scr0(vk, exri, c1, c1ao, c3, c4);
-	//printf("DEBUG: after SCR0 TFSAS = (%lE, %lE)\n", c3->tfsas.real(), c3->tfsas.imag());
 	double sqk = vk * vk * sconf->exdc;
 	aps(zpv, c4->li, nsph, c1, sqk, gaps);
 	rabas(inpol, c4->li, nsph, c1, tqse, tqspe, tqss, tqsps);
@@ -372,19 +400,19 @@ void cluster(string config_file, string data_file, string output_path) {
 	    if (c1->nshl[i] != 1) {
 	      fprintf(output, "  SIZE=%15.7lE\n", c2->vsz[i]);
 	    } else { // label 162
-	      fprintf(output, "  SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", c2->vsz[i], c2->vkt[i].real(), c2->vkt[i].imag());
+	      fprintf(output, "  SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n", c2->vsz[i], real(c2->vkt[i]), imag(c2->vkt[i]));
 	    }
 	    // label 164
 	    fprintf(output, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n");
 	    fprintf(output, " %14.7lE%15.7lE%15.7lE%15.7lE\n", c1->sscs[i], c1->sabs[i], c1->sexs[i], albeds);
 	    fprintf(output, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n");
 	    fprintf(output, " %14.7lE%15.7lE%15.7lE\n", c1->sqscs[i], c1->sqabs[i], c1->sqexs[i]);
-	    fprintf(output, "  FSAS=%15.7lE%15.7lE\n", c1->fsas[i].real(), c1->fsas[i].imag());
+	    fprintf(output, "  FSAS=%15.7lE%15.7lE\n", real(c1->fsas[i]), imag(c1->fsas[i]));
 	    csch = 2.0 * vk * sqsfi / c1->gcsv[i];
 	    s0 = c1->fsas[i] * exri;
-	    qschu = s0.imag() * csch;
-	    pschu = s0.real() * csch;
-	    s0mag = abs(s0) * cs0;
+	    qschu = imag(s0) * csch;
+	    pschu = real(s0) * csch;
+	    s0mag = cabs(s0) * cs0;
 	    fprintf(output, "  QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", qschu, pschu, s0mag);
 	    double rapr = c1->sexs[i] - gaps[i];
 	    double cosav = gaps[i] / c1->sscs[i];
@@ -393,12 +421,12 @@ void cluster(string config_file, string data_file, string output_path) {
 	    fprintf(output, "  IPO= 2, TQEk=%15.7lE, TQSk=%15.7lE\n", tqse[1][i], tqss[1][i]);
 	  }
 	} // i170 loop
-	fprintf(output, "  FSAT=%15.7lE%15.7lE\n", c3->tfsas.real(), c3->tfsas.imag());
+	fprintf(output, "  FSAT=%15.7lE%15.7lE\n", real(c3->tfsas), imag(c3->tfsas));
 	csch = 2.0 * vk * sqsfi / c3->gcs;
 	s0 = c3->tfsas * exri;
-	qschu = s0.imag() * csch;
-	pschu = s0.real() * csch;
-	s0mag = abs(s0) * cs0;
+	qschu = imag(s0) * csch;
+	pschu = real(s0) * csch;
+	s0mag = cabs(s0) * cs0;
 	fprintf(output, "  QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n", qschu, pschu, s0mag);
 	tppoan.write(reinterpret_cast<char *>(&vk), sizeof(double));
 	pcrsm0(vk, exri, inpol, c1, c1ao, c4);
@@ -508,24 +536,24 @@ void cluster(string config_file, string data_file, string output_path) {
 		  for (int i = 0; i < 2; i++) {
 		    double value = c1ao->scscm[i];
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->scscpm[i].real();
+		    value = real(c1ao->scscpm[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->scscpm[i].imag();
+		    value = imag(c1ao->scscpm[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		    value = c1ao->ecscm[i];
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->ecscpm[i].real();
+		    value = real(c1ao->ecscpm[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->ecscpm[i].imag();
+		    value = imag(c1ao->ecscpm[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		  }
 		  for (int i = 0; i < 3; i++) {
 		    for (int j = 0; j < 2; j++) {
 		      double value = gapm[i][j];
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = gappm[i][j].real();
+		      value = real(gappm[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = gappm[i][j].imag();
+		      value = imag(gappm[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		    }
 		  }
@@ -546,12 +574,12 @@ void cluster(string config_file, string data_file, string output_path) {
 		    double absrm = abssm / c3->acs;
 		    double acsecs = c3->acs / c3->ecs;
 		    if (acsecs >= -1.0e-6 && acsecs <= 1.0e-6) absrm = 1.0;
-		    complex<double> s0m = c1ao->fsacm[ilr210 - 1][ilr210 - 1] * exri;
-		    double qschum = s0m.imag() * csch;
-		    double pschum = s0m.real() * csch;
-		    double s0magm = abs(s0m) * cs0;
-		    double rfinrm = c1ao->fsacm[ilr210 - 1][ilr210 - 1].real() / c3->tfsas.real();
-		    double extcrm = c1ao->fsacm[ilr210 - 1][ilr210 - 1].imag() / c3->tfsas.imag();
+		    dcomplex s0m = c1ao->fsacm[ilr210 - 1][ilr210 - 1] * exri;
+		    double qschum = imag(s0m) * csch;
+		    double pschum = real(s0m) * csch;
+		    double s0magm = cabs(s0m) * cs0;
+		    double rfinrm = real(c1ao->fsacm[ilr210 - 1][ilr210 - 1]) / real(c3->tfsas);
+		    double extcrm = imag(c1ao->fsacm[ilr210 - 1][ilr210 - 1]) / imag(c3->tfsas);
 		    if (inpol == 0) {
 		      fprintf(output, "   LIN %2d\n", ipol);
 		    } else { // label 206
@@ -566,9 +594,9 @@ void cluster(string config_file, string data_file, string output_path) {
 		    fprintf(output, " %14.7lE%15.7lE%15.7lE\n", scarm, absrm, extrm);
 		    fprintf(
 			    output, "  FSAC(%1d,%1d)=%15.7lE%15.7lE   FSAC(%1d,%1d)=%15.7lE%15.7lE\n",
-			    ilr210, ilr210, c1ao->fsacm[ilr210 - 1][ilr210 - 1].real(),
-			    c1ao->fsacm[ilr210 - 1][ilr210 - 1].imag(), jlr, ilr210,
-			    c1ao->fsacm[jlr - 1][ilr210 - 1].real(), c1ao->fsacm[jlr - 1][ilr210 - 1].imag()
+			    ilr210, ilr210, real(c1ao->fsacm[ilr210 - 1][ilr210 - 1]),
+			    imag(c1ao->fsacm[ilr210 - 1][ilr210 - 1]), jlr, ilr210,
+			    real(c1ao->fsacm[jlr - 1][ilr210 - 1]), imag(c1ao->fsacm[jlr - 1][ilr210 - 1])
 			    );
 		    fprintf(
 			    output, "  RE(FSAC(%1d,%1d))/RE(TFSAS)=%15.7lE, IM(FSAC(%1d,%1d))/IM(TFSAS)=%15.7lE\n",
@@ -581,8 +609,8 @@ void cluster(string config_file, string data_file, string output_path) {
 		    fprintf(output, "  COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr);
 		    fprintf(output, "  Fk=%15.7lE\n", fz);
 		  } // ilr210 loop
-		  double rmbrif = (c1ao->fsacm[0][0].real() - c1ao->fsacm[1][1].real()) / c1ao->fsacm[0][0].real();
-		  double rmdchr = (c1ao->fsacm[0][0].imag() - c1ao->fsacm[1][1].imag()) / c1ao->fsacm[0][0].imag();
+		  double rmbrif = (real(c1ao->fsacm[0][0]) - real(c1ao->fsacm[1][1])) / real(c1ao->fsacm[0][0]);
+		  double rmdchr = (imag(c1ao->fsacm[0][0]) - imag(c1ao->fsacm[1][1])) / imag(c1ao->fsacm[0][0]);
 		  fprintf(output, "  (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))=%15.7lE\n", rmbrif);
 		  fprintf(output, "  (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))=%15.7lE\n", rmdchr);
 		}
@@ -612,13 +640,13 @@ void cluster(string config_file, string data_file, string output_path) {
 		    fprintf(output, "     SPHERE %2d\n", i226);
 		    fprintf(
 			    output, "  SAS(1,1)=%15.7lE%15.7lE, SAS(2,1)=%15.7lE%15.7lE\n",
-			    c1->sas[i226 - 1][0][0].real(), c1->sas[i226 - 1][0][0].imag(),
-			    c1->sas[i226 - 1][1][0].real(), c1->sas[i226 - 1][1][0].imag()
+			    real(c1->sas[i226 - 1][0][0]), imag(c1->sas[i226 - 1][0][0]),
+			    real(c1->sas[i226 - 1][1][0]), imag(c1->sas[i226 - 1][1][0])
 			    );
 		    fprintf(
 			    output, "  SAS(1,2)=%15.7lE%15.7lE, SAS(2,2)=%15.7lE%15.7lE\n",
-			    c1->sas[i226 - 1][0][1].real(), c1->sas[i226 - 1][0][1].imag(),
-			    c1->sas[i226 - 1][1][1].real(), c1->sas[i226 - 1][1][1].imag()
+			    real(c1->sas[i226 - 1][0][1]), imag(c1->sas[i226 - 1][0][1]),
+			    real(c1->sas[i226 - 1][1][1]), imag(c1->sas[i226 - 1][1][1])
 			    );
 		    for (int j225 = 0; j225 < 16; j225++) { // QUESTION: check that 16 is a fixed dimension
 		      c1ao->vint[j225] = c1ao->vints[i226 - 1][j225];
@@ -642,13 +670,13 @@ void cluster(string config_file, string data_file, string output_path) {
 		} // i226 loop
 		fprintf(
 			output, "  SAT(1,1)=%15.7lE%15.7lE, SAT(2,1)=%15.7lE%15.7lE\n",
-			c3->tsas[0][0].real(), c3->tsas[0][0].imag(),
-			c3->tsas[1][0].real(), c3->tsas[1][0].imag()
+			real(c3->tsas[0][0]), imag(c3->tsas[0][0]),
+			real(c3->tsas[1][0]), imag(c3->tsas[1][0])
 			);
 		fprintf(
 			output, "  SAT(1,2)=%15.7lE%15.7lE, SAT(2,2)=%15.7lE%15.7lE\n",
-			c3->tsas[0][1].real(), c3->tsas[0][1].imag(),
-			c3->tsas[1][1].real(), c3->tsas[1][1].imag()
+			real(c3->tsas[0][1]), imag(c3->tsas[0][1]),
+			real(c3->tsas[1][1]), imag(c3->tsas[1][1])
 			);
 		fprintf(output, "     CLUSTER\n");
 		pcros(vk, exri, c1, c1ao, c4);
@@ -666,24 +694,24 @@ void cluster(string config_file, string data_file, string output_path) {
 		  for (int i = 0; i < 2; i++) {
 		    double value = c1ao->scsc[i];
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->scscp[i].real();
+		    value = real(c1ao->scscp[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->scscp[i].imag();
+		    value = imag(c1ao->scscp[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		    value = c1ao->ecsc[i];
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->ecscp[i].real();
+		    value = real(c1ao->ecscp[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->ecscp[i].imag();
+		    value = imag(c1ao->ecscp[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		  }
 		  for (int i = 0; i < 3; i++) {
 		    for (int j = 0; j < 2; j++) {
 		      double value = gap[i][j];
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = gapp[i][j].real();
+		      value = real(gapp[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = gapp[i][j].imag();
+		      value = imag(gapp[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		    }
 		  }
@@ -691,9 +719,9 @@ void cluster(string config_file, string data_file, string output_path) {
 		    for (int j = 0; j < 3; j++) {
 		      double value = tqce[i][j];
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = tqcpe[i][j].real();
+		      value = real(tqcpe[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = tqcpe[i][j].imag();
+		      value = imag(tqcpe[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		    }
 		  }
@@ -701,9 +729,9 @@ void cluster(string config_file, string data_file, string output_path) {
 		    for (int j = 0; j < 3; j++) {
 		      double value = tqcs[i][j];
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = tqcps[i][j].real();
+		      value = real(tqcps[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		      value = tqcps[i][j].imag();
+		      value = imag(tqcps[i][j]);
 		      tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		    }
 		  }
@@ -718,9 +746,9 @@ void cluster(string config_file, string data_file, string output_path) {
 		}
 		// label 254
 		for (int i = 0; i < 16; i++) {
-		  double value = c1ao->vint[i].real();
+		  double value = real(c1ao->vint[i]);
 		  tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		  value = c1ao->vint[i].imag();
+		  value = imag(c1ao->vint[i]);
 		  tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		}
 		for (int i = 0; i < 4; i++) {
@@ -746,11 +774,11 @@ void cluster(string config_file, string data_file, string output_path) {
 		  double ratio = c3->acs / c3->ecs;
 		  if (ratio < -1.0e-6 || ratio > 1.0e-6) absrat = abssec / c3->acs;
 		  s0 = c1ao->fsac[ilr290 - 1][ilr290 - 1] * exri;
-		  double qschu = s0.imag() * csch;
-		  double pschu = s0.real() * csch;
-		  s0mag = abs(s0) * cs0;
-		  double refinr = c1ao->fsac[ilr290 - 1][ilr290 - 1].real() / c3->tfsas.real();
-		  double extcor = c1ao->fsac[ilr290 - 1][ilr290 - 1].imag() / c3->tfsas.imag();
+		  double qschu = imag(s0) * csch;
+		  double pschu = real(s0) * csch;
+		  s0mag = cabs(s0) * cs0;
+		  double refinr = real(c1ao->fsac[ilr290 - 1][ilr290 - 1]) / real(c3->tfsas);
+		  double extcor = imag(c1ao->fsac[ilr290 - 1][ilr290 - 1]) / imag(c3->tfsas);
 		  if (inpol == 0) {
 		    fprintf(output, "   LIN %2d\n", ipol);
 		  } else { // label 273
@@ -774,13 +802,13 @@ void cluster(string config_file, string data_file, string output_path) {
 			  );
 		  fprintf(
 			  output, "  FSAC(%1d,%1d)=%15.7lE%15.7lE   FSAC(%1d,%1d)=%15.7lE%15.7lE\n",
-			  ilr290, ilr290, c1ao->fsac[ilr290 - 1][ilr290 - 1].real(), c1ao->fsac[ilr290 - 1][ilr290 - 1].imag(),
-			  jlr, ilr290, c1ao->fsac[jlr - 1][ilr290 - 1].real(), c1ao->fsac[jlr - 1][ilr290 - 1].imag()
+			  ilr290, ilr290, real(c1ao->fsac[ilr290 - 1][ilr290 - 1]), imag(c1ao->fsac[ilr290 - 1][ilr290 - 1]),
+			  jlr, ilr290, real(c1ao->fsac[jlr - 1][ilr290 - 1]), imag(c1ao->fsac[jlr - 1][ilr290 - 1])
 			  );
 		  fprintf(
 			  output, "   SAC(%1d,%1d)=%15.7lE%15.7lE    SAC(%1d,%1d)=%15.7lE%15.7lE\n",
-			  ilr290, ilr290, c1ao->sac[ilr290 - 1][ilr290 - 1].real(), c1ao->sac[ilr290 - 1][ilr290 - 1].imag(),
-			  jlr, ilr290, c1ao->sac[jlr - 1][ilr290 - 1].real(), c1ao->sac[jlr - 1][ilr290 - 1].imag()
+			  ilr290, ilr290, real(c1ao->sac[ilr290 - 1][ilr290 - 1]), imag(c1ao->sac[ilr290 - 1][ilr290 - 1]),
+			  jlr, ilr290, real(c1ao->sac[jlr - 1][ilr290 - 1]), imag(c1ao->sac[jlr - 1][ilr290 - 1])
 			  );
 		  fprintf(
 			  output, "  RE(FSAC(%1d,%1d))/RE(TFSAS)=%15.7lE, IM(FSAC(%1d,%1d))/IM(TFSAS)=%15.7lE\n",
@@ -822,8 +850,8 @@ void cluster(string config_file, string data_file, string output_path) {
 			    );
 		  }
 		} //ilr290 loop
-		double rbirif = (c1ao->fsac[0][0].real() - c1ao->fsac[1][1].real()) / c1ao->fsac[0][0].real();
-		double rdichr = (c1ao->fsac[0][0].imag() - c1ao->fsac[1][1].imag()) / c1ao->fsac[0][0].imag();
+		double rbirif = (real(c1ao->fsac[0][0]) - real(c1ao->fsac[1][1])) / real(c1ao->fsac[0][0]);
+		double rdichr = (imag(c1ao->fsac[0][0]) - imag(c1ao->fsac[1][1])) / imag(c1ao->fsac[0][0]);
 		fprintf(output, "  (RE(FSAC(1,1))-RE(FSAC(2,2)))/RE(FSAC(1,1))=%15.7lE\n", rbirif);
 		fprintf(output, "  (IM(FSAC(1,1))-IM(FSAC(2,2)))/IM(FSAC(1,1))=%15.7lE\n", rdichr);
 		fprintf(output, "  MULC\n");
@@ -845,9 +873,9 @@ void cluster(string config_file, string data_file, string output_path) {
 		  // Some implicit loops writing to binary.
 		  for (int i = 0; i < 16; i++) {
 		    double value;
-		    value = c1ao->vintm[i].real();
+		    value = real(c1ao->vintm[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = c1ao->vintm[i].imag();
+		    value = imag(c1ao->vintm[i]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		  }
 		  for (int i = 0; i < 4; i++) {
@@ -910,8 +938,9 @@ void cluster(string config_file, string data_file, string output_path) {
       delete[] zpv[zi];
     }
     delete[] zpv;
-    for (int ai = mxndm - 1; ai > -1; ai--) delete[] am[ai];
+    delete[] am_vector;
     delete[] am;
+    //delete[] tam;
     delete[] gaps;
     for (int ti = 1; ti > -1; ti--) {
       delete[] tqse[ti];
diff --git a/src/cluster/np_cluster.cpp b/src/cluster/np_cluster.cpp
index 73caa518f9d330b8ad4114a30f123ba320035756..66fb783bc2e9d51e32b5dbc6fb0c033793348936 100644
--- a/src/cluster/np_cluster.cpp
+++ b/src/cluster/np_cluster.cpp
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file np_cluster.cpp
  *
  * \brief Cluster of spheres scattering problem handler.
@@ -17,9 +19,12 @@
  */
 
 #include <cstdio>
-#include <complex>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_CONFIGURATION_H_
 #include "../include/Configuration.h"
 #endif
diff --git a/src/include/Commons.h b/src/include/Commons.h
index 6ad2a0110e6eb4ebae592402e9df43e9cb182687..e954544404d3ecc19c88377897b18c2d7e0ea1d8 100644
--- a/src/include/Commons.h
+++ b/src/include/Commons.h
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file Commons.h
  *
  * \brief C++ porting of common data structures.
@@ -42,15 +44,15 @@ protected:
 	int nlmmt;
 public:
 	//! \brief QUESTION: definition?
-	std::complex<double> **rmi;
+	dcomplex **rmi;
 	//! \brief QUESTION: definition?
-	std::complex<double> **rei;
+	dcomplex **rei;
 	//! \brief QUESTION: definition?
-	std::complex<double> **w;
+	dcomplex **w;
 	//! \brief QUESTION: definition?
-	std::complex<double> *fsas;
+	dcomplex *fsas;
 	//! \brief QUESTION: definition?
-	std::complex<double> **vints;
+	dcomplex **vints;
 	//! \brief QUESTION: definition?
 	double *sscs;
 	//! \brief QUESTION: definition?
@@ -80,7 +82,7 @@ public:
 	//! \brief Vector of numbers of spherical layers.
 	int *nshl;
 	//! \brief QUESTION: definition?
-	std::complex<double> ***sas;
+	dcomplex ***sas;
 
 	/*! \brief C1 instance constructor.
 	 *
@@ -105,13 +107,13 @@ class C2 {
 	int nhspo;
 public:
 	//! \brief QUESTION: definition?
-	std::complex<double> *ris;
+	dcomplex *ris;
 	//! \brief QUESTION: definition?
-	std::complex<double> *dlri;
+	dcomplex *dlri;
 	//! \brief QUESTION: definition?
-	std::complex<double> *dc0;
+	dcomplex *dc0;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vkt;
+	dcomplex *vkt;
 	//! Vector of scaled sizes. QUESTION: correct?
 	double *vsz;
 
@@ -133,9 +135,9 @@ public:
 class C3 {
 public:
 	//! \brief QUESTION: definition?
-	std::complex<double> tfsas;
+	dcomplex tfsas;
 	//! \brief QUESTION: definition?
-	std::complex<double> **tsas;
+	dcomplex **tsas;
 	//! \brief QUESTION: definition?
 	double gcs;
 	//! \brief QUESTION: definition?
@@ -210,35 +212,35 @@ protected:
 	void allocate_vectors(C4 *c4);
 public:
 	//! \brief QUESTION: definition?
-	std::complex<double> *vh;
+	dcomplex *vh;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vj0;
+	dcomplex *vj0;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vj;
+	dcomplex *vj;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vyhj;
+	dcomplex *vyhj;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vyj0;
+	dcomplex *vyj0;
 	//! \brief QUESTION: definition?
-	std::complex<double> **am0m;
+	dcomplex **am0m;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vint;
+	dcomplex *vint;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vintm;
+	dcomplex *vintm;
 	//! \brief QUESTION: definition?
-	std::complex<double> **vints;
+	dcomplex **vints;
 	//! \brief QUESTION: definition?
-	std::complex<double> *vintt;
+	dcomplex *vintt;
 	//! \brief QUESTION: definition?
-	std::complex<double> **fsac;
+	dcomplex **fsac;
 	//! \brief QUESTION: definition?
-	std::complex<double> **sac;
+	dcomplex **sac;
 	//! \brief QUESTION: definition?
-	std::complex<double> **fsacm;
+	dcomplex **fsacm;
 	//! \brief QUESTION: definition?
 	double *scsc;
 	//! \brief QUESTION: definition?
-	std::complex<double> *scscp;
+	dcomplex *scscp;
 	//! \brief QUESTION: definition?
 	double *ecsc;
 	//! \brief QUESTION: definition?
@@ -246,11 +248,11 @@ public:
 	//! \brief QUESTION: definition?
 	double *scscm;
 	//! \brief QUESTION: definition?
-	std::complex<double> *ecscp;
+	dcomplex *ecscp;
 	//! \brief QUESTION: definition?
-	std::complex<double> *scscpm;
+	dcomplex *scscpm;
 	//! \brief QUESTION: definition?
-	std::complex<double> *ecscpm;
+	dcomplex *ecscpm;
 	//! \brief QUESTION: definition?
 	double *v3j0;
 	//! \brief QUESTION: definition?
@@ -296,11 +298,11 @@ protected:
 	int sam_size_0;
 public:
 	//! \brief QUESTION: definition?
-	std::complex<double> **gis;
+	dcomplex **gis;
 	//! \brief QUESTION: definition?
-	std::complex<double> **gls;
+	dcomplex **gls;
 	//! \brief QUESTION: definition?
-	std::complex<double> **sam;
+	dcomplex **sam;
 
 	/*! \brief C9 instance constructor.
 	 *
diff --git a/src/include/Configuration.h b/src/include/Configuration.h
index f3c4df91bcc64e6673865b739b5f7dd9a06af5a3..e8e3b8951b4b01538cbf4f541b13b100d84e3e94 100644
--- a/src/include/Configuration.h
+++ b/src/include/Configuration.h
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file Configuration.h
  *
  * \brief Configuration data structures.
@@ -168,7 +170,7 @@ class ScattererConfiguration {
   friend void sphere(std::string, std::string, std::string);
 protected:
   //! \brief Matrix of dielectric parameters with size [NON_TRANS_LAYERS x N_SPHERES x N_SCALES].
-  std::complex<double> ***dc0_matrix;
+  dcomplex ***dc0_matrix;
   //! \brief Vector of sphere radii expressed in m, with size [N_SPHERES].
   double *radii_of_spheres;
   //! \brief Matrix of fractional transition radii with size [N_SPHERES x LAYERS].
@@ -258,7 +260,7 @@ public:
    * \param dielectric_func_type: `int` Type of dielectric function definition (=0 for constant,
    * \>0 as function of scale parameter, <0 for functions at XIP value and XI is scale factor
    * for dimensions).
-   * \param dc_matrix: Matrix of reference dielectric constants.
+   * \param dc_matrix: `complex double ***` Matrix of reference dielectric constants.
    * \param has_external: `bool` Flag to set whether to add an external spherical layer.
    * \param exdc: `double` External medium dielectric constant.
    * \param wp: `double` wp
@@ -274,7 +276,7 @@ public:
 			 int *nshl_vector,
 			 double **rcf_vector,
 			 int dielectric_func_type,
-			 std::complex<double> ***dc_matrix,
+			 dcomplex ***dc_matrix,
 			 bool has_external,
 			 double exdc,
 			 double wp,
diff --git a/src/include/TransitionMatrix.h b/src/include/TransitionMatrix.h
index 447457f43eb009556fcc422b75e1fd171f636ed0..3966abdab0b48463eaefb256dd6d128fe84e4e75 100644
--- a/src/include/TransitionMatrix.h
+++ b/src/include/TransitionMatrix.h
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file TransitionMatrix.h
  *
  * \brief Representation of the Transition Matrix.
@@ -19,7 +21,7 @@ class TransitionMatrix {
   //! External medium refractive index.
   double exri;
   //! Vectorized matrix elements.
-  std::complex<double> *elements;
+  dcomplex *elements;
   //! Sphere radius.
   double sphere_radius;
   //! Matrix shape
@@ -66,11 +68,11 @@ class TransitionMatrix {
    * \param _lm: `int` Maximum field expansion order.
    * \param _vk: `double` Wave number in scale units.
    * \param _exri: `double` External medium refractive index.
-   * \param _elements: `complex<double> *` Vectorized elements of the matrix.
+   * \param _elements: `complex double *` Vectorized elements of the matrix.
    * \param _radius: `double` Radius for the single sphere case (defaults to 0.0).
    */
   TransitionMatrix(
-		   int _is, int _lm, double _vk, double _exri, std::complex<double> *_elements,
+		   int _is, int _lm, double _vk, double _exri, dcomplex *_elements,
 		   double _radius=0.0
   );
 
@@ -82,13 +84,13 @@ class TransitionMatrix {
    * \param _lm: `int` Maximum field expansion order.
    * \param _vk: `double` Wave number in scale units.
    * \param _exri: `double` External medium refractive index.
-   * \param _rmi: Matrix of complex.
-   * \param _rei: Matrix of complex.
+   * \param _rmi: `complex double **`
+   * \param _rei: `complex double **`
    * \param _sphere_radius: `double` Radius of the sphere.
    */
   TransitionMatrix(
-		   int _lm, double _vk, double _exri, std::complex<double> **_rmi,
-		   std::complex<double> **_rei, double _sphere_radius
+		   int _lm, double _vk, double _exri, dcomplex **_rmi,
+		   dcomplex **_rei, double _sphere_radius
   );
 
   /*! \brief Transition Matrix instance constructor for a cluster of spheres.
@@ -100,9 +102,9 @@ class TransitionMatrix {
    * \param _lm: `int` Maximum field expansion order.
    * \param _vk: `double` Wave number in scale units.
    * \param _exri: `double` External medium refractive index.
-   * \param _am0m: Matrix of complex.
+   * \param _am0m: `complex double **`
    */
-  TransitionMatrix(int _nlemt, int _lm, double _vk, double _exri, std::complex<double> **_am0m);
+  TransitionMatrix(int _nlemt, int _lm, double _vk, double _exri, dcomplex **_am0m);
 
   /*! \brief Transition Matrix instance destroyer.
    */
diff --git a/src/include/algebraic.h b/src/include/algebraic.h
new file mode 100644
index 0000000000000000000000000000000000000000..01437ac9d3f21d49610ae6921421e5933ebefc42
--- /dev/null
+++ b/src/include/algebraic.h
@@ -0,0 +1,42 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
+/*! \file algebraic.h
+ *
+ * \brief Declaration of algebraic functions with different call-backs.
+ *
+ * In principle, the system that runs NP_TMcode may offer various types of
+ * optimized features, such as multi-core or multi-node scaling, GPU offload,
+ * or external libraries. This header collects a set of functions that can
+ * perform standard algebraic operations choosing the most optimized available
+ * system as a call-back. If no optimization is detected, eventually the 
+ * legacy serial function implementation is used as a fall-back.
+ */
+
+#ifdef USE_LAPACK
+#ifdef USE_MKL
+#include <mkl_lapacke.h>
+#else
+#include <lapacke.h>
+#endif
+#else
+#define lapack_int int64_t
+#endif
+
+#ifndef INCLUDE_ALGEBRAIC_H_
+#define INCLUDE_ALGEBRAIC_H_
+
+#ifndef np_int
+#define np_int lapack_int
+#endif
+
+/*! \brief Perform in-place matrix inversion.
+ *
+ * \param mat: `complex double **` The matrix to be inverted (must be a square matrix).
+ * \param size: `np_int` The size of the matrix (i.e. the number of its rows or columns).
+ * \param ier: `int &` Reference to an integer variable for returning a result flag.
+ * \param max_size: `np_int` The maximum expected size (required by some call-backs,
+ * optional, defaults to 0).
+ */
+void invert_matrix(dcomplex **mat, np_int size, int &ier, np_int max_size=0);
+
+#endif
diff --git a/src/include/clu_subs.h b/src/include/clu_subs.h
index 49b89e20875919f916cea21a269fa7b210da3a9f..6852a46906998e878b0021dc5d606ac8500e8322 100644
--- a/src/include/clu_subs.h
+++ b/src/include/clu_subs.h
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file clu_subs.h
  *
  * \brief C++ porting of CLU functions and subroutines.
@@ -15,6 +17,14 @@
 #ifndef INCLUDE_CLU_SUBS_H_
 #define INCLUDE_CLU_SUBS_H_
 
+#ifndef np_int
+#ifndef lapack_int
+#define np_int int64_t
+#else
+#define np_int lapack_int
+#endif
+#endif
+
 /*! \brief Compute the asymmetry-corrected scattering cross-section of a cluster.
  *
  * This function computes the product between the geometrical asymmetry parameter and
@@ -23,15 +33,15 @@
  *
  * \param zpv: `double ****`
  * \param le: `int`
- * \param am0m: Matrix of complex.
- * \param w: Matrix of complex.
+ * \param am0m: `complex double **`
+ * \param w: `complex double **`
  * \param sqk: `double`
  * \param gapr: `double **`
- * \param gapp: Matrix of complex.
+ * \param gapp: `complex double **`
  */
 void apc(
-	 double ****zpv, int le, std::complex<double> **am0m, std::complex<double> **w,
-	 double sqk, double **gapr, std::complex<double> **gapp
+	 double ****zpv, int le, dcomplex **am0m, dcomplex **w,
+	 double sqk, double **gapr, dcomplex **gapp
 );
 
 /*! \brief Compute the asymmetry-corrected scattering cross-section under random average
@@ -42,32 +52,29 @@ void apc(
  *
  * \param zpv: `double ****`
  * \param le: `int`
- * \param am0m: Matrix of complex.
+ * \param am0m: `complex double **`
  * \param inpol: `int` Polarization type.
  * \param sqk: `double`
  * \param gaprm: `double **`
- * \param gappm: Matrix of complex.
+ * \param gappm: `complex double **`
  */
 void apcra(
-	   double ****zpv, const int le, std::complex<double> **am0m, int inpol, double sqk,
-	   double **gaprm, std::complex<double> **gappm
+	   double ****zpv, const int le, dcomplex **am0m, int inpol, double sqk,
+	   double **gaprm, dcomplex **gappm
 );
 
 /*! \brief Complex inner product.
  *
  * This function performs the complex inner product. It is used by `lucin()`.
  *
- * \param z: `complex<double>`
- * \param am: Matrix of complex.
+ * \param z: `complex double`
+ * \param am: `complex double **`
  * \param i: `int`
  * \param jf: `int`
  * \param k: `int`
  * \param nj: `int`
  */
-std::complex<double> cdtp(
-			  std::complex<double> z, std::complex<double> **am, int i, int jf,
-			  int k, int nj
-);
+dcomplex cdtp(dcomplex z, dcomplex **am, int i, int jf, int k, int nj);
 
 /*! \brief C++ porting of CGEV. QUESTION: description?
  *
@@ -84,13 +91,13 @@ double cgev(int ipamo, int mu, int l, int m);
  * This function constructs the multi-centered M-matrix of the cluster, according
  * to Eq. (5.28) of Borghese, Denti & Saija (2007).
  *
- * \param am: Matrix of complex.
+ * \param am: `complex double **`
  * \param c1: `C1 *`
  * \param c1ao: `C1_AddOns *`
  * \param c4: `C4 *`
  * \param c6: `C6 *`
  */
-void cms(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6);
+void cms(dcomplex **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6);
 
 /*! \brief Compute orientation-averaged scattered field intensity.
  *
@@ -124,9 +131,9 @@ void crsm1(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6);
  * \param c4: `C4 *`
  * \param c6: `C6 *`
  */
-std::complex<double> ghit(
-			  int ihi, int ipamo, int nbl, int l1, int m1, int l2, int m2, C1 *c1,
-			  C1_AddOns *c1ao, C4 *c4, C6 *c6
+dcomplex ghit(
+	      int ihi, int ipamo, int nbl, int l1, int m1, int l2, int m2, C1 *c1,
+	      C1_AddOns *c1ao, C4 *c4, C6 *c6
 );
 
 /*! \brief Compute Hankel funtion and Bessel functions.
@@ -144,7 +151,7 @@ std::complex<double> ghit(
  * \param c4: `C4 *`
  */
 void hjv(
-	 double exri, double vk, int &jer, int &lcalc, std::complex<double> &arg,
+	 double exri, double vk, int &jer, int &lcalc, dcomplex &arg,
 	 C1 *c1, C1_AddOns *c1ao, C4 *c4
 );
 
@@ -153,12 +160,12 @@ void hjv(
  * This function performs the inversion of the multi-centered M-matrix through
  * LU decomposition. See Eq. (5.29) in Borghese, Denti & Saija (2007).
  *
- * \param am: Matrix of complex.
- * \param nddmst: `const int`
- * \param n: `int`
+ * \param am: `complex double **`
+ * \param nddmst: `const int64_t`
+ * \param n: `int64_t`
  * \param ier: `int &`
  */
-void lucin(std::complex<double> **am, const int nddmst, int n, int &ier);
+void lucin(dcomplex **am, const np_int nddmst, np_int n, int &ier);
 
 /*! \brief Compute the average extinction cross-section.
  *
@@ -172,7 +179,7 @@ void lucin(std::complex<double> **am, const int nddmst, int n, int &ier);
  * \param cextlr: `double **`
  * \param cext: `double **`
  */
-void mextc(double vk, double exri, std::complex<double> **fsac, double **cextlr, double **cext);
+void mextc(double vk, double exri, dcomplex **fsac, double **cextlr, double **cext);
 
 /*! \brief Compute cross-sections and forward scattering amplitude for the cluster.
  *
@@ -266,16 +273,16 @@ void r3jmr(int j1, int j2, int j3, int m1, C6 *c6);
  * in Borghese, Denti & Saija (2007).
  *
  * \param le: `int`
- * \param am0m: Matrix of complex.
- * \param w: Matrix of complex.
+ * \param am0m: `complex double **`
+ * \param w: `complex double **`
  * \param tqce: `double **`
- * \param tqcpe: Matrix of complex.
+ * \param tqcpe: `complex double **`
  * \param tqcs: `double **`
- * \param tqcps: Matrix of complex.
+ * \param tqcps: `complex double **`
  */
 void raba(
-	  int le, std::complex<double> **am0m, std::complex<double> **w, double **tqce,
-	  std::complex<double> **tqcpe, double **tqcs, std::complex<double> **tqcps
+	  int le, dcomplex **am0m, dcomplex **w, double **tqce,
+	  dcomplex **tqcpe, double **tqcs, dcomplex **tqcps
 );
 
 /*! \brief Compute the radiation force Cartesian components.
@@ -383,13 +390,13 @@ void tqr(
  * This function computes the single-centered inverrted M-matrix appearing in Eq. (5.28)
  * of Borghese, Denti & Saija (2007).
  *
- * \param am: Matrix of complex.
+ * \param am: `complex double **`
  * \param c1: `C1 *` Pointer to a C1 instance.
  * \param c1ao: `C1_AddOns *` Pointer to C1_AddOns instance.
  * \param c4: `C4 *` Pointer to a C4 structure.
  * \param c6: `C6 *` Pointer to a C6 instance.
  * \param c9: `C9 *` Pointer to a C9 instance.
  */
-void ztm(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6, C9 * c9);
+void ztm(dcomplex **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6, C9 * c9);
 
 #endif
diff --git a/src/include/lapack_calls.h b/src/include/lapack_calls.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f2f365bbc027bf2c4037ccbc2dcbe33403874bf
--- /dev/null
+++ b/src/include/lapack_calls.h
@@ -0,0 +1,23 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
+/*! \file lapack_calss.h
+ *
+ * \brief C++ interface to LAPACK calls.
+ *
+ */
+
+#ifndef INCLUDE_LAPACK_CALLS_H_
+#define INCLUDE_LAPACK_CALLS_H_
+
+/*! \brief Invert a complex matrix with double precision elements.
+ *
+ * Use LAPACKE64 to perform an in-place matrix inversion for a complex
+ * matrix with double precision elements.
+ *
+ * \param mat: Matrix of complex. The matrix to be inverted.
+ * \param n: `lapack_int` The number of rows and columns of the [n x n] matrix.
+ * \param jer: `int &` Reference to an integer return flag.
+ */
+void zinvert(dcomplex **mat, lapack_int n, int &jer);
+
+#endif
diff --git a/src/include/sph_subs.h b/src/include/sph_subs.h
index 2aafef2233caa43a8f76377afc65db380f056c45..427ae3a63af00fa92a1d2df86a8babcbaa91746c 100644
--- a/src/include/sph_subs.h
+++ b/src/include/sph_subs.h
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file sph_subs.h
  *
  * \brief C++ porting of SPH functions and subroutines.
@@ -35,11 +37,11 @@ void aps(double ****zpv, int li, int nsph, C1 *c1, double sqk, double *gaps);
  * backward recurrence. This is the `CSPHJ` implementation of the `specfun` library.
  *
  * \param n: `int` Order of the function.
- * \param z: `complex<double>` Argument of the function.
+ * \param z: `complex double` Argument of the function.
  * \param nm: `int &` Highest computed order.
- * \param csj: Vector of complex. The desired function \f$j\f$.
+ * \param csj: `complex double *` The desired function \f$j\f$.
  */
-void cbf(int n, std::complex<double> z, int &nm, std::complex<double> csj[]);
+void cbf(int n, dcomplex z, int &nm, dcomplex *csj);
 
 /*! \brief Clebsch-Gordan coefficients.
  *
@@ -56,10 +58,10 @@ double cg1(int lmpml, int mu, int l, int m);
 
 /*! \brief Conjugate of a double precision complex number
  *
- * \param z: `complex<double>` The input complex number.
- * \return result: `complex<double>` The conjugate of the input number.
+ * \param z: `complex double` The input complex number.
+ * \return result: `complex double` The conjugate of the input number.
  */
-std::complex<double> dconjg(std::complex<double> z);
+dcomplex dconjg(dcomplex z);
 
 /*! \brief Comute the continuous variation of the refractive index and of its radial derivative.
  *
@@ -95,11 +97,11 @@ void diel(int npntmo, int ns, int i, int ic, double vk, C1 *c1, C2 *c2);
  * \param c2: `C2 *` Pointer to a `C2` data structure.
  * \param jer: `int &` Reference to integer error code variable.
  * \param lcalc: `int &` Reference to integer variable recording the maximum expansion order accounted for.
- * \param arg: `complex<double> &`
+ * \param arg: `complex double &`
  */
 void dme(
 	 int li, int i, int npnt, int npntts, double vk, double exdc, double exri,
-	 C1 *c1, C2 *c2, int &jer, int &lcalc, std::complex<double> &arg
+	 C1 *c1, C2 *c2, int &jer, int &lcalc, dcomplex &arg
 );
 
 /*! \brief Bessel function calculation control parameters.
@@ -118,11 +120,11 @@ double envj(int n, double x);
  * This function computes the Mueller Transformation Matrix, or Phase Matrix. See
  * Sec. 2.8.1 of Borghese, Denti & Saija (2007).
  *
- * \param vint: Vector of complex.
+ * \param vint: `complex double *`
  * \param cmullr: `double **`
  * \param cmul: `double **`
  */
-void mmulc(std::complex<double> *vint, double **cmullr, double **cmul);
+void mmulc(dcomplex *vint, double **cmullr, double **cmul);
 
 /*! \brief Starting point for Bessel function magnitude.
  *
@@ -168,14 +170,14 @@ void orunve(double *u1, double *u2, double *u3, int iorth, double torth);
  *
  * \param up: `double *`
  * \param un: `double *`
- * \param ylm: Vector of complex. Field polar spherical harmonics.
+ * \param ylm: `complex double *` Field polar spherical harmonics.
  * \param inpol: `int` Incident field polarization type (0 - linear; 1 - circular).
  * \param lw: `int`
  * \param isq: `int`
  * \param c1: `C1 *` Pointer to a `C1` data structure.
  */
 void pwma(
-	  double *up, double *un, std::complex<double> *ylm, int inpol, int lw,
+	  double *up, double *un, dcomplex *ylm, int inpol, int lw,
 	  int isq, C1 *c1
 );
 
@@ -189,14 +191,14 @@ void pwma(
  * \param li: `int` Maximum field expansion order.
  * \param nsph: `int` Number of spheres.
  * \param c1: `C1 *` Pointer to `C1` data structure.
- * \param tqse: Matrix of complex.
- * \param tqspe: Matrix of complex.
- * \param tqss: Matrix of complex.
- * \param tqsps: Matrix of complex.
+ * \param tqse: `double **`
+ * \param tqspe: `complex double **`
+ * \param tqss: `double **`
+ * \param tqsps: `complex double **`
  */
 void rabas(
-	   int inpol, int li, int nsph, C1 *c1, double **tqse, std::complex<double> **tqspe,
-	   double **tqss, std::complex<double> **tqsps
+	   int inpol, int li, int nsph, C1 *c1, double **tqse, dcomplex **tqspe,
+	   double **tqss, dcomplex **tqsps
 );
 
 /*! \brief Real Bessel Function.
@@ -219,18 +221,17 @@ void rbf(int n, double x, int &nm, double sj[]);
  *
  * \param npntmo: `int`
  * \param step: `double`
- * \param dcc: `complex<double>`
+ * \param dcc: `complex double`
  * \param x: `double &`
  * \param lpo: `int`
- * \param y1: `complex<double> &`
- * \param y2: `complex<double> &`
- * \param dy1: `complex<double> &`
- * \param dy2: `complex<double> &`
+ * \param y1: `complex double &`
+ * \param y2: `complex double &`
+ * \param dy1: `complex double &`
+ * \param dy2: `complex double &`
  */
 void rkc(
-	 int npntmo, double step, std::complex<double> dcc, double &x, int lpo,
-	 std::complex<double> &y1, std::complex<double> &y2, std::complex<double> &dy1,
-	 std::complex<double> &dy2
+	 int npntmo, double step, dcomplex dcc, double &x, int lpo,
+	 dcomplex &y1, dcomplex &y2, dcomplex &dy1, dcomplex &dy2
 );
 
 /*! \brief Transition layer radial function and derivative.
@@ -242,16 +243,15 @@ void rkc(
  * \param step: `double`
  * \param x: `double &`
  * \param lpo: `int`
- * \param y1: `complex<double> &`
- * \param y2: `complex<double> &`
- * \param dy1: `complex<double> &`
- * \param dy2: `complex<double> &`
+ * \param y1: `complex double &`
+ * \param y2: `complex double &`
+ * \param dy1: `complex double &`
+ * \param dy2: `complex double &`
  * \param c2: `C2 *` Pointer to a `C2` data structure.
  */
 void rkt(
-	 int npntmo, double step, double &x, int lpo, std::complex<double> &y1,
-	 std::complex<double> &y2, std::complex<double> &dy1, std::complex<double> &dy2,
-	 C2 *c2
+	 int npntmo, double step, double &x, int lpo, dcomplex &y1,
+	 dcomplex &y2, dcomplex &dy1, dcomplex &dy2, C2 *c2
 );
 
 /*! \brief Spherical Bessel functions.
@@ -262,9 +262,9 @@ void rkt(
  * \param n: `int` Order of the function (from 0 up).
  * \param x: `double` Argumento of the function (\f$x > 0\f$).
  * \param nm: `int &` Highest computed order.
- * \param sy: `double[]` The desired function \f$y\f$.
+ * \param sy: `double *` The desired function \f$y\f$.
  */
-void rnf(int n, double x, int &nm, double sy[]);
+void rnf(int n, double x, int &nm, double *sy);
 
 /*! \brief Spherical harmonics for given direction.
  *
@@ -276,11 +276,11 @@ void rnf(int n, double x, int &nm, double sy[]);
  * \param cosrph: `double` Cosine of direction's azimuth.
  * \param sinrph: `double` Sine of direction's azimuth.
  * \param ll: `int` L value expansion order.
- * \param ylm: Vector of complex. The requested spherical harmonics.
+ * \param ylm: `complex double *` The requested spherical harmonics.
  */
 void sphar(
 	   double cosrth, double sinrth, double cosrph, double sinrph,
-	   int ll, std::complex<double> *ylm
+	   int ll, dcomplex *ylm
 );
 
 /*! \brief Compute scattering, absorption and extinction cross-sections.
@@ -288,14 +288,14 @@ void sphar(
  * This function computes the scattering, absorption and extinction cross-sections in terms
  * of Forward Scattering Amplitudes. See Sec. 4.2.1 in Borghese, Denti & Saija (2007).
  *
- * \param tfsas: `complex<double> &`
+ * \param tfsas: `complex double &`
  * \param nsph: `int` Number of spheres.
  * \param lm: `int` Maximum field expansion order.
  * \param vk: `double` Wave number in scale units.
  * \param exri: `double` External medium refractive index.
  * \param c1: `C1 *` Pointer to a `C1` data structure.
  */
-void sscr0(std::complex<double> &tfsas, int nsph, int lm, double vk, double exri, C1 *c1);
+void sscr0(dcomplex &tfsas, int nsph, int lm, double vk, double exri, C1 *c1);
 
 /*! \brief C++ Compute the scattering amplitude and the scattered field intensity.
  *
diff --git a/src/include/tfrfme.h b/src/include/tfrfme.h
index ba2954a742b5458f8cabb1ca64729befef232e20..2e55c4822b1d186bb7a8094e6ba89aafa46f176c 100644
--- a/src/include/tfrfme.h
+++ b/src/include/tfrfme.h
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file tfrfme.h
  *
  * \brief Representation of the trapping calculation objects.
@@ -18,7 +20,7 @@ protected:
   int nlmmt;
 
   //! QUESTION: definition?
-  std::complex<double> *wk;
+  dcomplex *wk;
 
   /*! \brief Load a Swap1 instance from a HDF5 binary file.
    *
@@ -60,9 +62,9 @@ public:
 
   /*! \brief Append an element at the end of the vector.
    *
-   * \param value: `complex<double>` The value to be added to the vector.
+   * \param value: `complex double` The value to be added to the vector.
    */
-  void append(std::complex<double> value) { wk[last_index++] = value; }
+  void append(dcomplex value) { wk[last_index++] = value; }
   
   /*! \brief Load a Swap1 instance from binary file.
    *
@@ -83,9 +85,9 @@ public:
   
   /*! \brief Get the pointer to the WK vector.
    *
-   * \return value: `complex<double> *` Memory address of the WK vector.
+   * \return value: `complex double *` Memory address of the WK vector.
    */
-  std::complex<double> *get_vector() { return wk; }
+  dcomplex *get_vector() { return wk; }
 
   /*! \brief Bring the pointer to the next element at the start of vector.
    */
@@ -311,7 +313,7 @@ protected:
   //! Vector of computed z positions
   double *zv;
   //! QUESTION: definition?
-  std::complex<double> **wsum;
+  dcomplex **wsum;
 
   /*! \brief Load a configuration instance from a HDF5 binary file.
    *
@@ -371,9 +373,9 @@ public:
 
   /*! \brief Get the pointer to the WSUM matrix.
    *
-   * \return value: `complex<double> **` Pointer to the WSUM matrix.
+   * \return value: `complex double **` Pointer to the WSUM matrix.
    */
-  std::complex<double> **get_matrix() { return wsum; }
+  dcomplex **get_matrix() { return wsum; }
 
   /*! \brief Calculate the necessary amount of memory to create a new instance.
    *
diff --git a/src/include/tra_subs.h b/src/include/tra_subs.h
index c32aa9ae9bffb58387d936afcf6547c12713be21..37e728507fe71f9444d7f1fd405044b2aad6e3e4 100644
--- a/src/include/tra_subs.h
+++ b/src/include/tra_subs.h
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file tra_subs.h
  *
  * \brief C++ porting of TRAPPING functions and subroutines.
@@ -48,17 +50,14 @@ struct CCR {
 
 /*! C++ porting of CAMP
  *
- * \param ac: Vector of complex. QUESTION: definition?
- * \param am0m: Matrix of complex. QUESTION: definition?
- * \param ws: Vector of complex. QUESTION: definition?
+ * \param ac: `complex double *` QUESTION: definition?
+ * \param am0m: `complex double **` QUESTION: definition?
+ * \param ws: `complex double *` QUESTION: definition?
  * \param cil: `CIL *` Pointer to a CIL structure.
  *
  * This function builds the AC vector using AM0M and WS.
  */
-void camp(
-	  std::complex<double> *ac, std::complex<double> **am0m, std::complex<double> *ws,
-	  CIL *cil
-);
+void camp(dcomplex *ac, dcomplex **am0m, dcomplex *ws, CIL *cil);
 
 /*! C++ porting of CZAMP
  *
@@ -70,26 +69,33 @@ void camp(
  *
  * This function builds the AC vector using AMD, INDAM and WS.
  */
-void czamp(
-	   std::complex<double> *ac, std::complex<double> **amd, int **indam,
-	   std::complex<double> *ws, CIL *cil
-);
+void czamp(dcomplex *ac, dcomplex **amd, int **indam, dcomplex *ws, CIL *cil);
 
 /*! C++ porting of FFRF
  *
  * \param zpv: `double ****`. QUESTION: definition?
- * \param ac: Vector of complex. QUESTION: definition?
- * \param ws: Vector of complex. QUESTION: definition?
+ * \param ac: `complex double *` QUESTION: definition?
+ * \param ws: `complex double *` QUESTION: definition?
  * \param fffe: `double *`. QUESTION: definition?
  * \param fffs: `double *`. QUESTION: definition?
  * \param cil: `CIL *` Pointer to a CIL structure.
  * \param ccr: `CCR *` Pointer to a CCR structure.
  */
 void ffrf(
-	  double ****zpv, std::complex<double> *ac, std::complex<double> *ws, double *fffe,
+	  double ****zpv, dcomplex *ac, dcomplex *ws, double *fffe,
 	  double *fffs, CIL *cil, CCR *ccr
 );
 
+/*! C++ porting of FFRT
+ *
+ * \param ac: `complex double *` QUESTION: definition?
+ * \param ws: `complex double *` QUESTION: definition?
+ * \param ffte: `double *`. QUESTION: definition?
+ * \param ffts: `double *`. QUESTION: definition?
+ * \param cil: `CIL *` Pointer to a CIL structure.
+ */
+void ffrt(dcomplex *ac, dcomplex *ws, double *ffte, double *ffts, CIL *cil);
+
 /*! C++ porting of FRFMER
  *
  * \param nkv: `int` QUESTION: definition?
@@ -105,68 +111,50 @@ void ffrf(
  * \param pmf: `double` QUESTION: definition?
  * \param tt1: `Swap1 *` Pointer to first swap object.
  * \param tt2: `Swap2 *` Pointer to second swap object.
+ * \return wk: `complex double *` QUESTION: definition?
  */
-std::complex<double> *frfmer(
+dcomplex *frfmer(
 	    int nkv, double vkm, double vknmx, double apfafa, double tra,
 	    double spd, double rir, double ftcn, int le, int lmode, double pmf,
 	    Swap1 *tt1, Swap2 *tt2
 );
 
-/*! C++ porting of FFRT
- *
- * \param ac: Vector of complex. QUESTION: definition?
- * \param ws: Vector of complex. QUESTION: definition?
- * \param ffte: `double *`. QUESTION: definition?
- * \param ffts: `double *`. QUESTION: definition?
- * \param cil: `CIL *` Pointer to a CIL structure.
- */
-void ffrt(
-	  std::complex<double> *ac, std::complex<double> *ws, double *ffte, double *ffts,
-	  CIL *cil
-);
-
 /*! C++ porting of PWMALP
  *
- * \param w: Matrix of complex. QUESTION: definition?
+ * \param w: `complex double *` QUESTION: definition?
  * \param up: `double *`
  * \param un: `double *`
- * \param ylm: Vector of complex
+ * \param ylm: `complex double *` Field vector spherical harmonics.
  * \param lw: `int`
  */
-void pwmalp(std::complex<double> **w, double *up, double *un, std::complex<double> *ylm, int lw);
+void pwmalp(dcomplex **w, double *up, double *un, dcomplex *ylm, int lw);
 
 /*! C++ porting of SAMP
  *
- * \param ac: Vector of complex. QUESTION: definition?
- * \param tmsm: Vector of complex. QUESTION: definition?
- * \param tmse: Vector of complex. QUESTION: definition?
- * \param ws: Vector of complex. QUESTION: definition?
+ * \param ac: `complex double *` QUESTION: definition?
+ * \param tmsm: `complex double *` QUESTION: definition?
+ * \param tmse: `complex double *` QUESTION: definition?
+ * \param ws: `complex double *` QUESTION: definition?
  * \param cil: `CIL *` Pointer to a CIL structure.
  *
  * This function builds the AC vector using TMSM, TMSE and WS.
  */
-void samp(
-	  std::complex<double> *ac, std::complex<double> *tmsm, std::complex<double> *tmse,
-	  std::complex<double> *ws, CIL *cil
-);
+void samp(dcomplex *ac, dcomplex *tmsm, dcomplex *tmse, dcomplex *ws, CIL *cil);
 
 /*! C++ porting of SAMPOA
  *
- * \param ac: Vector of complex. QUESTION: definition?
- * \param tms: Matrix of complex. QUESTION: definition?
- * \param ws: Vector of complex. QUESTION: definition?
+ * \param ac: `complex double *` QUESTION: definition?
+ * \param tms: `complex double **` QUESTION: definition?
+ * \param ws: `complex double *` QUESTION: definition?
  * \param cil: `CIL *` Pointer to a CIL structure.
  *
  * This function builds the AC vector using TMS and WS.
  */
-void sampoa(
-	    std::complex<double> *ac, std::complex<double> **tms, std::complex<double> *ws,
-	    CIL *cil
-);
+void sampoa(dcomplex *ac, dcomplex **tms, dcomplex *ws, CIL *cil);
 
 /*! C++ porting of WAMFF
  *
- * \param wk: `complex<double> *` QUESTION: definition?
+ * \param wk: `complex double *` QUESTION: definition?
  * \param x: `double`
  * \param y: `double`
  * \param z: `double`
@@ -180,6 +168,6 @@ void sampoa(
  * \param pmf: `double` QUESTION: definition?
  */
 void wamff(
-	   std::complex<double> *wk, double x, double y, double z, int lm, double apfafa,
+	   dcomplex *wk, double x, double y, double z, int lm, double apfafa,
 	   double tra, double spd, double rir, double ftcn, int lmode, double pmf
 );
diff --git a/src/include/types.h b/src/include/types.h
new file mode 100644
index 0000000000000000000000000000000000000000..0271769a73600adc8de3ff6dfe1cf4d9d0f8a49f
--- /dev/null
+++ b/src/include/types.h
@@ -0,0 +1,28 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
+/*! \file types.h
+ *
+ * \brief Definition of fundamental types in use.
+ */
+
+#ifndef INCLUDE_TYPES_H_
+#define INCLUDE_TYPES_H_
+
+#include <complex.h>
+
+typedef __complex__ double dcomplex;
+
+/*! \brief Get the real part of a complex number.
+ *
+ * \param z: `complex double` The argument of the function.
+ * \return rz: `double` The real part of the argument.
+ */
+double real(dcomplex z);
+
+/*! \brief Get the imaginary part of a complex number.
+ *
+ * \param z: `complex double` The argument of the function.
+ * \return iz: `double` The imaginary part of the argument.
+ */
+double imag(dcomplex z);
+#endif
diff --git a/src/libnptm/Commons.cpp b/src/libnptm/Commons.cpp
index d19e62b58843443c3c1540d43f353b05e55bd025..fc9498a839ede48183ce665b3fd15c01d8e404cb 100644
--- a/src/libnptm/Commons.cpp
+++ b/src/libnptm/Commons.cpp
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file Commons.cpp
  *
  * DEVELOPMENT NOTE:
@@ -10,38 +12,38 @@
  * to the configuration objects. These, on their turn, need to
  * expose methods to access the relevant data in read-only mode.
  */
-#include <complex>
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
 
 #ifndef INCLUDE_COMMONS_H
 #include "../include/Commons.h"
 #endif
 
-using namespace std;
-
 C1::C1(int ns, int l_max, int *_nshl, int *_iog) {
   nlmmt = 2 * (l_max * (l_max + 2));
   nsph = ns;
   lm = l_max;
 
-  rmi = new complex<double>*[lm];
-  rei = new complex<double>*[lm];
+  rmi = new dcomplex*[lm];
+  rei = new dcomplex*[lm];
   for (int ri = 0; ri < lm; ri++) {
-    rmi[ri] = new complex<double>[nsph]();
-    rei[ri] = new complex<double>[nsph]();
+    rmi[ri] = new dcomplex[nsph]();
+    rei[ri] = new dcomplex[nsph]();
   }
-  w = new complex<double>*[nlmmt];
-  for (int wi = 0; wi < nlmmt; wi++) w[wi] = new complex<double>[4]();
+  w = new dcomplex*[nlmmt];
+  for (int wi = 0; wi < nlmmt; wi++) w[wi] = new dcomplex[4]();
   int configurations = 0;
   for (int ci = 1; ci <= nsph; ci++) {
     if (_iog[ci - 1] >= ci) configurations++;
   }
-  vints = new complex<double>*[nsph];
+  vints = new dcomplex*[nsph];
   rc = new double*[configurations];
   nshl = new int[configurations]();
   iog = new int[nsph]();
   int conf_index = 0;
   for (int vi = 0; vi < nsph; vi++) {
-    vints[vi] = new complex<double>[16]();
+    vints[vi] = new dcomplex[16]();
     iog[vi] = _iog[vi];
     if (iog[vi] >= vi + 1) {
       nshl[conf_index] = _nshl[conf_index];
@@ -49,7 +51,7 @@ C1::C1(int ns, int l_max, int *_nshl, int *_iog) {
       conf_index++;
     }
   }
-  fsas = new complex<double>[nsph]();
+  fsas = new dcomplex[nsph]();
   sscs = new double[nsph]();
   sexs = new double[nsph]();
   sabs = new double[nsph]();
@@ -62,11 +64,11 @@ C1::C1(int ns, int l_max, int *_nshl, int *_iog) {
   rzz = new double[nsph]();
   ros = new double[nsph]();
 
-  sas = new complex<double>**[nsph];
+  sas = new dcomplex**[nsph];
   for (int si = 0; si < nsph; si++) {
-    sas[si] = new complex<double>*[2];
-    sas[si][0] = new complex<double>[2]();
-    sas[si][1] = new complex<double>[2]();
+    sas[si] = new dcomplex*[2];
+    sas[si][0] = new dcomplex[2]();
+    sas[si][1] = new dcomplex[2]();
   }
 }
 
@@ -112,32 +114,32 @@ C1_AddOns::C1_AddOns(C4 *c4) {
   nsph = c4->nsph;
   lmpo = c4->lmpo;
   nlemt = 2 * c4->nlem;
-  vh = new complex<double>[(nsph * nsph - 1) * c4->litpo]();
-  vj0 = new complex<double>[nsph * c4->lmtpo]();
-  vj = new complex<double>[1](); // QUESTION: is 1 really enough for a general case?
-  vyhj = new complex<double>[(nsph * nsph - 1) * c4->litpos]();
-  vyj0 = new complex<double>[nsph * c4->lmtpos]();
-  am0m = new complex<double>*[nlemt];
+  vh = new dcomplex[(nsph * nsph - 1) * c4->litpo]();
+  vj0 = new dcomplex[nsph * c4->lmtpo]();
+  vj = new dcomplex[1](); // QUESTION: is 1 really enough for a general case?
+  vyhj = new dcomplex[(nsph * nsph - 1) * c4->litpos]();
+  vyj0 = new dcomplex[nsph * c4->lmtpos]();
+  am0m = new dcomplex*[nlemt];
   for (int ai = 0; ai < nlemt; ai++) {
-    am0m[ai] = new complex<double>[nlemt]();
+    am0m[ai] = new dcomplex[nlemt]();
   }
-  vint = new complex<double>[16](); // QUESTION: is dimension 16 generally fixed?
-  vintm = new complex<double>[16]();
-  vintt = new complex<double>[16]();
-  vints = new complex<double>*[nsph];
-  for (int vi = 0; vi < nsph; vi++) vints[vi] = new complex<double>[16]();
-  fsac = new complex<double>*[2];
-  sac = new complex<double>*[2];
-  fsacm = new complex<double>*[2];
+  vint = new dcomplex[16](); // QUESTION: is dimension 16 generally fixed?
+  vintm = new dcomplex[16]();
+  vintt = new dcomplex[16]();
+  vints = new dcomplex*[nsph];
+  for (int vi = 0; vi < nsph; vi++) vints[vi] = new dcomplex[16]();
+  fsac = new dcomplex*[2];
+  sac = new dcomplex*[2];
+  fsacm = new dcomplex*[2];
   for (int fi = 0; fi < 2; fi++) {
-    fsac[fi] = new complex<double>[2]();
-    sac[fi] = new complex<double>[2]();
-    fsacm[fi] = new complex<double>[2]();
+    fsac[fi] = new dcomplex[2]();
+    sac[fi] = new dcomplex[2]();
+    fsacm[fi] = new dcomplex[2]();
   }
-  scscp = new complex<double>[2]();
-  ecscp = new complex<double>[2]();
-  scscpm = new complex<double>[2]();
-  ecscpm = new complex<double>[2]();
+  scscp = new dcomplex[2]();
+  ecscp = new dcomplex[2]();
+  scscpm = new dcomplex[2]();
+  ecscpm = new dcomplex[2]();
   allocate_vectors(c4);
   sscs = new double[nsph]();
   ecscm = new double[2]();
@@ -191,20 +193,20 @@ void C1_AddOns::allocate_vectors(C4 *c4) {
   for (int ii = 0; ii < lmpo; ii++) ind3j[ii] = new int[c4->lm]();
   // This calculates the size of vyhj
   int ivy = (nsph * nsph - 1) * c4->litpos;
-  vyhj = new complex<double>[ivy]();
+  vyhj = new dcomplex[ivy]();
   // This calculates the size of vyj0
   ivy = c4->lmtpos * c4->nsph;
-  vyj0 = new complex<double>[ivy]();
+  vyj0 = new dcomplex[ivy]();
 }
 
 C2::C2(int ns, int nl, int npnt, int npntts) {
   nsph = ns;
   int max_n = (npnt > npntts) ? npnt : npntts;
   nhspo = 2 * max_n - 1;
-  ris = new complex<double>[nhspo]();
-  dlri = new complex<double>[nhspo]();
-  vkt = new complex<double>[nsph]();
-  dc0 = new complex<double>[nl]();
+  ris = new dcomplex[nhspo]();
+  dlri = new dcomplex[nhspo]();
+  vkt = new dcomplex[nsph]();
+  dc0 = new dcomplex[nl]();
   vsz = new double[nsph]();
 }
 
@@ -217,10 +219,10 @@ C2::~C2() {
 }
 
 C3::C3() {
-  tsas = new complex<double>*[2];
-  tsas[0] = new complex<double>[2];
-  tsas[1] = new complex<double>[2];
-  tfsas = complex<double>(0.0, 0.0);
+  tsas = new dcomplex*[2];
+  tsas[0] = new dcomplex[2];
+  tsas[1] = new dcomplex[2];
+  tfsas = 0.0 + 0.0 * I;
   gcs = 0.0;
   scs = 0.0;
   ecs = 0.0;
@@ -242,14 +244,14 @@ C6::~C6() {
 }
 
 C9::C9(int ndi, int nlem, int ndit, int nlemt) {
-  gis = new complex<double>*[ndi];
-  gls = new complex<double>*[ndi];
+  gis = new dcomplex*[ndi];
+  gls = new dcomplex*[ndi];
   for (int gi = 0; gi < ndi; gi++) {
-    gis[gi] = new complex<double>[nlem]();
-    gls[gi] = new complex<double>[nlem]();
+    gis[gi] = new dcomplex[nlem]();
+    gls[gi] = new dcomplex[nlem]();
   }
-  sam = new complex<double>*[ndit];
-  for (int si = 0; si < ndit; si++) sam[si] = new complex<double>[nlemt]();
+  sam = new dcomplex*[ndit];
+  for (int si = 0; si < ndit; si++) sam[si] = new dcomplex[nlemt]();
   gis_size_0 = ndi;
   sam_size_0 = ndit;
 }
diff --git a/src/libnptm/Configuration.cpp b/src/libnptm/Configuration.cpp
index 04cdb5c03a0930affa172afb46d7db960166914b..1bf78b7db3e571858bee6ad893f0c575dbb33644 100644
--- a/src/libnptm/Configuration.cpp
+++ b/src/libnptm/Configuration.cpp
@@ -1,10 +1,11 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file Configuration.cpp
  *
  * \brief Implementation of the configuration classes.
  */
 
 #include <cmath>
-#include <complex>
 #include <cstdio>
 #include <exception>
 #include <fstream>
@@ -12,6 +13,10 @@
 #include <regex>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_ERRORS_H_
 #include "../include/errors.h"
 #endif
@@ -202,7 +207,7 @@ ScattererConfiguration::ScattererConfiguration(
 					       int *nshl_vector,
 					       double **rcf_vector,
 					       int dielectric_func_type,
-					       complex<double> ***dc_matrix,
+					       dcomplex ***dc_matrix,
 					       bool is_external,
 					       double ex,
 					       double w,
@@ -477,12 +482,12 @@ ScattererConfiguration* ScattererConfiguration::from_dedfb(string dedfb_file_nam
     } // ns112 loop
   } // i113 loop
 
-  complex<double> ***dc0m = new complex<double>**[configurations];
-  complex<double> *dc0 = new complex<double>[configurations]();
+  dcomplex ***dc0m = new dcomplex**[configurations];
+  dcomplex *dc0 = new dcomplex[configurations]();
   int dim3 = (_idfc == 0) ? nxi : 1;
   for (int di = 0; di < configurations; di++) {
-    dc0m[di] = new complex<double>*[nsph];
-    for (int dj = 0; dj < nsph; dj++) dc0m[di][dj] = new complex<double>[dim3]();
+    dc0m[di] = new dcomplex*[nsph];
+    for (int dj = 0; dj < nsph; dj++) dc0m[di][dj] = new dcomplex[dim3]();
   } // di loop
   for (int jxi468 = 1; jxi468 <= nxi; jxi468++) {
     if (_idfc != 0 && jxi468 > 1) continue; // jxi468 loop
@@ -504,7 +509,7 @@ ScattererConfiguration* ScattererConfiguration::from_dedfb(string dedfb_file_nam
 	  str_number = regex_replace(str_number, regex("D"), "e");
 	  str_number = regex_replace(str_number, regex("d"), "e");
 	  double ival = stod(str_number);
-	  dc0[ic157] = complex<double>(rval, ival);
+	  dc0[ic157] = rval + ival * I;
 	  dc0m[ic157][i162 - 1][jxi468 - 1] = dc0[ic157];
 	} // ic157 loop
       }
@@ -547,7 +552,7 @@ ScattererConfiguration* ScattererConfiguration::from_hdf5(string file_name) {
     double *xi_vec;
     double *ros_vector;
     double **rcf_vector;
-    complex<double> ***dc0m;
+    dcomplex ***dc0m;
     status = hdf_file->read("NSPH", "INT32_(1)", &nsph);
     status = hdf_file->read("IES", "INT32_(1)", &ies);
     status = hdf_file->read("EXDC", "FLOAT64_(1)", &_exdc);
@@ -591,17 +596,17 @@ ScattererConfiguration* ScattererConfiguration::from_hdf5(string file_name) {
     str_name = "DC0M";
     str_type = "FLOAT64_(" + to_string(element_size) + ")";
     status = hdf_file->read(str_name, str_type, elements);
-    dc0m = new complex<double>**[configuration_count];
+    dc0m = new dcomplex**[configuration_count];
     int dc_index = 0;
     for (int di = 0; di < configuration_count; di++) {
-      dc0m[di] = new complex<double>*[nsph];
+      dc0m[di] = new dcomplex*[nsph];
       for (int dj = 0; dj < nsph; dj++) {
-	dc0m[di][dj] = new complex<double>[dim3]();
+	dc0m[di][dj] = new dcomplex[dim3]();
 	for (int dk = 0; dk < dim3; dk++) {
 	  double rval = elements[2 * dc_index];
 	  double ival = elements[2 * dc_index + 1];
 	  dc_index++;
-	  dc0m[di][dj][dk] = complex<double>(rval, ival);
+	  dc0m[di][dj][dk] = rval + ival * I;
 	}
       } // dj loop
     } // di loop
@@ -638,7 +643,7 @@ ScattererConfiguration* ScattererConfiguration::from_legacy(string file_name) {
   double *_xi_vec;
   double *_ros_vec;
   double **_rcf_vec;
-  complex<double> ***_dc0m;
+  dcomplex ***_dc0m;
 
   fstream input;
   input.open(file_name.c_str(), ios::in | ios::binary);
@@ -672,11 +677,11 @@ ScattererConfiguration* ScattererConfiguration::from_legacy(string file_name) {
     for (int nsi = 0; nsi < nsh; nsi++)
       input.read(reinterpret_cast<char *>(&(_rcf_vec[i115 - 1][nsi])), sizeof(double));
   }
-  _dc0m = new complex<double>**[configurations];
+  _dc0m = new dcomplex**[configurations];
   int dim3 = (_idfc == 0) ? _nxi : 1;
   for (int di = 0; di < configurations; di++) {
-    _dc0m[di] = new complex<double>*[_nsph];
-    for (int dj = 0; dj < _nsph; dj++) _dc0m[di][dj] = new complex<double>[dim3]();
+    _dc0m[di] = new dcomplex*[_nsph];
+    for (int dj = 0; dj < _nsph; dj++) _dc0m[di][dj] = new dcomplex[dim3]();
   } // di loop
   for (int jxi468 = 1; jxi468 <= _nxi; jxi468++) {
     if (_idfc != 0 && jxi468 > 1) continue;
@@ -689,7 +694,7 @@ ScattererConfiguration* ScattererConfiguration::from_legacy(string file_name) {
 	double rval, ival;
 	input.read(reinterpret_cast<char *>(&rval), sizeof(double));
 	input.read(reinterpret_cast<char *>(&ival), sizeof(double));
-	_dc0m[i157][i162 - 1][jxi468 - 1] = complex<double>(rval, ival);
+	_dc0m[i157][i162 - 1][jxi468 - 1] = rval + ival * I;
       }
     }
   }
@@ -771,7 +776,7 @@ void ScattererConfiguration::print() {
       printf("          [");
       for (int k = 0; k < number_of_scales; k++) {
 	if (idfc != 0 and k > 0) continue;
-	printf("\t%lg + i(%lg)", dc0_matrix[i][j][k].real(), dc0_matrix[i][j][k].imag());
+	printf("\t%lg + i(%lg)", real(dc0_matrix[i][j][k]), imag(dc0_matrix[i][j][k]));
       }
       printf("\t]\n");
     }
@@ -862,8 +867,8 @@ void ScattererConfiguration::write_hdf5(string file_name) {
       if (i162 == 1) ici = ici + ies;
       for (int i157 = 0; i157 < ici; i157++) {
 	double dc0_real, dc0_imag;
-	dc0_real = dc0_matrix[i157][i162 - 1][jxi468 - 1].real();
-	dc0_imag = dc0_matrix[i157][i162 - 1][jxi468 - 1].imag();
+	dc0_real = real(dc0_matrix[i157][i162 - 1][jxi468 - 1]);
+	dc0_imag = imag(dc0_matrix[i157][i162 - 1][jxi468 - 1]);
 	dc0m[2 * dc0_index] = dc0_real;
 	dc0m[2 * dc0_index + 1] = dc0_imag;
 	dc0_index++;
@@ -926,8 +931,8 @@ void ScattererConfiguration::write_legacy(string file_name) {
       if (i162 == 1) ici = ici + ies;
       for (int i157 = 0; i157 < ici; i157++) {
 	double dc0_real, dc0_img;
-	dc0_real = dc0_matrix[i157][i162 - 1][jxi468 - 1].real();
-	dc0_img = dc0_matrix[i157][i162 - 1][jxi468 - 1].imag();
+	dc0_real = real(dc0_matrix[i157][i162 - 1][jxi468 - 1]);
+	dc0_img = imag(dc0_matrix[i157][i162 - 1][jxi468 - 1]);
 	// The FORTRAN code writes the complex numbers as a 16-byte long binary stream.
 	// Here we assume that the 16 bytes are equally split in 8 bytes to represent the
 	// real part and 8 bytes to represent the imaginary one.
@@ -1096,7 +1101,8 @@ void ScattererConfiguration::write_formatted(string file_name) {
       if (i473 == 1) ici += ies;
       fprintf(output, " SPHERE N.%4d\n", i473);
       for (int ic472 = 0; ic472 < ici; ic472++) {
-	double dc0_real = dc0_matrix[ic472][i473 - 1][0].real(), dc0_img = dc0_matrix[ic472][i473 - 1][0].imag();
+	double dc0_real = real(dc0_matrix[ic472][i473 - 1][0]);
+	double dc0_img = imag(dc0_matrix[ic472][i473 - 1][0]);
 	fprintf(output, "%5d %12.4lE%12.4lE\n", (ic472 + 1), dc0_real, dc0_img);
       }
     }
@@ -1110,8 +1116,8 @@ void ScattererConfiguration::write_formatted(string file_name) {
       for (int ic477 = 1; ic477 <= ici; ic477++) {
 	fprintf(output, " NONTRANSITION LAYER N.%2d, SCALE = %3s\n", ic477, reference_variable_name.c_str());
 	for (int jxi476 = 0; jxi476 < number_of_scales; jxi476++) {
-	  double dc0_real = dc0_matrix[ic477 - 1][i478 - 1][jxi476].real();
-	  double dc0_img = dc0_matrix[ic477 - 1][i478 - 1][jxi476].imag();
+	  double dc0_real = real(dc0_matrix[ic477 - 1][i478 - 1][jxi476]);
+	  double dc0_img = imag(dc0_matrix[ic477 - 1][i478 - 1][jxi476]);
 	  fprintf(output, "%5d %12.4lE%12.4lE\n", (jxi476 + 1), dc0_real, dc0_img);
 	}
       }
diff --git a/src/libnptm/Makefile b/src/libnptm/Makefile
index b2fbc322c6b1a227ba0e29e80cd2d8e8c2c688bd..43b886ffe2745399f4e1389471c4050f1d0c4c48 100644
--- a/src/libnptm/Makefile
+++ b/src/libnptm/Makefile
@@ -19,11 +19,11 @@ endif
 include ../make.inc
 
 
-CXX_NPTM_OBJS=$(OBJDIR)/Commons.o $(OBJDIR)/Configuration.o $(OBJDIR)/file_io.o $(OBJDIR)/Parsers.o $(OBJDIR)/sph_subs.o $(OBJDIR)/clu_subs.o $(OBJDIR)/tfrfme.o $(OBJDIR)/tra_subs.o $(OBJDIR)/TransitionMatrix.o
+CXX_NPTM_OBJS=$(OBJDIR)/Commons.o $(OBJDIR)/Configuration.o $(OBJDIR)/file_io.o $(OBJDIR)/Parsers.o $(OBJDIR)/sph_subs.o $(OBJDIR)/clu_subs.o $(OBJDIR)/tfrfme.o $(OBJDIR)/tra_subs.o $(OBJDIR)/TransitionMatrix.o $(OBJDIR)/lapack_calls.o $(OBJDIR)/algebraic.o $(OBJDIR)/types.o
 
-CXX_NPTM_DYNOBJS=$(DYNOBJDIR)/Commons.o $(DYNOBJDIR)/Configuration.o $(DYNOBJDIR)/file_io.o $(DYNOBJDIR)/Parsers.o $(DYNOBJDIR)/sph_subs.o $(DYNOBJDIR)/clu_subs.o $(DYNOBJDIR)/tfrfme.o $(DYNOBJDIR)/tra_subs.o $(DYNOBJDIR)/TransitionMatrix.o
+CXX_NPTM_DYNOBJS=$(DYNOBJDIR)/Commons.o $(DYNOBJDIR)/Configuration.o $(DYNOBJDIR)/file_io.o $(DYNOBJDIR)/Parsers.o $(DYNOBJDIR)/sph_subs.o $(DYNOBJDIR)/clu_subs.o $(DYNOBJDIR)/tfrfme.o $(DYNOBJDIR)/tra_subs.o $(DYNOBJDIR)/TransitionMatrix.o $(DYNOBJDIR)/lapack_calls.o $(DYNOBJDIR)/algebraic.o $(DYNOBJDIR)/types.o
 
-CXX_NPTM_DEBUG=$(OBJDIR)/Commons.g* $(OBJDIR)/Configuration.g* $(OBJDIR)/file_io.g* $(OBJDIR)/Parsers.g* $(OBJDIR)/sph_subs.g* $(OBJDIR)/clu_subs.g* $(OBJDIR)/tfrfme.g* $(OBJDIR)/tra_subs.g* $(OBJDIR)/TransitionMatrix.g*
+CXX_NPTM_DEBUG=$(OBJDIR)/Commons.g* $(OBJDIR)/Configuration.g* $(OBJDIR)/file_io.g* $(OBJDIR)/Parsers.g* $(OBJDIR)/sph_subs.g* $(OBJDIR)/clu_subs.g* $(OBJDIR)/tfrfme.g* $(OBJDIR)/tra_subs.g* $(OBJDIR)/TransitionMatrix.g* $(OBJDIR)/lapack_calls.g* $(OBJDIR)/algebraic.g* $(OBJDIR)/types.g* $(DYNOBJDIR)/Commons.g* $(DYNOBJDIR)/Configuration.g* $(DYNOBJDIR)/file_io.g* $(DYNOBJDIR)/Parsers.g* $(DYNOBJDIR)/sph_subs.g* $(DYNOBJDIR)/clu_subs.g* $(DYNOBJDIR)/tfrfme.g* $(DYNOBJDIR)/tra_subs.g* $(DYNOBJDIR)/TransitionMatrix.g* $(DYNOBJDIR)/lapack_calls.g* $(DYNOBJDIR)/algebraic.g* $(DYNOBJDIR)/types.g*
 
 all: $(BUILDDIR_NPTM)/libnptm.a $(BUILDDIR_NPTM)/libnptm.so
 
diff --git a/src/libnptm/TransitionMatrix.cpp b/src/libnptm/TransitionMatrix.cpp
index 30126ff17ad8cf8511ce395ce3fa0df3f69b80e4..fc6c92af6c77dca0aabce667de72f1e51ef15fec 100644
--- a/src/libnptm/TransitionMatrix.cpp
+++ b/src/libnptm/TransitionMatrix.cpp
@@ -1,13 +1,18 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file TransitionMatrix.cpp
  *
  * \brief Implementation of the Transition Matrix structure.
  */
-#include <complex>
 #include <exception>
 #include <fstream>
 #include <hdf5.h>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_ERRORS_H_
 #include "../include/errors.h"
 #endif
@@ -32,7 +37,7 @@ TransitionMatrix::~TransitionMatrix() {
 }
 
 TransitionMatrix::TransitionMatrix(
-				   int _is, int _lm, double _vk, double _exri, std::complex<double> *_elements,
+				   int _is, int _lm, double _vk, double _exri, dcomplex *_elements,
 				   double _radius
 ) {
   is = _is;
@@ -53,8 +58,8 @@ TransitionMatrix::TransitionMatrix(
 }
 
 TransitionMatrix::TransitionMatrix(
-				   int _lm, double _vk, double _exri, std::complex<double> **_rmi,
-				   std::complex<double> **_rei, double _sphere_radius
+				   int _lm, double _vk, double _exri, dcomplex **_rmi,
+				   dcomplex **_rei, double _sphere_radius
 ) {
   is = 1111;
   shape = new int[2];
@@ -64,7 +69,7 @@ TransitionMatrix::TransitionMatrix(
   vk = _vk;
   exri = _exri;
   sphere_radius = _sphere_radius;
-  elements = new complex<double>[2 * l_max]();
+  elements = new dcomplex[2 * l_max]();
   for (int ei = 0; ei < l_max; ei++) {
     elements[2 * ei] = -1.0 / _rmi[ei][0];
     elements[2 * ei + 1] = -1.0 / _rei[ei][0];
@@ -73,7 +78,7 @@ TransitionMatrix::TransitionMatrix(
 
 TransitionMatrix::TransitionMatrix(
 				   int _nlemt, int _lm, double _vk, double _exri,
-				   std::complex<double> **_am0m
+				   dcomplex **_am0m
 ) {
   is = 1;
   shape = new int[2];
@@ -83,7 +88,7 @@ TransitionMatrix::TransitionMatrix(
   vk = _vk;
   exri = _exri;
   sphere_radius = 0.0;
-  elements = new complex<double>[_nlemt * _nlemt]();
+  elements = new dcomplex[_nlemt * _nlemt]();
   for (int ei = 0; ei < _nlemt; ei++) {
     for (int ej = 0; ej < _nlemt; ej++) elements[_nlemt * ei + ej] = _am0m[ei][ej];
   }
@@ -113,7 +118,7 @@ TransitionMatrix* TransitionMatrix::from_hdf5(string file_name) {
     double _vk;
     double _exri;
     // This vector will be passed to the new object. DO NOT DELETE HERE!
-    complex<double> *_elements;
+    dcomplex *_elements;
     double _radius = 0.0;
     status = hdf_file->read("IS", "INT32", &_is);
     status = hdf_file->read("L_MAX", "INT32", &_lm);
@@ -125,9 +130,9 @@ TransitionMatrix* TransitionMatrix::from_hdf5(string file_name) {
       hid_t file_id = hdf_file->get_file_id();
       hid_t dset_id = H5Dopen2(file_id, "ELEMENTS", H5P_DEFAULT);
       status = H5Dread(dset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, file_vector);
-      _elements = new complex<double>[num_elements]();
+      _elements = new dcomplex[num_elements]();
       for (int ei = 0; ei < num_elements; ei++) {
-	_elements[ei] = complex<double>(file_vector[2 * ei], file_vector[2 * ei + 1]);
+	_elements[ei] = file_vector[2 * ei] + file_vector[2 * ei + 1] * I;
       }
       status = H5Dclose(dset_id);
       status = hdf_file->read("RADIUS", "FLOAT64", &_radius);
@@ -140,9 +145,9 @@ TransitionMatrix* TransitionMatrix::from_hdf5(string file_name) {
       hid_t file_id = hdf_file->get_file_id();
       hid_t dset_id = H5Dopen2(file_id, "ELEMENTS", H5P_DEFAULT);
       status = H5Dread(dset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, file_vector);
-      _elements = new complex<double>[num_elements]();
+      _elements = new dcomplex[num_elements]();
       for (int ei = 0; ei < num_elements; ei++) {
-	_elements[ei] = complex<double>(file_vector[2 * ei], file_vector[2 * ei + 1]);
+	_elements[ei] = file_vector[2 * ei] + file_vector[2 * ei + 1] * I;
       }
       status = H5Dclose(dset_id);
       tm = new TransitionMatrix(_is, _lm, _vk, _exri, _elements, _radius);
@@ -166,7 +171,7 @@ TransitionMatrix* TransitionMatrix::from_legacy(string file_name) {
     double _vk;
     double _exri;
     // This vector will be passed to the new object. DO NOT DELETE HERE!
-    complex<double> *_elements;
+    dcomplex *_elements;
     double _radius = 0.0;
     ttms.read(reinterpret_cast<char *>(&_is), sizeof(int));
     ttms.read(reinterpret_cast<char *>(&_lm), sizeof(int));
@@ -174,12 +179,12 @@ TransitionMatrix* TransitionMatrix::from_legacy(string file_name) {
     ttms.read(reinterpret_cast<char *>(&_exri), sizeof(double));
     if (_is == 1111) {
       num_elements = _lm * 2;
-      _elements = new complex<double>[num_elements]();
+      _elements = new dcomplex[num_elements]();
       for (int ei = 0; ei < num_elements; ei++) {
 	double vreal, vimag;
 	ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	_elements[ei] = complex<double>(vreal, vimag);
+	_elements[ei] = vreal + vimag * I;
       }
       double _radius;
       ttms.read(reinterpret_cast<char *>(&_radius), sizeof(double));
@@ -187,12 +192,12 @@ TransitionMatrix* TransitionMatrix::from_legacy(string file_name) {
     } else if (_is == 1) {
       int nlemt = 2 * _lm * (_lm + 2);
       num_elements = nlemt * nlemt;
-      _elements = new complex<double>[num_elements]();
+      _elements = new dcomplex[num_elements]();
       for (int ei = 0; ei < num_elements; ei++) {
 	double vreal, vimag;
 	ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	_elements[ei] = complex<double>(vreal, vimag);
+	_elements[ei] = vreal + vimag * I;
       }
       tm = new TransitionMatrix(_is, _lm, _vk, _exri, _elements);
     }
@@ -239,8 +244,8 @@ void TransitionMatrix::write_hdf5(string file_name) {
     int num_elements = 2 * shape[0] * shape[1];
     double *ptr_elements = new double[num_elements]();
     for (int ei = 0; ei < num_elements / 2; ei++) {
-      ptr_elements[2 * ei] = elements[ei].real();
-      ptr_elements[2 * ei + 1] = elements[ei].imag();
+      ptr_elements[2 * ei] = real(elements[ei]);
+      ptr_elements[2 * ei + 1] = imag(elements[ei]);
     }
     rec_ptr_list.append(ptr_elements);
     if (is == 1111) {
@@ -287,10 +292,10 @@ void TransitionMatrix::write_legacy(string file_name) {
   if (ttms.is_open()) {
     int num_elements = shape[0] * shape[1];
     for (int ei = 0; ei < num_elements; ei++) {
-      complex<double> element1 = elements[ei];
+      dcomplex element1 = elements[ei];
       double vreal, vimag;
-      vreal = element1.real();
-      vimag = element1.imag();
+      vreal = real(element1);
+      vimag = imag(element1);
       ttms.write(reinterpret_cast<char *>(&vreal), sizeof(double));
       ttms.write(reinterpret_cast<char *>(&vimag), sizeof(double));
     }
diff --git a/src/libnptm/algebraic.cpp b/src/libnptm/algebraic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..48335792275ba7097b29f5b639fe828bbd1aa8d2
--- /dev/null
+++ b/src/libnptm/algebraic.cpp
@@ -0,0 +1,39 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
+/*! \file algebraic.cpp
+ *
+ * \brief Implementation of algebraic functions with different call-backs.
+ */
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
+#ifdef USE_LAPACK
+#ifdef USE_MKL
+#include <mkl_lapacke.h>
+#else
+#include <lapacke.h>
+#endif
+#ifndef INCLUDE_LAPACK_CALLS_H_
+#include "../include/lapack_calls.h"
+#endif
+#endif
+
+#ifndef INCLUDE_ALGEBRAIC_H_
+#include "../include/algebraic.h"
+#endif
+
+// >>> FALL-BACK FUNCTIONS DECLARATION <<< //
+extern void lucin(dcomplex **mat, np_int max_size, np_int size, int &ier);
+// >>>   END OF FALL-BACK FUNCTIONS    <<< //
+
+using namespace std;
+
+void invert_matrix(dcomplex **mat, np_int size, int &ier, np_int max_size) {
+  ier = 0;
+#ifdef USE_LAPACK
+  zinvert(mat, size, ier);
+#else
+  lucin(mat, max_size, size, ier);
+#endif
+}
diff --git a/src/libnptm/clu_subs.cpp b/src/libnptm/clu_subs.cpp
index 22287bb7c734fcfc067c4e185b4b4f7932c03918..72cac9914a8d1d61a6f67e93783871476f03ea21 100644
--- a/src/libnptm/clu_subs.cpp
+++ b/src/libnptm/clu_subs.cpp
@@ -1,8 +1,13 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file clu_subs.cpp
  *
  * \brief C++ implementation of CLUSTER subroutines.
  */
-#include <complex>
+
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
 
 #ifndef INCLUDE_COMMONS_H_
 #include "../include/Commons.h"
@@ -19,22 +24,22 @@
 using namespace std;
 
 void apc(
-	 double ****zpv, int le, std::complex<double> **am0m, std::complex<double> **w,
-	 double sqk, double **gapr, std::complex<double> **gapp
+	 double ****zpv, int le, dcomplex **am0m, dcomplex **w,
+	 double sqk, double **gapr, dcomplex **gapp
 ) {
-  complex<double> **ac, **gap;
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> uimmp, summ, sume, suem, suee, summp, sumep;
-  complex<double> suemp, sueep;
+  dcomplex **ac, **gap;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex uimmp, summ, sume, suem, suee, summp, sumep;
+  dcomplex suemp, sueep;
   double cof = 1.0 / sqk;
   double cimu = cof / sqrt(2.0);
   int nlem = le * (le + 2);
   const int nlemt = nlem + nlem;
-  ac = new complex<double>*[nlemt];
-  gap = new complex<double>*[3];
-  for (int ai = 0; ai < nlemt; ai++) ac[ai] = new complex<double>[2]();
-  for (int gi = 0; gi < 3; gi++) gap[gi] = new complex<double>[2]();
+  ac = new dcomplex*[nlemt];
+  gap = new dcomplex*[3];
+  for (int ai = 0; ai < nlemt; ai++) ac[ai] = new dcomplex[2]();
+  for (int gi = 0; gi < 3; gi++) gap[gi] = new dcomplex[2]();
   for (int j45 = 1; j45 <= nlemt; j45++) {
     int j = j45 - 1;
     ac[j][0] = cc0;
@@ -119,9 +124,9 @@ void apc(
     sume = gap[0][ipo95 - 1] * cimu;
     suee = gap[1][ipo95 - 1] * cof;
     suem = gap[2][ipo95 - 1] * cimu;
-    gapr[0][ipo95 - 1] = (sume - suem).real();
-    gapr[1][ipo95 - 1] = ((sume + suem) * uim).real();
-    gapr[2][ipo95 - 1] = suee.real();
+    gapr[0][ipo95 - 1] = real(sume - suem);
+    gapr[1][ipo95 - 1] = real((sume + suem) * uim);
+    gapr[2][ipo95 - 1] = real(suee);
     sumep = gapp[0][ipo95 - 1] * cimu;
     sueep = gapp[1][ipo95 - 1] * cof;
     suemp = gapp[2][ipo95 - 1] * cimu;
@@ -137,24 +142,24 @@ void apc(
 }
 
 void apcra(
-	   double ****zpv, const int le, std::complex<double> **am0m, int inpol, double sqk,
-	   double **gaprm, std::complex<double> **gappm
+	   double ****zpv, const int le, dcomplex **am0m, int inpol, double sqk,
+	   double **gaprm, dcomplex **gappm
 ) {
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> uimtl, uimtls, ca11, ca12, ca21, ca22;
-  complex<double> a11, a12, a21, a22, sum1, sum2, fc;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex uimtl, uimtls, ca11, ca12, ca21, ca22;
+  dcomplex a11, a12, a21, a22, sum1, sum2, fc;
   double ****svw = new double***[le];
-  complex<double> ****svs = new complex<double>***[le];
+  dcomplex ****svs = new dcomplex***[le];
   for (int i = 0; i < le; i++) {
     svw[i] = new double**[3];
-    svs[i] = new complex<double>**[3];
+    svs[i] = new dcomplex**[3];
     for (int j = 0; j < 3; j++) {
       svw[i][j] = new double*[2];
-      svs[i][j] = new complex<double>*[2];
+      svs[i][j] = new dcomplex*[2];
       for (int k = 0; k < 2; k++) {
 	svw[i][j][k] = new double[2]();
-	svs[i][j][k] = new complex<double>[2]();
+	svs[i][j][k] = new dcomplex[2]();
       }
     }
   }
@@ -206,7 +211,7 @@ void apcra(
       int lmp = l58 + lmpml;
       int impmm = lmp * (lmp + 1);
       uimtl = uim * (1.0 * lmpml);
-      if (lmpml == 0) uimtl = complex<double>(1.0, 0.0);
+      if (lmpml == 0) uimtl = 1.0 + 0.0 * I;
       for (int im54 = 1; im54 <= ltpo; im54++) {
 	int m = im54 - lpo;
 	int i = imm + m;
@@ -229,7 +234,7 @@ void apcra(
 		int lsmp = ls + lsmpml;
 		int ismpmm = lsmp * (lsmp + 1);
 		uimtls = -uim * (1.0 * lsmpml);
-		if (lsmpml == 0) uimtls = complex<double>(1.0, 0.0);
+		if (lsmpml == 0) uimtls = 1.0 + 0.0 * I;
 		for (int ims = 1; ims <= lstpo; ims++) {
 		  int ms = ims - lspo;
 		  int msmp = ms - mu;
@@ -328,14 +333,14 @@ void apcra(
   if (inpol == 0) {
     sum1 *= cofs;
     sum2 *= cofs;
-    gaprm[2][0] = sum1.real();
-    gaprm[2][1] = sum1.real();
+    gaprm[2][0] = real(sum1);
+    gaprm[2][1] = real(sum1);
     gappm[2][0] = sum2 * uim;
     gappm[2][1] = -gappm[2][0];
   } else { // label 72
     cofs *= 2.0;
-    gaprm[2][0] = sum1.real() * cofs;
-    gaprm[2][1] = sum2.real() * cofs;
+    gaprm[2][0] = real(sum1) * cofs;
+    gaprm[2][1] = real(sum2) * cofs;
     gappm[2][0] = cc0;
     gappm[2][1] = cc0;
   }
@@ -357,15 +362,12 @@ void apcra(
   delete[] svs;
 }
 
-complex<double> cdtp(
-		     std::complex<double> z, std::complex<double> **am, int i, int jf,
-		     int k, int nj
-) {
+dcomplex cdtp(dcomplex z, dcomplex **am, int i, int jf, int k, int nj) {
   /* NOTE: the original FORTRAN code treats the AM matrix as a
    * vector. This is not directly allowed in C++ and it requires
    * accounting for the different dimensions.
    */
-  complex<double> result = z;
+  dcomplex result = z;
   if (nj > 0) {
     int jl = jf + nj - 1;
     for (int j = jf; j <= jl; j++) {
@@ -409,9 +411,9 @@ double cgev(int ipamo, int mu, int l, int m) {
   return result;
 }
 
-void cms(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6) {
-  complex<double> dm, de, cgh, cgk;
-  const complex<double> cc0(0.0, 0.0);
+void cms(dcomplex **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6) {
+  dcomplex dm, de, cgh, cgk;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
   int ndi = c4->nsph * c4->nlim;
   int nbl = 0;
   int nsphmo = c4->nsph - 1;
@@ -492,19 +494,19 @@ void cms(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6) {
 }
 
 void crsm1(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6) {
-  complex<double> ***svf, ***svw, **svs;
-  const complex<double> cc0(0.0, 0.0);
-  complex<double> cam(0.0, 0.0);
+  dcomplex ***svf, ***svw, **svs;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  dcomplex cam = cc0;
   const int le4po = 4 * c4->le + 1;
-  svf = new complex<double>**[le4po];
-  svw = new complex<double>**[le4po];
-  svs = new complex<double>*[le4po];
+  svf = new dcomplex**[le4po];
+  svw = new dcomplex**[le4po];
+  svs = new dcomplex*[le4po];
   for (int si = 0; si < le4po; si++) {
-    svf[si] = new complex<double>*[le4po];
-    svw[si] = new complex<double>*[4];
-    svs[si] = new complex<double>[4]();
-    for (int sj = 0; sj < le4po; sj++) svf[si][sj] = new complex<double>[4]();
-    for (int sj = 0; sj < 4; sj++) svw[si][sj] = new complex<double>[4]();
+    svf[si] = new dcomplex*[le4po];
+    svw[si] = new dcomplex*[4];
+    svs[si] = new dcomplex[4]();
+    for (int sj = 0; sj < le4po; sj++) svf[si][sj] = new dcomplex[4]();
+    for (int sj = 0; sj < 4; sj++) svw[si][sj] = new dcomplex[4]();
   }
   double exdc = exri * exri;
   double ccs = 1.0 / (vk * vk);
@@ -611,22 +613,22 @@ void crsm1(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6) {
   delete[] svs;
 }
 
-complex<double> ghit(
-		     int ihi, int ipamo, int nbl, int l1, int m1, int l2, int m2, C1 *c1,
-		     C1_AddOns *c1ao, C4 *c4, C6 *c6
+dcomplex ghit(
+	      int ihi, int ipamo, int nbl, int l1, int m1, int l2, int m2, C1 *c1,
+	      C1_AddOns *c1ao, C4 *c4, C6 *c6
 ) {
   /* NBL identifies transfer vector going from N2 to N1;
    * IHI=0 for Hankel, IHI=1 for Bessel, IHI=2 for Bessel from origin;
    * depending on IHI, IPAM=0 gives H or I, IPAM= 1 gives K or L. */
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> csum(0.0, 0.0), cfun(0.0, 0.0);
-  complex<double> result = cc0;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex csum = cc0, cfun = cc0;
+  dcomplex result = cc0;
 
   if (ihi == 2) {
     if (c1->rxx[nbl - 1] == 0.0 && c1->ryy[nbl - 1] == 0.0 && c1->rzz[nbl - 1] == 0.0) {
       if (ipamo == 0) {
-	if (l1 == l2 && m1 == m2) result = complex<double>(1.0, 0.0);
+	if (l1 == l2 && m1 == m2) result = 1.0 + 0.0 * I;
       }
       return result;
     }
@@ -823,7 +825,7 @@ complex<double> ghit(
 }
 
 void hjv(
-	 double exri, double vk, int &jer, int &lcalc, std::complex<double> &arg,
+	 double exri, double vk, int &jer, int &lcalc, dcomplex &arg,
 	 C1 *c1, C1_AddOns *c1ao, C4 *c4
 ) {
   int nsphmo = c4->nsph - 1;
@@ -844,7 +846,7 @@ void hjv(
       double rz = c1->rzz[nf40 - 1] - c1->rzz[ns40 - 1];
       double rr = sqrt(rx * rx + ry * ry + rz * rz);
       double rarg = rr * vk * exri;
-      arg = complex<double>(rarg, 0.0);
+      arg = rarg +  0.0 * I;
       rbf(lit, rarg, lcalc, rfj);
       if (lcalc < lit) {
 	jer = 1;
@@ -862,7 +864,7 @@ void hjv(
       for (int lpo38 = 1; lpo38 <= c4->litpo; lpo38++) {
 	double rpart = rfj[lpo38 - 1];
 	double ipart = rfn[lpo38 - 1];
-	c1ao->vh[lpo38 + ivhb - 1] = complex<double>(rpart, ipart);
+	c1ao->vh[lpo38 + ivhb - 1] = rpart + ipart * I;
       }
       ivhb += c4->litpo;
     } // ns40 loop
@@ -892,23 +894,23 @@ void hjv(
   delete[] rfn;
 }
 
-void lucin(std::complex<double> **am, const int nddmst, int n, int &ier) {
+void lucin(dcomplex **am, const np_int nddmst, np_int n, int &ier) {
   /* NDDMST  FIRST DIMENSION OF AM AS DECLARED IN DIMENSION
    *         STATEMENT.
    * N       NUMBER OF ROWS IN AM.
    * IER     IS REPLACED BY 1 FOR SINGULARITY.
    */
   double *v = new double[nddmst];
-  complex<double> ctemp, cfun;
-  complex<double> cc0 = complex<double>(0.0, 0.0);
+  dcomplex ctemp, cfun;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
   ier = 0;
   int nminus = n - 1;
-  for (int i = 1; i <= n; i++) {
+  for (int64_t i = 1; i <= n; i++) {
     double sum = 0.0;
-    for (int j = 1; j <= n; j++) {
+    for (int64_t j = 1; j <= n; j++) {
       sum += (
-	      am[i - 1][j - 1].real() * am[i - 1][j - 1].real()
-	      + am[i - 1][j - 1].imag() * am[i - 1][j - 1].imag()
+	      real(am[i - 1][j - 1]) * real(am[i - 1][j - 1])
+	      + imag(am[i - 1][j - 1]) * imag(am[i - 1][j - 1])
 	      );
     } // j1319 loop
     v[i - 1] = 1.0 / sum;
@@ -917,24 +919,23 @@ void lucin(std::complex<double> **am, const int nddmst, int n, int &ier) {
   //    REPLACE L(I,I) BY 1/L(I,I), READY FOR SECTION 4.
   //    (ROW INTERCHANGES TAKE PLACE, AND THE INDICES OF THE PIVOTAL ROWS
   //    ARE PLACED IN V.)
-  /* >>> THERE APPEARS TO BE A BUG IN THE FOLLOWING LOOP <<< */
-  for (int k = 1; k <= n; k++) {
-    int kplus = k + 1;
-    int kminus = k - 1;
-    int l = k;
+  for (int64_t k = 1; k <= n; k++) {
+    int64_t kplus = k + 1;
+    int64_t kminus = k - 1;
+    int64_t l = k;
     double psqmax = 0.0;
-    for (int i = k; i <= n; i++) {
+    for (int64_t i = k; i <= n; i++) {
       cfun = cdtp(-am[i - 1][k - 1], am, i, 1, k, kminus);
       ctemp = -cfun;
       am[i - 1][k - 1] = ctemp;
-      double psq = v[i - 1] * (ctemp.real() * ctemp.real() + ctemp.imag() * ctemp.imag());
+      double psq = v[i - 1] * (real(ctemp) * real(ctemp) + imag(ctemp) * imag(ctemp));
       if (psq > psqmax) {
 	psqmax = psq;
 	l = i;
       }
     } // i2029 loop
     if (l != k) {
-      for (int j = 1; j <= n; j++) {
+      for (int64_t j = 1; j <= n; j++) {
 	ctemp = am[k - 1][j - 1];
 	am[k - 1][j - 1] = am[l - 1][j - 1];
 	am[l - 1][j - 1] = ctemp;
@@ -951,7 +952,7 @@ void lucin(std::complex<double> **am, const int nddmst, int n, int &ier) {
     ctemp = 1.0 / am[k - 1][k - 1];
     am[k - 1][k - 1] = ctemp;
     if (kplus <= n) {
-      for (int j = kplus; j <= n; j++) {
+      for (int64_t j = kplus; j <= n; j++) {
 	cfun = cdtp(-am[k - 1][j - 1], am, k, 1, j, kminus);
 	am[k - 1][j - 1] = -ctemp * cfun;
       } // j2059 loop
@@ -959,9 +960,9 @@ void lucin(std::complex<double> **am, const int nddmst, int n, int &ier) {
   } // k2019 loop
   // 4.  REPLACE AM BY ITS INVERSE AMINV.
   // 4.1 REPLACE L AND U BY THEIR INVERSE LINV AND UINV.
-  for (int k = 1; k <= nminus; k++) {
-    int kplus = k + 1;
-    for (int i = kplus; i <= n; i++) {
+  for (int64_t k = 1; k <= nminus; k++) {
+    int64_t kplus = k + 1;
+    for (int64_t i = kplus; i <= n; i++) {
       cfun = cdtp(cc0, am, i, k, k, i - k);
       am[i - 1][k - 1] = -am[i - 1][i - 1] * cfun;
       cfun = cdtp(am[k - 1][i - 1], am, k, kplus, i, i - k - 1);
@@ -969,8 +970,8 @@ void lucin(std::complex<double> **am, const int nddmst, int n, int &ier) {
     } // i4119 loop
   } // k4109 loop
   // 4.2 FORM AMINV=UINV*LINV.
-  for (int k = 1; k <= n; k++) {
-    for (int i = 1; i <= n; i++) {
+  for (int64_t k = 1; k <= n; k++) {
+    for (int64_t i = 1; i <= n; i++) {
       if (i < k) {
 	cfun = cdtp(cc0, am, i, k, k, n - k + 1);
 	am[i - 1][k -1] = cfun;
@@ -983,11 +984,11 @@ void lucin(std::complex<double> **am, const int nddmst, int n, int &ier) {
   } // k4209 loop
   // 4.3 INTERCHANGE COLUMNS OF AMINV AS SPECIFIED BY V, BUT IN REVERSE
   //     ORDER.
-  for (int l = 1; l <= n; l++) {
-    int k = n - l + 1;
-    int kcol = (int)(v[k - 1]);
+  for (int64_t l = 1; l <= n; l++) {
+    int64_t k = n - l + 1;
+    int64_t kcol = (int64_t)(v[k - 1]);
     if (kcol != k) {
-      for (int i = 1; i <= n; i++) {
+      for (int64_t i = 1; i <= n; i++) {
 	ctemp = am[i - 1][k - 1];
 	am[i - 1][k - 1] = am[i - 1][kcol - 1];
 	am[i - 1][kcol - 1] = ctemp;
@@ -997,15 +998,15 @@ void lucin(std::complex<double> **am, const int nddmst, int n, int &ier) {
   delete[] v;
 }
 
-void mextc(double vk, double exri, std::complex<double> **fsac, double **cextlr, double **cext) {
-  double fa11r = fsac[0][0].real();
-  double fa11i = fsac[0][0].imag();
-  double fa21r = fsac[1][0].real();
-  double fa21i = fsac[1][0].imag();
-  double fa12r = fsac[0][1].real();
-  double fa12i = fsac[0][1].imag();
-  double fa22r = fsac[1][1].real();
-  double fa22i = fsac[1][1].imag();
+void mextc(double vk, double exri, dcomplex **fsac, double **cextlr, double **cext) {
+  double fa11r = real(fsac[0][0]);
+  double fa11i = imag(fsac[0][0]);
+  double fa21r = real(fsac[1][0]);
+  double fa21i = imag(fsac[1][0]);
+  double fa12r = real(fsac[0][1]);
+  double fa12i = imag(fsac[0][1]);
+  double fa22r = real(fsac[1][1]);
+  double fa22i = imag(fsac[1][1]);
   cextlr[0][0] = fa11i * 2.0;
   cextlr[0][1] = 0.0;
   cextlr[0][2] = -fa12i;
@@ -1048,12 +1049,12 @@ void mextc(double vk, double exri, std::complex<double> **fsac, double **cextlr,
 }
 
 void pcros(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4) {
-  const complex<double> cc0(0.0, 0.0);
-  complex<double> sump, sum1, sum2, sum3, sum4, am, amp, cc, csam;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  dcomplex sump, sum1, sum2, sum3, sum4, am, amp, cc, csam;
   const double exdc = exri * exri;
   double ccs = 1.0 / (vk * vk);
   double cccs = ccs / exdc;
-  csam = -(ccs / (exri * vk)) * complex<double>(0.0, 0.5);
+  csam = -(ccs / (exri * vk)) * 0.5 * I;
   const double pi4sq = 64.0 * acos(0.0) * acos(0.0);
   double cfsq = 4.0 / (pi4sq *ccs * ccs);
   const int nlemt = c4->nlem + c4->nlem;
@@ -1077,7 +1078,7 @@ void pcros(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4) {
 	am += (c1ao->am0m[i][j] * c1->w[j][ipo18 - 1]);
 	amp += (c1ao->am0m[i][j] * c1->w[j][jpo - 1]);
       } // j10 loop
-      sum += (dconjg(am) * am).real();
+      sum += real(dconjg(am) * am);
       sump += (dconjg(amp) * am);
       sum1 += (dconjg(c1->w[i][ipo18 - 1]) * am);
       sum2 += (dconjg(c1->w[i][jpo - 1]) * am);
@@ -1086,7 +1087,7 @@ void pcros(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4) {
     } // i12 loop
     c1ao->scsc[ipo18 - 1] = cccs * sum;
     c1ao->scscp[ipo18 - 1] = cccs * sump;
-    c1ao->ecsc[ipo18 - 1] = -cccs * sum1.real();
+    c1ao->ecsc[ipo18 - 1] = -cccs * real(sum1);
     c1ao->ecscp[ipo18 - 1] = -cccs * sum2;
     c1ao->fsac[ipo18 - 1][ipo18 - 1] = csam * sum1;
     c1ao->fsac[jpo - 1][ipo18 - 1] = csam * sum2;
@@ -1107,14 +1108,14 @@ void pcros(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C4 *c4) {
 }
 
 void pcrsm0(double vk, double exri, int inpol, C1 *c1, C1_AddOns *c1ao, C4 *c4) {
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> sum1, sum2, sum3, sum4, sumpd;
-  complex<double> sums1, sums2, sums3, sums4, csam;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex sum1, sum2, sum3, sum4, sumpd;
+  dcomplex sums1, sums2, sums3, sums4, csam;
   double exdc = exri * exri;
   double ccs = 4.0 * acos(0.0) / (vk * vk);
   double cccs = ccs / exdc;
-  csam = -(ccs / (exri * vk)) * complex<double>(0.0, 0.5);
+  csam = -(ccs / (exri * vk)) * 0.5 * I;
   sum2 = cc0;
   sum3 = cc0;
   for (int i14 = 1; i14 <= c4->nlem; i14++) { // GPU portable?
@@ -1128,10 +1129,10 @@ void pcrsm0(double vk, double exri, int inpol, C1 *c1, C1_AddOns *c1ao, C4 *c4)
   for (int i16 = 1; i16 <= nlemt; i16++) {
     for (int j16 = 1; j16 <= c4->nlem; j16++) {
       int je = j16 + c4->nlem;
-      double rvalue = (
-		       dconjg(c1ao->am0m[i16 - 1][j16 - 1]) * c1ao->am0m[i16 - 1][j16 - 1]
-		       + dconjg(c1ao->am0m[i16 - 1][je - 1]) * c1ao->am0m[i16 - 1][je - 1]
-		       ).real();
+      double rvalue = real(
+			   dconjg(c1ao->am0m[i16 - 1][j16 - 1]) * c1ao->am0m[i16 - 1][j16 - 1]
+			   + dconjg(c1ao->am0m[i16 - 1][je - 1]) * c1ao->am0m[i16 - 1][je - 1]
+			   );
       sumpi += rvalue;
       sumpd += (
 		dconjg(c1ao->am0m[i16 - 1][j16 - 1]) * c1ao->am0m[i16 - 1][je - 1]
@@ -1158,16 +1159,16 @@ void pcrsm0(double vk, double exri, int inpol, C1 *c1, C1_AddOns *c1ao, C4 *c4)
     sums4 = cc0;
   }
   // label 20
-  c1ao->ecscm[0] = -cccs * sum2.real();
-  c1ao->ecscm[1] = -cccs * sum1.real();
+  c1ao->ecscm[0] = -cccs * real(sum2);
+  c1ao->ecscm[1] = -cccs * real(sum1);
   c1ao->ecscpm[0] = -cccs * sum4;
   c1ao->ecscpm[1] = -cccs * sum3;
   c1ao->fsacm[0][0] = csam * sum2;
   c1ao->fsacm[1][0] = csam * sum4;
   c1ao->fsacm[1][1] = csam * sum1;
   c1ao->fsacm[0][1] = csam * sum3;
-  c1ao->scscm[0] = cccs * sums1.real();
-  c1ao->scscm[1] = cccs * sums2.real();
+  c1ao->scscm[0] = cccs * real(sums1);
+  c1ao->scscm[1] = cccs * real(sums2);
   c1ao->scscpm[0] = cccs * sums3;
   c1ao->scscpm[1] = cccs * sums4;
 }
@@ -1538,23 +1539,23 @@ void r3jmr(int j1, int j2, int j3, int m1, C6 *c6) {
 }
 
 void raba(
-	  int le, std::complex<double> **am0m, std::complex<double> **w, double **tqce,
-	  std::complex<double> **tqcpe, double **tqcs, std::complex<double> **tqcps
+	  int le, dcomplex **am0m, dcomplex **w, double **tqce,
+	  dcomplex **tqcpe, double **tqcs, dcomplex **tqcps
 ) {
-  complex<double> **a, **ctqce, **ctqcs;
-  complex<double> acw, acwp, aca, acap, c1, c2, c3;
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
+  dcomplex **a, **ctqce, **ctqcs;
+  dcomplex acw, acwp, aca, acap, c1, c2, c3;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
   const double sq2i = 1.0 / sqrt(2.0);
   int nlem = le * (le + 2);
   const int nlemt = nlem + nlem;
-  a = new complex<double>*[nlemt];
-  ctqce = new complex<double>*[2];
-  ctqcs = new complex<double>*[2];
-  for (int ai = 0; ai < nlemt; ai++) a[ai] = new complex<double>[2]();
+  a = new dcomplex*[nlemt];
+  ctqce = new dcomplex*[2];
+  ctqcs = new dcomplex*[2];
+  for (int ai = 0; ai < nlemt; ai++) a[ai] = new dcomplex[2]();
   for (int ci = 0; ci < 2; ci++) {
-    ctqce[ci] = new complex<double>[3]();
-    ctqcs[ci] = new complex<double>[3]();
+    ctqce[ci] = new dcomplex[3]();
+    ctqcs[ci] = new dcomplex[3]();
   }
   for (int i20 = 1; i20 <= nlemt; i20++) {
     int i = i20 - 1;
@@ -1638,18 +1639,18 @@ void raba(
   } // ipo70 loop
   for (int ipo78 = 1; ipo78 <= 2; ipo78++) {
     int ipo = ipo78 - 1;
-    tqce[ipo][0] = (ctqce[ipo][0] - ctqce[ipo][2]).real() * sq2i;
-    tqce[ipo][1] = ((ctqce[ipo][0] + ctqce[ipo][2]) * uim).real() * sq2i;
-    tqce[ipo][2] = ctqce[ipo][1].real();
+    tqce[ipo][0] = real(ctqce[ipo][0] - ctqce[ipo][2]) * sq2i;
+    tqce[ipo][1] = real((ctqce[ipo][0] + ctqce[ipo][2]) * uim) * sq2i;
+    tqce[ipo][2] = real(ctqce[ipo][1]);
     c1 = tqcpe[ipo][0];
     c2 = tqcpe[ipo][1];
     c3 = tqcpe[ipo][2];
     tqcpe[ipo][0] = (c1 - c3) * sq2i;
     tqcpe[ipo][1] = (c1 + c3) * (uim * sq2i);
     tqcpe[ipo][2] = c2;
-    tqcs[ipo][0] = -sq2i * (ctqcs[ipo][0] - ctqcs[ipo][2]).real();
-    tqcs[ipo][1] = -sq2i * ((ctqcs[ipo][0] + ctqcs[ipo][2]) * uim).real();
-    tqcs[ipo][2] = -1.0 * ctqcs[ipo][1].real();
+    tqcs[ipo][0] = -sq2i * real(ctqcs[ipo][0] - ctqcs[ipo][2]);
+    tqcs[ipo][1] = -sq2i * real((ctqcs[ipo][0] + ctqcs[ipo][2]) * uim);
+    tqcs[ipo][2] = -1.0 * real(ctqcs[ipo][1]);
     c1 = tqcps[ipo][0];
     c2 = tqcps[ipo][1];
     c3 = tqcps[ipo][2];
@@ -1685,12 +1686,12 @@ void rftr(
 }
 
 void scr0(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C3 *c3, C4 * c4) {
-  const complex<double> cc0(0.0, 0.0);
+  const dcomplex cc0 = 0.0 + 0.0 * I;
   double exdc = exri * exri;
   double ccs = 4.0 * acos(0.0) / (vk * vk);
   double cccs = ccs / exdc;
-  complex<double> sum21, rm, re, csam;
-  csam = -(ccs / (exri * vk)) * complex<double>(0.0, 0.5);
+  dcomplex sum21, rm, re, csam;
+  csam = -(ccs / (exri * vk)) * 0.5 * I;
   //double scs = 0.0, ecs = 0.0, acs = 0.0;
   c3->scs = 0.0;
   c3->ecs = 0.0;
@@ -1705,13 +1706,13 @@ void scr0(double vk, double exri, C1 *c1, C1_AddOns *c1ao, C3 *c3, C4 * c4) {
 	double fl = 1.0 * (l10 + l10 + 1);
 	rm = 1.0 / c1->rmi[l10 - 1][i14 - 1];
 	re = 1.0 / c1->rei[l10 - 1][i14 - 1];
-	double rvalue = (dconjg(rm) * rm + dconjg(re) * re).real() * fl;
+	double rvalue = real(dconjg(rm) * rm + dconjg(re) * re) * fl;
 	sums += rvalue;
 	sum21 += ((rm + re) * fl);
       } // l10 loop
       sum21 *= -1.0;
       double scasec = cccs * sums;
-      double extsec = -cccs * sum21.real();
+      double extsec = -cccs * real(sum21);
       double abssec = extsec - scasec;
       c1->sscs[i14 - 1] = scasec;
       c1->sexs[i14 - 1] = extsec;
@@ -1734,11 +1735,11 @@ void scr2(
 	  double vk, double vkarg, double exri, double *duk, C1 *c1, C1_AddOns *c1ao,
 	  C3 *c3, C4 *c4
 ) {
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> s11, s21, s12, s22, rm, re, csam, cph, phas, cc;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex s11, s21, s12, s22, rm, re, csam, cph, phas, cc;
   double ccs = 1.0 / (vk * vk);
-  csam = -(ccs / (exri * vk)) * complex<double>(0.0, 0.5);
+  csam = -(ccs / (exri * vk)) * 0.5 * I;
   const double pi4sq = 64.0 * acos(0.0) * acos(0.0);
   double cfsq = 4.0 / (pi4sq * ccs * ccs);
   cph = uim * exri * vkarg;
@@ -1776,7 +1777,7 @@ void scr2(
       c1->sas[i][1][1] = s22 * csam;
     }
     // label 12
-    phas = exp(cph * (duk[0] * c1->rxx[i] + duk[1] * c1->ryy[i] + duk[2] * c1->rzz[i]));
+    phas = cexp(cph * (duk[0] * c1->rxx[i] + duk[1] * c1->ryy[i] + duk[2] * c1->rzz[i]));
     c3->tsas[0][0] += (c1->sas[iogi - 1][0][0] * phas);
     c3->tsas[1][0] += (c1->sas[iogi - 1][1][0] * phas);
     c3->tsas[0][1] += (c1->sas[iogi - 1][0][1] * phas);
@@ -1814,7 +1815,7 @@ void scr2(
 }
 
 void str(double **rcf, C1 *c1, C1_AddOns *c1ao, C3 *c3, C4 *c4, C6 *c6) {
-  complex<double> *ylm;
+  dcomplex *ylm;
   const double pi = acos(-1.0);
   c3->gcs = 0.0;
   double gcss = 0.0;
@@ -1831,7 +1832,7 @@ void str(double **rcf, C1 *c1, C1_AddOns *c1ao, C3 *c3, C4 *c4, C6 *c6) {
     c3->gcs += gcss;
   } // i18 loop
   int ylm_size = (c4->litpos > c4->lmtpos) ? c4->litpos : c4->lmtpos;
-  ylm = new complex<double>[ylm_size]();
+  ylm = new dcomplex[ylm_size]();
   int i = 0;
   for (int l1po28 = 1; l1po28 <= c4->lmpo; l1po28++) {
     int l1 = l1po28 - 1;
@@ -1901,9 +1902,9 @@ void tqr(
   tsk = u[0] * tqsv[0] + u[1] * tqsv[1] + u[2] * tqsv[2];
 }
 
-void ztm(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6, C9 * c9) {
-  complex<double> gie, gle, a1, a2, a3, a4, sum1, sum2, sum3, sum4;
-  const complex<double> cc0(0.0, 0.0);
+void ztm(dcomplex **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6, C9 * c9) {
+  dcomplex gie, gle, a1, a2, a3, a4, sum1, sum2, sum3, sum4;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
   int ndi = c4->nsph * c4->nlim;
   int i2 = 0;
   for (int n2 = 1; n2 <= c4->nsph; n2++) { // GPU portable?
diff --git a/src/libnptm/lapack_calls.cpp b/src/libnptm/lapack_calls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0b1dac5ac92ec6e876a560c0ab239e49a77314c2
--- /dev/null
+++ b/src/libnptm/lapack_calls.cpp
@@ -0,0 +1,45 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
+/*! \file lapack_calls.cpp
+ *
+ * \brief Implementation of the interface with LAPACK libraries.
+ */
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
+#ifdef USE_LAPACK
+#ifdef USE_MKL
+#include <mkl_lapacke.h>
+#else
+#include <lapacke.h>
+#endif
+
+#ifndef INCLUDE_LAPACK_CALLS_H_
+#include "../include/lapack_calls.h"
+#endif
+#endif
+
+#ifdef USE_LAPACK
+void zinvert(dcomplex **mat, lapack_int n, int &jer) {
+  jer = 0;
+  dcomplex *arr = &(mat[0][0]);
+  const dcomplex uim = 0.0 + 1.0 * I;
+
+#ifdef USE_MKL
+  MKL_Complex16 *arr2 = (MKL_Complex16 *) arr;
+#endif
+  
+  lapack_int* IPIV = new lapack_int[n]();
+  
+#ifdef USE_MKL
+  LAPACKE_zgetrf(LAPACK_ROW_MAJOR, n, n, arr2, n, IPIV);
+  LAPACKE_zgetri(LAPACK_ROW_MAJOR, n, arr2, n, IPIV);
+#else
+  LAPACKE_zgetrf(LAPACK_ROW_MAJOR, n, n, arr, n, IPIV);
+  LAPACKE_zgetri(LAPACK_ROW_MAJOR, n, arr, n, IPIV);
+#endif
+
+  delete[] IPIV;
+}
+#endif
diff --git a/src/libnptm/sph_subs.cpp b/src/libnptm/sph_subs.cpp
index 30e31bf9ec78e83a8e545a408d93c22fb6a267af..72f8cb1024912d78193dedbb3d71467e8e35de53 100644
--- a/src/libnptm/sph_subs.cpp
+++ b/src/libnptm/sph_subs.cpp
@@ -1,8 +1,12 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file sph_subs.cpp
  *
  * \brief C++ implementation of SPHERE subroutines.
  */
-#include <complex>
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
 
 #ifndef INCLUDE_COMMONS_H_
 #include "../include/Commons.h"
@@ -12,11 +16,9 @@
 #include "../include/sph_subs.h"
 #endif
 
-using namespace std;
-
 void aps(double ****zpv, int li, int nsph, C1 *c1, double sqk, double *gaps) {
-  complex<double> cc0 = complex<double>(0.0, 0.0);
-  complex<double> summ, sume, suem, suee, sum;
+  dcomplex cc0 = 0.0 + 0.0 * I;
+  dcomplex summ, sume, suem, suee, sum;
   double half_pi = acos(0.0);
   double cofs = half_pi * 2.0 / sqk;
   for (int i40 = 0; i40 < nsph; i40++) {
@@ -60,11 +62,11 @@ void aps(double ****zpv, int li, int nsph, C1 *c1, double sqk, double *gaps) {
 	}
       }
     }
-    gaps[i40] = sum.real() * cofs;
+    gaps[i40] = real(sum) * cofs;
   }
 }
 
-void cbf(int n, std::complex<double> z, int &nm, std::complex<double> csj[]) {
+void cbf(int n, dcomplex z, int &nm, dcomplex *csj) {
   /*
    * FROM CSPHJY OF LIBRARY specfun
    *
@@ -79,40 +81,40 @@ void cbf(int n, std::complex<double> z, int &nm, std::complex<double> csj[]) {
    *            point for backward recurrence
    * ==========================================================
    */
-  double zz = z.real() * z.real() + z.imag() * z.imag();
+  double zz = real(z) * real(z) + imag(z) * imag(z);
   double a0 = sqrt(zz);
   nm = n;
   if (a0 < 1.0e-60) {
     for (int k = 2; k <= n + 1; k++) {
       csj[k - 1] = 0.0;
     }
-    csj[0] = complex<double>(1.0, 0.0);
+    csj[0] = 1.0 + 0.0 * I;
     return;
   }
-  csj[0] = std::sin(z) / z;
+  csj[0] = csin(z) / z;
   if (n == 0) {
     return;
   }
-  csj[1] = (csj[0] -std::cos(z)) / z;
+  csj[1] = (csj[0] -ccos(z)) / z;
   if (n == 1) {
     return;
   }
-  complex<double> csa = csj[0];
-  complex<double> csb = csj[1];
+  dcomplex csa = csj[0];
+  dcomplex csb = csj[1];
   int m = msta1(a0, 200);
   if (m < n) nm = m;
   else m = msta2(a0, n, 15);
-  complex<double> cf0 = 0.0;
-  complex<double> cf1 = 1.0e-100;
-  complex<double> cf, cs;
+  dcomplex cf0 = 0.0;
+  dcomplex cf1 = 1.0e-100;
+  dcomplex cf, cs;
   for (int k = m; k >= 0; k--) {
     cf = (2.0 * k + 3.0) * cf1 / z - cf0;
     if (k <= nm) csj[k] = cf;
     cf0 = cf1;
     cf1 = cf;
   }
-  double abs_csa = abs(csa);
-  double abs_csb = abs(csb);
+  double abs_csa = cabs(csa);
+  double abs_csb = cabs(csb);
   if (abs_csa > abs_csb) cs = csa / cf;
   else cs = csb / cf0;
   for (int k = 0; k <= nm; k++) {
@@ -177,20 +179,20 @@ double cg1(int lmpml, int mu, int l, int m) {
   return result;
 }
 
-complex<double> dconjg(std::complex<double> z) {
-  double zreal = z.real();
-  double zimag = z.imag();
-  return complex<double>(zreal, -zimag);
+dcomplex dconjg(dcomplex z) {
+  double zreal = real(z);
+  double zimag = imag(z);
+  return (zreal - zimag * I);
 }
 
 void diel(int npntmo, int ns, int i, int ic, double vk, C1 *c1, C2 *c2) {
   const double dif = c1->rc[i - 1][ns] - c1->rc[i - 1][ns - 1];
   const double half_step = 0.5 * dif / npntmo;
   double rr = c1->rc[i - 1][ns - 1];
-  const complex<double> delta = c2->dc0[ic] - c2->dc0[ic - 1];
+  const dcomplex delta = c2->dc0[ic] - c2->dc0[ic - 1];
   const int kpnt = npntmo + npntmo;
   c2->ris[kpnt] = c2->dc0[ic];
-  c2->dlri[kpnt] = complex<double>(0.0, 0.0);
+  c2->dlri[kpnt] = 0.0 + 0.0 * I;
   const int i90 = i - 1;
   const int ns90 = ns - 1;
   const int ic90 = ic - 1;
@@ -204,29 +206,29 @@ void diel(int npntmo, int ns, int i, int ic, double vk, C1 *c1, C2 *c2) {
 
 void dme(
 	 int li, int i, int npnt, int npntts, double vk, double exdc, double exri,
-	 C1 *c1, C2 *c2, int &jer, int &lcalc, std::complex<double> &arg
+	 C1 *c1, C2 *c2, int &jer, int &lcalc, dcomplex &arg
 ) {
   const int lipo = li + 1;
   const int lipt = li + 2;
   double *rfj = new double[lipt];
   double *rfn = new double[lipt];
-  complex<double> cfj[lipt], fbi[lipt], fb[lipt], fn[lipt];
-  complex<double> rmf[li], drmf[li], ref[li], dref[li];
-  complex<double> dfbi, dfb, dfn, ccna, ccnb, ccnc, ccnd;
-  complex<double> y1, dy1, y2, dy2, arin, cri, uim;
+  dcomplex cfj[lipt], fbi[lipt], fb[lipt], fn[lipt];
+  dcomplex rmf[li], drmf[li], ref[li], dref[li];
+  dcomplex dfbi, dfb, dfn, ccna, ccnb, ccnc, ccnd;
+  dcomplex y1, dy1, y2, dy2, arin, cri;
+  const dcomplex uim = 1.0 * I;
   jer = 0;
-  uim = complex<double>(0.0, 1.0);
   int nstp = npnt - 1;
   int nstpts = npntts - 1;
   double sz = vk * c1->ros[i - 1];
   c2->vsz[i - 1] = sz;
   double vkr1 = vk * c1->rc[i - 1][0];
   int nsh = c1->nshl[i - 1];
-  c2->vkt[i - 1] = std::sqrt(c2->dc0[0]);
+  c2->vkt[i - 1] = csqrt(c2->dc0[0]);
   arg = vkr1 * c2->vkt[i - 1];
   arin = arg;
   bool goto32 = false;
-  if (arg.imag() != 0.0) {
+  if (imag(arg) != 0.0) {
     cbf(lipo, arg, lcalc, cfj);
     if (lcalc < lipo) {
       jer = 5;
@@ -238,7 +240,7 @@ void dme(
     goto32 = true;
   }
   if (!goto32) {
-    rbf(lipo, arg.real(), lcalc, rfj);
+    rbf(lipo, real(arg), lcalc, rfj);
     if (lcalc < lipo) {
       jer = 5;
       delete[] rfj;
@@ -353,23 +355,23 @@ double envj(int n, double x) {
   return result;
 }
 
-void mmulc(std::complex<double> *vint, double **cmullr, double **cmul) {
-  double sm2 = vint[0].real();
-  double s24 = vint[1].real();
-  double d24 = vint[1].imag();
-  double sm4 = vint[5].real();
-  double s23 = vint[8].real();
-  double d32 = vint[8].imag();
-  double s34 = vint[9].real();
-  double d34 = vint[9].imag();
-  double sm3 = vint[10].real();
-  double s31 = vint[11].real();
-  double d31 = vint[11].imag();
-  double s21 = vint[12].real();
-  double d12 = vint[12].imag();
-  double s41 = vint[13].real();
-  double d14 = vint[13].imag();
-  double sm1 = vint[15].real();
+void mmulc(dcomplex *vint, double **cmullr, double **cmul) {
+  double sm2 = real(vint[0]);
+  double s24 = real(vint[1]);
+  double d24 = imag(vint[1]);
+  double sm4 = real(vint[5]);
+  double s23 = real(vint[8]);
+  double d32 = imag(vint[8]);
+  double s34 = real(vint[9]);
+  double d34 = imag(vint[9]);
+  double sm3 = real(vint[10]);
+  double s31 = real(vint[11]);
+  double d31 = imag(vint[11]);
+  double s21 = real(vint[12]);
+  double d12 = imag(vint[12]);
+  double s41 = real(vint[13]);
+  double d14 = imag(vint[13]);
+  double sm1 = real(vint[15]);
   cmullr[0][0] = sm2;
   cmullr[0][1] = sm3;
   cmullr[0][2] = -s23;
@@ -462,7 +464,7 @@ int msta2(double x, int n, int mp) {
   return result;
 }
 
-void orunve( double *u1, double *u2, double *u3, int iorth, double torth) {
+void orunve(double *u1, double *u2, double *u3, int iorth, double torth) {
   if (iorth <= 0) {
     double cp = u1[0] * u2[0] + u1[1] * u2[1] + u1[2] * u2[2];
     double abs_cp = cp;
@@ -481,7 +483,7 @@ void orunve( double *u1, double *u2, double *u3, int iorth, double torth) {
 }
 
 void pwma(
-	  double *up, double *un, std::complex<double> *ylm, int inpol, int lw,
+	  double *up, double *un, dcomplex *ylm, int inpol, int lw,
 	  int isq, C1 *c1
 ) {
   const double four_pi = 8.0 * acos(0.0);
@@ -492,19 +494,19 @@ void pwma(
   int nlwm = lw * (lw + 2);
   int nlwmt = nlwm + nlwm;
   const double sqrtwi = 1.0 / sqrt(2.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> cm1 = 0.5 * complex<double>(up[0], up[1]);
-  complex<double> cp1 = 0.5 * complex<double>(up[0], -up[1]);
+  const dcomplex uim = 1.0 * I;
+  dcomplex cm1 = 0.5 * (up[0] + up[1] * I);
+  dcomplex cp1 = 0.5 * (up[0] - up[1] * I);
   double cz1 = up[2];
-  complex<double> cm2 = 0.5 * complex<double>(un[0], un[1]);
-  complex<double> cp2 = 0.5 * complex<double>(un[0], -un[1]);
+  dcomplex cm2 = 0.5 * (un[0] + un[1] * I);
+  dcomplex cp2 = 0.5 * (un[0] - un[1] * I);
   double cz2 = un[2];
   for (int l20 = 0; l20 < lw; l20++) {
     int l = l20 + 1;
     int lf = l + 1;
     int lftl = lf * l;
     double x = 1.0 * lftl;
-    complex<double> cl = complex<double>(four_pi / sqrt(x), 0.0);
+    dcomplex cl = four_pi / sqrt(x) + 0.0 * I;
     for (int powi = 1; powi <= l; powi++) cl *= uim;
     int mv = l + lf;
     int m = -lf;
@@ -536,8 +538,8 @@ void pwma(
   if (inpol != 0) {
     for (int k40 = 0; k40 < nlwm; k40++) {
       int i = k40 + nlwm;
-      complex<double> cc1 = sqrtwi * (c1->w[k40][ispo - 1] + uim * c1->w[k40][ispt - 1]);
-      complex<double> cc2 = sqrtwi * (c1->w[k40][ispo - 1] - uim * c1->w[k40][ispt - 1]);
+      dcomplex cc1 = sqrtwi * (c1->w[k40][ispo - 1] + uim * c1->w[k40][ispt - 1]);
+      dcomplex cc2 = sqrtwi * (c1->w[k40][ispo - 1] - uim * c1->w[k40][ispt - 1]);
       c1->w[k40][ispo - 1] = cc2;
       c1->w[i][ispo - 1] = -cc2;
       c1->w[k40][ispt - 1] = cc1;
@@ -560,11 +562,11 @@ void pwma(
 }
 
 void rabas(
-	   int inpol, int li, int nsph, C1 *c1, double **tqse, std::complex<double> **tqspe,
-	   double **tqss, std::complex<double> **tqsps
+	   int inpol, int li, int nsph, C1 *c1, double **tqse, dcomplex **tqspe,
+	   double **tqss, dcomplex **tqsps
 ) {
-  complex<double> cc0 = complex<double>(0.0, 0.0);
-  complex<double> uim = complex<double>(0.0, 1.0);
+  dcomplex cc0 = 0.0 + 0.0 * I;
+  dcomplex uim = 0.0 + 1.0 * I;
   double two_pi = 4.0 * acos(0.0);
   for (int i80 = 0; i80 < nsph; i80++) {
     int i = i80 + 1;
@@ -580,19 +582,19 @@ void rabas(
       for (int l70 = 0; l70 < li; l70++) {
 	int l = l70 + 1;
 	double fl = 1.0 * (l + l + 1);
-	complex<double> rm = 1.0 / c1->rmi[l70][i80];
-	double rmm = (rm * dconjg(rm)).real();
-	complex<double> re = 1.0 / c1->rei[l70][i80];
-	double rem = (re * dconjg(re)).real();
+	dcomplex rm = 1.0 / c1->rmi[l70][i80];
+	double rmm = real(rm * dconjg(rm));
+	dcomplex re = 1.0 / c1->rei[l70][i80];
+	double rem = real(re * dconjg(re));
 	if (inpol == 0) {
-	  complex<double> pce = ((rm + re) * uim) * fl;
-	  complex<double> pcs = ((rmm + rem) * fl) * uim;
+	  dcomplex pce = ((rm + re) * uim) * fl;
+	  dcomplex pcs = ((rmm + rem) * fl) * uim;
 	  tqspe[0][i80] -= pce;
 	  tqspe[1][i80] += pce;
 	  tqsps[0][i80] -= pcs;
 	  tqsps[1][i80] += pcs;
 	} else {
-	  double ce = (rm + re).real() * fl;
+	  double ce = real(rm + re) * fl;
 	  double cs = (rmm + rem) * fl;
 	  tqse[0][i80] -= ce;
 	  tqse[1][i80] += ce;
@@ -672,12 +674,11 @@ void rbf(int n, double x, int &nm, double sj[]) {
 }
 
 void rkc(
-	 int npntmo, double step, std::complex<double> dcc, double &x, int lpo,
-	 std::complex<double> &y1, std::complex<double> &y2, std::complex<double> &dy1,
-	 std::complex<double> &dy2
+	 int npntmo, double step, dcomplex dcc, double &x, int lpo,
+	 dcomplex &y1, dcomplex &y2, dcomplex &dy1, dcomplex &dy2
 ) {
-  complex<double> cy1, cdy1, c11, cy23, yc2, c12, c13;
-  complex<double> cy4, yy, c14, c21, c22, c23, c24;
+  dcomplex cy1, cdy1, c11, cy23, yc2, c12, c13;
+  dcomplex cy4, yy, c14, c21, c22, c23, c24;
   double half_step = 0.5 * step;
   double cl = 1.0 * lpo * (lpo - 1);
   for (int ipnt60 = 0; ipnt60 < npntmo; ipnt60++) {
@@ -710,12 +711,11 @@ void rkc(
 }
 
 void rkt(
-	 int npntmo, double step, double &x, int lpo, std::complex<double> &y1,
-	 std::complex<double> &y2, std::complex<double> &dy1, std::complex<double> &dy2,
-	 C2 *c2
+	 int npntmo, double step, double &x, int lpo, dcomplex &y1,
+	 dcomplex &y2, dcomplex &dy1, dcomplex &dy2, C2 *c2
 ) {
-  complex<double> cy1, cdy1, c11, cy23, cdy23, yc2, c12, c13;
-  complex<double> cy4, cdy4, yy, c14, c21, c22, c23, c24;
+  dcomplex cy1, cdy1, c11, cy23, cdy23, yc2, c12, c13;
+  dcomplex cy4, cdy4, yy, c14, c21, c22, c23, c24;
   double half_step = 0.5 * step;
   double cl = 1.0 * lpo * (lpo - 1);
   for (int ipnt60 = 0; ipnt60 < npntmo; ipnt60++) {
@@ -758,7 +758,7 @@ void rkt(
   }
 }
 
-void rnf(int n, double x, int &nm, double sy[]) {
+void rnf(int n, double x, int &nm, double *sy) {
   /*
    * FROM SPHJY OF LIBRARY specfun
    *
@@ -804,7 +804,7 @@ void rnf(int n, double x, int &nm, double sy[]) {
 
 void sphar(
 	   double cosrth, double sinrth, double cosrph, double sinrph,
-	   int ll, std::complex<double> *ylm
+	   int ll, dcomplex *ylm
 ) {
   const int rmp_size = ll;
   const int plegn_size = (ll + 1) * ll / 2 + ll + 1;
@@ -867,10 +867,10 @@ void sphar(
   lmp = l0p + m;
   save = pi4irs * plegn[lmp - 1];
   lmy = l0y + m;
-  ylm[lmy - 1] = save * complex<double>(cosrmp[m - 1], sinrmp[m - 1]);
+  ylm[lmy - 1] = save * (cosrmp[m - 1] + sinrmp[m - 1] * I);
   if (m % 2 != 0) ylm[lmy - 1] *= -1.0;
   lmy = l0y - m;
-  ylm[lmy - 1] = save * complex<double>(cosrmp[m - 1], -sinrmp[m - 1]);
+  ylm[lmy - 1] = save * (cosrmp[m - 1] - sinrmp[m - 1] * I);
  label45:
   if (m >= l) goto label47;
   m += 1;
@@ -881,33 +881,33 @@ void sphar(
   goto label40;
 }
 
-void sscr0(std::complex<double> &tfsas, int nsph, int lm, double vk, double exri, C1 *c1) {
-  complex<double> sum21, rm, re, csam;
-  const complex<double> cc0 = complex<double>(0.0, 0.0);
+void sscr0(dcomplex &tfsas, int nsph, int lm, double vk, double exri, C1 *c1) {
+  dcomplex sum21, rm, re, csam;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
   const double exdc = exri * exri;
   double ccs = 4.0 * acos(0.0) / (vk * vk);
   double cccs = ccs / exdc;
-  csam = -(ccs / (exri * vk)) * complex<double>(0.0, 0.5);
+  csam = -(ccs / (exri * vk)) * (0.0 + 0.5 * I);
   tfsas = cc0;
   for (int i12 = 0; i12 < nsph; i12++) {
     int i = i12 + 1;
     int iogi = c1->iog[i12];
     if (iogi >= i) {
       double sums = 0.0;
-      complex<double> sum21 = cc0;
+      dcomplex sum21 = cc0;
       for (int l10 = 0; l10 < lm; l10++) {
 	int l = l10 + 1;
 	double fl = 1.0 + l + l;
 	rm = 1.0 / c1->rmi[l10][i12];
 	re = 1.0 / c1->rei[l10][i12];
-	complex<double> rm_cnjg = dconjg(rm);
-	complex<double> re_cnjg = dconjg(re);
-	sums += (rm_cnjg * rm + re_cnjg * re).real() * fl;
+	dcomplex rm_cnjg = dconjg(rm);
+	dcomplex re_cnjg = dconjg(re);
+	sums += real(rm_cnjg * rm + re_cnjg * re) * fl;
 	sum21 += (rm + re) * fl;
       }
       sum21 *= -1.0;
       double scasec = cccs * sums;
-      double extsec = -cccs * sum21.real();
+      double extsec = -cccs * real(sum21);
       double abssec = extsec - scasec;
       c1->sscs[i12] = scasec;
       c1->sexs[i12] = extsec;
@@ -923,10 +923,10 @@ void sscr0(std::complex<double> &tfsas, int nsph, int lm, double vk, double exri
 }
 
 void sscr2(int nsph, int lm, double vk, double exri, C1 *c1) {
-  std::complex<double> s11, s21, s12, s22, rm, re, csam, cc;
-  const complex<double> cc0(0.0, 0.0);
+  dcomplex s11, s21, s12, s22, rm, re, csam, cc;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
   double ccs = 1.0 / (vk * vk);
-  csam = -(ccs / (exri * vk)) * complex<double>(0.0, 0.5);
+  csam = -(ccs / (exri * vk)) * (0.0 + 0.5 * I);
   const double pigfsq = 64.0 * acos(0.0) * acos(0.0);
   double cfsq = 4.0 / (pigfsq * ccs * ccs);
   int nlmm = lm * (lm + 2);
@@ -966,7 +966,7 @@ void sscr2(int nsph, int lm, double vk, double exri, C1 *c1) {
       int j = 0;
       for (int ipo1 = 0; ipo1 < 2; ipo1++) {
 	for (int jpo1 = 0; jpo1 < 2; jpo1++) {
-	  complex<double> cc = dconjg(c1->sas[i24][jpo1][ipo1]);
+	  dcomplex cc = dconjg(c1->sas[i24][jpo1][ipo1]);
 	  for (int ipo2 = 0; ipo2 < 2; ipo2++) {
 	    for (int jpo2 = 0; jpo2 < 2; jpo2++) {
 	      c1->vints[i24][j++] = c1->sas[i24][jpo2][ipo2] * cc * cfsq;
@@ -1111,9 +1111,9 @@ void wmamp(
 	   double *un, C1 *c1
 ) {
   const int ylm_size = (lm + 1) * (lm + 1) + 1;
-  complex<double> *ylm = new complex<double>[ylm_size];
+  dcomplex *ylm = new dcomplex[ylm_size];
   const int nlmp = lm * (lm + 2) + 2;
-  ylm[nlmp - 1] = complex<double>(0.0, 0.0);
+  ylm[nlmp - 1] = 0.0 + 0.0 * I;
   if (idot != 0) {
     if (idot != 1) {
       for (int n40 = 0; n40 < nsph; n40++) {
@@ -1140,9 +1140,9 @@ void wmasp(
 	   int nsph, double *argi, double *args, C1 *c1
 ) {
   const int ylm_size = (lm + 1) * (lm + 1) + 1;
-  complex<double> *ylm = new complex<double>[ylm_size];
+  dcomplex *ylm = new dcomplex[ylm_size];
   const int nlmp = lm * (lm + 2) + 2;
-  ylm[nlmp - 1] = complex<double>(0.0, 0.0);
+  ylm[nlmp - 1] = 0.0 + 0.0 * I;
   if (idot != 0) {
     if (idot != 1) {
       for (int n40 = 0; n40 < nsph; n40++) {
diff --git a/src/libnptm/tfrfme.cpp b/src/libnptm/tfrfme.cpp
index b3478d3cc34850289b6a583a6db78fbd0ae0f663..a1a8e1aecf19841471964057b2d3442711638e82 100644
--- a/src/libnptm/tfrfme.cpp
+++ b/src/libnptm/tfrfme.cpp
@@ -1,14 +1,19 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file tfrfme.cpp
  *
  * \brief Implementation of the trapping calculation objects.
  */
 
-#include <complex>
 #include <exception>
 #include <fstream>
 #include <hdf5.h>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_ERRORS_H_
 #include "../include/errors.h"
 #endif
@@ -32,7 +37,7 @@ Swap1::Swap1(int lm, int _nkv) {
   nkv = _nkv;
   nlmmt = 2 * lm * (lm + 2);
   const int size = nkv * nkv * nlmmt;
-  wk = new complex<double>[size]();
+  wk = new dcomplex[size]();
   last_index = 0;
 }
 
@@ -57,8 +62,8 @@ Swap1* Swap1::from_hdf5(string file_name) {
   double *elements;
   string str_type;
   int _nlmmt, _nkv, lm, num_elements, index;
-  complex<double> value;
-  complex<double> *_wk = NULL;
+  dcomplex value;
+  dcomplex *_wk = NULL;
   if (status == 0) {
     status = hdf_file->read("NLMMT", "INT32", &_nlmmt);
     status = hdf_file->read("NKV", "INT32", &_nkv);
@@ -71,7 +76,7 @@ Swap1* Swap1::from_hdf5(string file_name) {
     status = hdf_file->read("WK", str_type, elements);
     for (int wi = 0; wi < num_elements / 2; wi++) {
       index = 2 * wi;
-      value = complex<double>(elements[index], elements[index + 1]);
+      value = elements[index] + elements[index + 1] * I;
       _wk[wi] = value;
     } // wi loop
     delete[] elements;
@@ -84,7 +89,7 @@ Swap1* Swap1::from_hdf5(string file_name) {
 Swap1* Swap1::from_legacy(string file_name) {
   fstream input;
   Swap1 *instance = NULL;
-  complex<double> *_wk = NULL;
+  dcomplex *_wk = NULL;
   int _nlmmt, _nkv, lm;
   double rval, ival;
   input.open(file_name.c_str(), ios::in | ios::binary);
@@ -98,7 +103,7 @@ Swap1* Swap1::from_legacy(string file_name) {
     for (int j = 0; j < num_elements; j++) {
       input.read(reinterpret_cast<char *>(&rval), sizeof(double));
       input.read(reinterpret_cast<char *>(&ival), sizeof(double));
-      _wk[j] = complex<double>(rval, ival);
+      _wk[j] = rval + ival * I;
     }
     input.close();
   } else {
@@ -109,7 +114,7 @@ Swap1* Swap1::from_legacy(string file_name) {
 
 long Swap1::get_memory_requirement(int lm, int _nkv) {
   long size = (long)(3 * sizeof(int));
-  size += (long)(sizeof(complex<double>) * 2 * lm * (lm + 2) * _nkv * _nkv);
+  size += (long)(sizeof(dcomplex) * 2 * lm * (lm + 2) * _nkv * _nkv);
   return size;
 }
 
@@ -142,8 +147,8 @@ void Swap1::write_hdf5(string file_name) {
   rec_type_list.append(str_type);
   double *ptr_elements = new double[num_elements]();
   for (int wi = 0; wi < num_elements / 2; wi++) {
-      ptr_elements[2 * wi] = wk[wi].real();
-      ptr_elements[2 * wi + 1] = wk[wi].imag();
+    ptr_elements[2 * wi] = real(wk[wi]);
+    ptr_elements[2 * wi + 1] = imag(wk[wi]);
   }
   rec_ptr_list.append(ptr_elements);
 
@@ -173,8 +178,8 @@ void Swap1::write_legacy(string file_name) {
     output.write(reinterpret_cast<char *>(&nlmmt), sizeof(int));
     output.write(reinterpret_cast<char *>(&nkv), sizeof(int));
     for (int j = 0; j < num_elements; j++) {
-      rval = wk[j].real();
-      ival = wk[j].imag();
+      rval = real(wk[j]);
+      ival = imag(wk[j]);
       output.write(reinterpret_cast<char *>(&rval), sizeof(double));
       output.write(reinterpret_cast<char *>(&ival), sizeof(double));
     }
@@ -591,8 +596,8 @@ TFRFME::TFRFME(int _lmode, int _lm, int _nkv, int _nxv, int _nyv, int _nzv) {
   zv = new double[nzv]();
   nlmmt = lm * (lm + 2) * 2;
   nrvc = nxv * nyv * nzv;
-  wsum = new complex<double>*[nlmmt];
-  for (int wi = 0; wi < nlmmt; wi++) wsum[wi] = new complex<double>[nrvc]();
+  wsum = new dcomplex*[nlmmt];
+  for (int wi = 0; wi < nlmmt; wi++) wsum[wi] = new dcomplex[nrvc]();
 }
 
 TFRFME::~TFRFME() {
@@ -624,8 +629,8 @@ TFRFME* TFRFME::from_hdf5(string file_name) {
   double *elements;
   string str_type;
   int _nlmmt, _nrvc, num_elements;
-  complex<double> value;
-  complex<double> **_wsum = NULL;
+  dcomplex value;
+  dcomplex **_wsum = NULL;
   if (status == 0) {
     int lmode, lm, nkv, nxv, nyv, nzv;
     double vk, exri, an, ff, tra, spd, frsh, exril;
@@ -668,7 +673,7 @@ TFRFME* TFRFME::from_hdf5(string file_name) {
     int index = 0;
     for (int wj = 0; wj < _nrvc; wj++) {
       for (int wi = 0; wi < _nlmmt; wi++) {
-	value = complex<double>(elements[index], elements[index + 1]);
+	value = elements[index] + elements[index + 1] * I;
 	_wsum[wi][wj] = value;
 	index += 2;
       } // wi loop
@@ -683,7 +688,7 @@ TFRFME* TFRFME::from_hdf5(string file_name) {
 TFRFME* TFRFME::from_legacy(string file_name) {
   fstream input;
   TFRFME *instance = NULL;
-  complex<double> **_wsum = NULL;
+  dcomplex **_wsum = NULL;
   double *coord_vec = NULL;
   input.open(file_name.c_str(), ios::in | ios::binary);
   if (input.is_open()) {
@@ -735,7 +740,7 @@ TFRFME* TFRFME::from_legacy(string file_name) {
       for (int wi = 0; wi < _nlmmt; wi++) {
 	input.read(reinterpret_cast<char *>(&rval), sizeof(double));
 	input.read(reinterpret_cast<char *>(&ival), sizeof(double));
-	complex<double> value(rval, ival);
+	dcomplex value = rval + ival * I;
 	_wsum[wi][wj] = value;
       } // wi loop
     } // wj loop
@@ -754,7 +759,7 @@ long TFRFME::get_memory_requirement(
   int _nrvc = _nxv * _nyv * _nzv;
   long size = (long)(8 * sizeof(int) + 8 * sizeof(double));
   size += (long)((_nxv + _nyv + _nzv) * sizeof(double));
-  size += (long)(_nlmmt * _nrvc * sizeof(complex<double>));
+  size += (long)(_nlmmt * _nrvc * sizeof(dcomplex));
   return size;
 }
 
@@ -877,8 +882,8 @@ void TFRFME::write_hdf5(string file_name) {
   int index = 0;
   for (int wj = 0; wj < nrvc; wj++) {
     for (int wi = 0; wi < nlmmt; wi++) {
-      ptr_elements[index++] = wsum[wi][wj].real();
-      ptr_elements[index++] = wsum[wi][wj].imag();
+      ptr_elements[index++] = real(wsum[wi][wj]);
+      ptr_elements[index++] = imag(wsum[wi][wj]);
     } // wi loop
   } // wj loop
   rec_ptr_list.append(ptr_elements);
@@ -926,8 +931,8 @@ void TFRFME::write_legacy(string file_name) {
       output.write(reinterpret_cast<char *>(&(zv[zi])), sizeof(double));
     for (int wj = 0; wj < nrvc; wj++) {
       for (int wi = 0; wi < nlmmt; wi++) {
-	double rval = wsum[wi][wj].real();
-	double ival = wsum[wi][wj].imag();
+	double rval = real(wsum[wi][wj]);
+	double ival = imag(wsum[wi][wj]);
 	output.write(reinterpret_cast<char *>(&rval), sizeof(double));
 	output.write(reinterpret_cast<char *>(&ival), sizeof(double));
       } // wi loop
diff --git a/src/libnptm/tra_subs.cpp b/src/libnptm/tra_subs.cpp
index 47c2b28edfc1fb784f06712f8f70baff9830b5ad..2591b8c335a245a64cd41ae26ad50e6720810ace 100644
--- a/src/libnptm/tra_subs.cpp
+++ b/src/libnptm/tra_subs.cpp
@@ -1,11 +1,16 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file tra_subs.cpp
  *
  * \brief C++ implementation of TRAPPING subroutines.
  */
 #include <cmath>
-#include <complex>
 #include <fstream>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_COMMONS_H_
 #include "../include/Commons.h"
 #endif
@@ -22,12 +27,7 @@
 #include "../include/tra_subs.h"
 #endif
 
-using namespace std;
-
-void camp(
-	  std::complex<double> *ac, std::complex<double> **am0m, std::complex<double> *ws,
-	  CIL *cil
-) {
+void camp(dcomplex *ac, dcomplex **am0m, dcomplex *ws, CIL *cil) {
   for (int j = 0; j < cil->nlemt; j++) {
     for (int i = 0; i < cil->nlemt; i++) {
       ac[j] += (am0m[j][i] * ws[i]);
@@ -35,13 +35,10 @@ void camp(
   } // j loop
 }
 
-void czamp(
-	   std::complex<double> *ac, std::complex<double> **amd, int **indam,
-	   std::complex<double> *ws, CIL *cil
-) {
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> summ, sume;
+void czamp(dcomplex *ac, dcomplex **amd, int **indam, dcomplex *ws, CIL *cil) {
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex summ, sume;
   for (int im20 = 1; im20 <= cil->mxim; im20++) {
     int m = im20 - cil->mxmpo;
     int abs_m = (m < 0) ? -m : m;
@@ -65,13 +62,13 @@ void czamp(
 }
 
 void ffrf(
-	  double ****zpv, std::complex<double> *ac, std::complex<double> *ws, double *fffe,
+	  double ****zpv, dcomplex *ac, dcomplex *ws, double *fffe,
 	  double *fffs, CIL *cil, CCR *ccr
 ) {
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> uimmp, summ, sume, suem, suee;
-  complex<double> *gap = new complex<double>[3]();
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex uimmp, summ, sume, suem, suee;
+  dcomplex *gap = new dcomplex[3]();
 
   for (int imu50 = 1; imu50 <= 3; imu50++) {
     int mu = imu50 - 2;
@@ -123,9 +120,9 @@ void ffrf(
   sume = -gap[0] * ccr->cimu;
   suee = -gap[1] * ccr->cof;
   suem = -gap[2] * ccr->cimu;
-  fffe[0] = (sume - suem).real();
-  fffe[1] = ((sume + suem) * uim).real();
-  fffe[2] = suee.real();
+  fffe[0] = real(sume - suem);
+  fffe[1] = real((sume + suem) * uim);
+  fffe[2] = real(suee);
 
   for (int imu90 = 1; imu90 <= 3; imu90++) {
     int mu = imu90 - 2;
@@ -177,25 +174,22 @@ void ffrf(
   sume = gap[0] * ccr->cimu;
   suee = gap[1] * ccr->cof;
   suem = gap[2] * ccr->cimu;
-  fffs[0] = (sume - suem).real();
-  fffs[1] = ((sume + suem) * uim).real();
-  fffs[2] = suee.real();
+  fffs[0] = real(sume - suem);
+  fffs[1] = real((sume + suem) * uim);
+  fffs[2] = real(suee);
   delete[] gap;
 }
 
-void ffrt(
-	  std::complex<double> *ac, std::complex<double> *ws, double *ffte, double *ffts,
-	  CIL *cil
-) {
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
+void ffrt(dcomplex *ac, dcomplex *ws, double *ffte, double *ffts, CIL *cil) {
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
   const double sq2i = 1.0 / sqrt(2.0);
-  const complex<double> sq2iti = uim * sq2i;
-  complex<double> aca, acw;
-  complex<double> *ctqce, *ctqcs;
+  const dcomplex sq2iti = uim * sq2i;
+  dcomplex aca, acw;
+  dcomplex *ctqce, *ctqcs;
 
-  ctqce = new complex<double>[3]();
-  ctqcs = new complex<double>[3]();
+  ctqce = new dcomplex[3]();
+  ctqcs = new dcomplex[3]();
   for (int l60 = 1; l60 <= cil->le; l60++) {
     int lpo = l60 + 1;
     int il = l60 * lpo;
@@ -235,28 +229,28 @@ void ffrt(
       }
     } // im60 loop
   } // l60 loop
-  ffte[0] = (ctqce[0] - ctqce[2]).real() * sq2i;
-  ffte[1] = (sq2iti * (ctqce[0] + ctqce[2])).real();
-  ffte[2] = ctqce[1].real();
-  ffts[0] = -sq2i * (ctqcs[0] - ctqcs[2]).real();
-  ffts[1] = -1.0 * (sq2iti * (ctqcs[0] + ctqcs[2])).real();
-  ffts[2] = -1.0 * ctqcs[1].real();
+  ffte[0] = real(ctqce[0] - ctqce[2]) * sq2i;
+  ffte[1] = real(sq2iti * (ctqce[0] + ctqce[2]));
+  ffte[2] = real(ctqce[1]);
+  ffts[0] = -sq2i * real(ctqcs[0] - ctqcs[2]);
+  ffts[1] = -1.0 * real(sq2iti * (ctqcs[0] + ctqcs[2]));
+  ffts[2] = -1.0 * real(ctqcs[1]);
 
   delete[] ctqce;
   delete[] ctqcs;
 }
 
-complex<double> *frfmer(
+dcomplex *frfmer(
 	    int nkv, double vkm, double vknmx, double apfafa, double tra,
 	    double spd, double rir, double ftcn, int le, int lmode, double pmf,
 	    Swap1 *tt1, Swap2 *tt2
 ) {
   const int nlemt = le * (le + 2) * 2;
-  const complex<double> cc0(0.0, 0.0);
+  const dcomplex cc0 = 0.0 + 0.0 * I;
   double sq = vkm * vkm;
   double *_vkv = tt2->get_vector();
   double **_vkzm = tt2->get_matrix();
-  complex<double> *wk = new complex<double>[nlemt]();
+  dcomplex *wk = new dcomplex[nlemt]();
   for (int jy90 = 0; jy90 < nkv; jy90++) {
     double vky = _vkv[jy90];
     double sqy = vky * vky;
@@ -282,22 +276,22 @@ complex<double> *frfmer(
   return wk;
 }
 
-void pwmalp(std::complex<double> **w, double *up, double *un, std::complex<double> *ylm, int lw) {
-  complex<double> cp1, cm1, cp2, cm2, cl;
-  const complex<double> uim(0.0, 1.0);
+void pwmalp(dcomplex **w, double *up, double *un, dcomplex *ylm, int lw) {
+  dcomplex cp1, cm1, cp2, cm2, cl;
+  const dcomplex uim = 0.0 + 1.0 * I;
   const double four_pi = acos(0.0) * 8.0;
   const int nlwm = lw * (lw + 2);
-  cm1 = 0.5 * complex<double>(up[0], up[1]);
-  cp1 = 0.5 * complex<double>(up[0], -up[1]);
+  cm1 = 0.5 * (up[0] + up[1] * I);
+  cp1 = 0.5 * (up[0] - up[1] * I);
   double cz1 = up[2];
-  cm2 = 0.5 * complex<double>(un[0], un[1]);
-  cp2 = 0.5 * complex<double>(un[0], -un[1]);
+  cm2 = 0.5 * (un[0] + un[1] * I);
+  cp2 = 0.5 * (un[0] - un[1] * I);
   double cz2 =un[2];
   for (int l20 = 1; l20 <= lw; l20++) {
     int lf = l20 + 1;
     int lftl = lf * l20;
     double x = 1.0 * lftl;
-    complex<double> cl = (four_pi / sqrt(x)) * std::pow(uim, 1.0 * l20);
+    dcomplex cl = (four_pi / sqrt(x)) * cpow(uim, 1.0 * l20);
     int mv = l20 + lf;
     int m = -lf;
     for (int mf20 = 1; mf20 <= mv; mf20++) {
@@ -319,10 +313,7 @@ void pwmalp(std::complex<double> **w, double *up, double *un, std::complex<doubl
   } // k30 loop
 }
 
-void samp(
-	  std::complex<double> *ac, std::complex<double> *tmsm, std::complex<double> *tmse,
-	  std::complex<double> *ws, CIL *cil
-) {
+void samp(dcomplex *ac, dcomplex *tmsm, dcomplex *tmse, dcomplex *ws, CIL *cil) {
   int i = 0;
   for (int l20 = 0; l20 < cil->le; l20++) {
     int l = l20 + 1;
@@ -336,13 +327,10 @@ void samp(
   } // l20 loop
 }
 
-void sampoa(
-	    std::complex<double> *ac, std::complex<double> **tms, std::complex<double> *ws,
-	    CIL *cil
-) {
-  complex<double> **tm = new complex<double>*[2];
-  tm[0] = new complex<double>[2]();
-  tm[1] = new complex<double>[2]();
+void sampoa(dcomplex *ac, dcomplex **tms, dcomplex *ws, CIL *cil) {
+  dcomplex **tm = new dcomplex*[2];
+  tm[0] = new dcomplex[2]();
+  tm[1] = new dcomplex[2]();
   int i = 0;
   for (int l20 = 0; l20 < cil->le; l20++) {
     tm[0][0] = tms[l20][0];
@@ -364,23 +352,23 @@ void sampoa(
 }
 
 void wamff(
-	   std::complex<double> *wk, double x, double y, double z, int lm, double apfafa,
+	   dcomplex *wk, double x, double y, double z, int lm, double apfafa,
 	   double tra, double spd, double rir, double ftcn, int lmode, double pmf
 ) {
   const int nlmm = lm * (lm + 2);
   const int nlmmt = 2 * nlmm;
   const int nlmp = nlmm + 2;
-  complex<double> **w, *ylm;
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
-  complex<double> cfam, cf1, cf2;
+  dcomplex **w, *ylm;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
+  dcomplex cfam, cf1, cf2;
   double rho, cph, sph, cth, sth, r;
   double ftc1, ftc2;
   double *up = new double[3];
   double *un = new double[3];
-  w = new complex<double>*[nlmmt];
-  for (int wi = 0; wi < nlmmt; wi++) w[wi] = new complex<double>[2]();
-  ylm = new complex<double>[nlmp]();
+  w = new dcomplex*[nlmmt];
+  for (int wi = 0; wi < nlmmt; wi++) w[wi] = new dcomplex[2]();
+  ylm = new dcomplex[nlmp]();
   bool onx = (y == 0.0);
   bool ony = (x == 0.0);
   bool onz = (onx && ony);
@@ -446,7 +434,7 @@ void wamff(
       double sthl = sth * rir;
       double cthl = sqrt(1.0 - sthl * sthl);
       double arg = spd * (z - (r / rir) * cthl);
-      cfam = (tra * std::exp(-apfa * apfa) / sqrt(cthl)) * std::exp(uim * arg);
+      cfam = (tra * cexp(-apfa * apfa) / sqrt(cthl)) * cexp(uim * arg);
       if (lmode == 0) {
 	if (sth == 0.0) { // label 45
 	  ftc1 = ftcn;
@@ -478,7 +466,7 @@ void wamff(
 	skip62 = false;
       }
     } else { // label 57
-      double fam = tra * std::exp(-apfa * apfa) / sqrt(cth);
+      double fam = tra * exp(-apfa * apfa) / sqrt(cth);
       if (lmode == 0) {
 	double f1 = cph * fam;
 	double f2 = -sph * fam;
diff --git a/src/libnptm/types.cpp b/src/libnptm/types.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9fd71be5682403b831ca13926fb6eff88ebac69
--- /dev/null
+++ b/src/libnptm/types.cpp
@@ -0,0 +1,13 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
+/*! \file types.cpp
+ *
+ * \brief Implementation of the functions connected with types.
+ */
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
+double real(dcomplex z) { return __real__ z; }
+
+double imag(dcomplex z) { return __imag__ z; }
diff --git a/src/make.inc b/src/make.inc
index dcdd896f0619de451fcf37eaeb62ec664f21c8e6..2ba3d6b135da8c1627da9b0e5504c6c266cc8777 100644
--- a/src/make.inc
+++ b/src/make.inc
@@ -38,10 +38,48 @@ ifndef HDF5_INCLUDE
 override HDF5_INCLUDE=/usr/include/hdf5/serial
 endif
 
+# define (outside) USE_LAPACK for lapacke support, LAPACK_ILP64 for ilp64 interface, MKL_ILP64 the same if using MKL implementation
+ifdef USE_LAPACK
+ifndef LAPACK_ILP64
+override LAPACK_ILP64=1
+endif
+# define (outside) USE_MKL to use the MKL implementation of lapacke
+ifdef USE_MKL
+ifndef MKL_ILP64
+override MKL_ILP64=1
+endif
+ifndef LAPACK_INCLUDE
+# this is for the MKL implementation
+override LAPACK_INCLUDE=$(MKLROOT)/include
+endif
+ifndef LAPACK_LDFLAGS
+# this is for the MKL implementation
+override LAPACK_LDFLAGS=-L$(MKLROOT)/lib -Wl,--no-as-needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lpthread -lm -ldl
+endif
+# the next else refers to USE_MKL
+else
+ifndef LAPACK_INCLUDE
+# this is for standard "vanilla" lapacke64
+override LAPACK_INCLUDE=/usr/include
+endif
+ifndef LAPACK_LDFLAGS
+# this is for standard "vanilla" lapacke64
+override LAPACK_LDFLAGS=-llapacke64
+endif
+# the next endif is for USE_MKL
+endif
+#the next endif is for USE_LAPACK
+endif
+
 # CXXFLAGS defines the default compilation options for the C++ compiler
 ifndef CXXFLAGS
 override CXXFLAGS=-O3 -ggdb -pg -coverage -I$(HDF5_INCLUDE)
-#override CXXFLAGS=-O3 -I$(HDF5_INCLUDE)
+ifdef USE_LAPACK
+override CXXFLAGS+= -DUSE_LAPACK -DLAPACK_ILP64 
+ifdef USE_MKL
+override CXXFLAGS+= -DMKL_ILP64 -DUSE_MKL -I$(MKLROOT)/include
+endif
+endif
 endif
 
 # HDF5_LIB defines the default path to the HDF5 libraries to use
@@ -50,9 +88,11 @@ ifndef CXXLDFLAGS
 ifndef HDF5_LIB
 override HDF5_LIB=/usr/lib/x86_64-linux-gnu/hdf5/serial
 endif
-override CXXLDFLAGS=-L/usr/lib64 -L$(HDF5_LIB) -lhdf5 $(LDFLAGS)
-#else
-#override CXXLDFLAGS=-L/usr/lib64 -L$(HDF5_LIB) -lhdf5 $(CXXLDFLAGS)
+override CXXLDFLAGS=-L/usr/lib64 -L$(HDF5_LIB) -lhdf5
+ifdef USE_LAPACK
+override CXXLDFLAGS+= $(LAPACK_LDFLAGS)
+endif
+override CXXLDFLAGS+= $(LDFLAGS)
 endif
 
 #SOFLAGS defines the additional flags for the c++ compiler to create a shared object file
diff --git a/src/scripts/README.md b/src/scripts/README.md
index b865eacaa0946125f0a30195fba197fc3f6c385d..59a757141c8c6627065b4b809e774a0bc9f079fd 100644
--- a/src/scripts/README.md
+++ b/src/scripts/README.md
@@ -1,3 +1,5 @@
+Distributed under the terms of *GNU GPL-3.0-or-later*
+
 # Folder instructions
 
 This directory contains scripts and tools to evaluate the code functionality.
diff --git a/src/sphere/np_sphere.cpp b/src/sphere/np_sphere.cpp
index e3033dae6fa36f373e17c1fda92f802537ce3b53..7f381e41ee28b645b53376828ddf33c4c68b7a88 100644
--- a/src/sphere/np_sphere.cpp
+++ b/src/sphere/np_sphere.cpp
@@ -1,3 +1,5 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file np_sphere.cpp
  *
  * \brief Single sphere scattering problem handler.
@@ -15,10 +17,13 @@
  * while the advanced mode implements the possibility to change input and
  * output options, without having to modify the code.
  */
-#include <complex>
 #include <cstdio>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_CONFIGURATION_H_
 #include "../include/Configuration.h"
 #endif
diff --git a/src/sphere/sphere.cpp b/src/sphere/sphere.cpp
index 7016d8361eb8d61fef8437f504516352f0444948..b4bf9652d3e0a9401e076f750b92615073750b97 100644
--- a/src/sphere/sphere.cpp
+++ b/src/sphere/sphere.cpp
@@ -1,13 +1,18 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file sphere.cpp
  *
  * \brief Implementation of the single sphere calculation.
  */
-#include <complex>
 #include <cstdio>
 #include <exception>
 #include <fstream>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_ERRORS_H_
 #include "../include/errors.h"
 #endif
@@ -37,7 +42,7 @@ using namespace std;
  *  \param output_path: `string` Directory to write the output files in.
  */
 void sphere(string config_file, string data_file, string output_path) {
-  complex<double> arg, s0, tfsas;
+  dcomplex arg, s0, tfsas;
   double th, ph;
   printf("INFO: making legacy configuration...\n");
   ScattererConfiguration *sconf = NULL;
@@ -57,7 +62,7 @@ void sphere(string config_file, string data_file, string output_path) {
   } catch(const OpenConfigurationFileException &ex) {
     printf("\nERROR: failed to open geometry configuration file.\n");
     printf("FILE: %s\n", ex.what());
-    if (sconf) delete sconf;
+    if (sconf != NULL) delete sconf;
     exit(1);
   }
   if (sconf->number_of_spheres == gconf->number_of_spheres) {
@@ -83,21 +88,21 @@ void sphere(string config_file, string data_file, string output_path) {
       cmul[i] = new double[4];
       cmullr[i] = new double[4];
     }
-    complex<double> **tqspe, **tqsps;
+    dcomplex **tqspe, **tqsps;
     double **tqse, **tqss;
     tqse = new double*[2];
     tqss = new double*[2];
-    tqspe = new std::complex<double>*[2];
-    tqsps = new std::complex<double>*[2];
+    tqspe = new dcomplex*[2];
+    tqsps = new dcomplex*[2];
     for (int ti = 0; ti < 2; ti++) {
       tqse[ti] = new double[2]();
       tqss[ti] = new double[2]();
-      tqspe[ti] = new std::complex<double>[2]();
-      tqsps[ti] = new std::complex<double>[2]();
+      tqspe[ti] = new dcomplex[2]();
+      tqsps[ti] = new dcomplex[2]();
     }
     double frx = 0.0, fry = 0.0, frz = 0.0;
     double cfmp, cfsp, sfmp, sfsp;
-    complex<double> *vint = new complex<double>[16];
+    dcomplex *vint = new dcomplex[16];
     int jw;
     int nsph = gconf->number_of_spheres;
     C1 *c1 = new C1(nsph, gconf->l_max, sconf->nshl_vec, sconf->iog_vec);
@@ -244,8 +249,8 @@ void sphere(string config_file, string data_file, string output_path) {
 	fprintf(output, " \n");
       }
       for (int jxi488 = 0; jxi488 < sconf->number_of_scales; jxi488++) {
-	printf("INFO: running scale iteration...\n");
 	int jxi = jxi488 + 1;
+	printf("INFO: running scale iteration %d of %d...\n", jxi, sconf->number_of_scales);
 	fprintf(output, "========== JXI =%3d ====================\n", jxi);
 	double xi = sconf->scale_vec[jxi488];
 	if (sconf->idfc >= 0) {
@@ -289,7 +294,7 @@ void sphere(string config_file, string data_file, string output_path) {
 	      );
 	  if (jer != 0) {
 	    fprintf(output, "  STOP IN DME\n");
-	    fprintf(output, "  AT %1d LCALC=%3d TOO SMALL WITH ARG=%15.7lE+i(%15.7lE)\n", jer, lcalc, arg.real(), arg.imag());
+	    fprintf(output, "  AT %1d LCALC=%3d TOO SMALL WITH ARG=%15.7lE+i(%15.7lE)\n", jer, lcalc, real(arg), imag(arg));
 	    tppoan.close();
 	    fclose(output);
 	    return;
@@ -323,8 +328,8 @@ void sphere(string config_file, string data_file, string output_path) {
 		      output,
 		      "  SIZE=%15.7lE, REFRACTIVE INDEX=%15.7lE%15.7lE\n",
 		      c2->vsz[i170],
-		      c2->vkt[i170].real(),
-		      c2->vkt[i170].imag()
+		      real(c2->vkt[i170]),
+		      imag(c2->vkt[i170])
 		      );
 	    }
 	    fprintf(output, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n");
@@ -341,12 +346,12 @@ void sphere(string config_file, string data_file, string output_path) {
 		    c1->sqscs[i170], c1->sqabs[i170],
 		    c1->sqexs[i170]
 		    );
-	    fprintf(output, "  FSAS=%15.7lE%15.7lE\n", c1->fsas[i170].real(), c1->fsas[i170].imag());
+	    fprintf(output, "  FSAS=%15.7lE%15.7lE\n", real(c1->fsas[i170]), imag(c1->fsas[i170]));
 	    double csch = 2.0 * vk * sqsfi / c1->gcsv[i170];
 	    s0 = c1->fsas[i170] * exri;
-	    double qschu = csch * s0.imag();
-	    double pschu = csch * s0.real();
-	    double s0mag = cs0 * abs(s0);
+	    double qschu = csch * imag(s0);
+	    double pschu = csch * real(s0);
+	    double s0mag = cs0 * cabs(s0);
 	    fprintf(
 		    output,
 		    "  QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n",
@@ -359,33 +364,33 @@ void sphere(string config_file, string data_file, string output_path) {
 	    fprintf(output, "  IPO=%2d, TQEk=%15.7lE, TQSk=%15.7lE\n", 2, tqse[1][i170], tqss[1][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&(tqse[0][i170])), sizeof(double));
 	    tppoan.write(reinterpret_cast<char *>(&(tqss[0][i170])), sizeof(double));
-	    double val = tqspe[0][i170].real();
+	    double val = real(tqspe[0][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
-	    val = tqspe[0][i170].imag();
+	    val = imag(tqspe[0][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
-	    val = tqsps[0][i170].real();
+	    val = real(tqsps[0][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
-	    val = tqsps[0][i170].imag();
+	    val = imag(tqsps[0][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
 	    tppoan.write(reinterpret_cast<char *>(&(tqse[1][i170])), sizeof(double));
 	    tppoan.write(reinterpret_cast<char *>(&(tqss[1][i170])), sizeof(double));
-	    val = tqspe[1][i170].real();
+	    val = real(tqspe[1][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
-	    val = tqspe[1][i170].imag();
+	    val = imag(tqspe[1][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
-	    val = tqsps[1][i170].real();
+	    val = real(tqsps[1][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
-	    val = tqsps[1][i170].imag();
+	    val = imag(tqsps[1][i170]);
 	    tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
 	  } // End if iog[i170] >= i
 	} // i170 loop
 	if (nsph != 1) {
-	  fprintf(output, "  FSAT=(%15.7lE,%15.7lE)\n", tfsas.real(), tfsas.imag());
+	  fprintf(output, "  FSAT=(%15.7lE,%15.7lE)\n", real(tfsas), imag(tfsas));
 	  double csch = 2.0 * vk * sqsfi / gcs;
 	  s0 = tfsas * exri;
-	  double qschu = csch * s0.imag();
-	  double pschu = csch * s0.real();
-	  double s0mag = cs0 * abs(s0);
+	  double qschu = csch * imag(s0);
+	  double pschu = csch * real(s0);
+	  double s0mag = cs0 * cabs(s0);
 	  fprintf(
 		  output,
 		  "  QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n",
@@ -491,13 +496,13 @@ void sphere(string config_file, string data_file, string output_path) {
 		  fprintf(output, "     SPHERE %2d\n", ns);
 		  fprintf(
 			  output, "  SAS(1,1)=%15.7lE%15.7lE, SAS(2,1)=%15.7lE%15.7lE\n",
-			  c1->sas[ns226][0][0].real(), c1->sas[ns226][0][0].imag(),
-			  c1->sas[ns226][1][0].real(), c1->sas[ns226][1][0].imag()
+			  real(c1->sas[ns226][0][0]), imag(c1->sas[ns226][0][0]),
+			  real(c1->sas[ns226][1][0]), imag(c1->sas[ns226][1][0])
 			  );
 		  fprintf(
 			  output, "  SAS(1,2)=%15.7lE%15.7lE, SAS(2,2)=%15.7lE%15.7lE\n",
-			  c1->sas[ns226][0][1].real(), c1->sas[ns226][0][1].imag(),
-			  c1->sas[ns226][1][1].real(), c1->sas[ns226][1][1].imag()
+			  real(c1->sas[ns226][0][1]), imag(c1->sas[ns226][0][1]),
+			  real(c1->sas[ns226][1][1]), imag(c1->sas[ns226][1][1])
 			  );
 		  if (jths == 1 && jphs == 1)
 		    fprintf(
@@ -523,9 +528,9 @@ void sphere(string config_file, string data_file, string output_path) {
 		    else fprintf(output, "\n");
 		  }
 		  for (int vi = 0; vi < 16; vi++) {
-		    double value = vint[vi].real();
+		    double value = real(vint[vi]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
-		    value = vint[vi].imag();
+		    value = imag(vint[vi]);
 		    tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
 		  }
 		  for (int imul = 0; imul < 4; imul++) {
diff --git a/src/testing/test_TEDF.cpp b/src/testing/test_TEDF.cpp
index 98a681d3895a63659978cd130352083a7028c6e7..b790afd907df1dbb229e0f0ac4b214fd42ea7d5b 100644
--- a/src/testing/test_TEDF.cpp
+++ b/src/testing/test_TEDF.cpp
@@ -1,11 +1,16 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 //! \file test_TEDF.cpp
 
-#include <complex>
 #include <cstdio>
 #include <exception>
 #include <hdf5.h>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_ERRORS_H_
 #include "../include/errors.h"
 #endif
diff --git a/src/testing/test_TTMS.cpp b/src/testing/test_TTMS.cpp
index 7c55d16a7939a67ba211f90644b23ba2d329852e..77b8d7c22b1fdc59a73a7165ae2369c2e3c368ff 100644
--- a/src/testing/test_TTMS.cpp
+++ b/src/testing/test_TTMS.cpp
@@ -1,11 +1,16 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 //! \file test_TTMS.cpp
 
-#include <complex>
 #include <cstdio>
 #include <exception>
 #include <hdf5.h>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_ERRORS_H_
 #include "../include/errors.h"
 #endif
diff --git a/src/trapping/cfrfme.cpp b/src/trapping/cfrfme.cpp
index c4866e1f65073bcc2f61ec54d7a23a125ac315ca..2cd6ab9f33a227aff22d4255d4cdf48d01ccdb08 100644
--- a/src/trapping/cfrfme.cpp
+++ b/src/trapping/cfrfme.cpp
@@ -1,14 +1,19 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file cfrfme.cpp
  *
  * C++ implementation of FRFME functions.
  */
-#include <complex>
 #include <cstdio>
 #include <exception>
 #include <fstream>
 #include <regex>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_PARSERS_H_
 #include "../include/Parsers.h"
 #endif
@@ -47,10 +52,10 @@ void frfme(string data_file, string output_path) {
   Swap2 *tt2 = NULL;
   char namef[7];
   char more;
-  complex<double> **w = NULL;
-  complex<double> *wk = NULL;
-  const complex<double> cc0(0.0, 0.0);
-  const complex<double> uim(0.0, 1.0);
+  dcomplex **w = NULL;
+  dcomplex *wk = NULL;
+  const dcomplex cc0 = 0.0 + 0.0 * I;
+  const dcomplex uim = 0.0 + 1.0 * I;
   int line_count = 0, last_read_line = 0;
   regex re = regex("-?[0-9]+");
   string *file_lines = load_file(data_file, &line_count);
@@ -255,7 +260,7 @@ void frfme(string data_file, string output_path) {
 	double *_xv = tfrfme->get_x();
 	double *_yv = tfrfme->get_y();
 	double *_zv = tfrfme->get_z();
-	complex<double> **_wsum = tfrfme->get_matrix();
+	dcomplex **_wsum = tfrfme->get_matrix();
 	for (int i24 = nxshpo; i24 <= nxs; i24++) {
 	  _xv[i24] = _xv[i24 - 1] + delxyz;
 	  _xv[nxv - i24 - 1] = -_xv[i24];
@@ -307,15 +312,15 @@ void frfme(string data_file, string output_path) {
 	  tt2->set_param("nrvc", 1.0 * nrvc);
 	  tt2->write_binary(temp_name2, "HDF5");
 	  for (int j80 = jlmf; j80 <= jlml; j80++) {
-	    complex<double> *tt1_wk = tt1->get_vector();
+	    dcomplex *tt1_wk = tt1->get_vector();
 	    int wk_index = 0;
 	    // w matrix
 	    if (w != NULL) {
 	      for (int wi = nkv - 1; wi > -1; wi--) delete[] w[wi];
 	      delete[] w;
 	    }
-	    w = new complex<double>*[nkv];
-	    for (int wi = 0; wi < nkv; wi++) w[wi] = new complex<double>[nkv]();
+	    w = new dcomplex*[nkv];
+	    for (int wi = 0; wi < nkv; wi++) w[wi] = new dcomplex[nkv]();
 	    for (int jy50 = 0; jy50 < nkv; jy50++) {
 	      for (int jx50 = 0; jx50 < nkv; jx50++) {
 		for (int wi = 0; wi < nlmmt; wi++) wk[wi] = tt1_wk[wk_index++];
@@ -331,19 +336,19 @@ void frfme(string data_file, string output_path) {
 		for (int ix65 = 0; ix65 < nxv; ix65++) {
 		  double x = _xv[ix65];
 		  ixyz++;
-		  complex<double> sumy = cc0;
+		  dcomplex sumy = cc0;
 		  for (int jy60 = 0; jy60 < nkv; jy60++) {
 		    double vky = vkv[jy60];
 		    double vkx = vkv[nkv - 1];
 		    double vkzf = vkzm[0][jy60];
-		    complex<double> phasf = exp(uim * (-vkx * x + vky * y + vkzf * z));
+		    dcomplex phasf = cexp(uim * (-vkx * x + vky * y + vkzf * z));
 		    double vkzl = vkzm[nkv - 1][jy60];
-		    complex<double> phasl = exp(uim * (vkx * x + vky * y + vkzl * z));
-		    complex<double> sumx = 0.5 * (w[0][jy60] * phasf + w[nkv - 1][jy60] * phasl);
+		    dcomplex phasl = cexp(uim * (vkx * x + vky * y + vkzl * z));
+		    dcomplex sumx = 0.5 * (w[0][jy60] * phasf + w[nkv - 1][jy60] * phasl);
 		    for (int jx55 = 2; jx55 <= nks; jx55++) {
 		      vkx = vkv[jx55 - 1];
 		      double vkz = vkzm[jx55 - 1][jy60];
-		      complex<double> phas = exp(uim * (vkx * x + vky * y + vkz * z));
+		      dcomplex phas = cexp(uim * (vkx * x + vky * y + vkz * z));
 		      sumx += (w[jx55 - 1][jy60] * phas);
 		    } // jx55 loop
 		    if (jy60 == 0 || jy60 == nkv - 1) sumx *= 0.5;
diff --git a/src/trapping/clffft.cpp b/src/trapping/clffft.cpp
index 7e3619a252ada2d7102a4d88b3b2a2ba97e60f19..a8033d8098c08694464fe1ab1ac206c84fd18f04 100644
--- a/src/trapping/clffft.cpp
+++ b/src/trapping/clffft.cpp
@@ -1,14 +1,19 @@
+/* Distributed under the terms of GPLv3 or later. See COPYING for details. */
+
 /*! \file clffft.cpp
  *
  * \brief C++ implementation of LFFFT functions.
  */
-#include <complex>
 #include <cstdio>
 #include <exception>
 #include <fstream>
 #include <regex>
 #include <string>
 
+#ifndef INCLUDE_TYPES_H_
+#include "../include/types.h"
+#endif
+
 #ifndef INCLUDE_PARSERS_H_
 #include "../include/Parsers.h"
 #endif
@@ -37,18 +42,18 @@ using namespace std;
  *  \param output_path: `string` Directory to write the output files in.
  */
 void lffft(string data_file, string output_path) {
-  const complex<double> uim(0.0, 1.0);
+  const dcomplex uim = 0.0 + 1.0 * I;
   const double sq2i = 1.0 / sqrt(2.0);
-  const complex<double> sq2iti = sq2i * uim;
+  const dcomplex sq2iti = sq2i * uim;
 
   fstream tlfff, tlfft;
   double ****zpv = NULL;
-  complex<double> *ac = NULL, *ws = NULL, *wsl = NULL;
-  complex<double> **am0m = NULL;
-  complex<double> **amd = NULL;
+  dcomplex *ac = NULL, *ws = NULL, *wsl = NULL;
+  dcomplex **am0m = NULL;
+  dcomplex **amd = NULL;
   int **indam = NULL;
-  complex<double> *tmsm = NULL, *tmse = NULL, **tms = NULL;
-  complex<double> **_wsum = NULL;
+  dcomplex *tmsm = NULL, *tmse = NULL, **tms = NULL;
+  dcomplex **_wsum = NULL;
   int jft, jss, jtw;
   int is, le, nvam = 0;
   double vks, exris;
@@ -79,55 +84,55 @@ void lffft(string data_file, string output_path) {
     cil->nlem = le * (le + 2);
     cil->nlemt = cil->nlem + cil->nlem;
     if (is >= 2222) { // label 120
-      tms = new complex<double>*[le];
-      for (int ti = 0; ti < le; ti++) tms[ti] = new complex<double>[3]();
+      tms = new dcomplex*[le];
+      for (int ti = 0; ti < le; ti++) tms[ti] = new dcomplex[3]();
       // QUESTION|WARNING: original code uses LM without defining it. Where does it come from?
       int lm = le;
       for (int i = 0; i < lm; i++) {
 	double vreal, vimag;
 	ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	tms[i][0] = complex<double>(vreal, vimag);
+	tms[i][0] = vreal + vimag * I;
 	ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	tms[i][1] = complex<double>(vreal, vimag);
+	tms[i][1] = vreal + vimag * I;
 	ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	tms[i][2] = complex<double>(vreal, vimag);
+	tms[i][2] = vreal + vimag * I;
       } // i loop
     } else if (is >= 1111) { // label 125
-      tmsm = new complex<double>[le]();
-      tmse = new complex<double>[le]();
+      tmsm = new dcomplex[le]();
+      tmse = new dcomplex[le]();
       for (int i = 0; i < le; i++) {
 	double vreal, vimag;
 	ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	tmsm[i] = complex<double>(vreal, vimag);
+	tmsm[i] = vreal + vimag * I;
 	ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	tmse[i] = complex<double>(vreal, vimag);
+	tmse[i] = vreal + vimag * I;
       } // i loop
     } else if (is >= 0) { // label 135
-      am0m = new complex<double>*[cil->nlemt];
-      for (int ai = 0; ai < cil->nlemt; ai++) am0m[ai] = new complex<double>[cil->nlemt]();
+      am0m = new dcomplex*[cil->nlemt];
+      for (int ai = 0; ai < cil->nlemt; ai++) am0m[ai] = new dcomplex[cil->nlemt]();
       for (int i = 0; i < cil->nlemt; i++) {
 	for (int j = 0; j < cil->nlemt; j++) {
 	  double vreal, vimag;
 	  ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	  ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	  am0m[i][j] = complex<double>(vreal, vimag);
+	  am0m[i][j] = vreal + vimag * I;
 	} // j loop
       } // i loop
     } else if (is < 0) {
       nvam = le * le + (le * (le + 1) * (le * 2 + 1)) / 3;
-      amd = new complex<double>*[nvam];
-      for (int ai = 0; ai < nvam; ai++) amd[ai] = new complex<double>[4]();
+      amd = new dcomplex*[nvam];
+      for (int ai = 0; ai < nvam; ai++) amd[ai] = new dcomplex[4]();
       for (int i = 0; i < nvam; i++) {
 	for (int j = 0; j < 4; j++) {
 	  double vreal, vimag;
 	  ttms.read(reinterpret_cast<char *>(&vreal), sizeof(double));
 	  ttms.read(reinterpret_cast<char *>(&vimag), sizeof(double));
-	  amd[i][j] = complex<double>(vreal, vimag);
+	  amd[i][j] = vreal + vimag * I;
 	} // j loop
       } // i loop
       indam = new int*[le];
@@ -265,8 +270,8 @@ void lffft(string data_file, string output_path) {
 	  // label 160
 	  const int nlmm = lm * (lm + 2);
 	  const int nlmmt = nlmm + nlmm;
-	  ws = new complex<double>[nlmmt]();
-	  if (lm > le) wsl = new complex<double>[nlmmt]();
+	  ws = new dcomplex[nlmmt]();
+	  if (lm > le) wsl = new dcomplex[nlmmt]();
 	  // FORTRAN writes two output formatted files without opening them
 	  // explicitly. It is assumed thay can be opened here.
 	  string out66_name = output_path + "/c_out66.txt";
@@ -282,12 +287,10 @@ void lffft(string data_file, string output_path) {
 		  //binary_input.read(reinterpret_cast<char *>(&vimag), sizeof(double));
 		  int row = i;
 		  int col = (nyv * nxv * iz475) + (nxv * iy475) + ix475;
-		  complex<double> value = _wsum[row][col];
+		  dcomplex value = _wsum[row][col];
 		  if (lm <= le) {
-		    //ws[i] = complex<double>(vreal, vimag);
 		    ws[i] = value;
 		  } else { // label 170
-		    //wsl[i] = complex<double>(vreal, vimag);
 		    wsl[i] = value;
 		    for (int i175 = 0; i175 < cil->nlem; i175++) {
 		      int ie = i175 + cil->nlem;
@@ -301,21 +304,21 @@ void lffft(string data_file, string output_path) {
 		if (is != 2222) {
 		  if (is != 1111) {
 		    if (is > 0) { // Goes to 305
-		      ac = new complex<double>[cil->nlemt]();
+		      ac = new dcomplex[cil->nlemt]();
 		      camp(ac, am0m, ws, cil);
 		      // Goes to 445
 		    } else if (is < 0) { // Goes to 405
-		      ac = new complex<double>[cil->nlemt]();
+		      ac = new dcomplex[cil->nlemt]();
 		      czamp(ac, amd, indam, ws, cil);
 		      // Goes to 445
 		    }
 		  } else {
-		    ac = new complex<double>[cil->nlemt]();
+		    ac = new dcomplex[cil->nlemt]();
 		    samp(ac, tmsm, tmse, ws, cil);
 		    // Goes to 445
 		  }
 		} else {
-		  ac = new complex<double>[cil->nlemt]();
+		  ac = new dcomplex[cil->nlemt]();
 		  sampoa(ac, tms, ws, cil);
 		  // Goes to 445
 		}
diff --git a/test_data/README.md b/test_data/README.md
index b075b9e1ef924bca544715635cc6537cd8112578..4db4e5af7e9ab05240bbd9a95fb0d6f0efb0a80c 100644
--- a/test_data/README.md
+++ b/test_data/README.md
@@ -1,3 +1,5 @@
+Distributed under the terms of *GNU GPL-3.0-or-later*
+
 # Folder instructions
 
 This directory collects the input files to test the code.