diff --git a/.gitignore b/.gitignore
index ecb83700cb4f01a8442484d33b4b02010c8592a6..db0984b6c6b0f612e3c708ac3d67bd154628173a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ build/cluster/*
 build/sphere/*
 build/trapping/*
 doc/build/*
+
diff --git a/src/Makefile b/src/Makefile
index ac867ef74084ce78f2e17cff9b63ca1b60585e48..544534f8a4ef39c6e646749269d7ad3b732cc37c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,8 +1,13 @@
 SUBDIRS := cluster sphere trapping
-BUILDDIR=../build
+SRCDIR=$(PWD)
+BUILDDIR=$(SRCDIR)/../build
+DOCSDIR=$(SRCDIR)/../doc
 
 all: $(SUBDIRS)
 
+docs:
+	cd $(DOCSDIR)/src; doxygen config.dox
+
 $(SUBDIRS):
 	$(MAKE) -C $@
 
@@ -15,5 +20,7 @@ wipe:
 	rm -f $(BUILDDIR)/cluster/*
 	rm -f $(BUILDDIR)/sphere/*
 	rm -f $(BUILDDIR)/trapping/*
+	if [ -d $(DOCSDIR)/build/html ]; then rm -r $(DOCSDIR)/build/html; fi
+	if [ -d $(DOCSDIR)/build/latex ]; then rm -r $(DOCSDIR)/build/latex; fi
 
 .PHONY: all $(SUBDIRS)
diff --git a/src/README.md b/src/README.md
index 29f340e1f259c9566529d369e6e9dc3923058a8d..83c9bcbc7082cbb0bd38dd4c20536ab6b7e5364d 100644
--- a/src/README.md
+++ b/src/README.md
@@ -7,3 +7,27 @@ This directory collects the source code of the original programs and the develop
 The original code is contained in the folders named `cluster`, `sphere` and `trapping`. Each folder contains a `Makefile` to compile either the whole program set or the single programs. A global `Makefile`, which contains instructions to build all the original source code, is available directly in the `src` folder.
 
 In all cases, build commands executed through `make` will output the object files and the linked binaries in the proper folders under the build directory.
+
+## FORTRAN code setup and execution (requires `gfortran` and GNU `make`)
+
+1. cd to the `src` folder
+2. run `make`
+
+   > make
+
+3. cd to the `build/sphere` folder
+4. run `sph` following the instructions given in `build\README.md`
+
+## C++ code setup and execution (requires `g++` and GNU `make`)
+
+1. cd to the `src` folder
+2. run `make np_sphere`
+
+   > make np_sphere
+
+3. cd to the `build/sphere` folder
+4. run `np_sphere`
+
+   > ./np_sphere
+
+5. check the consistency between the text files named `OSPH` and `c_OSPH`
diff --git a/src/include/Commons.h b/src/include/Commons.h
new file mode 100644
index 0000000000000000000000000000000000000000..088dcc74771f967511b579964e8278000db1f3e3
--- /dev/null
+++ b/src/include/Commons.h
@@ -0,0 +1,131 @@
+/*! \file Commons.h
+ *
+ * \brief C++ porting of common data structures.
+ *
+ * Many functions of the original FORTRAN code share complex data blocks in
+ * form of COMMON blocks. This poses the limit of freezing the structure of
+ * the data blocks in the code, therefore implying the necessity to modify
+ * the code to adapt it to the input and to recompile before running. C++,
+ * on the contrary, offers the possibility to represent the necessary data
+ * structures as classes that can dinamically instantiate the shared information
+ * in the most convenient format for the current configuration. This approach
+ * adds an abstraction layer that lifts the need to modify and recompile the
+ * code depending on the input.
+ *
+ */
+
+#ifndef SRC_INCLUDE_COMMONS_
+#define SRC_INCLUDE_COMMONS_
+
+#include <complex>
+
+/*! \brief Representation of the FORTRAN C1 common blocks.
+ *
+ * C1 common blocks are used to store vector field expansions and geometric
+ * properties, such as sphere sizes, positions and cross-sections. These are
+ * used by functions such as `aps`, `diel`, `pwma`, `rabas`, `sscr0`, `sscr2`,
+ * `wmamp`, `wmasp` and `dme`. QUESTION: correct?
+ *
+ * Due to the necessity to share the class contents with many functions that
+ * need to read and update various fields, all shared members of C1 are declared
+ * public (i.e., the class is just a structure with more advanced constructor
+ * and destroyer). Further development may go in the direction of creating
+ * a better encapsulation, either by unpacking the contents (recommended) or
+ * by creating public methods to access protected fields (standard way, but not
+ * recommended for HPC applications).
+ */
+class C1 {
+protected:
+	//! \brief Number of spheres.
+	int nsph;
+	//! \brief Maximum order of field expansion.
+	int lm;
+	//! \brief NLMMT. QUESTION: definition?
+	int nlmmt;
+public:
+	//! \brief QUESTION: definition?
+	std::complex<double> **rmi;
+	//! \brief QUESTION: definition?
+	std::complex<double> **rei;
+	//! \brief QUESTION: definition?
+	std::complex<double> **w;
+	//! \brief QUESTION: definition?
+	std::complex<double> *fsas;
+	//! \brief QUESTION: definition?
+	std::complex<double> **vints;
+	//! \brief QUESTION: definition?
+	double *sscs;
+	//! \brief QUESTION: definition?
+	double *sexs;
+	//! \brief QUESTION: definition?
+	double *sabs;
+	//! \brief QUESTION: definition?
+	double *sqscs;
+	//! \brief QUESTION: definition?
+	double *sqexs;
+	//! \brief QUESTION: definition?
+	double *sqabs;
+	//! \brief QUESTION: definition?
+	double *gcsv;
+	//! \brief Vector of sphere X coordinates.
+	double *rxx;
+	//! \brief Vector of sphere X coordinates.
+	double *ryy;
+	//! \brief Vector of sphere X coordinates.
+	double *rzz;
+	//! \brief Vector of sphere radii.
+	double *ros;
+	//! \brief Matrix of spherical layer break radii. QUESTION: correct?
+	double **rc;
+	//! \brief Vector of spherical component identifiers.
+	int *iog;
+	//! \brief Vector of numbers of spherical layers.
+	int *nshl;
+	//! \brief QUESTION: definition?
+	std::complex<double> ***sas;
+
+	/*! \brief C1 instance constructor.
+	 *
+	 * \param ns: `int` Number of spheres.
+	 * \param l_max: `int` Maximum order of field expansion.
+	 */
+	C1(int ns, int l_max);
+
+	//! \brief C1 instance destroyer.
+	~C1();
+};
+
+/*! \brief Representation of the FORTRAN C2 blocks.
+ *
+ */
+class C2 {
+	//! \brief Number of spheres.
+	int nsph;
+	//! \brief Number of required orders.
+	int nhspo;
+public:
+	//! \brief QUESTION: definition?
+	std::complex<double> *ris;
+	//! \brief QUESTION: definition?
+	std::complex<double> *dlri;
+	//! \brief QUESTION: definition?
+	std::complex<double> *dc0;
+	//! \brief QUESTION: definition?
+	std::complex<double> *vkt;
+	//! Vector of scaled sizes. QUESTION: correct?
+	double *vsz;
+
+	/*! \brief C2 instance constructor.
+	 *
+	 * \param ns: `int` Number of spheres.
+	 * \param nl: `int`
+	 * \param npnt: `int`
+	 * \param npntts: `int`
+	 */
+	C2(int ns, int nl, int npnt, int npntts);
+
+	//! \brief C2 instance destroyer.
+	~C2();
+};
+
+#endif
diff --git a/src/include/Configuration.h b/src/include/Configuration.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdc36184be5f58f321b221b8752113d210583349
--- /dev/null
+++ b/src/include/Configuration.h
@@ -0,0 +1,321 @@
+/*! \file Configuration.h
+ */
+
+#ifndef INCLUDE_CONFIGURATION_H_
+#define INCLUDE_CONFIGURATION_H_
+
+#include <complex>
+#include <exception>
+#include <string>
+
+/**
+ * \brief Exception for open file error handlers.
+ */
+class OpenConfigurationFileException: public std::exception {
+protected:
+	//! \brief Name of the file that was accessed.
+	std::string file_name;
+
+public:
+	/**
+	 * \brief Exception instance constructor.
+	 *
+	 * \param name: `string` Name of the file that was accessed.
+	 */
+	OpenConfigurationFileException(std::string name) { file_name = name; }
+
+	/**
+	 * \brief Exception message.
+	 */
+	virtual const char* what() const throw() {
+		std::string message = "Error opening configuration file: " + file_name;
+		return message.c_str();
+	}
+};
+
+/**
+ * \brief Exception for unrecognized configuration data sets.
+ */
+class UnrecognizedConfigurationException: public std::exception {
+protected:
+	//! Description of the problem.
+	std::string message;
+public:
+	/**
+	 * \brief Exception instance constructor.
+	 *
+	 * \param problem: `string` Description of the problem that occurred.
+	 */
+	UnrecognizedConfigurationException(std::string problem) { message = problem; }
+	/**
+	 * \brief Exception message.
+	 */
+	virtual const char* what() const throw() {
+		return message.c_str();
+	}
+};
+
+/**
+ * \brief A class to represent the configuration of the scattering geometry.
+ *
+ * GeometryConfiguration is a class designed to store the necessary configuration
+ * data to describe the scattering geometry, including the distribution of the
+ * particle components, the orientation of the incident and scattered radiation
+ * fields and their polarization properties.
+ */
+class GeometryConfiguration {
+	//! Temporary work-around to allow sphere() peeking in.
+	friend void sphere();
+protected:
+	//! \brief Number of spherical components.
+	int number_of_spheres;
+	//! \brief Maximum expansion order of angular momentum.
+	int l_max;
+	//! \brief Incident field polarization status (0 - linear, 1 - circular).
+	int in_pol;
+	//! \brief Number of transition points. QUESTION: correct?
+	int npnt;
+	//! \brief Transition smoothness. QUESTION: correct?
+	int npntts;
+	//! \brief Type of meridional plane definition.
+	int meridional_type;
+	//! \brief Transition matrix layer ID. QUESTION: correct?
+	int jwtm;
+	//! \brief Incident field initial azimuth.
+	double in_theta_start;
+	//! \brief Incident field azimuth step.
+	double in_theta_step;
+	//! \brief Incident field final azimuth.
+	double in_theta_end;
+	//! \brief Scattered field initial azimuth.
+	double sc_theta_start;
+	//! \brief Scattered field azimuth step.
+	double sc_theta_step;
+	//! \brief Scattered field final azimuth.
+	double sc_theta_end;
+	//! \brief Incident field initial elevation.
+	double in_phi_start;
+	//! \brief Incident field elevation step.
+	double in_phi_step;
+	//! \brief Incident field final elevation.
+	double in_phi_end;
+	//! \brief Scattered field initial elevation.
+	double sc_phi_start;
+	//! \brief Scattered field elevation step.
+	double sc_phi_step;
+	//! \brief Scattered field final elevation.
+	double sc_phi_end;
+	//! \brief Vector of spherical components X coordinates.
+	double *sph_x;
+	//! \brief Vector of spherical components Y coordinates.
+	double *sph_y;
+	//! \brief Vector of spherical components Z coordinates.
+	double *sph_z;
+
+public:
+	/*! \brief Build a scattering geometry configuration structure.
+	 *
+	 * \param nsph: `int` Number of spheres to be used in calculation.
+	 * \param lm: `int` Maximum field angular momentum expansion order.
+	 * \param in_pol: `int` Incident field polarization status
+	 * \param npnt: `int` Number of transition points. QUESTION: correct?
+	 * \param npntts: `int` Transition smoothness. QUESTION: correct?
+	 * \param meridional_type: `int` Type of meridional plane definition (<0
+	 * for incident angles, 0 if determined by incidence and observation, =1
+	 * accross z-axis for incidence and observation, >1 across z-axis as a
+	 * function of incidence angles for fixed scattering).
+	 * \param x: `double*` Vector of spherical components X coordinates.
+	 * \param y: `double*` Vector of spherical components Y coordinates.
+	 * \param z: `double*` Vector of spherical components Z coordinates.
+	 * \param in_th_start: `double` Incident field starting azimuth angle.
+	 * \param in_th_step: `double` Incident field azimuth angle step.
+	 * \param in_th_end: `double` Incident field final azimuth angle.
+	 * \param sc_th_start: `double` Scattered field starting azimuth angle.
+	 * \param sc_th_step: `double` Scattered field azimuth angle step.
+	 * \param sc_th_end: `double` Scattered field final azimuth angle.
+	 * \param in_ph_start: `double` Incident field starting elevation angle.
+	 * \param in_ph_step: `double` Incident field elevation angle step.
+	 * \param in_ph_end: `double` Incident field final elevation angle.
+	 * \param sc_ph_start: `double` Scattered field starting elevation angle.
+	 * \param sc_ph_step: `double` Scattered field elevation angle step.
+	 * \param sc_ph_end: `double` Scattered field final elevation angle.
+	 * \param jwtm: `int` Transition Matrix layer ID. QUESTION: correct?
+	 */
+	GeometryConfiguration(
+			int nsph, int lm, int in_pol, int npnt, int npntts, int meridional_type,
+			double *x, double *y, double *z,
+			double in_th_start, double in_th_step, double in_th_end,
+			double sc_th_start, double sc_th_step, double sc_th_end,
+			double in_ph_start, double in_ph_step, double in_ph_end,
+			double sc_ph_start, double sc_ph_step, double sc_ph_end,
+			int jwtm
+	);
+
+	/*! \brief Destroy a GeometryConfiguration instance.
+	 */
+	~GeometryConfiguration();
+
+	/*! \brief Build geometry configuration from legacy configuration input file.
+	 *
+	 * To allow for consistency tests and backward compatibility, geometry
+	 * configurations can be built from legacy configuration files. This function
+	 * replicates the approach implemented by the FORTRAN SPH and CLU codes, but
+	 * using a C++ oriented work-flow.
+	 *
+	 * \param file_name: `string` Name of the legacy configuration data file.
+	 * \return config: `GeometryConfiguration*` Pointer to object containing the
+	 * configuration data.
+	 */
+	static GeometryConfiguration *from_legacy(std::string file_name);
+};
+
+/**
+ * \brief A class to represent scatterer configuration objects.
+ *
+ * ScattererConfiguration is a class designed to store the necessary configuration
+ * data to describe the scatterer properties.
+ */
+class ScattererConfiguration {
+	//! Temporary work-around to allow sphere() peeking in.
+	friend void sphere();
+protected:
+	//! \brief Matrix of dielectric parameters with size [NON_TRANS_LAYERS x N_SPHERES x LAYERS].
+	std::complex<double> ***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].
+	double **rcf;
+	//! \brief Vector of sphere ID numbers, with size [N_SPHERES].
+	int *iog_vec;
+	//! \brief Vector of layer numbers for every sphere, with size [N_SPHERES].
+	int *nshl_vec;
+	//! \brief Vector of scale parameters, with size [N_SCALES].
+	double *scale_vec;
+	//! \brief Name of the reference variable type (one of XIV, WNS, WLS, PUS, EVS).
+	std::string reference_variable_name;
+	//! \brief Number of spherical components.
+	int number_of_spheres;
+	//! \brief Number of scales to use in calculation.
+	int number_of_scales;
+	//! \brief Type of dielectric functions (<0 at XIP, =0 as function of XI, >0 contants).
+	int idfc;
+	//! \brief External medium dielectric constant. QUESTION: correct?
+	double exdc;
+	//! \brief WP. QUESTION: better definition?
+	double wp;
+	//! \brief Peak XI. QUESTION: correct?
+	double xip;
+	//! \brief Flag to control whether to add an external layer.
+	bool use_external_sphere;
+
+public:
+	/*! \brief Build a scatterer configuration structure.
+	 *
+	 * Prepare a default configuration structure by allocating the necessary
+	 * memory structures.
+	 *
+	 * \param nsph: `int` The number of spheres in the simulation.
+	 * \param scale_vector: `double*` The radiation-particle scale vector.
+	 * \param nxi: `int` The number of radiation-particle scalings.
+	 * \param variable_name: `string` The name of the radiation-particle scaling type.
+	 * \param iog_vector: `int*` Array of sphere identification numbers. QUESTION: correct?
+	 * \param ros_vector: `double*` Sphere radius array.
+	 * \param nshl_vector: `int*` Array of layer numbers.
+	 * \param rcf_vector: `double**` Array of fractional break radii. QUESTION: correct?
+	 * \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 has_external: `bool` Flag to set whether to add an external spherical layer.
+	 * \param exdc: `double` EXDC
+	 * \param wp: `double` wp
+	 * \param xip: `double` xip
+	 */
+	ScattererConfiguration(
+			int nsph,
+			double *scale_vector,
+			int nxi,
+			std::string variable_name,
+			int *iog_vector,
+			double *ros_vector,
+			int *nshl_vector,
+			double **rcf_vector,
+			int dielectric_func_type,
+			std::complex<double> ***dc_matrix,
+			bool has_external,
+			double exdc,
+			double wp,
+			double xip
+			);
+
+	/*! \brief Destroy a scatterer configuration instance.
+	 */
+	~ScattererConfiguration();
+
+	/*! \brief Build configuration from binary configuration input file.
+	 *
+	 * The configuration step can save configuration data as a binary file. The original
+	 * FORTRAN code used this possibility to manage communication between the configuring
+	 * code and the calculation program. This possibility is maintained, in case the
+	 * configuration step needs to be separated from the calculation execution. In this
+	 * case, `from_binary()` is the class method that restores a ScattererConfiguration
+	 * object from a previously saved binary file.
+	 *
+	 * \param file_name: `string` Name of the binary configuration data file.
+	 * \param mode: `string` Binary encoding. Can be one of "LEGACY", ... . Optional
+	 * (default is "LEGACY").
+	 * \return config: `ScattererConfiguration*` Pointer to object containing the
+	 * scatterer configuration data.
+	 */
+	static ScattererConfiguration* from_binary(std::string file_name, std::string mode = "LEGACY");
+
+	/*! \brief Build scatterer configuration from legacy configuration input file.
+	 *
+	 * To allow for consistency tests and backward compatibility, ScattererConfiguration
+	 * objects can be built from legacy configuration files. This function replicates
+	 * the approach implemented by the FORTRAN EDFB code, but using a C++ oriented
+	 * work-flow.
+	 *
+	 * \param file_name: `string` Name of the legacy configuration data file.
+	 * \return config: `ScattererConfiguration*` Pointer to object containing the
+	 * scatterer configuration data.
+	 */
+	static ScattererConfiguration* from_dedfb(std::string file_name);
+
+	/*! \brief Print the contents of the configuration object to terminal.
+	 *
+	 * In case of quick debug testing, `ScattererConfiguration.print()` allows printing
+	 * a formatted summary of the configuration data to terminal.
+	 */
+	void print();
+
+	/*! \brief Write the scatterer configuration data to binary output.
+	 *
+	 * The execution work-flow may be split in a configuration step and one or more
+	 * calculation steps. In case the calculation is not being run all-in-one, it can
+	 * be useful to save the configuration data. `ScattererConfiguration.write_binary()`
+	 * performs the operation of saving the configuration in binary format. This function
+	 * can work in legacy mode, to write backward compatible configuration files, as well
+	 * as by wrapping the data into common scientific formats (NB: this last option still
+	 * needs to be implemented).
+	 *
+	 * \param file_name: `string` Name of the file to be written.
+	 * \param mode: `string` Binary encoding. Can be one of "LEGACY", ... . Optional
+	 * (default is "LEGACY").
+	 */
+	void write_binary(std::string file_name, std::string mode = "LEGACY");
+
+	/*! \brief Write the scatterer configuration data to formatted text output.
+	 *
+	 * Writing configuration to formatted text is an optional operation, which may turn
+	 * out to be useful for consistency checks. As a matter of fact, formatted configuration
+	 * output is not read back by the FORTRAN code work-flow and it can be safely omitted,
+	 * unless there is a specific interest in assessing that the legacy code and the
+	 * updated one are doing the same thing.
+	 *
+	 * \param file_name: `string` Name of the file to be written.
+	 */
+	void write_formatted(std::string file_name);
+};
+
+#endif
diff --git a/src/include/List.h b/src/include/List.h
index 047616aaa574c6b9159600b043bdc2c46fc75065..c0f859922f6238be2b193074b1c82b15046e5973 100644
--- a/src/include/List.h
+++ b/src/include/List.h
@@ -1,9 +1,51 @@
 /*! \file List.h
  */
 
-#ifndef LIST_OUT_OF_BOUNDS_EXCEPTION
-#define LIST_OUT_OF_BOUNDS_EXCEPTION 1
-#endif
+#ifndef INCLUDE_LIST_H_
+#define INCLUDE_LIST_H_
+
+#include <exception>
+#include <string>
+
+/**
+ * \brief Exception for out of bounds List requests.
+ */
+class ListOutOfBoundsException: public std::exception {
+protected:
+	//! \brief Minimum index defined in the List.
+	int min_index;
+	//! \brief Maximum index defined in the List.
+	int max_index;
+	//! \brief List index requested by user.
+	int requested_index;
+
+public:
+	/**
+	 * \brief Exception instance constructor.
+	 *
+	 * \param requested: `int` The index that was requested.
+	 * \param min: `int` The minimum index allowed by the list.
+	 * \param max: `int` The maximum index allowed by the list.
+	 */
+	ListOutOfBoundsException(int requested, int min, int max) {
+		min_index = min;
+		max_index = max;
+		requested_index = requested;
+	}
+	/**
+	 * \brief Exception message.
+	 */
+	virtual const char* what() const throw() {
+		std::string message = "Error: requested index ";
+		message += requested_index;
+		message += " is out of range [";
+		message += min_index;
+		message += ", ";
+		message += (max_index - 1);
+		message += "]";
+		return message.c_str();
+	}
+};
 
 /**
  * \brief A class to represent dynamic lists.
@@ -16,7 +58,7 @@
  *
  * For this reason, the best use of List objects is to collect all the
  * desired members and then, once the element number is known, to convert
- * the List to C array, by calling List.to_array(). This function returns
+ * the List to C array, by calling `List.to_array()`. This function returns
  * a contiguous array of type T[SIZE] that can be used for indexed access.
  */
 template<class T> class List {
@@ -33,18 +75,19 @@ template<class T> class List {
  public:
   /*! \brief List constructor.
    *
-   * Use the constructor List<T>([int length]) to create a new list with a given
+   * Use the constructor `List<T>([int length])` to create a new list with a given
    * size. If the required size is not known in advance, it is recommended
    * to create a List with SIZE=1 (this is the default behavior) and then
-   * to append the elements dynamically, using List.append(ELEMENT) (where
+   * to append the elements dynamically, using `List.append(ELEMENT)` (where
    * ELEMENT needs to be a value of type T, corresponding to the class
    * template specialization). Note that, due to the default behavior, the
    * following calls are equivalent and they both produce an integer List
    * with size equal to 1:
    *
-   * a = List<int>(1);
-   *
-   * b = List<int>();
+   * \code{.cpp}
+   * List<int> a = List<int>(1);
+   * List<int> b = List<int>();
+   * \endcode
    *
    * \param length: `int` The size of the list to be constructed [OPTIONAL, default=1].
    */
@@ -52,7 +95,7 @@ template<class T> class List {
     size = length;
     first = new element;
     first->p_prev = NULL;
-    element *current = first;
+    current = first;
     element *p_prev = first;
     for (int i = 1; i < size; i++) {
       current = new element;
@@ -62,6 +105,8 @@ template<class T> class List {
     last = current;
   }
 
+  /*! \brief Destroy a List instance.
+   */
   ~List() {
     current = last;
     element *old;
@@ -72,14 +117,14 @@ template<class T> class List {
     }
   }
   
-  /*! \brief Append an element at the end of the list.
+  /*! \brief Append an element at the end of the List.
    *
    * To dynamically create a list whose size is not known in advance,
    * elements can be appended in an iterative way. Note that element
    * manipulation is much more effective in a C array than in a List
    * object. For this reason, after the List has been created, it is
    * strongly advised to convert it to a C array by calling the function
-   * List.to_array().
+   * `List.to_array()`.
    *
    * \param value: `T` The value of the element to be appended.
    */
@@ -99,22 +144,22 @@ template<class T> class List {
    *
    * \param index: `int` The index of the element to be retrieved. 0 for first.
    * \return value `T` The value of the element at the requested position.
-   * \throws LIST_OUT_OF_BOUNDS_EXCEPTION: Raised if the index is out of bounds.
+   * \throws ListOutOfBoundsException: Raised if the index is out of bounds.
    */
   T get(int index) {
     if (index < 0 || index > size - 1) {
-      throw LIST_OUT_OF_BOUNDS_EXCEPTION;
+      throw ListOutOfBoundsException(index, 0, size - 1);
     }
     current = last;
     for (int i = size - 1; i > index; i--) current = current->p_prev;
     return current->value;
   }
 
-  /*! \brief Get the number of elements in the list.
+  /*! \brief Get the number of elements in the List.
    *
-   * Get the number of elements currently stored in the list.
+   * Get the number of elements currently stored in the List.
    *
-   * \return size `int` The size of the list.
+   * \return size `int` The size of the List.
    */
   int length() {
     return size;
@@ -127,11 +172,11 @@ template<class T> class List {
    *
    * \param index: `int` The index of the element to be set. 0 for first.
    * \param value: `int` The value to store in the pointed element.
-   * \throws LIST_OUT_OF_BOUNDS_EXCEPTION: Raised if the index is out of bounds.
+   * \throws ListOutOfBoundsException: Raised if the index is out of bounds.
    */
   void set(int index, T value) {
     if (index < 0 || index > size - 1) {
-      throw LIST_OUT_OF_BOUNDS_EXCEPTION;
+        throw ListOutOfBoundsException(index, 0, size - 1);
     }
     current = last;
     for (int i = size - 1; i > index; i--) current = current->p_prev;
@@ -145,7 +190,7 @@ template<class T> class List {
    * resulting object is not contiguosly stored in memory. As a result,
    * access to specific elements in the middle of the list is not very
    * effective, because the list needs to be walked every time up to
-   * the desired position. In order to avoid this, List.to_array() makes
+   * the desired position. In order to avoid this, `List.to_array()` makes
    * a conversion from List to C array, returning a contiguous object,
    * where indexed access can be used.
    *
@@ -161,3 +206,5 @@ template<class T> class List {
     return array;
   }
 };
+
+#endif
diff --git a/src/include/Parsers.h b/src/include/Parsers.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4523de6d03c78d8efe2467e5e37b067ddcbe1e3
--- /dev/null
+++ b/src/include/Parsers.h
@@ -0,0 +1,34 @@
+/*! \file Parsers.h
+ */
+
+#ifndef INCLUDE_PARSERS_H_
+#define INCLUDE_PARSERS_H_
+
+#ifndef FILE_NOT_FOUND_ERROR
+//! Error code if a file is not found.
+#define FILE_NOT_FOUND_ERROR 21
+#endif
+
+/*! \brief Load a text file as a sequence of strings in memory.
+ *
+ * The configuration of the field expansion code in FORTRAN uses
+ * shared memory access and file I/O operations managed by different
+ * functions. Although this approach could be theoretically replicated,
+ * it is more convenient to handle input and output to distinct files
+ * using specific functions. load_file() helps in the task of handling
+ * input such as configuration files or text data structures that need
+ * to be loaded entirely. The function performs a line-by line scan of
+ * the input file and returns an array of strings that can be later
+ * parsed and ingested by the concerned code blocks. An optional pointer
+ * to integer allows the function to keep track of the number of file
+ * lines that were read, if needed.
+ *
+ * \param file_name: `string` The path of the file to be read.
+ * \param count: `int*` Pointer to an integer recording the number of
+ * read lines [OPTIONAL, default=NULL].
+ * \return array_lines `string*` An array of strings, one for each input
+ * file line.
+ */
+std::string *load_file(std::string file_name, int *count);
+
+#endif /* INCLUDE_PARSERS_H_ */
diff --git a/src/include/sph_subs.h b/src/include/sph_subs.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c562fb1f586d34b37481c1317daa491f0ed4ca5
--- /dev/null
+++ b/src/include/sph_subs.h
@@ -0,0 +1,1491 @@
+/*! \file sph_subs.h
+ *
+ * \brief C++ porting of SPH functions and subroutines.
+ *
+ * Remember that FORTRAN passes arguments by reference, so, every time we use
+ * a subroutine call, we need to add a referencing layer to the C++ variable.
+ * All the functions defined below need to be properly documented and ported
+ * to C++.
+ *
+ * Currently, only basic documenting information about functions and parameter
+ * types are given, to avoid doxygen warning messages.
+ */
+
+#ifndef INCLUDE_COMMONS_H_
+#include "Commons.h"
+#endif
+
+#ifndef INCLUDE_SPH_SUBS_H_
+#define INCLUDE_SPH_SUBS_H_
+
+#include <complex>
+
+/*! \brief Conjugate of a double precision complex number
+ *
+ * \param z: `std::complex\<double\>` The input complex number.
+ * \return result: `std::complex\<double\>` The conjugate of the input number.
+ */
+std::complex<double> dconjg(std::complex<double> z) {
+	double zreal = z.real();
+	double zimag = z.imag();
+	return std::complex<double>(zreal, -zimag);
+}
+
+/*! \brief C++ porting of CG1
+ *
+ * \param lmpml: `int`
+ * \param mu: `int`
+ * \param l: `int`
+ * \param m: `int`
+ * \return result: `double`
+ */
+double cg1(int lmpml, int mu, int l, int m) {
+	double result = 0.0;
+	double xd, xn;
+	if (lmpml == -1) { // Interpreted as GOTO 30
+		xd = 2.0 * l * (2 * l - 1);
+		if (mu == -1) {
+			xn = 1.0 * (l - 1 - m) * (l - m);
+		} else if (mu == 0) {
+			xn = 2.0 * (l - m) * (l + m);
+		} else if (mu == 1) {
+			xn = 1.0 * (l - 1 + m) * (l + m);
+		} else {
+			throw 111; // Need an exception for unpredicted indices.
+		}
+		result = sqrt(xn / xd);
+	} else if (lmpml == 0) { // Interpreted as GOTO 5
+		bool goto10 = (m != 0) || (mu != 0);
+		if (!goto10) {
+			result = 0.0;
+			return result;
+		}
+		if (mu != 0) {
+			xd = 2.0 * l * (l + 1);
+			if (mu == -1) {
+				xn = 1.0 * (l - m) * (l + m + 1);
+				result = -sqrt(xn / xd);
+			} else if (mu == 1) { // mu > 0
+				xn = 1.0 * (l + m) * (l - m + 1);
+				result = sqrt(xn / xd);
+			} else {
+				throw 111; // Need an exception for unpredicted indices.
+			}
+		} else { // mu = 0
+			xd = 1.0 * l * (l + 1);
+			xn = -1.0 * m;
+			result = xn / sqrt(xd);
+		}
+	} else if (lmpml == 1) { // Interpreted as GOTO 60
+		xd = 2.0 * (l * 2 + 3) * (l + 1);
+		if (mu == -1) {
+			xn = 1.0 * (l + 1 + m) * (l + 2 + m);
+			result = sqrt(xn / xd);
+		} else if (mu == 0) {
+			xn = 2.0 * (l + 1 - m) * (l + 1 + m);
+			result = -sqrt(xn / xd);
+		} else if (mu == 1) {
+			xn = 1.0 * (l + 1 - m) * (l + 2 - m);
+			result = sqrt(xn / xd);
+		} else { // mu was not recognized.
+			throw 111; // Need an exception for unpredicted indices.
+		}
+	} else { // lmpml was not recognized
+		throw 111; // Need an exception for unpredicted indices.
+	}
+	return result;
+}
+
+/*! \brief C++ porting of APS
+ *
+ * \param zpv: `double ****`
+ * \param li: `int`
+ * \param nsph: `int`
+ * \param c1: `C1 *`
+ * \param sqk: `double`
+ * \param gaps: `double *`
+ */
+void aps(double ****zpv, int li, int nsph, C1 *c1, double sqk, double *gaps) {
+	std::complex<double> cc0 = std::complex<double>(0.0, 0.0);
+	std::complex<double> summ, sume, suem, suee, sum;
+	double half_pi = acos(0.0);
+	double cofs = half_pi * 2.0 / sqk;
+	for (int i40 = 1; i40 <= nsph; i40++) {
+		int iogi = c1->iog[i40 - 1];
+		if (iogi >= i40) {
+			sum = cc0;
+			for (int l30 = 1; l30 <= li; l30++) {
+				int ltpo = l30 + l30 + 1;
+				for (int ilmp = 1; ilmp <= 3; ilmp++) {
+					bool goto30 = (l30 == 1 && ilmp == 1) || (l30 == li && ilmp == 3);
+					if (!goto30) {
+						int lmpml = ilmp - 2;
+						int lmp = l30 + lmpml;
+						double cofl = sqrt(1.0 * (ltpo * (lmp + lmp + 1)));
+						summ = zpv[l30 - 1][ilmp - 1][0][0] /
+								(
+										dconjg(c1->rmi[l30 - 1][i40 - 1]) *
+										c1->rmi[lmp - 1][i40 - 1]
+								);
+						sume = zpv[l30 - 1][ilmp - 1][0][1] /
+								(
+										dconjg(c1->rmi[l30 - 1][i40 - 1]) *
+										c1->rei[lmp - 1][i40 - 1]
+								);
+						suem = zpv[l30 - 1][ilmp - 1][1][0] /
+								(
+										dconjg(c1->rei[l30 - 1][i40 - 1]) *
+										c1->rmi[lmp - 1][i40 - 1]
+								);
+						suee = zpv[l30 - 1][ilmp - 1][1][1] /
+								(
+										dconjg(c1->rei[l30 - 1][i40 - 1]) *
+										c1->rei[lmp - 1][i40 - 1]
+								);
+						sum += (cg1(lmpml, 0, l30, -1) * (summ - sume - suem + suee) +
+								cg1(lmpml, 0, l30, 1) * (summ + sume + suem + suee)) * cofl;
+					}
+				}
+			}
+		}
+		gaps[i40 - 1] = sum.real() * cofs;
+		printf("DEBUG: gaps[%d] = %lE\n", i40, gaps[i40 - 1]);
+	}
+}
+
+/*! \brief C++ porting of DIEL
+ *
+ * \param npntmo: `int`
+ * \param ns: `int`
+ * \param i: `int`
+ * \param ic: `int`
+ * \param vk: `double`
+ * \param c1: `C1 *`
+ * \param c2: `C2 *`
+ */
+void diel(int npntmo, int ns, int i, int ic, double vk, C1 *c1, C2 *c2) {
+	double dif = c1->rc[i - 1][ns] - c1->rc[i - 1][ns - 1];
+	double half_step = 0.5 * dif / npntmo;
+	double rr = c1->rc[i - 1][ns - 1];
+	std::complex<double> delta = c2->dc0[ic] - c2->dc0[ic - 1];
+	int kpnt = npntmo + npntmo;
+	c2->ris[kpnt] = c2->dc0[ic];
+	c2->dlri[kpnt] = std::complex<double>(0.0, 0.0);
+	for (int np90 = 0; np90 < kpnt; np90++) {
+		double ff = (rr - c1->rc[i - 1][ns - 1]) / dif;
+		c2->ris[np90] = delta * ff * ff * (-2.0 * ff + 3.0) + c2->dc0[ic - 1];
+		c2->dlri[np90] = 3.0 * delta * ff * (1.0 - ff) / (dif * vk * c2->ris[np90]);
+		rr += half_step;
+	}
+}
+
+/*! \brief C++ porting of ENVJ
+ *
+ * \param n: `int`
+ * \param x: `double`
+ * \return result: `double`
+ */
+double envj(int n, double x) {
+	double result = 0.0;
+	double xn;
+	if (n == 0) {
+		xn = 1.0e-100;
+		result = 0.5 * log10(6.28 * xn) - xn * log10(1.36 * x / xn);
+	} else {
+		result = 0.5 * log10(6.28 * n) - n * log10(1.36 * x / n);
+	}
+	return result;
+}
+
+/*! \brief C++ porting of MSTA1
+ *
+ * \param x: `double`
+ * \param mp: `int`
+ * \return result: `int`
+ */
+int msta1(double x, int mp) {
+	int result = 0;
+	double a0 = x;
+	if (a0 < 0.0) a0 *= -1.0;
+	int n0 = (int)(1.1 * a0) + 1;
+	double f0 = envj(n0, a0) - mp;
+	int n1 = n0 + 5;
+	double f1 = envj(n1, a0) - mp;
+	for (int it10 = 0; it10 < 20; it10++) {
+		int nn = n1 - (int)((n1 - n0) / (1.0 - f0 / f1));
+		double f = envj(nn, a0) - mp;
+		int test_n = nn - n1;
+		if (test_n < 0) test_n *= -1;
+		if (test_n < 1) {
+			return nn;
+		}
+		n0 = n1;
+		f0 = f1;
+		n1 = nn;
+		f1 = f;
+		result = nn;
+	}
+	return result;
+}
+
+/*! \brief C++ porting of MSTA2
+ *
+ * \param x: `double`
+ * \param n: `int`
+ * \param mp: `int`
+ * \return result: `int`
+ */
+int msta2(double x, int n, int mp) {
+	int result = 0;
+	double a0 = x;
+	if (a0 < 0) a0 *= -1.0;
+	double half_mp = 0.5 * mp;
+	double ejn = envj(n, a0);
+	double obj;
+	int n0;
+	if (ejn <= half_mp) {
+		obj = 1.0 * mp;
+		n0 = (int)(1.1 * a0) + 1;
+	} else {
+		obj = half_mp + ejn;
+		n0 = n;
+	}
+	double f0 = envj(n0, a0) - obj;
+	int n1 = n0 + 5;
+	double f1 = envj(n1, a0) - obj;
+	for (int it10 = 0; it10 < 20; it10 ++) {
+		int nn = n1 - (int)((n1 - n0) / (1.0 - f0 / f1));
+		double f = envj(nn, a0) - obj;
+		int test_n = nn - n1;
+		if (test_n < 0) test_n *= -1;
+		if (test_n < 1) return (nn + 10);
+		n0 = n1;
+		f0 = f1;
+		n1 = nn;
+		f1 = f;
+		result = nn + 10;
+	}
+	return result;
+}
+
+/*! \brief C++ porting of CBF
+ *
+ * This is the Complex Bessel Function.
+ *
+ * \param n: `int`
+ * \param z: `complex\<double\>`
+ * \param nm: `int &`
+ * \param csj: Vector of complex.
+ */
+void cbf(int n, std::complex<double> z, int &nm, std::complex<double> csj[]) {
+	/*
+	 * FROM CSPHJY OF LIBRARY specfun
+	 *
+	 * ==========================================================
+	 *   Purpose: Compute spherical Bessel functions j
+	 *   Input :  z --- Complex argument of j
+	 *            n --- Order of j ( n = 0,1,2,... )
+	 *   Output:  csj(n+1) --- j
+	 *            nm --- Highest order computed
+	 *   Routines called:
+	 *            msta1 and msta2 for computing the starting
+	 *            point for backward recurrence
+	 * ==========================================================
+	 */
+	double zz = z.real() * z.real() + z.imag() * z.imag();
+	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] = std::complex<double>(1.0, 0.0);
+		return;
+	}
+	csj[0] = std::sin(z) / z;
+	if (n == 0) {
+		return;
+	}
+	csj[1] = (csj[0] -std::cos(z)) / z;
+	if (n == 1) {
+		return;
+	}
+	std::complex<double> csa = csj[0];
+	std::complex<double> csb = csj[1];
+	int m = msta1(a0, 200);
+	if (m < n) nm = m;
+	else m = msta2(a0, n, 15);
+	std::complex<double> cf0 = 0.0;
+	std::complex<double> cf1 = 1.0e-100;
+	std::complex<double> 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 = sqrt(csa.real() * csa.real() + csa.imag() * csa.imag());
+	double abs_csb = sqrt(csb.real() * csb.real() + csb.imag() * csb.imag());
+	if (abs_csa > abs_csb) cs = csa / cf;
+	else cs = csb / cf0;
+	for (int k = 0; k <= nm; k++) {
+		csj[k] = cs * csj[k];
+	}
+}
+
+/*! \brief C++ porting of MMULC
+ *
+ * \param vint: Vector of complex.
+ * \param cmullr: `double **`
+ * \param cmul: `double **`
+ */
+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();
+    cmullr[0][0] = sm2;
+    cmullr[0][1] = sm3;
+    cmullr[0][2] = -s23;
+    cmullr[0][3] = -d32;
+    cmullr[1][0] = sm4;
+    cmullr[1][1] = sm1;
+    cmullr[1][2] = -s41;
+    cmullr[1][3] = -d14;
+    cmullr[2][0] = -s24 * 2.0;
+    cmullr[2][1] = -s31 * 2.0;
+    cmullr[2][2] = s21 + s34;
+    cmullr[2][3] = d34 + d12;
+    cmullr[3][0] = -d24 * 2.0;
+    cmullr[3][1] = -d31 * 2.0;
+    cmullr[3][2] = d34 - d12;
+    cmullr[3][3] = s21 - s34;
+    cmul[0][0] = (sm2 + sm3 + sm4 + sm1) * 0.5;
+    cmul[0][1] = (sm2 - sm3 + sm4 - sm1) * 0.5;
+    cmul[0][2] = -s23 - s41;
+    cmul[0][3] = -d32 - d14;
+    cmul[1][0] = (sm2 + sm3 - sm4 - sm1) * 0.5;
+    cmul[1][1] = (sm2 - sm3 - sm4 + sm1) * 0.5;
+    cmul[1][2] = -s23 + s41;
+    cmul[1][3] = -d32 + d14;
+    cmul[2][0] = -s24 - s31;
+    cmul[2][1] = -s24 + s31;
+    cmul[2][2] = s21 + s34;
+    cmul[2][3] = d34 + d12;
+    cmul[3][0] = -d24 - d31;
+    cmul[3][1] = -d24 + d31;
+    cmul[3][2] = d34 - d12;
+    cmul[3][3] = s21 - s34;
+}
+
+/*! \brief C++ porting of ORUNVE
+ *
+ * \param u1: `double *`
+ * \param u2: `double *`
+ * \param u3: `double *`
+ * \param iorth: `int`
+ * \param torth: `double`
+ */
+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;
+		if (abs_cp < 0.0) abs_cp *= -1.0;
+		if (iorth == 0 || abs_cp >= torth) {
+			double fn = 1.0 / sqrt(1.0 - cp * cp);
+			u3[0] = (u1[1] * u2[2] - u1[2] * u2[1]) * fn;
+			u3[1] = (u1[2] * u2[0] - u1[0] * u2[2]) * fn;
+			u3[2] = (u1[0] * u2[1] - u1[1] * u2[0]) * fn;
+			return;
+		}
+	}
+	u3[0] = u1[1] * u2[2] - u1[2] * u2[1];
+    u3[1] = u1[2] * u2[0] - u1[0] * u2[2];
+    u3[2] = u1[0] * u2[1] - u1[1] * u2[0];
+}
+
+/*! \brief C++ porting of PWMA
+ *
+ * \param up: `double *`
+ * \param un: `double *`
+ * \param ylm: Vector of complex
+ * \param inpol: `int`
+ * \param lw: `int`
+ * \param isq: `int`
+ * \param c1: `C1 *`
+ */
+void pwma(
+		double *up, double *un, std::complex<double> *ylm, int inpol, int lw,
+		int isq, C1 *c1
+) {
+	//std::complex<double> cp1, cm1, cc1, cp2, c2, cc2, uim, cl;
+	double four_pi = 8.0 * acos(0.0);
+	int is = isq;
+	if (isq == -1) is = 0;
+	int ispo = is + 1;
+	int ispt = is + 2;
+	int nlwm = lw * (lw + 2);
+	int nlwmt = nlwm + nlwm;
+	double sqrtwi = 1.0 / sqrt(2.0);
+	std::complex<double> uim(0.0, 1.0);
+	std::complex<double> cm1 = 0.5 * std::complex<double>(up[0], up[1]);
+	std::complex<double> cp1 = 0.5 * std::complex<double>(up[0], -up[1]);
+	double cz1 = up[2];
+	std::complex<double> cm2 = 0.5 * std::complex<double>(un[0], un[1]);
+	std::complex<double> cp2 = 0.5 * std::complex<double>(un[0], -un[1]);
+	double cz2 = un[2];
+	//printf("DEBUG: in PWMA YLM(2) = (%lE, %lE)\n", ylm[1].real(), ylm[1].imag());
+	for (int l20 = 1; l20 <= lw; l20++) {
+		//if (ispo == 1) printf("DEBUG: l20 = %d\n", l20);
+		int lf = l20 + 1;
+		int lftl = lf * l20;
+		double x = 1.0 * lftl;
+		std::complex<double> cl = std::complex<double>(four_pi / sqrt(x), 0.0);
+		for (int powi = 1; powi <= l20; powi++) cl *= uim;
+		int mv = l20 + lf;
+		int m = -lf;
+		for (int mf20 = 1; mf20 <= mv; mf20++) {
+			m += 1;
+			int k = lftl + m;
+			x = 1.0 * (lftl - m * (m + 1));
+			double cp = sqrt(x);
+			x = 1.0 * (lftl - m * (m - 1));
+			double cm = sqrt(x);
+			double cz = 1.0 * m;
+			c1->w[k - 1][ispo - 1] = dconjg(
+					cp1 * cp * ylm[k + 1] +
+					cm1 * cm * ylm[k - 1] +
+					cz1 * cz * ylm[k]
+			) * cl;
+			//if (ispo == 1) printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", k, ispo, c1->w[k - 1][ispo - 1].real(), c1->w[k - 1][ispo - 1].imag());
+			c1->w[k - 1][ispt - 1] = dconjg(
+					cp2 * cp * ylm[k + 1] +
+					cm2 * cm * ylm[k - 1] +
+					cz2 * cz * ylm[k]
+			) * cl;
+			//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", k, ispt, c1->w[k - 1][ispt - 1].real(), c1->w[k - 1][ispt - 1].imag());
+		}
+	}
+	for (int k30 = 1; k30 <= nlwm; k30++) {
+		int i = k30 + nlwm;
+		c1->w[i - 1][ispo - 1] = uim * c1->w[k30 - 1][ispt - 1];
+		//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", i, ispo, c1->w[i - 1][ispo - 1].real(), c1->w[i - 1][ispo - 1].imag());
+		c1->w[i - 1][ispt - 1] = -uim * c1->w[k30 - 1][ispo - 1];
+		//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", i, ispt, c1->w[i - 1][ispt - 1].real(), c1->w[i - 1][ispt - 1].imag());
+	}
+	if (inpol != 0) {
+		for (int k40 = 1; k40 <= nlwm; k40++) {
+			int i = k40 + nlwm;
+			std::complex<double> cc1 = sqrtwi * (c1->w[k40 - 1][ispo - 1] + uim * c1->w[k40 - 1][ispt - 1]);
+			std::complex<double> cc2 = sqrtwi * (c1->w[k40 - 1][ispo - 1] - uim * c1->w[k40 - 1][ispt - 1]);
+			c1->w[k40 - 1][ispo - 1] = cc2;
+			//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", k40, ispo, c1->w[k40 - 1][ispo - 1].real(), c1->w[k40 - 1][ispo - 1].imag());
+			c1->w[i - 1][ispo - 1] = -cc2;
+			//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", i, ispo, c1->w[i - 1][ispo - 1].real(), c1->w[i - 1][ispo - 1].imag());
+			c1->w[k40 - 1][ispt - 1] = cc1;
+			//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", k40, ispt, c1->w[k40 - 1][ispt - 1].real(), c1->w[k40 - 1][ispt - 1].imag());
+			c1->w[i - 1][ispt - 1] = cc1;
+			//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", i, ispt, c1->w[i - 1][ispt - 1].real(), c1->w[i - 1][ispt - 1].imag());
+		}
+	} else {
+		if (isq == 0) {
+			return;
+		}
+	}
+	if (isq != 0) {
+		for (int i50 = 1; i50 <= 2; i50++) {
+			int ipt = i50 + 2;
+			int ipis = i50 + is;
+			for (int k50 = 1; k50 <= nlwmt; k50++) {
+				c1->w[k50 - 1][ipt - 1] = dconjg(c1->w[k50 - 1][ipis - 1]);
+				//printf("DEBUG: W( %d , %d) = (%lE,%lE)\n", k50, ipt, c1->w[k50 - 1][ipt - 1].real(), c1->w[k50 - 1][ipt - 1].imag());
+			}
+		}
+	}
+	//printf("DEBUG: out PWMA W(1,1) = (%lE, %lE)\n", c1->w[0][0].real(), c1->w[0][0].imag());
+}
+
+/*! \brief C++ porting of RABAS
+ *
+ * \param inpol: `int`
+ * \param li: `int`
+ * \param nsph: `int`
+ * \param c1: `C1 *`
+ * \param tqse: Matrix of complex.
+ * \param tqspe: Matrix of complex.
+ * \param tqss: Matrix of complex.
+ * \param tqsps: Matrix of complex.
+ */
+void rabas(
+			int inpol, int li, int nsph, C1 *c1, double **tqse, std::complex<double> **tqspe,
+			double **tqss, std::complex<double> **tqsps
+) {
+	std::complex<double> cc0 = std::complex<double>(0.0, 0.0);
+	std::complex<double> uim = std::complex<double>(0.0, 1.0);
+	double two_pi = 4.0 * acos(0.0);
+	for (int i80 = 1; i80 <= nsph; i80++) {
+		if(c1->iog[i80 - 1] >= i80) {
+			tqse[0][i80 - 1] = 0.0;
+			tqse[1][i80 - 1] = 0.0;
+			tqspe[0][i80 - 1] = cc0;
+			tqspe[1][i80 - 1] = cc0;
+			tqss[0][i80 - 1] = 0.0;
+			tqss[1][i80 - 1] = 0.0;
+			tqsps[0][i80 - 1] = cc0;
+			tqsps[1][i80 - 1] = cc0;
+			for (int l70 = 1; l70 <= li; l70++) {
+				double fl = 1.0 * l70 + l70 + 1;
+				std::complex<double> rm = 1.0 / c1->rmi[l70 - 1][i80 - 1];
+				double rmm = (rm * dconjg(rm)).real();
+				std::complex<double> re = 1.0 / c1->rei[l70 - 1][i80 - 1];
+				double rem = (re * dconjg(re)).real();
+				if (inpol == 0) {
+					std::complex<double> pce = ((rm + re) * uim) * fl;
+					std::complex<double> pcs = ((rmm + rem) * fl) * uim;
+					tqspe[0][i80 - 1] -= pce;
+					tqspe[1][i80 - 1] += pce;
+					tqsps[0][i80 - 1] -= pcs;
+					tqsps[1][i80 - 1] += pcs;
+				} else {
+					double ce = (rm + re).real() * fl;
+					double cs = (rmm + rem) * fl;
+					tqse[0][i80 - 1] -= ce;
+					tqse[1][i80 - 1] += ce;
+					tqss[0][i80 - 1] -= cs;
+					tqss[1][i80 - 1] += cs;
+				}
+			}
+			if (inpol == 0) {
+				tqspe[0][i80 - 1] *= two_pi;
+				tqspe[1][i80 - 1] *= two_pi;
+				tqsps[0][i80 - 1] *= two_pi;
+				tqsps[1][i80 - 1] *= two_pi;
+				printf("DEBUG: TQSPE(1, %d ) = ( %lE, %lE)\n", i80, tqspe[0][i80 - 1].real(), tqspe[0][i80 - 1].imag());
+				printf("DEBUG: TQSPE(2, %d ) = ( %lE, %lE)\n", i80, tqspe[1][i80 - 1].real(), tqspe[1][i80 - 1].imag());
+				printf("DEBUG: TQSPS(1, %d ) = ( %lE, %lE)\n", i80, tqsps[0][i80 - 1].real(), tqsps[0][i80 - 1].imag());
+				printf("DEBUG: TQSPS(2, %d ) = ( %lE, %lE)\n", i80, tqsps[1][i80 - 1].real(), tqsps[1][i80 - 1].imag());
+			} else {
+				tqse[0][i80 - 1] *= two_pi;
+				tqse[1][i80 - 1] *= two_pi;
+				tqss[0][i80 - 1] *= two_pi;
+				tqss[1][i80 - 1] *= two_pi;
+				printf("DEBUG: TQSE(1, %d ) = %lE)\n", i80, tqse[0][i80 - 1]);
+				printf("DEBUG: TQSE(2, %d ) = %lE)\n", i80, tqse[1][i80 - 1]);
+				printf("DEBUG: TQSS(1, %d ) = %lE)\n", i80, tqss[0][i80 - 1]);
+				printf("DEBUG: TQSS(2, %d ) = %lE)\n", i80, tqss[1][i80 - 1]);
+			}
+		}
+	}
+}
+
+/*! \brief C++ porting of RBF
+ *
+ * This is the Real Bessel Function.
+ *
+ * \param n: `int`
+ * \param x: `double`
+ * \param nm: `int &`
+ * \param sj: `double[]`
+ */
+void rbf(int n, double x, int &nm, double sj[]) {
+	/*
+	 * FROM SPHJ OF LIBRARY specfun
+	 *
+	 * ==========================================================
+	 *   Purpose: Compute spherical Bessel functions j
+	 *   Input :  x --- Argument of j
+	 *            n --- Order of j ( n = 0,1,2,... )
+	 *   Output:  sj(n+1) --- j
+	 *            nm --- Highest order computed
+	 *   Routines called:
+	 *            msta1 and msta2 for computing the starting
+	 *            point for backward recurrence
+	 * ==========================================================
+	 */
+	double a0 = x;
+	if (a0 < 0.0) a0 *= -1.0;
+	nm = n;
+	if (a0 < 1.0e-60) {
+		for (int k = 2; k <= n + 1; k++)
+			sj[k - 1] = 0.0;
+		sj[0] = 1.0;
+		return;
+	}
+	sj[0] = sin(x) / x;
+	if (n == 0) {
+		return;
+	}
+	sj[1] = (sj[0] - cos(x)) / x;
+	if (n == 1) {
+		return;
+	}
+	double sa = sj[0];
+	double sb = sj[1];
+	int m = msta1(a0, 200);
+	if (m < n) nm = m;
+	else m = msta2(a0, n, 15);
+	double f0 = 0.0;
+	double f1 = 1.0e-100;
+	double f;
+	for (int k = m; k >= 0; k--) {
+		f = (2.0 * k +3.0) * f1 / x - f0;
+		if (k <= nm) sj[k] = f;
+		f0 = f1;
+		f1 = f;
+	}
+	double cs;
+	double abs_sa = sa;
+	if (abs_sa < 0.0) abs_sa *= -1.0;
+	double abs_sb = sb;
+	if (abs_sb < 0.0) abs_sb *= -1.0;
+	if (abs_sa > abs_sb) cs = sa / f;
+	else cs = sb / f0;
+	for (int k = 0; k <= nm; k++) {
+		sj[k] = cs * sj[k];
+	}
+}
+
+/*! \brief C++ porting of RKC
+ *
+ * \param npntmo: `int`
+ * \param step: `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\> &`
+ */
+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
+) {
+	std::complex<double> cy1, cdy1, c11, cy23, yc2, c12, c13;
+	std::complex<double> cy4, yy, c14, c21, c22, c23, c24;
+	double half_step = 0.5 * step;
+	double cl = 1.0 * lpo * (lpo - 1);
+	for (int ipnt60 = 1; ipnt60 <= npntmo; ipnt60++) {
+		cy1 = cl / (x * x) - dcc;
+		cdy1 = -2.0 / x;
+		c11 = (cy1 * y1 + cdy1 * dy1) * step;
+		double xh = x + half_step;
+		cy23 = cl / (xh * xh) - dcc;
+		double cdy23 = -2.0 / xh;
+		yc2 = y1 + dy1 * half_step;
+		c12 = (cy23 * yc2 + cdy23 * (dy1 + 0.5 * c11)) * step;
+		c13 = (cy23 * (yc2 + 0.25 * c11 * step) + cdy23 * (dy1 + 0.5 * c12)) * step;
+		double xn = x + step;
+		cy4 = cl / (xn * xn) - dcc;
+		double cdy4 = -2.0 / xn;
+		yy = y1 + dy1 * step;
+		c14 = (cy4 * (yy + 0.5 * c12 * step) + cdy4 * (dy1 + c13)) * step;
+		y1 = yy + (c11 + c12 + c13) * step / 6.0;
+		dy1 += (0.5 * c11 + c12 + c13 + 0.5 * c14) / 3.0;
+		c21 = (cy1 * y2 + cdy1 * dy2) * step;
+		yc2 = y2 + dy2 * half_step;
+		c22 = (cy23 * yc2 + cdy23 * (dy2 + 0.5 * c21)) * step;
+		c23= (cy23 * (yc2 + 0.25 * c21 * step) + cdy23 * (dy2 + 0.5 * c22)) * step;
+		yy = y2 + dy2 * step;
+		c24 = (cy4 * (yc2 + 0.5 * c22 * step) + cdy4 * (dy2 + c23)) * step;
+		y2 = yy + (c21 + c22 + c23) * step / 6.0;
+		dy2 += (0.5 * c21 + c22 + c23 + 0.5 * c24) / 3.0;
+		x = xn;
+	}
+}
+
+/*! \brief C++ porting of RKT
+ *
+ * \param npntmo: `int`
+ * \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 c2: `C2 *`
+ */
+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
+) {
+	std::complex<double> cy1, cdy1, c11, cy23, cdy23, yc2, c12, c13;
+	std::complex<double> cy4, cdy4, yy, c14, c21, c22, c23, c24;
+	double half_step = 0.5 * step;
+	double cl = 1.0 * lpo * (lpo - 1);
+	for (int ipnt60 = 1; ipnt60 <= npntmo; ipnt60++) {
+		int jpnt = ipnt60 + ipnt60 - 1;
+		cy1 = cl / (x * x) - c2->ris[jpnt - 1];
+		cdy1 = -2.0 / x;
+		c11 = (cy1 * y1 + cdy1 * dy1) * step;
+		double xh = x + half_step;
+		int jpntpo = jpnt + 1;
+		cy23 = cl / (xh * xh) - c2->ris[jpntpo - 1];
+		cdy23 = -2.0 / xh;
+		yc2 = y1 + dy1 * half_step;
+		c12 = (cy23 * yc2 + cdy23 * (dy1 + 0.5 * c11)) * step;
+		c13= (cy23 * (yc2 + 0.25 * c11 *step) + cdy23 * (dy1 + 0.5 * c12)) * step;
+		double xn = x + step;
+		int jpntpt = jpnt + 2;
+		cy4 = cl / (xn * xn) - c2->ris[jpntpt - 1];
+		cdy4 = -2.0 / xn;
+		yy = y1 + dy1 * step;
+		c14 = (cy4 * (yy + 0.5 * c12 * step) + cdy4 * (dy1 + c13)) * step;
+		y1= yy + (c11 + c12 + c13) * step / 6.0;
+		dy1 += (0.5 * c11 + c12 + c13 + 0.5 * c14) /3.0;
+		cy1 -= cdy1 * c2->dlri[jpnt - 1];
+		cdy1 += 2.0 * c2->dlri[jpnt - 1];
+		c21 = (cy1 * y2 + cdy1 * dy2) * step;
+		cy23 -= cdy23 * c2->dlri[jpntpo - 1];
+		cdy23 += 2.0 * c2->dlri[jpntpo - 1];
+		yc2 = y2 + dy2 * half_step;
+		c22 = (cy23 * yc2 + cdy23 * (dy2 + 0.5 * c21)) * step;
+		c23 = (cy23 * (yc2 + 0.25 * c21 * step) + cdy23 * (dy2 + 0.5 * c22)) * step;
+		cy4 -= cdy4 * c2->dlri[jpntpt - 1];
+		cdy4 += 2.0 * c2->dlri[jpntpt - 1];
+		yy = y2 + dy2 * step;
+		c24 = (cy4 * (yc2 + 0.5 * c22 * step) + cdy4 * (dy2 + c23)) * step;
+		y2 = yy + (c21 + c22 + c23) * step / 6.0;
+		dy2 += (0.5 * c21 + c22 + c23 + 0.5 * c24) / 3.0;
+		x = xn;
+	}
+}
+
+/*! \brief C++ porting of RNF
+ *
+ * This is a real spherical Bessel function.
+ *
+ * \param n: `int`
+ * \param x: `double`
+ * \param nm: `int &`
+ * \param sy: `double[]`
+ */
+void rnf(int n, double x, int &nm, double sy[]) {
+	/*
+	 * FROM SPHJY OF LIBRARY specfun
+	 *
+	 * ==========================================================
+	 *   Purpose: Compute spherical Bessel functions y
+	 *   Input :  x --- Argument of y ( x > 0 )
+	 *            n --- Order of y ( n = 0,1,2,... )
+	 *   Output:  sy(n+1) --- y
+	 *            nm --- Highest order computed
+	 * ==========================================================
+	 */
+	if (x < 1.0e-60) {
+		for (int k = 0; k <= n; k++)
+			sy[k] = -1.0e300;
+		return;
+	}
+	sy[0] = -1.0 * cos(x) / x;
+	if (n == 0) {
+		return;
+	}
+	sy[1] = (sy[0] - sin(x)) / x;
+	if (n == 1) {
+		return;
+	}
+	double f0 = sy[0];
+	double f1 = sy[1];
+	double f;
+	for (int k = 2; k <= n; k++) {
+		f = (2.0 * k - 1.0) * f1 / x - f0;
+		sy[k] = f;
+		double abs_f = f;
+		if (abs_f < 0.0) abs_f *= -1.0;
+		if (abs_f >= 1.0e300) {
+			nm = k;
+			break;
+		}
+		f0 = f1;
+		f1 = f;
+		nm = k;
+	}
+	return;
+}
+
+/*! \brief C++ porting of SSCR0
+ *
+ * \param tfsas: `complex<double> &`
+ * \param nsph: `int`
+ * \param lm: `int`
+ * \param vk: `double`
+ * \param exri: `double`
+ * \param c1: `C1 *`
+ */
+void sscr0(std::complex<double> &tfsas, int nsph, int lm, double vk, double exri, C1 *c1) {
+	std::complex<double> sum21, rm, re, csam;
+	std::complex<double> cc0 = std::complex<double>(0.0, 0.0);
+	double exdc = exri * exri;
+	double ccs = 4.0 * acos(0.0) / (vk * vk);
+	double cccs = ccs / exdc;
+	csam = -(ccs / (exri * vk)) * std::complex<double>(0.0, 0.5);
+	tfsas = cc0;
+	for (int i12 = 1; i12 <= nsph; i12++) {
+		int iogi = c1->iog[i12 - 1];
+		if (iogi >= i12) {
+			double sums = 0.0;
+			std::complex<double> sum21 = cc0;
+			for (int l10 = 1; l10 <= lm; l10++) {
+				double fl = 1.0 + l10 + l10;
+				rm = 1.0 / c1->rmi[l10 - 1][i12 - 1];
+				re = 1.0 / c1->rei[l10 - 1][i12 - 1];
+				std::complex<double> rm_cnjg = std::complex<double>(rm.real(), -rm.imag());
+				std::complex<double> re_cnjg = std::complex<double>(re.real(), -re.imag());
+				sums += (rm_cnjg * rm + re_cnjg * re).real() * fl;
+				sum21 += (rm + re) * fl;
+			}
+			sum21 *= -1.0;
+			double scasec = cccs * sums;
+			double extsec = -cccs * sum21.real();
+			double abssec = extsec - scasec;
+			c1->sscs[i12 - 1] = scasec;
+			c1->sexs[i12 - 1] = extsec;
+			c1->sabs[i12 - 1] = abssec;
+			double gcss = c1-> gcsv[i12 - 1];
+			c1->sqscs[i12 - 1] = scasec / gcss;
+			c1->sqexs[i12 - 1] = extsec / gcss;
+			c1->sqabs[i12 - 1] = abssec / gcss;
+			c1->fsas[i12 - 1] = sum21 * csam;
+			//printf("DEBUG: FSAS( %d ) = (%lE,%lE)\n", i12, c1->fsas[i12 - 1].real(), c1->fsas[i12 - 1].imag());
+		}
+		tfsas += c1->fsas[iogi - 1];
+	}
+}
+
+/*! \brief C++ porting of SSCR2
+ *
+ * \param nsph: `int`
+ * \param lm: `int`
+ * \param vk: `double`
+ * \param exri: `double`
+ * \param c1: `C1 *`
+ */
+void sscr2(int nsph, int lm, double vk, double exri, C1 *c1) {
+	std::complex<double> s11, s21, s12, s22, rm, re, csam, cc;
+	std::complex<double> cc0 = std::complex<double>(0.0, 0.0);
+	double ccs = 1.0 / (vk * vk);
+	csam = -(ccs / (exri * vk)) * std::complex<double>(0.0, 0.5);
+	double pigfsq = 64.0 * acos(0.0) * acos(0.0);
+	double cfsq = 4.0 / (pigfsq * ccs * ccs);
+	int nlmm = lm * (lm + 2);
+	//printf("DEBUG: in SSCR2 W(1,1) = (%lE,%lE)\n", c1->w[0][0].real(), c1->w[0][0].imag());
+	for (int i14 = 1; i14 <= nsph; i14++) {
+		int iogi = c1->iog[i14 - 1];
+		if (iogi >= i14) {
+			int k = 0;
+			s11 = cc0;
+			s21 = cc0;
+			s12 = cc0;
+			s22 = cc0;
+			for (int l10 = 1; l10 <= lm; l10++) {
+				rm = 1.0 / c1->rmi[l10 - 1][i14 - 1];
+				re = 1.0 / c1->rei[l10 - 1][i14 - 1];
+				//printf("DEBUG: rm = (%lE,%lE)\n", rm.real(), rm.imag());
+				//printf("DEBUG: re = (%lE,%lE)\n", re.real(), re.imag());
+				int ltpo = l10 + l10 + 1;
+				for (int im10 = 1; im10 <= ltpo; im10++) {
+					k += 1;
+					int ke = k + nlmm;
+					//printf("DEBUG: W( %d, 3) = (%lE,%lE)\n", k, c1->w[k - 1][2].real(), c1->w[k - 1][2].imag());
+					//printf("DEBUG: W( %d, 1) = (%lE,%lE)\n", k, c1->w[k - 1][0].real(), c1->w[k - 1][0].imag());
+					//printf("DEBUG: W( %d, 3) = (%lE,%lE)\n", ke, c1->w[ke - 1][2].real(), c1->w[ke - 1][2].imag());
+					//printf("DEBUG: W( %d, 1) = (%lE,%lE)\n", ke, c1->w[ke - 1][0].real(), c1->w[ke - 1][0].imag());
+					s11 = s11 - c1->w[k - 1][2] * c1->w[k - 1][0] * rm - c1->w[ke - 1][2] * c1->w[ke - 1][0] * re;
+					//printf("DEBUG: W( %d, 4) = (%lE,%lE)\n", k, c1->w[k - 1][3].real(), c1->w[k - 1][3].imag());
+					//printf("DEBUG: W( %d, 4) = (%lE,%lE)\n", ke, c1->w[ke - 1][3].real(), c1->w[ke - 1][3].imag());
+					s21 = s21 - c1->w[k - 1][3] * c1->w[k - 1][0] * rm - c1->w[ke - 1][3] * c1->w[ke - 1][0] * re;
+					//printf("DEBUG: W( %d, 2) = (%lE,%lE)\n", k, c1->w[k - 1][1].real(), c1->w[k - 1][1].imag());
+					//printf("DEBUG: W( %d, 2) = (%lE,%lE)\n", ke, c1->w[ke - 1][1].real(), c1->w[ke - 1][1].imag());
+					s12 = s12 - c1->w[k - 1][2] * c1->w[k - 1][1] * rm - c1->w[ke - 1][2] * c1->w[ke - 1][1] * re;
+					s22 = s22 - c1->w[k - 1][3] * c1->w[k - 1][1] * rm - c1->w[ke - 1][3] * c1->w[ke - 1][1] * re;
+				}
+			}
+			c1->sas[i14 - 1][0][0] = s11 * csam;
+			c1->sas[i14 - 1][1][0] = s21 * csam;
+			c1->sas[i14 - 1][0][1] = s12 * csam;
+			c1->sas[i14 - 1][1][1] = s22 * csam;
+		}
+	} // loop i14
+	for (int i24 = 1; i24 <= nsph; i24++) {
+		int iogi = c1->iog[i24 - 1];
+		if (iogi >= i24) {
+			int j = 0;
+			for (int ipo1 = 0; ipo1 < 2; ipo1++) {
+				for (int jpo1 = 0; jpo1 < 2; jpo1++) {
+					std::complex<double> cc = dconjg(c1->sas[i24 - 1][jpo1][ipo1]);
+					for (int ipo2 = 0; ipo2 < 2; ipo2++) {
+						for (int jpo2 = 0; jpo2 < 2; jpo2++) {
+							j += 1;
+							c1->vints[i24 - 1][j - 1] = c1->sas[i24 - 1][jpo2][ipo2] * cc * cfsq;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+/*! \brief C++ porting of SPHAR
+ *
+ * \param cosrth: `double`
+ * \param sinrth: `double`
+ * \param cosrph: `double`
+ * \param sinrph: `double`
+ * \param ll: `int`
+ * \param ylm: Vector of complex.
+ */
+void sphar(
+		double cosrth, double sinrth, double cosrph, double sinrph,
+		int ll, std::complex<double> *ylm
+) {
+	double sinrmp[40], cosrmp[40], plegn[861];
+	double four_pi = 8.0 * acos(0.0);
+	double pi4irs = 1.0 / sqrt(four_pi);
+	double x = cosrth;
+	double y = sinrth;
+	//printf("DEBUG: X = %lE\n", x);
+	if (y < 0.0) y *= -1.0;
+	//printf("DEBUG: Y = %lE\n", y);
+	double cllmo = 3.0;
+	double cll = 1.5;
+	double ytol = y;
+	plegn[0] = 1.0;
+	//printf("DEBUG: PLEGN( %d ) = %lE\n", 1, plegn[0]);
+	plegn[1] = x * sqrt(cllmo);
+	//printf("DEBUG: PLEGN( %d ) = %lE\n", 2, plegn[1]);
+	plegn[2] = ytol * sqrt(cll);
+	//printf("DEBUG: PLEGN( %d ) = %lE\n", 3, plegn[2]);
+	sinrmp[0] = sinrph;
+	cosrmp[0] = cosrph;
+	if (ll >= 2) {
+		int k = 3;
+		for (int l20 = 2; l20 <= ll; l20++) {
+			int lmo = l20 - 1;
+			int ltpo = l20 + l20 + 1;
+			int ltmo = ltpo - 2;
+			int lts = ltpo * ltmo;
+			double cn = 1.0 * lts;
+			for (int mpo10 = 1; mpo10 <= lmo; mpo10++) {
+				int m = mpo10 - 1;
+				int mpopk = mpo10 + k;
+				int ls = (l20 + m) * (l20 - m);
+				double cd = 1.0 * ls;
+				double cnm = 1.0 * ltpo * (lmo + m) * (l20 - mpo10);
+				double cdm = 1.0 * ls * (ltmo - 2);
+				plegn[mpopk - 1] = plegn[mpopk - l20 - 1] * x * sqrt(cn / cd) -
+						plegn[mpopk - ltmo - 1] * sqrt(cnm / cdm);
+				//printf("DEBUG: PLEGN( %d ) = %lE\n", mpopk, plegn[mpopk - 1]);
+			}
+			int lpk = l20 + k;
+			double cltpo = 1.0 * ltpo;
+			plegn[lpk - 1] = plegn[k - 1] * x * sqrt(cltpo);
+			//printf("DEBUG: PLEGN( %d ) = %lE\n", lpk, plegn[lpk - 1]);
+			k = lpk + 1;
+			double clt = 1.0 * (ltpo - 1);
+			cll *= (cltpo / clt);
+			ytol *= y;
+			plegn[k - 1] = ytol * sqrt(cll);
+			//printf("DEBUG: PLEGN( %d ) = %lE\n", k, plegn[k - 1]);
+			sinrmp[l20 - 1] = sinrph * cosrmp[lmo - 1] + cosrph * sinrmp[lmo - 1];
+			cosrmp[l20 - 1] = cosrph * cosrmp[lmo - 1] - sinrph * sinrmp[lmo - 1];
+		} // end l20 loop
+	}
+	// label 30
+	int l = 0;
+	int m, k, l0y, l0p, lmy, lmp;
+	double save;
+label40:
+	m = 0;
+	k = l * (l + 1);
+	l0y = k + 1;
+	l0p = k / 2 + 1;
+	ylm[l0y - 1] = pi4irs * plegn[l0p - 1];
+	//printf("DEBUG: YLM( %d ) = (%lE,%lE)\n", l0y, ylm[l0y - 1].real(), ylm[l0y - 1].imag());
+	goto label45;
+label44:
+	lmp = l0p + m;
+	save = pi4irs * plegn[lmp - 1];
+	lmy = l0y + m;
+	ylm[lmy - 1] = save * std::complex<double>(cosrmp[m - 1], sinrmp[m - 1]);
+	if (m % 2 != 0) ylm[lmy - 1] *= -1.0;
+	//printf("DEBUG: YLM( %d ) = (%lE,%lE)\n", lmy, ylm[lmy - 1].real(), ylm[lmy - 1].imag());
+	lmy = l0y - m;
+	ylm[lmy - 1] = save * std::complex<double>(cosrmp[m - 1], -sinrmp[m - 1]);
+	//printf("DEBUG: YLM( %d ) = (%lE,%lE)\n", lmy, ylm[lmy - 1].real(), ylm[lmy - 1].imag());
+label45:
+	if (m >= l) goto label47;
+	m += 1;
+	goto label44;
+label47:
+	if (l >= ll) return;
+	l += 1;
+	goto label40;
+}
+
+/*! \brief C++ porting of THDPS
+ *
+ * \param lm: `int`
+ * \param zpv: `double ****`
+ */
+void thdps(int lm, double ****zpv) {
+	// WARNING: unclear nested loop in THDPS
+	// The optimized interpretation was adopted here.
+	for (int l10 = 1; l10 <= lm; l10++) {
+		for (int ilmp = 1; ilmp <= 3; ilmp++) {
+			zpv[l10 - 1][ilmp - 1][0][0] = 0.0;
+			zpv[l10 - 1][ilmp - 1][0][1] = 0.0;
+			zpv[l10 - 1][ilmp - 1][1][0] = 0.0;
+			zpv[l10 - 1][ilmp - 1][1][1] = 0.0;
+		}
+	}
+	for (int l15 = 1; l15 <= lm; l15++) {
+		double xd = 1.0 * l15 * (l15 + 1);
+		double zp = -1.0 / sqrt(xd);
+		zpv[l15 - 1][1][0][1] = zp;
+		zpv[l15 - 1][1][1][0] = zp;
+	}
+	if (lm != 1) {
+		for (int l20 = 2; l20 <= lm; l20++) {
+			double xn = 1.0 * (l20 - 1) * (l20 + 1);
+			double xd = 1.0 * l20 * (l20 + l20 + 1);
+			double zp = sqrt(xn / xd);
+			zpv[l20 - 1][0][0][0] = zp;
+			zpv[l20 - 1][0][1][1] = zp;
+		}
+		int lmmo = lm - 1;
+		for (int l25 = 1; l25 <= lmmo; l25++) {
+			double xn = 1.0 * l25 * (l25 + 2);
+			double xd = (l25 + 1) * (l25 + l25 + 1);
+			double zp = -1.0 * sqrt(xn / xd);
+			zpv[l25 - 1][2][0][0] = zp;
+			zpv[l25 - 1][2][1][1] = zp;
+		}
+	}
+}
+
+/*! \brief C++ porting of UPVMP
+ *
+ * \param thd: `double`
+ * \param phd: `double`
+ * \param icspnv: `int`
+ * \param cost: `double`
+ * \param sint: `double`
+ * \param cosp: `double`
+ * \param sinp: `double`
+ * \param u: `double *`
+ * \param up: `double *`
+ * \param un: `double *`
+ */
+void upvmp(
+		double thd, double phd, int icspnv, double &cost, double &sint,
+		double &cosp, double &sinp, double *u, double *up, double *un
+) {
+	double half_pi = acos(0.0);
+	double rdr = half_pi / 90.0;
+	double th = thd * rdr;
+	double ph = phd * rdr;
+	cost = cos(th);
+	sint = sin(th);
+	cosp = cos(ph);
+	sinp = sin(ph);
+	//printf("DEBUG: cost = %lE\n", cost);
+	//printf("DEBUG: sint = %lE\n", sint);
+	//printf("DEBUG: cosp = %lE\n", cosp);
+	//printf("DEBUG: sinp = %lE\n", sinp);
+	u[0] = cosp * sint;
+	u[1] = sinp * sint;
+	u[2] = cost;
+	up[0] = cosp * cost;
+	up[1] = sinp * cost;
+	up[2] = -sint;
+	un[0] = -sinp;
+	un[1] = cosp;
+	un[2] = 0.0;
+	if (icspnv != 0) {
+		up[0] *= -1.0;
+		up[1] *= -1.0;
+		up[2] *= -1.0;
+		un[0] *= -1.0;
+		un[1] *= -1.0;
+	}
+}
+
+/*! \brief C++ porting of UPVSP
+ *
+ * \param u: `double *`
+ * \param upmp: `double *`
+ * \param unmp: `double *`
+ * \param us: `double *`
+ * \param upsmp: `double *`
+ * \param unsmp: `double *`
+ * \param up: `double *`
+ * \param un: `double *`
+ * \param ups: `double *`
+ * \param uns: `double *`
+ * \param duk: `double *`
+ * \param isq: `int &`
+ * \param ibf: `int &`
+ * \param scand: `double &`
+ * \param cfmp: `double &`
+ * \param sfmp: `double &`
+ * \param cfsp: `double &`
+ * \param sfsp: `double &`
+ */
+void upvsp(
+		double *u, double *upmp, double *unmp, double *us, double *upsmp, double *unsmp,
+		double *up, double *un, double *ups, double *uns, double *duk, int &isq,
+		int &ibf, double &scand, double &cfmp, double &sfmp, double &cfsp, double &sfsp
+) {
+	double rdr = acos(0.0) / 90.0;
+	double small = 1.0e-6;
+	isq = 0;
+	scand = u[0] * us[0] + u[1] * us[1] + u[2] * us[2];
+	double abs_scand = scand - 1.0;
+	if (abs_scand < 0.0) abs_scand *= -1.0;
+	if (abs_scand >= small) {
+		abs_scand = scand + 1.0;
+		if (abs_scand < 0.0) abs_scand *= -1.0;
+		if (abs_scand >= small) {
+			scand = acos(scand) / rdr;
+			duk[0] = u[0] - us[0];
+			duk[1] = u[1] - us[1];
+			duk[2] = u[2] - us[2];
+			ibf = 0;
+		} else {
+			// label 15
+			scand = 180.0;
+			duk[0] = 2.0 * u[0];
+			duk[1] = 2.0 * u[1];
+			duk[2] = 2.0 * u[2];
+			ibf = 1;
+			ups[0] = -upsmp[0];
+			ups[1] = -upsmp[1];
+			ups[2] = -upsmp[2];
+			uns[0] = -unsmp[0];
+			uns[1] = -unsmp[1];
+			uns[2] = -unsmp[2];
+		}
+	} else {
+		// label 10
+		scand = 0.0;
+		duk[0] = 0.0;
+		duk[1] = 0.0;
+		duk[2] = 0.0;
+		ibf = -1;
+		isq = -1;
+		ups[0] = upsmp[0];
+		ups[1] = upsmp[1];
+		ups[2] = upsmp[2];
+		uns[0] = unsmp[0];
+		uns[1] = unsmp[1];
+		uns[2] = unsmp[2];
+	}
+	if (ibf == -1 || ibf == 1) { // label 20
+		up[0] = upmp[0];
+		up[1] = upmp[1];
+		up[2] = upmp[2];
+		un[0] = unmp[0];
+		un[1] = unmp[1];
+		un[2] = unmp[2];
+	} else { // label 25
+		orunve(u, us, un, -1, small);
+		uns[0] = un[0];
+		uns[1] = un[1];
+		uns[2] = un[2];
+		orunve(un, u, up, 1, small);
+		orunve(uns, us, ups, 1, small);
+	}
+	// label 85
+	cfmp = upmp[0] * up[0] + upmp[1] * up[1] + upmp[2] * up[2];
+	sfmp = unmp[0] * up[0] + unmp[1] * up[1] + unmp[2] * up[2];
+    cfsp = ups[0] * upsmp[0] + ups[1] * upsmp[1] + ups[2] * upsmp[2];
+    sfsp = uns[0] * upsmp[0] + uns[1] * upsmp[1] + uns[2] * upsmp[2];
+}
+
+/*! \brief C++ porting of WMAMP
+ *
+ * \param iis: `int`
+ * \param cost: `double`
+ * \param sint: `double`
+ * \param cosp: `double`
+ * \param sinp: `double`
+ * \param inpol: `int`
+ * \param lm: `int`
+ * \param idot: `int`
+ * \param nsph: `int`
+ * \param arg: `double *`
+ * \param u: `double *`
+ * \param up: `double *`
+ * \param un: `double *`
+ * \param c1: `C1 *`
+ */
+void wmamp(
+		int iis, double cost, double sint, double cosp, double sinp, int inpol,
+		int lm, int idot, int nsph, double *arg, double *u, double *up,
+		double *un, C1 *c1
+) {
+	std::complex<double> *ylm = new std::complex<double>[1682];
+	int nlmp = lm * (lm + 2) + 2;
+	ylm[nlmp - 1] = std::complex<double>(0.0, 0.0);
+	if (idot != 0) {
+		if (idot != 1) {
+			for (int n40 = 0; n40 < nsph; n40++) {
+				arg[n40] = u[0] * c1->rxx[n40] + u[1] * c1->ryy[n40] + u[2] * c1->rzz[n40];
+			}
+		} else {
+			for (int n50 = 0; n50 < nsph; n50++) {
+				arg[n50] = c1->rzz[n50];
+			}
+		}
+		if (iis == 2) {
+			for (int n60 = 0; n60 < nsph; n60++) arg[n60] *= -1;
+		}
+	}
+	sphar(cost, sint, cosp, sinp, lm, ylm);
+	//printf("DEBUG: in WMAMP and calling PWMA with lm = %d and iis = %d\n", lm, iis);
+	pwma(up, un, ylm, inpol, lm, iis, c1);
+	delete[] ylm;
+}
+
+/*! \brief C++ porting of WMASP
+ *
+ * \param cost: `double`
+ * \param sint: `double`
+ * \param cosp: `double`
+ * \param sinp: `double`
+ * \param costs: `double`
+ * \param sints: `double`
+ * \param cosps: `double`
+ * \param sinps: `double`
+ * \param u: `double *`
+ * \param up: `double *`
+ * \param un: `double *`
+ * \param us: `double *`
+ * \param ups: `double *`
+ * \param uns: `double *`
+ * \param isq: `int`
+ * \param ibf: `int`
+ * \param inpol: `int`
+ * \param lm: `int`
+ * \param idot: `int`
+ * \param nsph: `int`
+ * \param argi: `double *`
+ * \param args: `double *`
+ * \param c1: `C1 *`
+ */
+void wmasp(
+		double cost, double sint, double cosp, double sinp, double costs, double sints,
+		double cosps, double sinps, double *u, double *up, double *un, double *us,
+		double *ups, double *uns, int isq, int ibf, int inpol, int lm, int idot,
+		int nsph, double *argi, double *args, C1 *c1
+) {
+	std::complex<double> *ylm = new std::complex<double>[1682];
+	int nlmp = lm * (lm + 2) + 2;
+	ylm[nlmp - 1] = std::complex<double>(0.0, 0.0);
+	if (idot != 0) {
+		if (idot != 1) {
+			for (int n40 = 1; n40 <= nsph; n40++) {
+				argi[n40 - 1] = u[0] * c1->rxx[n40 - 1] + u[1] * c1->ryy[n40 - 1] + u[2] * c1->rzz[n40 - 1];
+				if (ibf != 0) {
+					args[n40 - 1] = argi[n40 - 1] * ibf;
+				} else {
+					args[n40 - 1] = -1.0 * (us[0] * c1->rxx[n40 - 1] + us[1] * c1->ryy[n40 - 1] + us[2] * c1->rzz[n40 - 1]);
+				}
+			}
+		} else { // label 50
+			for (int n60 = 1; n60 <= nsph; n60++) {
+				argi[n60 - 1] = cost * c1->rzz[n60 - 1];
+				if (ibf != 0) {
+					args[n60 - 1] = argi[n60 - 1] * ibf;
+				} else {
+					args[n60 - 1] = -costs * c1->rzz[n60 - 1];
+				}
+			}
+		}
+	}
+	sphar(cost, sint, cosp, sinp, lm, ylm);
+	//printf("DEBUG: in WMASP and calling PWMA with isq = %d\n", isq);
+	pwma(up, un, ylm, inpol, lm, isq, c1);
+	if (ibf >= 0) {
+		sphar(costs, sints, cosps, sinps, lm, ylm);
+		//printf("DEBUG: in WMASP and calling PWMA with isq = 2 and ibf = %d\n", ibf);
+		pwma(ups, uns, ylm, inpol, lm, 2, c1);
+	}
+	delete[] ylm;
+}
+
+
+/*! \brief C++ porting of DME
+ *
+ * \param li: `int`
+ * \param i: `int`
+ * \param npnt: `int`
+ * \param npntts: `int`
+ * \param vk: `double`
+ * \param exdc: `double`
+ * \param exri: `double`
+ * \param c1: `C1 *`
+ * \param c2: `C2 *`
+ * \param jer: `int &`
+ * \param lcalc: `int &`
+ * \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) {
+	double *rfj = new double[42];
+	double *rfn = new double[42];
+	std::complex<double> cfj[42], fbi[42], fb[42], fn[42];
+	std::complex<double> rmf[40], drmf[40], ref[40], dref[40];
+	std::complex<double> dfbi, dfb, dfn, ccna, ccnb, ccnc, ccnd;
+	std::complex<double> y1, dy1, y2, dy2, arin, cri, uim;
+	jer = 0;
+	uim = std::complex<double>(0.0, 1.0);
+	int nstp = npnt - 1;
+	int nstpts = npntts - 1;
+	int lipo = li + 1;
+	int lipt = li + 2;
+	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]);
+	arg = vkr1 * c2->vkt[i - 1];
+	arin = arg;
+	bool goto32 = false;
+	if (arg.imag() != 0.0) {
+		cbf(lipo, arg, lcalc, cfj);
+		if (lcalc < lipo) {
+			jer = 5;
+			delete[] rfj;
+			delete[] rfn;
+			return;
+		}
+		for (int j24 = 1; j24 <= lipt; j24++) fbi[j24 - 1] = cfj[j24 - 1];
+		goto32 = true;
+	}
+	if (!goto32) {
+		rbf(lipo, arg.real(), lcalc, rfj);
+		if (lcalc < lipo) {
+			jer = 5;
+			delete[] rfj;
+			delete[] rfn;
+			return;
+		}
+		for (int j30 = 1; j30 <= lipt; j30++) fbi[j30 - 1] = rfj[j30 - 1];
+	}
+	double arex = sz * exri;
+	arg = arex;
+	rbf(lipo, arex, lcalc, rfj);
+	if (lcalc < lipo) {
+		jer = 7;
+		delete[] rfj;
+		delete[] rfn;
+		return;
+	}
+	rnf(lipo, arex, lcalc, rfn);
+	if (lcalc < lipo) {
+		jer = 8;
+		delete[] rfj;
+		delete[] rfn;
+		return;
+	}
+	for (int j43 = 1; j43 <= lipt; j43++) {
+		fb[j43 - 1] = rfj[j43 - 1];
+		//printf("DEBUG: fb[%d] = (%lE,%lE)\n", j43, fb[j43 - 1].real(), fb[j43 - 1].imag());
+		fn[j43 - 1] = rfn[j43 - 1];
+		//printf("DEBUG: fn[%d] = (%lE,%lE)\n", j43, fn[j43 - 1].real(), fn[j43 - 1].imag());
+	}
+	if (nsh <= 1) {
+		cri = c2->dc0[0] / exdc;
+		for (int l60 = 1; l60 <= li; l60++) {
+			int lpo = l60 + 1;
+			int ltpo = lpo + l60;
+			int lpt = lpo + 1;
+			dfbi = ((1.0 * l60) * fbi[l60 - 1] - (1.0 * lpo) * fbi[lpt - 1]) * arin + fbi[lpo - 1] * (1.0 * ltpo);
+			dfb = ((1.0 * l60) * fb[l60 - 1] - (1.0 * lpo) * fb[lpt - 1]) * arex + fb[lpo - 1] * (1.0 * ltpo);
+			dfn = ((1.0 * l60) * fn[l60 - 1] - (1.0 * lpo) * fn[lpt - 1]) * arex + fn[lpo - 1] * (1.0 * ltpo);
+			ccna = fbi[lpo - 1] * dfn;
+			ccnb = fn[lpo - 1] * dfbi;
+			ccnc = fbi[lpo - 1] * dfb;
+			ccnd = fb[lpo - 1] * dfbi;
+			c1->rmi[l60 - 1][i - 1] = 1.0 + uim * (ccna - ccnb) / (ccnc - ccnd);
+			c1->rei[l60 - 1][i - 1] = 1.0 + uim * (cri * ccna - ccnb) / (cri * ccnc - ccnd);
+		}
+	} else { // nsh > 1
+		int ic = 1;
+		for (int l80 = 1; l80 <= li; l80++) {
+			int lpo = l80 + 1;
+			int ltpo = lpo + l80;
+			int lpt = lpo + 1;
+			int dltpo = ltpo;
+			y1 = fbi[lpo - 1];
+			dy1 = ((1.0 * l80) * fbi[l80 - 1] - (1.0 * lpo) * fbi[lpt - 1]) * c2->vkt[i - 1] / (1.0 * dltpo);
+			y2 = y1;
+			dy2 = dy1;
+			ic = 1;
+			for (int ns76 = 2; ns76 <= nsh; ns76++) {
+				int nsmo = ns76 - 1;
+				double vkr = vk * c1->rc[i - 1][nsmo - 1];
+				if (ns76 % 2 != 0) {
+					ic += 1;
+					double step = 1.0 * nstp;
+					step = vk * (c1->rc[i - 1][ns76 - 1] - c1->rc[i - 1][nsmo - 1]) / step;
+					arg = c2->dc0[ic - 1];
+					rkc(nstp, step, arg, vkr, lpo, y1, y2, dy1, dy2);
+				} else {
+					diel(nstpts, nsmo, i, ic, vk, c1, c2);
+					double stepts = 1.0 * nstpts;
+					stepts = vk * (c1->rc[i - 1][ns76 - 1] - c1->rc[i - 1][nsmo - 1]) / stepts;
+					rkt(nstpts, stepts, vkr, lpo, y1, y2, dy1, dy2, c2);
+				}
+			}
+			rmf[l80 - 1] = y1 * sz;
+			drmf[l80 - 1] = dy1 * sz + y1;
+			ref[l80 - 1] = y2 * sz;
+			dref[l80 - 1] = dy2 * sz + y2;
+		}
+		cri = 1.0 + uim * 0.0;
+		if (nsh % 2 != 0) cri = c2->dc0[ic - 1] / exdc;
+		for (int l90 = 1; l90 <= li; l90++) {
+			int lpo = l90 + 1;
+			int ltpo = lpo + l90;
+			int lpt = lpo + 1;
+			dfb = ((1.0 * l90) * fb[l90 - 1] - (1.0 * lpo) * fb[lpt - 1]) * arex + fb[lpo - 1] * (1.0 * ltpo);
+			dfn = ((1.0 * l90) * fn[l90 - 1] - (1.0 * lpo) * fn[lpt - 1]) * arex + fn[lpo - 1] * (1.0 * ltpo);
+			ccna = rmf[l90 - 1] * dfn;
+			ccnb = drmf[l90 - 1] * fn[lpo - 1] * (1.0 * sz * ltpo);
+			ccnc = rmf[l90 - 1] * dfb;
+			ccnd = drmf[l90 - 1] * fb[lpo -1] * (1.0 * sz * ltpo);
+			c1->rmi[l90 - 1][i - 1] = 1.0 + uim *(ccna - ccnb) / (ccnc - ccnd);
+			//printf("DEBUG: gone 90, rmi[%d][%d] = (%lE,%lE)\n", l90, i, c1->rmi[l90 - 1][i - 1].real(), c1->rmi[l90 - 1][i - 1].imag());
+			ccna = ref[l90 - 1] * dfn;
+			ccnb = dref[l90 - 1] * fn[lpo - 1] * (1.0 * sz * ltpo);
+			ccnc = ref[l90 - 1] * dfb;
+			ccnd = dref[l90 - 1] *fb[lpo - 1] * (1.0 * sz * ltpo);
+			c1->rei[l90 - 1][i - 1] = 1.0 + uim * (cri * ccna - ccnb) / (cri * ccnc - ccnd);
+			//printf("DEBUG: gone 90, rei[%d][%d] = (%lE,%lE)\n", l90, i, c1->rei[l90 - 1][i - 1].real(), c1->rei[l90 - 1][i - 1].imag());
+		}
+	} // nsh <= 1 ?
+	delete[] rfj;
+	delete[] rfn;
+	return;
+}
+
+#endif /* SRC_INCLUDE_SPH_SUBS_H_ */
diff --git a/src/libnptm/Commons.cpp b/src/libnptm/Commons.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..809337ea7adb2475af3d0325d3cbd1b139c025d6
--- /dev/null
+++ b/src/libnptm/Commons.cpp
@@ -0,0 +1,96 @@
+/*! \file Commons.cpp
+ *
+ */
+
+#include "../include/Commons.h"
+
+using namespace std;
+
+C1::C1(int ns, int l_max) {
+	nlmmt = 2 * (l_max * (l_max + 2));
+	nsph = ns;
+	lm = l_max;
+
+	rmi = new complex<double>*[lm];
+	rei = new complex<double>*[lm];
+	for (int ri = 0; ri < lm; ri++) {
+		rmi[ri] = new complex<double>[nsph];
+		rei[ri] = new complex<double>[nsph];
+	}
+	w = new complex<double>*[nlmmt];
+	for (int wi = 0; wi < nlmmt; wi++) w[wi] = new complex<double>[4];
+	vints = new complex<double>*[nsph];
+	rc = new double*[nsph];
+	for (int vi = 0; vi < nsph; vi++) {
+		rc[vi] = new double[lm];
+		vints[vi] = new complex<double>[16];
+	}
+	fsas = new complex<double>[nsph];
+	sscs = new double[nsph];
+	sexs = new double[nsph];
+	sabs = new double[nsph];
+	sqscs = new double[nsph];
+	sqexs = new double[nsph];
+	sqabs = new double[nsph];
+	gcsv = new double[nsph];;
+	rxx = new double[nsph];
+	ryy = new double[nsph];
+	rzz = new double[nsph];
+	ros = new double[nsph];
+	iog = new int[nsph];
+	nshl = new int[nsph];
+
+	sas = new complex<double>**[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];
+	}
+}
+
+C1::~C1() {
+	delete[] rmi;
+	delete[] rei;
+	for (int wi = 1; wi <= nlmmt; wi++) delete[] w[wi];
+	for (int vi = 1; vi <= nsph; vi++) {
+		delete[] rc[nsph - vi];
+		delete[] vints[nsph - vi];
+	}
+	for (int si = 1; si <= nsph; si++) {
+		delete[] sas[nsph - si][1];
+		delete[] sas[nsph - si][0];
+	}
+	delete[] fsas;
+	delete[] sscs;
+	delete[] sexs;
+	delete[] sabs;
+	delete[] sqscs;
+	delete[] sqexs;
+	delete[] sqabs;
+	delete[] gcsv;
+	delete[] rxx;
+	delete[] ryy;
+	delete[] rzz;
+	delete[] ros;
+	delete[] iog;
+	delete[] nshl;
+}
+
+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];
+	vsz = new double[nsph];
+}
+
+C2::~C2() {
+	delete[] ris;
+	delete[] dlri;
+	delete[] vkt;
+	delete[] dc0;
+	delete[] vsz;
+}
diff --git a/src/libnptm/Configuration.cpp b/src/libnptm/Configuration.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6bb02bddd092ed30b02aebf2ef88b0e3f524645a
--- /dev/null
+++ b/src/libnptm/Configuration.cpp
@@ -0,0 +1,778 @@
+/*! \file Configuration.cpp
+*/
+
+#include <cmath>
+#include <cstdio>
+#include <fstream>
+#include <string>
+#include "../include/List.h"
+#include "../include/Parsers.h"
+#include "../include/Configuration.h"
+
+using namespace std;
+
+GeometryConfiguration::GeometryConfiguration(
+		int nsph, int lm, int _in_pol, int _npnt, int _npntts, int isam,
+		double *x, double *y, double *z,
+		double in_th_start, double in_th_step, double in_th_end,
+		double sc_th_start, double sc_th_step, double sc_th_end,
+		double in_ph_start, double in_ph_step, double in_ph_end,
+		double sc_ph_start, double sc_ph_step, double sc_ph_end,
+		int _jwtm
+	) {
+	number_of_spheres = nsph;
+	l_max = lm;
+	in_pol = _in_pol;
+	npnt = _npnt;
+	npntts = _npntts;
+	meridional_type = isam;
+	in_theta_start = in_th_start;
+	in_theta_step = in_th_step;
+	in_theta_end = in_th_end;
+	in_phi_start = in_ph_start;
+	in_phi_step = in_ph_step;
+	in_phi_end = in_ph_end;
+	sc_theta_start = sc_th_start;
+	sc_theta_step = sc_th_step;
+	sc_theta_end = sc_th_end;
+	sc_phi_start = sc_ph_start;
+	sc_phi_step = sc_ph_step;
+	sc_phi_end = sc_ph_end;
+	jwtm = _jwtm;
+	sph_x = x;
+	sph_y = y;
+	sph_z = z;
+}
+
+GeometryConfiguration::~GeometryConfiguration() {
+	delete[] sph_x;
+	delete[] sph_y;
+	delete[] sph_z;
+}
+
+GeometryConfiguration* GeometryConfiguration::from_legacy(string file_name) {
+	int num_lines = 0;
+	int last_read_line = 0;
+	string *file_lines;
+	try {
+		file_lines = load_file(file_name, &num_lines);
+	} catch (exception &ex) {
+		throw OpenConfigurationFileException(file_name);
+	}
+	int nsph, lm, _in_pol, _npnt, _npntts, isam;
+	sscanf(
+			file_lines[last_read_line++].c_str(),
+			" %d %d %d %d %d %d",
+			&nsph, &lm, &_in_pol, &_npnt, &_npntts, &isam
+	);
+	double *x, *y, *z;
+	x = new double[nsph];
+	y = new double[nsph];
+	z = new double[nsph];
+	if (nsph == 1) {
+		x[0] = 0.0;
+		y[0] = 0.0;
+		z[0] = 0.0;
+	} else {
+		for (int i = 0; i < nsph; i++) {
+			double sph_x, sph_y, sph_z;
+			int sph_x_exp, sph_y_exp, sph_z_exp;
+			sscanf(
+					file_lines[last_read_line++].c_str(),
+					" %lf D%d %lf D%d %lf D%d",
+					&sph_x, &sph_x_exp, &sph_y, &sph_y_exp, &sph_z, &sph_z_exp
+			);
+			x[i] = sph_x * pow(10.0, 1.0 * sph_x_exp);
+			y[i] = sph_y * pow(10.0, 1.0 * sph_y_exp);
+			z[i] = sph_z * pow(10.0, 1.0 * sph_z_exp);
+		}
+	}
+	double in_th_start, in_th_end, in_th_step, sc_th_start, sc_th_end, sc_th_step;
+	int in_th_start_exp, in_th_end_exp, in_th_step_exp, sc_th_start_exp, sc_th_end_exp, sc_th_step_exp;
+	sscanf(
+			file_lines[last_read_line++].c_str(),
+			" %lf D%d %lf D%d %lf D%d %lf D%d %lf D%d %lf D%d",
+			&in_th_start, &in_th_start_exp,
+			&in_th_step, &in_th_step_exp,
+			&in_th_end, &in_th_end_exp,
+			&sc_th_start, &sc_th_start_exp,
+			&sc_th_step, &sc_th_step_exp,
+			&sc_th_end, &sc_th_end_exp
+	);
+	in_th_start *= pow(10.0, 1.0 * in_th_start_exp);
+	in_th_step *= pow(10.0, 1.0 * in_th_step_exp);
+	in_th_end *= pow(10.0, 1.0 * in_th_end_exp);
+	sc_th_start *= pow(10.0, 1.0 * sc_th_start_exp);
+	sc_th_step *= pow(10.0, 1.0 * sc_th_step_exp);
+	sc_th_end *= pow(10.0, 1.0 * sc_th_end_exp);
+	double in_ph_start, in_ph_end, in_ph_step, sc_ph_start, sc_ph_end, sc_ph_step;
+	int in_ph_start_exp, in_ph_end_exp, in_ph_step_exp, sc_ph_start_exp, sc_ph_end_exp, sc_ph_step_exp;
+	sscanf(
+			file_lines[last_read_line++].c_str(),
+			" %lf D%d %lf D%d %lf D%d %lf D%d %lf D%d %lf D%d",
+			&in_ph_start, &in_ph_start_exp,
+			&in_ph_step, &in_ph_step_exp,
+			&in_ph_end, &in_ph_end_exp,
+			&sc_ph_start, &sc_ph_start_exp,
+			&sc_ph_step, &sc_ph_step_exp,
+			&sc_ph_end, &sc_ph_end_exp
+	);
+	in_ph_start *= pow(10.0, 1.0 * in_ph_start_exp);
+	in_ph_step *= pow(10.0, 1.0 * in_ph_step_exp);
+	in_ph_end *= pow(10.0, 1.0 * in_ph_end_exp);
+	sc_ph_start *= pow(10.0, 1.0 * sc_ph_start_exp);
+	sc_ph_step *= pow(10.0, 1.0 * sc_ph_step_exp);
+	sc_ph_end *= pow(10.0, 1.0 * sc_ph_end_exp);
+	int _jwtm;
+	sscanf(file_lines[last_read_line++].c_str(), " %d", &_jwtm);
+	GeometryConfiguration *conf = new GeometryConfiguration(
+			nsph, lm, _in_pol, _npnt, _npntts, isam,
+			x, y, z,
+			in_th_start, in_th_step, in_th_end,
+			sc_th_start, sc_th_step, sc_th_end,
+			in_ph_start, in_ph_step, in_ph_end,
+			sc_ph_start, sc_ph_step, sc_ph_end,
+			_jwtm
+	);
+	return conf;
+}
+
+ScattererConfiguration::ScattererConfiguration(
+		int nsph,
+		double *scale_vector,
+		int nxi,
+		string variable_name,
+		int *iog_vector,
+		double *ros_vector,
+		int *nshl_vector,
+		double **rcf_vector,
+		int dielectric_func_type,
+		complex<double> ***dc_matrix,
+		bool is_external,
+		double ex,
+		double w,
+		double x
+		) {
+	number_of_spheres = nsph;
+	scale_vec = scale_vector;
+	number_of_scales = nxi;
+	reference_variable_name = variable_name;
+	iog_vec = iog_vector;
+	radii_of_spheres = ros_vector;
+	nshl_vec = nshl_vector;
+	rcf = rcf_vector;
+	idfc = dielectric_func_type,
+	dc0_matrix = dc_matrix;
+	use_external_sphere = is_external;
+	exdc = ex;
+	wp = w;
+	xip = x;
+}
+
+ScattererConfiguration::~ScattererConfiguration() {
+	int max_ici = 0;
+	for (int i = 1; i <= number_of_spheres; i++) {
+		if (iog_vec[i - 1] < i) continue;
+		int nsh = nshl_vec[i - 1];
+		if (max_ici < (nsh + 1) / 2) max_ici = (nsh + 1) / 2;
+	}
+	for (int i = 0; i < max_ici; i++) {
+		for (int j = 0; j < number_of_spheres; j++) {
+			delete[] dc0_matrix[i][j];
+		}
+	}
+	for (int i = 0; i < number_of_spheres; i++) {
+		delete[] rcf[i];
+	}
+	delete[] nshl_vec;
+	delete[] radii_of_spheres;
+	delete[] iog_vec;
+	delete[] scale_vec;
+}
+
+ScattererConfiguration* ScattererConfiguration::from_binary(string file_name, string mode) {
+	int nsph;
+	int *iog;
+	double _exdc, _wp, _xip;
+	int _idfc, nxi;
+	int *nshl_vector;
+	double *xi_vec;
+	double *ros_vector;
+	double **rcf_vector;
+	complex<double> ***dc0m;
+	if (mode.compare("LEGACY") == 0) { // Legacy mode was chosen.
+		int max_ici = 0;
+		fstream input;
+		input.open(file_name.c_str(), ios::in | ios::binary);
+		if (input.is_open()) {
+			input.read(reinterpret_cast<char *>(&nsph), sizeof(int));
+			iog = new int[nsph];
+			for (int i = 0; i < nsph; i++) {
+				input.read(reinterpret_cast<char *>(&(iog[i])), sizeof(int));
+			}
+			input.read(reinterpret_cast<char *>(&_exdc), sizeof(double));
+			input.read(reinterpret_cast<char *>(&_wp), sizeof(double));
+			input.read(reinterpret_cast<char *>(&_xip), sizeof(double));
+			input.read(reinterpret_cast<char *>(&_idfc), sizeof(int));
+			input.read(reinterpret_cast<char *>(&nxi), sizeof(int));
+			try {
+				xi_vec = new double[nxi];
+			} catch (bad_alloc &ex) {
+				throw UnrecognizedConfigurationException("Wrong parameter set: invalid number of scales " + nxi);
+			}
+			for (int i = 0; i < nxi; i++) {
+				input.read(reinterpret_cast<char *>(&(xi_vec[i])), sizeof(double));
+			}
+			nshl_vector = new int[nsph];
+			ros_vector = new double[nsph];
+			rcf_vector = new double*[nsph];
+			for (int i115 = 1; i115 <= nsph; i115++) {
+				if (iog[i115 - 1] < i115) continue;
+				input.read(reinterpret_cast<char *>(&(nshl_vector[i115 - 1])), sizeof(int));
+				input.read(reinterpret_cast<char *>(&(ros_vector[i115 - 1])), sizeof(double));
+				int nsh = nshl_vector[i115 - 1];
+				if (max_ici < (nsh + 1) / 2) max_ici = (nsh + 1) / 2;
+				try {
+					rcf_vector[i115 - 1] = new double[nsh];
+				} catch (bad_alloc &ex) {
+					throw UnrecognizedConfigurationException("Wrong parameter set: invalid number of layers " + nsh);
+				}
+				for (int nsi = 0; nsi < nsh; nsi++) {
+					input.read(reinterpret_cast<char *>(&(rcf_vector[i115 - 1][nsi])), sizeof(double));
+				}
+			}
+			dc0m = new complex<double>**[max_ici];
+			for (int dim1 = 0; dim1 < max_ici; dim1++) {
+				dc0m[dim1] = new complex<double>*[nsph];
+			    for (int dim2 = 0; dim2 < nsph; dim2++) {
+			    	dc0m[dim1][dim2] = new complex<double>[nxi];
+			    }
+			}
+			for (int jxi468 = 1; jxi468 <= nxi; jxi468++) {
+				if (_idfc != 0 && jxi468 > 1) continue;
+			    for (int i162 = 1; i162 <= nsph; i162++) {
+			    	if (iog[i162 - 1] < i162) continue;
+			    	int nsh = nshl_vector[i162 - 1];
+			    	int ici = (nsh + 1) / 2; // QUESTION: is integer division really intended here?
+			    	for (int i157 = 0; i157 < ici; i157++) {
+			    		double dc0_real, dc0_img;
+			    		input.read(reinterpret_cast<char *>(&dc0_real), sizeof(double));
+			    		input.read(reinterpret_cast<char *>(&dc0_img), sizeof(double));
+			    		dc0m[i157][i162 - 1][jxi468 - 1] = dc0_real + 1i * dc0_img;
+			    	}
+			    }
+			}
+			input.close();
+		} else { // Opening of the input file did not succeed.
+			throw OpenConfigurationFileException(file_name);
+		}
+	} else { // A different binary format was chosen.
+		//TODO: this part is not yet implemented.
+		//      Functions to write optimized file formats may be invoked here.
+	}
+	ScattererConfiguration *conf = new ScattererConfiguration(
+			nsph,
+			xi_vec,
+			nxi,
+			"XIV",
+			iog,
+			ros_vector,
+			nshl_vector,
+			rcf_vector,
+			_idfc,
+			dc0m,
+			false,
+			_exdc,
+			_wp,
+			_xip
+	);
+	return conf;
+}
+
+ScattererConfiguration* ScattererConfiguration::from_dedfb(string dedfb_file_name) {
+	int num_lines = 0;
+	int last_read_line = 0;
+	string *file_lines;
+	try {
+		file_lines = load_file(dedfb_file_name, &num_lines);
+	} catch (exception &ex) {
+		throw OpenConfigurationFileException(dedfb_file_name);
+	}
+	int nsph, ies;
+	int max_ici = 0;
+	sscanf(file_lines[last_read_line].c_str(), " %d %d", &nsph, &ies);
+	if (ies != 0) ies = 1;
+	double _exdc, _wp, _xip;
+	int exdc_exp, wp_exp, xip_exp;
+	int _idfc, nxi, instpc, insn;
+	sscanf(
+			file_lines[++last_read_line].c_str(),
+			" %lf D%d %lf D%d %lf D%d %d %d %d %d",
+			&_exdc, &exdc_exp,
+			&_wp, &wp_exp,
+			&_xip, &xip_exp,
+			&_idfc, &nxi, &instpc, &insn
+	);
+	_exdc *= pow(10.0, 1.0 * 1.0 * exdc_exp);
+	_wp *= pow(10.0, 1.0 * wp_exp);
+	_xip *= pow(10.0, 1.0 * xip_exp);
+
+	double *variable_vector;
+	string variable_name;
+
+	if (_idfc < 0) { // Diel. functions at XIP value and XI is scale factor
+		variable_name = "XIV";
+		if (instpc < 1) { // The variable vector is explicitly defined.
+			double xi;
+			int xi_exp;
+			List<double> xi_vector;
+			sscanf(file_lines[++last_read_line].c_str(), " %9lE D%d", &xi, &xi_exp);
+			xi *= pow(10.0, 1.0 * xi_exp);
+			xi_vector.set(0, xi);
+			for (int jxi310 = 1; jxi310 < nxi; jxi310++) {
+				sscanf(file_lines[++last_read_line].c_str(), " %9lE D%d", &xi, &xi_exp);
+				xi *= pow(10.0, 1.0 * xi_exp);
+				xi_vector.append(xi);
+			}
+			variable_vector = xi_vector.to_array();
+		} else { // instpc >= 1: the variable vector is defined in steps
+			double xi, xi_step;
+			int xi_exp, xi_step_exp;
+			sscanf(file_lines[++last_read_line].c_str(), " %9lE D%d %9lE D%d", &xi, &xi_exp, &xi_step, &xi_step_exp);
+			xi *= pow(10.0, 1.0 * xi_exp);
+			xi_step *= pow(10.0, 1.0 * xi_step_exp);
+			variable_vector = new double[nxi];
+			for (int jxi320 = 0; jxi320 < nxi; jxi320++) {
+				variable_vector[jxi320] = xi;
+				xi += xi_step;
+			}
+		}
+	} else { // idfc >= 0
+		variable_vector = new double[nxi];
+		if (instpc == 0) { // The variable vector is explicitly defined
+			double vs;
+			int vs_exp;
+			for (int jxi_r = 0; jxi_r < nxi; jxi_r++) {
+				sscanf(file_lines[++last_read_line].c_str(), " %lf D%d", &vs, &vs_exp);
+				vs *= pow(10.0, 1.0 * vs_exp);
+				variable_vector[jxi_r] = vs;
+			}
+			switch (insn) {
+			case 1: //xi vector definition
+				variable_name = "XIV";
+				break;
+			case 2: //wave number vector definition
+				variable_name = "WNS";
+		    	break;
+			case 3: //wavelength vector definition
+				variable_name = "WLS";
+				break;
+			case 4: //pu vector definition
+				variable_name = "PUS";
+				break;
+			case 5: //eV vector definition
+				variable_name = "EVS";
+				break;
+		    }
+		} else { // The variable vector needs to be computed in steps
+			double vs, vs_step;
+			int vs_exp, vs_step_exp;
+			sscanf(file_lines[++last_read_line].c_str(), " %lf D%d %lf D%d", &vs, &vs_exp, &vs_step, &vs_step_exp);
+			vs *= pow(10.0, 1.0 * vs_exp);
+			vs_step *= pow(10.0, 1.0 * vs_step_exp);
+			for (int jxi110w = 0; jxi110w < nxi; jxi110w++) {
+				variable_vector[jxi110w] = vs;
+				vs += vs_step;
+			}
+			switch (insn) {
+			case 1: //xi vector definition
+				variable_name = "XIV";
+				break;
+			case 2: //wave number vector definition
+				variable_name = "WNS";
+				break;
+			case 3: //wavelength vector definition
+				variable_name = "WLS";
+				break;
+			case 4: //pu vector definition
+				variable_name = "PUS";
+				break;
+			case 5: //eV vector definition
+				variable_name = "EVS";
+				break;
+			}
+		}
+	}
+	last_read_line++;
+	int *iog_vector = new int[nsph];
+	double *ros_vector = new double[nsph];
+	double **rcf_vector = new double*[nsph];
+	int *nshl_vector = new int[nsph];
+	for (int i = 0; i < nsph; i++) {
+		string read_format = "";
+		for (int j = 0; j < i; j++) read_format += " %*d";
+		read_format += " %d";
+		sscanf(file_lines[last_read_line].c_str(), read_format.c_str(), (iog_vector + i));
+	}
+	for (int i113 = 1; i113 <= nsph; i113++) {
+		int i_val, nsh;
+	    double ros_val;
+	    int ros_val_exp;
+	    if (iog_vector[i113 - 1] < i113) continue;
+	    sscanf(file_lines[++last_read_line].c_str(), " %d %lf D%d", &i_val, &ros_val, &ros_val_exp);
+	    nshl_vector[i113 - 1] = i_val;
+	    if (max_ici < (i_val + 1) / 2) max_ici = (i_val + 1) / 2;
+	    ros_vector[i113 - 1] = ros_val * pow(10.0, 1.0 * ros_val_exp);
+	    nsh = nshl_vector[i113 - 1];
+	    if (i113 == 1) nsh += ies;
+	    rcf_vector[i113 - 1] = new double[nsh];
+	    for (int ns = 0; ns < nsh; ns++) {
+	    	double ns_rcf;
+	    	int ns_rcf_exp;
+	    	sscanf(file_lines[++last_read_line].c_str(), " %lf D%d", &ns_rcf, &ns_rcf_exp);
+	    	rcf_vector[i113 -1][ns] = ns_rcf * pow(10.0, 1.0 * ns_rcf_exp);
+	    }
+	}
+	complex<double> ***dc0m = new complex<double>**[max_ici];
+	for (int dim1 = 0; dim1 < max_ici; dim1++) {
+		dc0m[dim1] = new complex<double>*[nsph];
+	    for (int dim2 = 0; dim2 < nsph; dim2++) {
+	    	dc0m[dim1][dim2] = new complex<double>[nxi];
+	    }
+	}
+	for (int jxi468 = 1; jxi468 <= nxi; jxi468++) {
+		if (_idfc != 0 && jxi468 > 1) continue;
+	    for (int i162 = 1; i162 <= nsph; i162++) {
+	    	if (iog_vector[i162 - 1] < i162) continue;
+	    	int nsh = nshl_vector[i162 - 1];
+	    	int ici = (nsh + 1) / 2; // QUESTION: is integer division really intended here?
+	    	if (i162 == 1) ici = ici + ies;
+	    	for (int i157 = 0; i157 < ici; i157++) {
+	    		double dc0_real, dc0_img;
+	    		int dc0_real_exp, dc0_img_exp;
+	    		sscanf(file_lines[++last_read_line].c_str(), " (%lf D%d, %lf D%d)", &dc0_real, &dc0_real_exp, &dc0_img, &dc0_img_exp);
+	    		dc0_real *= pow(10.0, 1.0 * dc0_real_exp);
+	    		dc0_img *= pow(10.0, 1.0 * dc0_img_exp);
+	    		dc0m[i157][i162 - 1][jxi468 - 1] = dc0_real + 1i * dc0_img;
+	    	}
+	    }
+	}
+
+	ScattererConfiguration *config = new ScattererConfiguration(
+			nsph,
+			variable_vector,
+			nxi,
+			variable_name,
+			iog_vector,
+			ros_vector,
+			nshl_vector,
+			rcf_vector,
+			_idfc,
+			dc0m,
+			(ies > 0),
+			_exdc,
+			_wp,
+			_xip
+	);
+	return config;
+}
+
+void ScattererConfiguration::print() {
+	int ies = (use_external_sphere)? 1 : 0;
+	int max_ici = 0;
+	printf("### CONFIGURATION DATA ###\n");
+	printf("NSPH  = %d\n", number_of_spheres);
+	printf("ROS   = [");
+	for (int i = 0; i < number_of_spheres; i++) printf("\t%lg", radii_of_spheres[i]);
+	printf("\t]\n");
+	printf("IOG   = [");
+	for (int i = 0; i < number_of_spheres; i++) printf("\t%d", iog_vec[i]);
+	printf("\t]\n");
+	printf("NSHL  = [");
+	for (int i = 0; i < number_of_spheres; i++) printf("\t%d", nshl_vec[i]);
+	printf("\t]\n");
+	printf("RCF   = [\n");
+	for (int i = 1; i <= number_of_spheres; i++) {
+		int nsh = nshl_vec[i - 1];
+	    if (i == 1) nsh += ies;
+	    if (max_ici < (nsh + 1) / 2) max_ici = (nsh + 1) / 2;
+		printf("         [");
+	    for (int ns = 0; ns < nsh; ns++) {
+	    	printf("\t%lg", rcf[i - 1][ns]);
+	    }
+	    printf("\t]\n");
+	}
+	printf("        ]\n");
+	printf("SCALE = %s\n", reference_variable_name.c_str());
+	printf("NXI   = %d\n", number_of_scales);
+	printf("VEC   = [");
+	for (int i = 0; i < number_of_scales; i++) printf("\t%lg", scale_vec[i]);
+	printf("\t]\n");
+	printf("DC0M  = [\n");
+	for (int i = 0; i < max_ici; i++) {
+		printf("         [\n");
+	    for (int j = 0; j < number_of_spheres; j++) {
+			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]\n");
+	    }
+	    printf("         ]\n");
+	}
+	printf("        ]\n");
+}
+
+void ScattererConfiguration::write_binary(string file_name, string mode) {
+	const double two_pi = acos(0.0) * 4.0;
+	const double evc = 6.5821188e-16;
+	int max_ici = 0;
+	if (mode.compare("LEGACY") == 0) { // Legacy mode was chosen.
+		fstream output;
+		int ies = (use_external_sphere)? 1 : 0;
+		double *xi_vec;
+		if (reference_variable_name.compare("XIV") == 0) xi_vec = scale_vec;
+		else {
+			xi_vec = new double[number_of_scales];
+			if (reference_variable_name.compare("WNS") == 0) {
+				for (int i = 0; i < number_of_scales; i++)
+					xi_vec[i] = 3.0e8 * scale_vec[i] / wp;
+			} else if (reference_variable_name.compare("WLS") == 0) {
+				for (int i = 0; i < number_of_scales; i++) {
+					double wn = two_pi / scale_vec[i];
+					xi_vec[i] = 3.0e8 * wn / wp;
+				}
+			} else if (reference_variable_name.compare("PUS") == 0) {
+				for (int i = 0; i < number_of_scales; i++)
+					xi_vec[i] = scale_vec[i] / wp;
+			} else if (reference_variable_name.compare("EVS") == 0) {
+				for (int i = 0; i < number_of_scales; i++) {
+					double pu = scale_vec[i] / evc;
+					xi_vec[i] = pu / wp;
+				}
+			} else {
+				throw UnrecognizedConfigurationException(
+						"Wrong parameter set: unrecognized scale type "
+						+ reference_variable_name
+				);
+			}
+		}
+		output.open(file_name.c_str(), ios::out | ios::binary);
+		output.write(reinterpret_cast<char *>(&number_of_spheres), sizeof(int));
+		for (int i = 0; i < number_of_spheres; i++)
+			output.write(reinterpret_cast<char *>(&(iog_vec[i])), sizeof(int));
+		output.write(reinterpret_cast<char *>(&exdc), sizeof(double));
+		output.write(reinterpret_cast<char *>(&wp), sizeof(double));
+		output.write(reinterpret_cast<char *>(&xip), sizeof(double));
+		output.write(reinterpret_cast<char *>(&idfc), sizeof(int));
+		output.write(reinterpret_cast<char *>(&number_of_scales), sizeof(int));
+		for (int i = 0; i < number_of_scales; i++)
+			output.write(reinterpret_cast<char *>(&(xi_vec[i])), sizeof(double));
+		for (int i115 = 1; i115 <= number_of_spheres; i115++) {
+			if (iog_vec[i115 - 1] < i115) continue;
+			output.write(reinterpret_cast<char *>(&(nshl_vec[i115 - 1])), sizeof(int));
+			output.write(reinterpret_cast<char *>(&(radii_of_spheres[i115 - 1])), sizeof(double));
+			int nsh = nshl_vec[i115 - 1];
+			if (i115 == 1) nsh += ies;
+			if (max_ici < (nsh + 1) / 2) max_ici = (nsh + 1) / 2;
+			for (int nsi = 0; nsi < nsh; nsi++)
+				output.write(reinterpret_cast<char *>(&(rcf[i115 - 1][nsi])), sizeof(double));
+		}
+		for (int jxi468 = 1; jxi468 <= number_of_scales; jxi468++) {
+			if (idfc != 0 && jxi468 > 1) continue;
+		    for (int i162 = 1; i162 <= number_of_spheres; i162++) {
+		    	if (iog_vec[i162 - 1] < i162) continue;
+		    	int nsh = nshl_vec[i162 - 1];
+		    	int ici = (nsh + 1) / 2; // QUESTION: is integer division really intended here?
+		    	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();
+		    		// 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.
+		    		output.write(reinterpret_cast<char *>(&dc0_real), sizeof(double));
+		    		output.write(reinterpret_cast<char *>(&dc0_img), sizeof(double));
+		    	}
+		    }
+		}
+		output.close();
+	}
+}
+
+void ScattererConfiguration::write_formatted(string file_name) {
+	const double evc = 6.5821188e-16;
+	const double two_pi = acos(0.0) * 4.0;
+	double *xi_vec;
+	int ici;
+	int ies = (use_external_sphere)? 1: 0;
+	FILE *output = fopen(file_name.c_str(), "w");
+	int scale_type = -1;
+	if (reference_variable_name.compare("XIV") == 0) scale_type = 0;
+	else if (reference_variable_name.compare("WNS") == 0) scale_type = 1;
+	else if (reference_variable_name.compare("WLS") == 0) scale_type = 2;
+	else if (reference_variable_name.compare("PUS") == 0) scale_type = 3;
+	else if (reference_variable_name.compare("EVS") == 0) scale_type = 4;
+	if (idfc >= 0) { // Dielectric functions are constant or they depend on XI
+		double  *pu_vec, *ev_vec, *wn_vec, *wl_vec;
+	    xi_vec = new double[number_of_scales];
+	    pu_vec = new double[number_of_scales];
+	    ev_vec = new double[number_of_scales];
+	    wn_vec = new double[number_of_scales];
+	    wl_vec = new double[number_of_scales];
+		switch (scale_type) {
+		case 0:
+			fprintf(output, "  JXI     XIV          WNS          WLS          PUS          EVS\n");
+			for (int i = 0; i < number_of_scales; i++) {
+				xi_vec[i] = scale_vec[i];
+				pu_vec[i] = xi_vec[i] * wp;
+				ev_vec[i] = pu_vec[i] * evc;
+				wn_vec[i] = pu_vec[i] / 3.0e8;
+				wl_vec[i] = two_pi / wn_vec[i];
+				fprintf(
+						output,
+						"%5d %13.4lE %13.4lE %13.4lE %13.4lE %13.4lE\n",
+						(i + 1),
+						xi_vec[i],
+						wn_vec[i],
+						wl_vec[i],
+						pu_vec[i],
+						ev_vec[i]
+				);
+			}
+			break;
+		case 1:
+			fprintf(output, "  JXI     WNS          WLS          PUS          EVS          XIV\n");
+			for (int i = 0; i < number_of_scales; i++) {
+				wn_vec[i] = scale_vec[i];
+				wl_vec[i] = two_pi / wn_vec[i];
+				xi_vec[i] = 3.0e8 * wn_vec[i] / wp;
+				pu_vec[i] = xi_vec[i] * wp;
+				ev_vec[i] = pu_vec[i] * evc;
+				fprintf(
+						output,
+						"%5d %13.4lE %13.4lE %13.4lE %13.4lE %13.4lE\n",
+						(i + 1),
+						wn_vec[i],
+						wl_vec[i],
+						pu_vec[i],
+						ev_vec[i],
+						xi_vec[i]
+				);
+			}
+			break;
+		case 2:
+			fprintf(output, "  JXI     WLS          WNS          PUS          EVS          XIV\n");
+			for (int i = 0; i < number_of_scales; i++) {
+				wl_vec[i] = scale_vec[i];
+				wn_vec[i] = two_pi / wl_vec[i];
+				xi_vec[i] = 3.0e8 * wn_vec[i] / wp;
+				pu_vec[i] = xi_vec[i] * wp;
+				ev_vec[i] = pu_vec[i] * evc;
+				fprintf(
+						output,
+						"%5d %13.4lE %13.4lE %13.4lE %13.4lE %13.4lE\n",
+						(i + 1),
+						wl_vec[i],
+						wn_vec[i],
+						pu_vec[i],
+						ev_vec[i],
+						xi_vec[i]
+				);
+			}
+			break;
+		case 3:
+			fprintf(output, "  JXI     PUS          WNS          WLS          EVS          XIV\n");
+			for (int i = 0; i < number_of_scales; i++) {
+				pu_vec[i] = scale_vec[i];
+				xi_vec[i] = pu_vec[i] / wp;
+				wn_vec[i] = pu_vec[i] / 3.0e8;
+				wl_vec[i] = two_pi / wn_vec[i];
+				ev_vec[i] = pu_vec[i] * evc;
+				fprintf(
+						output,
+						"%5d %13.4lE %13.4lE %13.4lE %13.4lE %13.4lE\n",
+						(i + 1),
+						pu_vec[i],
+						wn_vec[i],
+						wl_vec[i],
+						ev_vec[i],
+						xi_vec[i]
+				);
+			}
+			break;
+		case 4:
+			fprintf(output, "  JXI     EVS          WNS          WLS          PUS          XIV\n");
+			for (int i = 0; i < number_of_scales; i++) {
+				ev_vec[i] = scale_vec[i];
+				pu_vec[i] = ev_vec[i] / evc;
+				xi_vec[i] = pu_vec[i] / wp;
+				wn_vec[i] = pu_vec[i] / 3.0e8;
+				wl_vec[i] = two_pi / wn_vec[i];
+				fprintf(
+						output,
+						"%5d %13.4lE %13.4lE %13.4lE %13.4lE %13.4lE\n",
+						(i + 1),
+						ev_vec[i],
+						wn_vec[i],
+						wl_vec[i],
+						pu_vec[i],
+						xi_vec[i]
+				);
+			}
+			break;
+		default:
+			throw UnrecognizedConfigurationException(
+					"Wonrg parameter set: unrecognized scale variable type "
+					+ reference_variable_name
+			);
+			break;
+		}
+	} else { // idfc < 0, Dielectric functions are at XIP and XI is scale for dimensions
+		double pu, wn;
+		xi_vec = scale_vec;
+		pu = xip * wp;
+		wn = pu / 3.0e8;
+		fprintf(output, "          XIP          WN           WL           PU           EV\n");
+		fprintf(output, "     %13.4lE", xip);
+		fprintf(output, "%13.4lE", wn);
+		fprintf(output, "%13.4lE", two_pi / wn);
+		fprintf(output, "%13.4lE", pu);
+		fprintf(output, "%13.4lE\n", pu * evc);
+		fprintf(output, "  SCALE FACTORS XI\n");
+		for (int i = 0; i < number_of_scales; i++)
+			fprintf(output, "%5d%13.4lE\n", (i + 1), xi_vec[i]);
+	}
+	if (idfc != 0) {
+		fprintf(output, "  DIELECTRIC CONSTANTS\n");
+	    for (int i473 = 1; i473 <= number_of_spheres; i473++) {
+	    	if (iog_vec[i473 - 1] != i473) continue;
+	    	ici = (nshl_vec[i473 - 1] + 1) / 2;
+	    	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();
+	    		fprintf(output, "%5d %12.4lE%12.4lE\n", (ic472 + 1), dc0_real, dc0_img);
+	    	}
+	    }
+	  } else {
+		  fprintf(output, "  DIELECTRIC FUNCTIONS\n");
+		  for (int i478 = 1; i478 <= number_of_spheres; i478++) {
+			  if (iog_vec[i478 - 1] != i478) continue;
+			  ici = (nshl_vec[i478 - 1] + 1) / 2;
+			  if (i478 == 1) ici += ies;
+			  fprintf(output, " SPHERE N. %4d\n", i478);
+			  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();
+					  fprintf(output, "%5d (%12.4lE,%12.4lE)\n", (jxi476 + 1), dc0_real, dc0_img);
+				  }
+			  }
+		  }
+	  }
+	fclose(output);
+}
diff --git a/src/libnptm/Parsers.cpp b/src/libnptm/Parsers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a327df810c95b58e3c0e94cfe207f104d482a5bd
--- /dev/null
+++ b/src/libnptm/Parsers.cpp
@@ -0,0 +1,26 @@
+/*! \file Parsers.cpp
+ */
+
+#include <fstream>
+#include <string>
+#include "../include/List.h"
+#include "../include/Parsers.h"
+
+std::string *load_file(std::string file_name, int *count = 0) {
+  std::fstream input_file(file_name.c_str(), std::ios::in);
+  List<std::string> file_lines = List<std::string>();
+  std::string line;
+  if (input_file.is_open()) {
+    getline(input_file, line);
+    file_lines.set(0, line);
+    while (getline(input_file, line)) {
+      file_lines.append(line);
+    }
+    input_file.close();
+  } else {
+	  throw FILE_NOT_FOUND_ERROR;
+  }
+  std::string *array_lines = file_lines.to_array();
+  if (count != 0) *count = file_lines.length();
+  return array_lines;
+}
diff --git a/src/np_sphere.cpp b/src/np_sphere.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac985ac4e8b292acd06534aad948586a61d39880
--- /dev/null
+++ b/src/np_sphere.cpp
@@ -0,0 +1,23 @@
+/*! \file np_sphere.cpp
+ */
+
+#include <cstdio>
+#include <string>
+#include "include/Configuration.h"
+
+using namespace std;
+
+extern void sphere();
+
+/*! \brief Main program entry point.
+ *
+ * This is the starting point of the execution flow. Here we may choose
+ * how to configure the code, e.g. by loading a legacy configuration file
+ * or some otherwise formatted configuration data set. The code can be
+ * linked to a luncher script or to a GUI oriented application that performs
+ * the configuration and runs the main program.
+ */
+int main(int argc, char **argv) {
+	sphere();
+	return 0;
+}
diff --git a/src/sphere/Makefile b/src/sphere/Makefile
index 41d1d3342ed431507d63447b539fe3813fb2d827..c42d9b04f701cfb823a0c443581c96c23207d920 100644
--- a/src/sphere/Makefile
+++ b/src/sphere/Makefile
@@ -2,8 +2,11 @@ BUILDDIR=../../build/sphere
 FC=gfortran
 FCFLAGS=-std=legacy -O3
 LFLAGS=
+CXX=g++
+CXXFLAGS=-O0 -ggdb -pg -coverage
+CXXLFLAGS=
 
-all: edfb sph
+all: edfb sph np_sphere
 
 edfb: edfb.o
 	$(FC) $(FCFLAGS) -o $(BUILDDIR)/edfb $(BUILDDIR)/edfb.o $(LFLAGS)
@@ -11,6 +14,24 @@ edfb: edfb.o
 sph: sph.o
 	$(FC) $(FCFLAGS) -o $(BUILDDIR)/sph $(BUILDDIR)/sph.o $(LFLAGS)
 
+np_sphere: $(BUILDDIR)/np_sphere.o $(BUILDDIR)/Commons.o $(BUILDDIR)/Configuration.o $(BUILDDIR)/Parsers.o $(BUILDDIR)/sphere.o
+	$(CXX) $(CXXFLAGS) $(CXXLFLAGS) -o $(BUILDDIR)/np_sphere $(BUILDDIR)/np_sphere.o $(BUILDDIR)/Commons.o $(BUILDDIR)/Configuration.o $(BUILDDIR)/Parsers.o $(BUILDDIR)/sphere.o
+
+$(BUILDDIR)/np_sphere.o:
+	$(CXX) $(CXXFLAGS) -c ../np_sphere.cpp -o $(BUILDDIR)/np_sphere.o
+
+$(BUILDDIR)/Commons.o:
+	$(CXX) $(CXXFLAGS) -c ../libnptm/Commons.cpp -o $(BUILDDIR)/Commons.o
+
+$(BUILDDIR)/Configuration.o:
+	$(CXX) $(CXXFLAGS) -c ../libnptm/Configuration.cpp -o $(BUILDDIR)/Configuration.o
+
+$(BUILDDIR)/Parsers.o:
+	$(CXX) $(CXXFLAGS) -c ../libnptm/Parsers.cpp -o $(BUILDDIR)/Parsers.o
+
+$(BUILDDIR)/sphere.o:
+	$(CXX) $(CXXFLAGS) -c sphere.cpp -o $(BUILDDIR)/sphere.o
+
 clean:
 	rm -f $(BUILDDIR)/*.o
 
diff --git a/src/sphere/sph.f b/src/sphere/sph.f
index 5eb62c2fa02e53689cd6a79063d48c98c026a1de..bebacd746a8dac1c960f0c6eb409db89425a3b75 100644
--- a/src/sphere/sph.f
+++ b/src/sphere/sph.f
@@ -83,9 +83,9 @@ CCC   DIMENSION DC0M(NSPH,NSHL-NTL),XIV(NXI)
  6991 FORMAT('========== JXI =',I3,' ====================')
  6992 FORMAT('********** JTH =',I3,', JPH =',I3,
      1', JTHS =',I3,', JPHS =',I3,' ********************')
-      IR=5
-      IW=6
-      IT=7
+      IR=25
+      IW=26
+      IT=27
       ITIN=17
 CCC
 CCC   OTHER COMMENTS IN FILE GLOBALCOMS
@@ -270,6 +270,7 @@ C
 
       CS0=0.25D0*VK*VK*VK/PIGH
       CALL SSCR0(TFSAS,NSPH,LM,VK,EXRI)
+      PRINT *,"DEBUG: TFSAS =", TFSAS
       SQK=VK*VK*EXDC
       CALL APS(ZPV,LM,NSPH,IOG,RMI,REI,SQK,GAPS)
       CALL RABAS(INPOL,LM,NSPH,IOG,RMI,REI,TQSE,TQSPE,TQSS,TQSPS)
@@ -455,11 +456,19 @@ CCC  1TQSE(2,NSPH),TQSPE(2,NSPH),TQSS(2,NSPH),TQSPS(2,NSPH)
       TQSPE(2,I)=TQSPE(2,I)*PIG2
       TQSPS(1,I)=TQSPS(1,I)*PIG2
       TQSPS(2,I)=TQSPS(2,I)*PIG2
+      PRINT *,"DEBUG: TQSPE(1,",I,") =",TQSPE(1,I)
+      PRINT *,"DEBUG: TQSPE(2,",I,") =",TQSPE(2,I)
+      PRINT *,"DEBUG: TQSPS(1,",I,") =",TQSPS(1,I)
+      PRINT *,"DEBUG: TQSPS(2,",I,") =",TQSPS(2,I)
       GO TO 80
    75 TQSE(1,I)=TQSE(1,I)*PIG2
       TQSE(2,I)=TQSE(2,I)*PIG2
       TQSS(1,I)=TQSS(1,I)*PIG2
       TQSS(2,I)=TQSS(2,I)*PIG2
+      PRINT *,"DEBUG: TQSE(1,",I,") =",TQSE(1,I)
+      PRINT *,"DEBUG: TQSE(2,",I,") =",TQSE(2,I)
+      PRINT *,"DEBUG: TQSS(1,",I,") =",TQSS(1,I)
+      PRINT *,"DEBUG: TQSS(2,",I,") =",TQSS(2,I)
    80 CONTINUE
       RETURN
       END
@@ -575,6 +584,7 @@ CCC  1TQSE(2,NSPH),TQSPE(2,NSPH),TQSS(2,NSPH),TQSPS(2,NSPH)
       PIGFSQ=6.4D+1*DACOS(C0)**2
       CFSQ=4.0D0/(PIGFSQ*CCS*CCS)
       NLMM=LM*(LM+2)
+C     PRINT *,"DEBUG: in SSCR2 W(1,1) =",W(1,1)
       DO 14 I=1,NSPH
       IOGI=IOG(I)
       IF(IOGI.LT.I)GO TO 14
@@ -586,14 +596,30 @@ CCC  1TQSE(2,NSPH),TQSPE(2,NSPH),TQSS(2,NSPH),TQSPS(2,NSPH)
       DO 10 L=1,LM
       RM=1.0D0/RMI(L,I)
       RE=1.0D0/REI(L,I)
+C     PRINT *,"DEBUG: RM =",RM
+C     PRINT *,"DEBUG: RE =",RE
       LTPO=L+L+1
       DO 10 IM=1,LTPO
       K=K+1
       KE=K+NLMM
+C     PRINT *,"DEBUG: W(",K,",3) =",W(K,3)
+C     PRINT *,"DEBUG: W(",K,",1) =",W(K,1)
+C     PRINT *,"DEBUG: W(",KE,",3) =",W(KE,3)
+C     PRINT *,"DEBUG: W(",KE,",1) =",W(KE,1)
       S11=S11-W(K,3)*W(K,1)*RM-W(KE,3)*W(KE,1)*RE
+C     PRINT *,"DEBUG: S11 =",S11
+C     PRINT *,"DEBUG: W(",K,",4) =",W(K,4)
+C     PRINT *,"DEBUG: W(",KE,",4) =",W(KE,4)
       S21=S21-W(K,4)*W(K,1)*RM-W(KE,4)*W(KE,1)*RE
+C     PRINT *,"DEBUG: W(",K,",2) =",W(K,2)
+C     PRINT *,"DEBUG: W(",KE,",2) =",W(KE,2)
       S12=S12-W(K,3)*W(K,2)*RM-W(KE,3)*W(KE,2)*RE
    10 S22=S22-W(K,4)*W(K,2)*RM-W(KE,4)*W(KE,2)*RE
+C     PRINT *,"DEBUG: CSAM =",CSAM
+C     PRINT *,"DEBUG: S11 =",S11
+C     PRINT *,"DEBUG: S21 =",S21
+C     PRINT *,"DEBUG: S12 =",S12
+C     PRINT *,"DEBUG: S22 =",S22
       SAS(I,1,1)=S11*CSAM
       SAS(I,2,1)=S21*CSAM
       SAS(I,1,2)=S12*CSAM
@@ -644,6 +670,7 @@ CCC  1RMI(LI,NSPH),REI(LI,NSPH),GAPS(NSPH)
      1CG1(LMPML,0,L,1)*(SUMM+SUME+SUEM+SUEE))*COFL
    30 CONTINUE
       GAPS(I)=DREAL(SUM)*COFS
+      PRINT *,"DEBUG: GAPS(",I,") =",GAPS(I)
    40 CONTINUE
       RETURN
       END
@@ -664,6 +691,11 @@ CCC   DIMENSION ZPV(LM,3,2,2)
       ZP=-1.0D0/DSQRT(XD)
       ZPV(L,2,1,2)=ZP
       ZPV(L,2,2,1)=ZP
+      IF(ZP.EQ.C0) GOTO 15
+C      PRINT 9010,L-1,ZP
+C      PRINT 9011,L-1,ZP
+ 9010 FORMAT("DEBUG: zpv[",I1,"][1][0][1] = ",E15.3)
+ 9011 FORMAT("DEBUG: zpv[",I1,"][1][1][0] = ",E15.3)
    15 CONTINUE
       IF(LM.EQ.1)GO TO 30
       DO 20 L=2,LM
@@ -672,6 +704,11 @@ CCC   DIMENSION ZPV(LM,3,2,2)
       ZP=DSQRT(XN/XD)
       ZPV(L,1,1,1)=ZP
       ZPV(L,1,2,2)=ZP
+      IF(ZP.EQ.C0) GOTO 20
+C      PRINT 9012,L-1,ZP
+C      PRINT 9013,L-1,ZP
+ 9012 FORMAT("DEBUG: zpv[",I1,"][0][0][0] = ",E15.3)
+ 9013 FORMAT("DEBUG: zpv[",I1,"][0][1][1] = ",E15.3)
    20 CONTINUE
       LMMO=LM-1
       DO 25 L=1,LMMO
@@ -680,6 +717,11 @@ CCC   DIMENSION ZPV(LM,3,2,2)
       ZP=-DSQRT(XN/XD)
       ZPV(L,3,1,1)=ZP
       ZPV(L,3,2,2)=ZP
+      IF(ZP.EQ.C0) GOTO 25
+C      PRINT 9014,L-1,ZP
+C      PRINT 9015,L-1,ZP
+ 9014 FORMAT("DEBUG: zpv[",I1,"][2][0][0] = ",E15.3)
+ 9015 FORMAT("DEBUG: zpv[",I1,"][2][1][1] = ",E15.3)
    25 CONTINUE
    30 CONTINUE
       RETURN
@@ -739,6 +781,10 @@ CCC   CG1(LMPML,MU,L,M)=CLGO(1,LMP,L;MU,M-MU,M)
       SINT=DSIN(TH)
       COSP=DCOS(PH)
       SINP=DSIN(PH)
+C     PRINT *,"DEBUG: cost =",COST
+C     PRINT *,"DEBUG: sint =",SINT
+C     PRINT *,"DEBUG: cosp =",COSP
+C     PRINT *,"DEBUG: sinp =",SINP
       U(1)=COSP*SINT
       U(2)=SINP*SINT
       U(3)=COST
@@ -781,7 +827,9 @@ CCC   NSPEF=1 CALLING WITH IDOT=0, NSPEF=NSPH OTHERWISE
    55 IF(IIS.NE.2)GO TO 65
       DO 60 N=1,NSPH
    60 ARG(N)=-ARG(N)
-   65 CALL SPHAR(COST,SINT,COSP,SINP,LM,YLM)
+ 65   CALL SPHAR(COST,SINT,COSP,SINP,LM,YLM)
+C     PRINT *,"DEBUG: in WMAMP and calling PWMA with lm =",LM,
+C    1"and iis =",IIS
       CALL PWMA(UP,UN,YLM,INPOL,LM,IIS)
       RETURN
       END
@@ -879,10 +927,12 @@ CCC   NSPEF=1 CALLING WITH IDOT=0, NSPEF=NSPH OTHERWISE
       GO TO 60
    55 ARGS(N)=-COSTS*RZZ(N)
    60 CONTINUE
-   75 CALL SPHAR(COST,SINT,COSP,SINP,LM,YLM)
+ 75   CALL SPHAR(COST,SINT,COSP,SINP,LM,YLM)
+C     PRINT *,"DEBUG: in WMASP and calling PWMA"
       CALL PWMA(UP,UN,YLM,INPOL,LM,ISQ)
       IF(IBF.LT.0)RETURN
       CALL SPHAR(COSTS,SINTS,COSPS,SINPS,LM,YLM)
+C     PRINT *,"DEBUG: in WMASP and calling PWMA with IBF =",IBF
       CALL PWMA(UPS,UNS,YLM,INPOL,LM,2)
       RETURN
       END
@@ -913,6 +963,7 @@ CCC   DIMENSION YLM(NLWM+2)
       CM2=.5D0*DCMPLX(UN(1),UN(2))
       CP2=.5D0*DCMPLX(UN(1),-UN(2))
       CZ2=UN(3)
+C     PRINT *,"DEBUG: in PWMA YLM(2) =",YLM(2)
       DO 20 L=1,LW
       LF=L+1
       LFTL=LF*L
@@ -929,26 +980,35 @@ CCC   DIMENSION YLM(NLWM+2)
       CM=DSQRT(X)
       CZ=M
       W(K,ISPO)=DCONJG(CP1*CP*YLM(K+2)+CM1*CM*YLM(K)+CZ1*CZ*YLM(K+1))*CL
-   20 W(K,ISPT)=DCONJG(CP2*CP*YLM(K+2)+CM2*CM*YLM(K)+CZ2*CZ*YLM(K+1))*CL
+C     IF(ISPO.EQ.1)PRINT *,"DEBUG: W(",K,",",ISPO,") =",W(K,ISPO)
+ 20   W(K,ISPT)=DCONJG(CP2*CP*YLM(K+2)+CM2*CM*YLM(K)+CZ2*CZ*YLM(K+1))*CL
+C 20  PRINT *,"DEBUG: W(",K,",",ISPT,") =",W(K,ISPT)
       DO 30 K=1,NLWM
       I=K+NLWM
       W(I,ISPO)=UIM*W(K,ISPT)
-   30 W(I,ISPT)=-UIM*W(K,ISPO)
+C     PRINT *,"DEBUG: W(",I,",",ISPO,") =",W(I,ISPO)
+ 30   W(I,ISPT)=-UIM*W(K,ISPO)
+C 30  PRINT *,"DEBUG: W(",I,",",ISPT,") =",W(I,ISPT)
       IF(INPOL.EQ.0)GO TO 42
       DO 40 K=1,NLWM
       I=K+NLWM
       C1=(W(K,ISPO)+UIM*W(K,ISPT))*SQRTWI
       C2=(W(K,ISPO)-UIM*W(K,ISPT))*SQRTWI
       W(K,ISPO)=C2
+C     PRINT *,"DEBUG: W(",K,",",ISPO,") =",W(K,ISPO)
       W(I,ISPO)=-C2
+C     PRINT *,"DEBUG: W(",I,",",ISPO,") =",W(I,ISPO)
       W(K,ISPT)=C1
-   40 W(I,ISPT)=C1
+C     PRINT *,"DEBUG: W(",K,",",ISPT,") =",W(K,ISPT)
+ 40   W(I,ISPT)=C1
+C 40  PRINT *,"DEBUG: W(",I,",",ISPT,") =",W(I,ISPT)
    42 IF(ISQ.EQ.0)RETURN
       DO 50 I=1,2
       IPT=I+2
       IPIS=I+IS
       DO 50 K=1,NLWMT
-   50 W(K,IPT)=DCONJG(W(K,IPIS))
+ 50   W(K,IPT)=DCONJG(W(K,IPIS))
+C 50  PRINT *,"DEBUG: W(",K,",",IPT,") =",W(K,IPT)
       RETURN
       END
       SUBROUTINE ORUNVE(U1,U2,U3,IORTH,TORTH)
@@ -1026,7 +1086,7 @@ CCC  2RMF(LI),DRMF(LI),REF(LI),DREF(LI)
       RETURN
    42 DO 43 J=1,LIPT
       FB(J)=RFJ(J)
-   43 FN(J)=RFN(J)
+ 43   FN(J)=RFN(J)
       IF(NSH.GT.1)GO TO 65
       CRI=DC0(1)/EXDC
       DO 60 L=1,LI
@@ -1041,7 +1101,9 @@ CCC  2RMF(LI),DRMF(LI),REF(LI),DREF(LI)
       CCNC=FBI(LPO)*DFB
       CCND=FB(LPO)*DFBI
       RMI(L,I)=1.0D0+UIM*(CCNA-CCNB)/(CCNC-CCND)
-   60 REI(L,I)=1.0D0+UIM*(CRI*CCNA-CCNB)/(CRI*CCNC-CCND)
+C     PRINT *,"DEBUG: gone 60, RMI(",L,",",I,") =",RMI(L,I)
+ 60   REI(L,I)=1.0D0+UIM*(CRI*CCNA-CCNB)/(CRI*CCNC-CCND)
+C 60  PRINT *,"DEBUG: gone 60, REI(",L,",",I,") =",REI(L,I)
       RETURN
    65 DO 80 L=1,LI
       LPO=L+1
@@ -1076,6 +1138,7 @@ cccccccccccccccccccccc
    80 DREF(L)=DY2*SZ+Y2
       CRI=(1.0D0,0.0D0)
       IF(MOD(NSH,2).NE.0)CRI=DC0(IC)/EXDC
+C     PRINT *,"DEBUG: going 90, AREX =",AREX
       DO 90 L=1,LI
       LPO=L+1
       LTPO=LPO+L
@@ -1087,11 +1150,13 @@ cccccccccccccccccccccc
       CCNC=RMF(L)*DFB
       CCND=DRMF(L)*FB(LPO)*SZ*LTPO
       RMI(L,I)=1.0D0+UIM*(CCNA-CCNB)/(CCNC-CCND)
+C      PRINT *,"DEBUG: gone 90, RMI(",L,",",I,") =",RMI(L,I)
       CCNA=REF(L)*DFN
       CCNB=DREF(L)*FN(LPO)*SZ*LTPO
       CCNC=REF(L)*DFB
       CCND=DREF(L)*FB(LPO)*SZ*LTPO
-   90 REI(L,I)=1.0D0+UIM*(CRI*CCNA-CCNB)/(CRI*CCNC-CCND)
+ 90   REI(L,I)=1.0D0+UIM*(CRI*CCNA-CCNB)/(CRI*CCNC-CCND)
+C 90  PRINT *,"DEBUG: gone 90, REI(",L,",",I,") =",REI(L,I)
       RETURN
       END
       SUBROUTINE RKT(NPNTMO,STEP,X,LPO,Y1,Y2,DY1,DY2)
@@ -1433,13 +1498,18 @@ CCC   LL=LM
       PI4=DACOS(0.0D0)*8.0D0
       PI4IRS=1.0D0/DSQRT(PI4)
       X=COSRTH
+C     PRINT *,"DEBUG: X =",X
       Y=DABS(SINRTH)
+C     PRINT *,"DEBUG: Y =",Y
       CLLMO=3.0D0
       CLL=1.5D0
       YTOL=Y
       PLEGN(1)=1.0D0
+C     PRINT *,"DEBUG: PLEGN( 1 ) =",PLEGN(1)
       PLEGN(2)=X*DSQRT(CLLMO)
+C     PRINT *,"DEBUG: PLEGN( 2 ) =",PLEGN(2)
       PLEGN(3)=YTOL*DSQRT(CLL)
+C     PRINT *,"DEBUG: PLEGN( 3 ) =",PLEGN(3)
       SINRMP(1)=SINRPH
       COSRMP(1)=COSRPH
       IF(LL.LT.2)GO TO 30
@@ -1457,16 +1527,19 @@ CCC   LL=LM
       CD=LS
       CNM=LTPO*(LMO+M)*(L-MPO)
       CDM=(LTMO-2)*LS
-   10 PLEGN(MPOPK)=PLEGN(MPOPK-L)*X*DSQRT(CN/CD)-
+ 10   PLEGN(MPOPK)=PLEGN(MPOPK-L)*X*DSQRT(CN/CD)-
      1PLEGN(MPOPK-LTMO)*DSQRT(CNM/CDM)
+C10   PRINT *,"DEBUG: PLEGN(",MPOPK,") =",PLEGN(MPOPK)
       LPK=L+K
       CLTPO=LTPO
       PLEGN(LPK)=PLEGN(K)*X*DSQRT(CLTPO)
+C     PRINT *,"DEBUG: PLEGN(",LPK,") =",PLEGN(LPK)
       K=LPK+1
       CLT=LTPO-1
       CLL=CLL*(CLTPO/CLT)
       YTOL=YTOL*Y
       PLEGN(K)=YTOL*DSQRT(CLL)
+C     PRINT *,"DEBUG: PLEGN(",K,") =",PLEGN(K)
       SINRMP(L)=SINRPH*COSRMP(LMO)+COSRPH*SINRMP(LMO)
    20 COSRMP(L)=COSRPH*COSRMP(LMO)-SINRPH*SINRMP(LMO)
    30 L=0
@@ -1475,14 +1548,17 @@ CCC   LL=LM
       L0Y=K+1
       L0P=K/2+1
       YLM(L0Y)=PI4IRS*PLEGN(L0P)
+C     PRINT *, "DEBUG: YLM(",L0Y,") =",YLM(L0Y)
       GO TO 45
    44 LMP=L0P+M
       SAVE=PI4IRS*PLEGN(LMP)
       LMY=L0Y+M
       YLM(LMY)=SAVE*DCMPLX(COSRMP(M),SINRMP(M))
       IF(MOD(M,2).NE.0)YLM(LMY)=-YLM(LMY)
+C     PRINT *, "DEBUG: YLM(",LMY,") =",YLM(LMY)
       LMY=L0Y-M
       YLM(LMY)=SAVE*DCMPLX(COSRMP(M),-SINRMP(M))
+C     PRINT *, "DEBUG: YLM(",LMY,") =",YLM(LMY)
  45   IF(M.GE.L)GO TO 47
       M=M+1
       GO TO 44
diff --git a/src/sphere/sphere.cpp b/src/sphere/sphere.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5d92b19255106177f5dc30201704280ecc4a3e90
--- /dev/null
+++ b/src/sphere/sphere.cpp
@@ -0,0 +1,558 @@
+#include <cstdio>
+#include <fstream>
+#include <string>
+#include <complex>
+#include "../include/Configuration.h"
+#include "../include/sph_subs.h"
+
+using namespace std;
+
+//! \brief C++ implementation of SPH
+void sphere() {
+	complex<double> arg, s0, tfsas;
+	complex<double> **tqspe, **tqsps;
+	double **tqse, **tqss;
+	double *argi, *args, *gaps;
+	double th, ph;
+	printf("INFO: making legacy configuration ...\n");
+	ScattererConfiguration *conf = ScattererConfiguration::from_dedfb("../../test_data/sphere/DEDFB");
+	conf->write_formatted("c_OEDFB");
+	conf->write_binary("c_TEDF");
+	delete conf;
+	printf("INFO: reading binary configuration ...\n");
+	ScattererConfiguration *sconf = ScattererConfiguration::from_binary("c_TEDF");
+	GeometryConfiguration *gconf = GeometryConfiguration::from_legacy("../../test_data/sphere/DSPH");
+	if (sconf->number_of_spheres == gconf->number_of_spheres) {
+		int isq, ibf;
+		double cost, sint, cosp, sinp;
+		double costs, sints, cosps, sinps;
+		double scan;
+		double *duk = new double[3];
+		double *u = new double[3];
+		double *us = new double[3];
+		double *un = new double[3];
+		double *uns = new double[3];
+		double *up = new double[3];
+		double *ups = new double[3];
+		double *upmp = new double[3];
+		double *upsmp = new double[3];
+		double *unmp = new double[3];
+		double *unsmp = new double[3];
+		double **cmul = new double*[4];
+		double **cmullr = new double*[4];
+		for (int i = 0; i < 4; i++) {
+			cmul[i] = new double[4];
+			cmullr[i] = new double[4];
+		}
+		double frx = 0.0, fry = 0.0, frz = 0.0;
+		double cfmp, cfsp, sfmp, sfsp;
+		complex<double> *vint = new complex<double>[16];
+		int jw;
+		int nsph = gconf->number_of_spheres;
+		C1 *c1 = new C1(nsph, gconf->l_max);
+		for (int i = 0; i < nsph; i++) {
+			c1->iog[i] = sconf->iog_vec[i];
+			c1->nshl[i] = sconf->nshl_vec[i];
+			c1->ros[i] = sconf->radii_of_spheres[i];
+		}
+		for (int i = 0; i < gconf->l_max; i++) {
+			c1->rmi[i][0] = complex<double>(0.0, 0.0);
+			c1->rmi[i][1] = complex<double>(0.0, 0.0);
+			c1->rei[i][0] = complex<double>(0.0, 0.0);
+			c1->rei[i][1] = complex<double>(0.0, 0.0);
+		}
+		C2 *c2 = new C2(nsph, 5, gconf->npnt, gconf->npntts);
+		argi = new double[1];
+		args = new double[1];
+		gaps = new double[2];
+		FILE *output = fopen("c_OSPH", "w");
+		fprintf(output, " READ(IR,*)NSPH,LM,INPOL,NPNT,NPNTTS,ISAM\n");
+		fprintf(
+				output,
+				" %5d%5d%5d%5d%5d%5d\n",
+				gconf->number_of_spheres,
+				gconf->l_max,
+				gconf->in_pol,
+				gconf->npnt,
+				gconf->npntts,
+				gconf->meridional_type
+		);
+		fprintf(output, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n");
+		fprintf(
+				output,
+				"  %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE\n",
+				gconf->in_theta_start,
+				gconf->in_theta_step,
+				gconf->in_theta_end,
+				gconf->sc_theta_start,
+				gconf->sc_theta_step,
+				gconf->sc_theta_end
+		);
+		fprintf(output, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n");
+		fprintf(
+				output,
+				"  %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE %9.3lE\n",
+				gconf->in_phi_start,
+				gconf->in_phi_step,
+				gconf->in_phi_end,
+				gconf->sc_phi_start,
+				gconf->sc_phi_step,
+				gconf->sc_phi_end
+		);
+		fprintf(output, " READ(IR,*)JWTM\n");
+		fprintf(
+				output,
+				" %5d\n",
+				gconf->jwtm
+		);
+		fprintf(output, "  READ(ITIN)NSPHT\n");
+		fprintf(output, "  READ(ITIN)(IOG(I),I=1,NSPH)\n");
+		fprintf(output, "  READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n");
+		fprintf(output, "  READ(ITIN)(XIV(I),I=1,NXI)\n");
+		fprintf(output, "  READ(ITIN)NSHL(I),ROS(I)\n");
+		fprintf(output, "  READ(ITIN)(RCF(I,NS),NS=1,NSH)\n \n");
+		double sml = 1.0e-3;
+		int nth = 0, nph = 0;
+		if (gconf->in_theta_step != 0.0)
+			nth = int((gconf->in_theta_end - gconf->in_theta_start) / gconf->in_theta_step + sml);
+		nth += 1;
+		if (gconf->in_phi_step != 0.0)
+			nph = int((gconf->in_phi_end - gconf->in_phi_start) / gconf->in_phi_step + sml);
+		nph += 1;
+		int nths = 0, nphs = 0;
+		double thsca;
+		if (gconf->meridional_type > 1) { // ISAM > 1, fixed scattering angle
+			nths = 1;
+			thsca = gconf->sc_theta_start - gconf->in_theta_start;
+		} else { //ISAM <= 1
+			if (gconf->in_theta_step != 0.0)
+				nths = int((gconf->sc_theta_end - gconf->sc_theta_start) / gconf->sc_theta_step + sml);
+			nths += 1;
+			if (gconf->meridional_type == 1) { // ISAM = 1
+				nphs = 1;
+			} else { // ISAM < 1
+				if (gconf->sc_phi_step != 0.0)
+					nphs = int((gconf->sc_phi_end - gconf->sc_phi_start) / gconf->sc_phi_step + sml);
+				nphs += 1;
+			}
+		}
+		int nk = nth * nph;
+		int nks = nths * nphs;
+		int nkks = nk * nks;
+		double th1 = gconf->in_theta_start;
+		double ph1 = gconf->in_phi_start;
+		double ths1 = gconf->sc_theta_start;
+		double phs1 = gconf->sc_phi_start;
+		const double half_pi = acos(0.0);
+		const double pi = 2.0 * half_pi;
+		double gcs = 0.0;
+		for (int i116 = 1; i116 <= nsph; i116++) {
+			int iogi = c1->iog[i116 - 1];
+			if (iogi >= i116) {
+				double gcss = pi * c1->ros[i116 - 1] * c1->ros[i116 - 1];
+				c1->gcsv[i116 - 1] = gcss;
+				int nsh = c1->nshl[i116 - 1];
+				for (int j115 = 1; j115 <= nsh; j115++) {
+					c1->rc[i116 - 1][j115 - 1] = sconf->rcf[i116 - 1][j115 - 1] * c1->ros[i116 - 1];
+				}
+			}
+			gcs += c1->gcsv[iogi - 1];
+		}
+		double ****zpv = new double***[gconf->l_max]; //[gconf->l_max][3][2][2]; // Matrix: dim[LM x 3 x 2 x 2]
+		for (int zi = 0; zi < gconf->l_max; zi++) {
+			zpv[zi] = new double**[3];
+			for (int zj = 0; zj < 3; zj++) {
+				zpv[zi][zj] = new double*[2];
+				for (int zk = 0; zk < 2; zk++) {
+					zpv[zi][zj][zk] = new double[2];
+				}
+			}
+		}
+		thdps(gconf->l_max, zpv);
+		double exri = sqrt(sconf->exdc);
+		fprintf(output, "  REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri);
+		fstream tppoan;
+		tppoan.open("c_TPPOAN", ios::binary|ios::out);
+		if (tppoan.is_open()) {
+			int imode = 10;
+			tppoan.write(reinterpret_cast<char *>(&imode), sizeof(int));
+			tppoan.write(reinterpret_cast<char *>(&(gconf->meridional_type)), sizeof(int));
+			tppoan.write(reinterpret_cast<char *>(&(gconf->in_pol)), sizeof(int));
+			tppoan.write(reinterpret_cast<char *>(&(sconf->number_of_scales)), sizeof(int));
+			tppoan.write(reinterpret_cast<char *>(&nth), sizeof(int));
+			tppoan.write(reinterpret_cast<char *>(&nph), sizeof(int));
+			tppoan.write(reinterpret_cast<char *>(&nths), sizeof(int));
+			tppoan.write(reinterpret_cast<char *>(&nphs), sizeof(int));
+
+			for (int nsi = 0; nsi < nsph; nsi++)
+				tppoan.write(reinterpret_cast<char *>(&(sconf->iog_vec[nsi])), sizeof(int));
+			if (gconf->in_pol == 0) fprintf(output, "   LIN\n");
+			else fprintf(output, "  CIRC\n");
+			fprintf(output, " \n");
+			double wn = sconf->wp / 3.0e8;
+			double sqsfi = 1.0;
+			double vk, vkarg;
+			if (sconf->idfc < 0) {
+				vk = sconf->xip * wn;
+				fprintf(output, "  VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n", vk);
+				fprintf(output, " \n");
+			}
+			for (int jxi488 = 1; jxi488 <= sconf->number_of_scales; jxi488++) {
+				fprintf(output, "========== JXI =%3d ====================\n", jxi488);
+				double xi = sconf->scale_vec[jxi488 - 1];
+				if (sconf->idfc >= 0) {
+					vk = xi * wn;
+					vkarg = vk;
+					fprintf(output, "  VK=%15.7lE, XI=%15.7lE\n", xi, vk);
+				} else { // IDFC < 0
+					vkarg = xi * vk;
+					sqsfi = 1.0 / (xi * xi);
+					fprintf(output, "  XI=%15.7lE\n", xi);
+				}
+				tppoan.write(reinterpret_cast<char *>(&vk), sizeof(double));
+				for (int i132 = 1; i132 <= nsph; i132++) {
+					int iogi = sconf->iog_vec[i132 - 1];
+					if (iogi != i132) {
+						for (int l123 = 1; l123 <= gconf->l_max; l123++) {
+							c1->rmi[l123 - 1][i132 - 1] = c1->rmi[l123 - 1][iogi - 1];
+							c1->rei[l123 - 1][i132 - 1] = c1->rei[l123 - 1][iogi - 1];
+						}
+						continue; // i132
+					}
+					int nsh = sconf->nshl_vec[i132 - 1];
+					int ici = (nsh + 1) / 2;
+					if (sconf->idfc == 0) {
+						for (int ic = 0; ic < ici; ic++)
+							c2->dc0[ic] = sconf->dc0_matrix[ic][i132 - 1][0]; // WARNING: IDFC=0 is not tested!
+					} else { // IDFC != 0
+						if (jxi488 == 1) {
+							for (int ic = 0; ic < ici; ic++) {
+								c2->dc0[ic] = sconf->dc0_matrix[ic][i132 - 1][jxi488 - 1];
+							}
+						}
+					}
+					if (nsh % 2 == 0) c2->dc0[ici] = sconf->exdc;
+					int jer = 0;
+					int lcalc = 0;
+					dme(
+							gconf->l_max, i132, gconf->npnt, gconf->npntts, vkarg,
+							sconf->exdc, exri, c1, c2, jer, lcalc, arg
+					);
+					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());
+						tppoan.close();
+						fclose(output);
+						return;
+					}
+				} // i132
+				if (sconf->idfc >= 0 and nsph == 1 and jxi488 == gconf->jwtm) {
+					// This is the condition that writes the transition matrix to output.
+					int is = 1111;
+					fstream ttms;
+					ttms.open("c_TTMS", ios::binary | ios::out);
+					if (ttms.is_open()) {
+						ttms.write(reinterpret_cast<char *>(&is), sizeof(int));
+						ttms.write(reinterpret_cast<char *>(&(gconf->l_max)), sizeof(int));
+						ttms.write(reinterpret_cast<char *>(&vk), sizeof(double));
+						ttms.write(reinterpret_cast<char *>(&exri), sizeof(double));
+						for (int lmi = 0; lmi < gconf->l_max; lmi++) {
+							complex<double> element1 = -1.0 / c1->rmi[0][lmi];
+							complex<double> element2 = -1.0 / c1->rei[0][lmi];
+							ttms.write(reinterpret_cast<char *>(&element1), sizeof(complex<double>));
+							ttms.write(reinterpret_cast<char *>(&element2), sizeof(complex<double>));
+						}
+						ttms.write(reinterpret_cast<char *>(&(sconf->radii_of_spheres[0])), sizeof(double));
+						ttms.close();
+					} else { // Failed to open output file. Should never happen.
+						printf("ERROR: could not open TTMS file.\n");
+						tppoan.close();
+						fclose(output);
+					}
+				}
+				double cs0 = 0.25 * vk * vk * vk / half_pi;
+				//printf("DEBUG: cs0 = %lE\n", cs0);
+				sscr0(tfsas, nsph, gconf->l_max, vk, exri, c1);
+				printf("DEBUG: TFSAS = (%lE,%lE)\n", tfsas.real(), tfsas.imag());
+				double sqk = vk * vk * sconf->exdc;
+				aps(zpv, gconf->l_max, nsph, c1, sqk, gaps);
+				tqse = new double*[2];
+				tqss = new double*[2];
+				tqspe = new std::complex<double>*[2];
+				tqsps = new std::complex<double>*[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];
+				}
+				rabas(gconf->in_pol, gconf->l_max, nsph, c1, tqse, tqspe, tqss, tqsps);
+				for (int i170 = 1; i170 <= nsph; i170++) {
+					if (c1->iog[i170 - 1] >= i170) {
+						double albeds = c1->sscs[i170 - 1] / c1->sexs[i170 - 1];
+						c1->sqscs[i170 - 1] *= sqsfi;
+						c1->sqabs[i170 - 1] *= sqsfi;
+						c1->sqexs[i170 - 1] *= sqsfi;
+						fprintf(output, "     SPHERE %2d\n", i170);
+						if (c1->nshl[i170 - 1] != 1) {
+							fprintf(output, "  SIZE=%15.7lE\n", c2->vsz[i170 - 1]);
+						} else {
+							fprintf(
+									output,
+									"  SIZE=%15.7lE, REFRACTIVE INDEX=(%15.7lE,%15.7lE)\n",
+									c2->vsz[i170 -1],
+									c2->vkt[i170 - 1].real(),
+									c2->vkt[i170 - 1].imag()
+							);
+						}
+						fprintf(output, " ----- SCS ----- ABS ----- EXS ----- ALBEDS --\n");
+						fprintf(
+								output,
+								" %14.7lE%15.7lE%15.7lE%15.7lE\n",
+								c1->sscs[i170 - 1], c1->sabs[i170 - 1],
+								c1->sexs[i170 - 1], albeds
+						);
+						fprintf(output, " ---- SCS/GS -- ABS/GS -- EXS/GS ---\n");
+						fprintf(
+								output,
+								" %14.7lE%15.7lE%15.7lE\n",
+								c1->sqscs[i170 - 1], c1->sqabs[i170 - 1],
+								c1->sqexs[i170 - 1]
+						);
+						fprintf(output, "  FSAS=%15.7lE%15.7lE\n", c1->fsas[i170 - 1].real(), c1->fsas[i170 - 1].imag());
+						double csch = 2.0 * vk * sqsfi / c1->gcsv[i170 -1];
+						//printf("DEBUG: csch = %lE\n", csch);
+						s0 = c1->fsas[i170 - 1] * exri;
+						//printf("DEBUG: s0 = (%lE,%lE)\n", s0.real(), s0.imag());
+						double qschu = csch * s0.imag();
+						//printf("DEBUG: qschu = %lE\n", qschu);
+						double pschu = csch * s0.real();
+						//printf("DEBUG: pschu = %lE\n", pschu);
+						double s0mag = cs0 * sqrt((s0.real() + s0.imag()) * (s0.real() - s0.imag()));
+						//printf("DEBUG: s0mag = %lE\n", s0mag);
+						fprintf(
+								output,
+								"  QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n",
+								qschu, pschu, s0mag
+						);
+						double rapr = c1->sexs[i170 - 1] - gaps[i170 - 1];
+						double cosav = gaps[i170 - 1] / c1->sscs[i170 - 1];
+						fprintf(output, "  COSAV=%15.7lE, RAPRS=%15.7lE\n", cosav, rapr);
+						fprintf(output, "  IPO=%2d, TQEk=%15.7lE, TQSk=%15.7lE\n", 1, tqse[0][i170 - 1], tqss[0][i170 - 1]);
+						fprintf(output, "  IPO=%2d, TQEk=%15.7lE, TQSk=%15.7lE\n", 2, tqse[1][i170 - 1], tqss[1][i170 - 1]);
+						tppoan.write(reinterpret_cast<char *>(&(tqse[0][i170 - 1])), sizeof(double));
+						tppoan.write(reinterpret_cast<char *>(&(tqss[0][i170 - 1])), sizeof(double));
+						double val = tqspe[0][i170 - 1].real();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+						val = tqspe[0][i170 - 1].imag();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+						val = tqsps[0][i170 - 1].real();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+						val = tqsps[0][i170 - 1].imag();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+						tppoan.write(reinterpret_cast<char *>(&(tqse[1][i170 - 1])), sizeof(double));
+						tppoan.write(reinterpret_cast<char *>(&(tqss[1][i170 - 1])), sizeof(double));
+						val = tqspe[1][i170 - 1].real();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+						val = tqspe[1][i170 - 1].imag();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+						val = tqsps[1][i170 - 1].real();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+						val = tqsps[1][i170 - 1].imag();
+						tppoan.write(reinterpret_cast<char *>(&val), sizeof(double));
+					} // End if iog[i170 - 1] >= i170
+				} // i170 loop
+				if (nsph != 1) {
+					fprintf(output, "  FSAT=(%15.7lE,%15.7lE)\n", tfsas.real(), tfsas.imag());
+					double csch = 2.0 * vk * sqsfi / gcs;
+					s0 = tfsas * exri;
+					double qschu = csch * s0.imag();
+					double pschu = csch * s0.real();
+					double s0mag = cs0 * sqrt((s0.real() + s0.imag()) * (s0.real() - s0.imag()));
+					fprintf(
+							output,
+							"  QSCHU=%15.7lE, PSCHU=%15.7lE, S0MAG=%15.7lE\n",
+							qschu, pschu, s0mag
+					);
+				}
+				th = th1;
+				for (int jth486 = 1; jth486 <= nth; jth486++) { // OpenMP parallelizable section
+					ph = ph1;
+					for (int jph484 = 1; jph484 <= nph; jph484++) {
+						bool goto182 = (nk == 1) && (jxi488 > 1);
+						if (!goto182) {
+							upvmp(th, ph, 0, cost, sint, cosp, sinp, u, upmp, unmp);
+						}
+						if (gconf->meridional_type >= 0) {
+							wmamp(0, cost, sint, cosp, sinp, gconf->in_pol, gconf->l_max, 0, nsph, argi, u, upmp, unmp, c1);
+							for (int i183 = 0; i183 < nsph; i183++) {
+								double rapr = c1->sexs[i183] - gaps[i183];
+								frx = rapr * u[0];
+								fry = rapr * u[1];
+								frz = rapr * u[2];
+							}
+							jw = 1;
+						}
+						double thsl = ths1;
+						double phsph = 0.0;
+						for (int jths482 = 1; jths482 <= nths; jths482++) {
+							double ths = thsl;
+							int icspnv = 0;
+							if (gconf->meridional_type > 1) ths = th + thsca;
+							if (gconf->meridional_type >= 1) {
+								phsph = 0.0;
+								if ((ths < 0.0) || (ths > 180.0)) phsph = 180.0;
+								if (ths < 0.0) ths *= -1.0;
+								if (ths > 180.0) ths = 360.0 - ths;
+								if (phsph != 0.0) icspnv = 1;
+							}
+							double phs = phs1;
+							for (int jphs480 = 1; jphs480 <= nphs; jphs480++) {
+								if (gconf->meridional_type >= 1) {
+									phs = ph + phsph;
+									if (phs >= 360.0) phs -= 360.0;
+								}
+								bool goto190 = (nks == 1) && ((jxi488 > 1) || (jth486 > 1) || (jph484 > 1));
+								if (!goto190) {
+									upvmp(ths, phs, icspnv, costs, sints, cosps, sinps, us, upsmp, unsmp);
+									if (gconf->meridional_type >= 0) {
+										wmamp(2, costs, sints, cosps, sinps, gconf->in_pol, gconf->l_max, 0, nsph, args, us, upsmp, unsmp, c1);
+									}
+								}
+								if (nkks != 0 || jxi488 == 1) {
+									upvsp(u, upmp, unmp, us, upsmp, unsmp, up, un, ups, uns, duk, isq, ibf, scan, cfmp, sfmp, cfsp, sfsp);
+									if (gconf->meridional_type < 0) {
+										wmasp(
+												cost, sint, cosp, sinp, costs, sints, cosps, sinps,
+												u, up, un, us, ups, uns, isq, ibf, gconf->in_pol,
+												gconf->l_max, 0, nsph, argi, args, c1
+										);
+									}
+									for (int i193 = 1; i193 <= 3; i193++) {
+										un[i193 - 1] = unmp[i193 - 1];
+										uns[i193 - 1] = unsmp[i193 - 1];
+									}
+								}
+								if (gconf->meridional_type < 0) jw = 1;
+								tppoan.write(reinterpret_cast<char *>(&th), sizeof(double));
+								tppoan.write(reinterpret_cast<char *>(&ph), sizeof(double));
+								tppoan.write(reinterpret_cast<char *>(&ths), sizeof(double));
+								tppoan.write(reinterpret_cast<char *>(&phs), sizeof(double));
+								tppoan.write(reinterpret_cast<char *>(&scan), sizeof(double));
+								if (jw != 0) {
+									jw = 0;
+									tppoan.write(reinterpret_cast<char *>(&(u[0])), sizeof(double));
+									tppoan.write(reinterpret_cast<char *>(&(u[1])), sizeof(double));
+									tppoan.write(reinterpret_cast<char *>(&(u[2])), sizeof(double));
+								}
+								fprintf(
+										output,
+										"********** JTH =%3d, JPH =%3d, JTHS =%3d, JPHS =%3d ********************\n",
+										jth486, jph484, jths482, jphs480
+								);
+								fprintf(
+										output,
+										"  TIDG=%10.3lE, PIDG=%10.3lE, TSDG=%10.3lE, PSDG=%10.3lE\n",
+										th, ph, ths, phs
+								);
+								fprintf(output, "  SCAND=%10.3lE\n", scan);
+								fprintf(output, "  CFMP=%15.7lE, SFMP=%15.7lE\n", cfmp, sfmp);
+								fprintf(output, "  CFSP=%15.7lE, SFSP=%15.7lE\n", cfsp, sfsp);
+								if (gconf->meridional_type >= 0) {
+									fprintf(output, "  UNI=(%12.5lE,%12.5lE,%12.5lE)\n", un[0], un[1], un[2]);
+									fprintf(output, "  UNS=(%12.5lE,%12.5lE,%12.5lE)\n", uns[0], uns[1], uns[2]);
+								} else {
+									fprintf(output, "  UN=(%12.5lE,%12.5lE,%12.5lE)\n", un[0], un[1], un[2]);
+								}
+								sscr2(nsph, gconf->l_max, vk, exri, c1);
+								for (int ns226 = 1; ns226 <= nsph; ns226++) {
+									fprintf(output, "     SPHERE %2d\n", ns226);
+									fprintf(
+											output, "  SAS(1,1)=%15.7lE%15.7lE, SAS(2,1)=%15.7lE%15.7lE\n",
+											c1->sas[ns226 - 1][0][0].real(), c1->sas[ns226 - 1][0][0].imag(),
+											c1->sas[ns226 - 1][1][0].real(), c1->sas[ns226 - 1][1][0].imag()
+									);
+									fprintf(
+											output, "  SAS(1,2)=%15.7lE%15.7lE, SAS(2,2)=%15.7lE%15.7lE\n",
+											c1->sas[ns226 - 1][0][1].real(), c1->sas[ns226 - 1][0][1].imag(),
+											c1->sas[ns226 - 1][1][1].real(), c1->sas[ns226 - 1][1][1].imag()
+									);
+									if (jths482 == 1 && jphs480 == 1)
+										fprintf(
+												output, "  Fx=%15.7lE, Fy=%15.7lE, Fz=%15.7lE\n",
+												frx, fry, frz
+										);
+									for (int i225 = 0; i225 < 16; i225++)
+										vint[i225] = c1->vints[ns226 - 1][i225];
+									mmulc(vint, cmullr, cmul);
+									fprintf(output, "  MULS\n        ");
+									for (int imul = 0; imul < 4; imul++) {
+										for (int jmul = 0; jmul < 4; jmul++) {
+											fprintf(output, "%15.7lE", cmul[imul][jmul]);
+										}
+										if (imul < 3) fprintf(output, "\n        ");
+										else fprintf(output, "\n");
+									}
+									fprintf(output, "  MULSLR\n        ");
+									for (int imul = 0; imul < 4; imul++) {
+										for (int jmul = 0; jmul < 4; jmul++) {
+											fprintf(output, "%15.7lE", cmullr[imul][jmul]);
+										}
+										if (imul < 3) fprintf(output, "\n        ");
+										else fprintf(output, "\n");
+									}
+									for (int vi = 0; vi < 16; vi++) {
+										double value = vint[vi].real();
+										tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
+										value = vint[vi].imag();
+										tppoan.write(reinterpret_cast<char *>(&value), sizeof(double));
+									}
+									for (int imul = 0; imul < 4; imul++) {
+										for (int jmul = 0; jmul < 4; jmul++) {
+											tppoan.write(reinterpret_cast<char *>(&(cmul[imul][jmul])), sizeof(double));
+										}
+									}
+								} // ns226 loop
+								if (gconf->meridional_type < 1) phs += gconf->sc_phi_step;
+							} // jphs480 loop
+							if (gconf->meridional_type <= 1) thsl += gconf->sc_theta_step;
+						} // jths482 loop
+						ph += gconf->in_phi_step;
+					} // jph484 loop on elevation
+					th += gconf->in_theta_step;
+				} // jth486 loop on azimuth
+			} //jxi488 loop on scales
+			tppoan.close();
+		} else { // In case TPPOAN could not be opened. Should never happen.
+			printf("ERROR: failed to open TPPOAN file.\n");
+		}
+		fclose(output);
+		delete c1;
+		delete c2;
+		delete[] duk;
+		delete[] u;
+		delete[] us;
+		delete[] un;
+		delete[] uns;
+		delete[] up;
+		delete[] ups;
+		delete[] upmp;
+		delete[] upsmp;
+		delete[] unmp;
+		delete[] unsmp;
+		delete[] vint;
+		delete[] argi;
+		delete[] args;
+		delete[] gaps;
+		for (int i = 0; i < 4; i++) {
+			delete[] cmul[i];
+			delete[] cmullr[i];
+		}
+		delete[] cmul;
+		delete[] cmullr;
+	} else { // NSPH mismatch between geometry and scatterer configurations.
+		throw UnrecognizedConfigurationException(
+				"Inconsistent geometry and scatterer configurations."
+		);
+	}
+}