/*****************************************************************************

    TRAVIS - Trajectory Analyzer and Visualizer

    http://www.travis-analyzer.de/

    Copyright (c) 2009-2026 Martin Brehm
                  2012-2017 Martin Thomas
                  2016-2020 Sascha Gehrke

    Please cite:  J. Chem. Phys. 2020, 152 (16), 164105.         (DOI 10.1063/5.0005078 )
                  J. Chem. Inf. Model. 2011, 51 (8), 2007-2023.  (DOI 10.1021/ci200217w )

    This file was written by Martin Thomas.

    ---------------------------------------------------------------------------

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*****************************************************************************/


// This must always be the first include directive
#include "config.h"

#include "structurefactor.h"

#include "globalvar.h"
#include "maintools.h"
#include "timestep.h"
#include "xobarray.h"
//>>>OMP
#ifdef USE_OMP
#include <omp.h>
#endif
//<<<OMP

const char *GetRevisionInfo_structurefactor(unsigned int len) {
	static char buf[256];
	GET_REVISION_INFO( buf, len );
	return buf;
}


const char *GetSourceVersion_structurefactor() {
	static char buf[256];
	GET_SOURCE_VERSION( buf );
	return buf;
}


#define BUF_SIZE 4096


static CxObArray g_oaSFacIsotopes;
static CxObArray g_oaSFacElements;
static CStructureFactor *g_structureFactor;
static CxObArray g_sFacObserv;



void AddSFacIsotope(
		const char *label,
		int iso,
		double Coh_b,    // bound coherent scattering length / fm
		double Inc_b,    // bound incoherent scattering length / fm
		double Coh_xs,   // bound coherent scattering cross section / barn
		double Inc_xs,   // bound incoherent scattering cross section / barn
		double Scatt_xs, // total bound scattering cross section / barn
		double Abs_xs    // absorption cross section for 2200 m/s neutrons / barn
	) {

	CSFacIsotope *isotope;

	try { isotope = new CSFacIsotope( (CSFacElement*)g_oaSFacElements[g_oaSFacElements.GetSize()-1], iso, label, Coh_b, Inc_b, Coh_xs, Inc_xs, Scatt_xs, Abs_xs ); } catch(...) { isotope = NULL; }
	if (isotope == NULL)
		NewException( (double)sizeof(CSFacIsotope), __FILE__, __LINE__, __PRETTY_FUNCTION__ );
	g_oaSFacIsotopes.Add( isotope );
	((CSFacElement*)g_oaSFacElements[g_oaSFacElements.GetSize()-1])->m_oaIsotopes.push_back( isotope );
}



void AddSFacElement(
		const char *label,
		int ord,
		double cma1, // Cromer-Mann X-Ray coefficients
		double cma2,
		double cma3,
		double cma4,
		double cmb1,
		double cmb2,
		double cmb3,
		double cmb4,
		double cmc
	) {

	CSFacElement *elem;

	try { elem = new CSFacElement( label, ord, cma1, cma2, cma3, cma4, cmb1, cmb2, cmb3, cmb4, cmc ); } catch(...) { elem = NULL; }
	if (elem == NULL)
		NewException( (double)sizeof(CSFacElement), __FILE__, __LINE__, __PRETTY_FUNCTION__ );
	g_oaSFacElements.Add( elem );
}



void createIsotopeList() {

	// Neutron factors from http://www.ncnr.nist.gov/resources/n-lengths/
	// X-Ray factors from http://www.ruppweb.org/new_comp/scattering_factors.htm

	AddSFacElement( "H", 1, 0.493, 0.323, 0.14, 0.041, 10.511, 26.126, 3.142, 57.8, 0.003 );
	AddSFacIsotope( "H", 0, -3.739, 0, 1.7568, 80.26, 82.02, 0.3326 );
	AddSFacIsotope( "1H", 1, -3.7406, 25.274, 1.7583, 80.27, 82.03, 0.3326 );
	AddSFacIsotope( "D", 2, 6.671, 4.04, 5.592, 2.05, 7.64, 0.000519 );
	AddSFacIsotope( "T", 3, 4.792, -1.04, 2.89, 0.14, 3.03, 0 );

	AddSFacElement( "He", 2, 0.873, 0.631, 0.311, 0.178, 9.104, 3.357, 22.928, 0.982, 0.006 );
	AddSFacIsotope( "He", 0, 3.263, 0, 1.34, 0, 1.34, 0.00747 );
	AddSFacIsotope( "3He", 3, 5.74, -2.5, 4.42, 1.6, 6, 5333 );
	AddSFacIsotope( "4He", 4, 3.26, 0, 1.34, 0, 1.34, 0 );

	AddSFacElement( "Li", 3, 1.128, 0.751, 0.618, 0.465, 3.955, 1.052, 85.391, 168.261, 0.038 );
	AddSFacIsotope( "Li", 0, -1.9, 0, 0.454, 0.92, 1.37, 70.5 );
	AddSFacIsotope( "6Li", 6, 2, -1.89, 0.51, 0.46, 0.97, 940 );
	AddSFacIsotope( "7Li", 7, -2.22, -2.49, 0.619, 0.78, 1.4, 0.0454 );

	AddSFacElement( "Be", 4, 1.592, 1.128, 0.539, 0.703, 43.643, 1.862, 103.483, 0.542, 0.038 );
	AddSFacIsotope( "Be", 0, 7.79, 0.12, 7.63, 0.0018, 7.63, 0.0076 );

	AddSFacElement( "B", 5, 2.055, 1.333, 1.098, 0.707, 23.219, 1.021, 60.35, 0.14, -0.193 );
	AddSFacIsotope( "B", 0, 5.3, 0, 3.54, 1.7, 5.24, 767 );
	AddSFacIsotope( "10B", 10, -0.1, -4.7, 0.144, 3, 3.1, 3835 );
	AddSFacIsotope( "11B", 11, 6.65, -1.3, 5.56, 0.21, 5.77, 0.0055 );

	AddSFacElement( "C", 6, 2.31, 1.02, 1.589, 0.865, 20.844, 10.208, 0.569, 51.651, 0.216 );
	AddSFacIsotope( "C", 0, 6.646, 0, 5.551, 0.001, 5.551, 0.0035 );
	AddSFacIsotope( "12C", 12, 6.6511, 0, 5.559, 0, 5.559, 0.00353 );
	AddSFacIsotope( "13C", 13, 6.19, -0.52, 4.81, 0.034, 4.84, 0.00137 );

	AddSFacElement( "N", 7, 12.213, 3.132, 2.013, 1.166, 0.006, 9.893, 28.997, 0.583, -11.529 );
	AddSFacIsotope( "N", 0, 9.36, 0, 11.01, 0.5, 11.51, 1.9 );
	AddSFacIsotope( "14N", 14, 9.37, 2, 11.03, 0.5, 11.53, 1.91 );
	AddSFacIsotope( "15N", 15, 6.44, -0.02, 5.21, 0.00005, 5.21, 0.000024 );

	AddSFacElement( "O", 8, 3.049, 2.287, 1.546, 0.867, 13.277, 5.701, 0.324, 32.909, 0.251 );
	AddSFacIsotope( "O", 0, 5.803, 0, 4.232, 0.0008, 4.232, 0.00019 );
	AddSFacIsotope( "16O", 16, 5.803, 0, 4.232, 0, 4.232, 0.0001 );
	AddSFacIsotope( "17O", 17, 5.78, 0.18, 4.2, 0.004, 4.2, 0.236 );
	AddSFacIsotope( "18O", 18, 5.84, 0, 4.29, 0, 4.29, 0.00016 );

	AddSFacElement( "F", 9, 3.539, 2.641, 1.517, 1.024, 10.283, 4.294, 0.262, 26.148, 0.278 );
	AddSFacIsotope( "F", 0, 5.654, -0.082, 4.017, 0.0008, 4.018, 0.0096 );

	AddSFacElement( "Ne", 10, 3.955, 3.112, 1.455, 1.125, 8.404, 3.426, 0.231, 21.718, 0.352 );
	AddSFacIsotope( "Ne", 0, 4.566, 0, 2.62, 0.008, 2.628, 0.039 );
	AddSFacIsotope( "20Ne", 20, 4.631, 0, 2.695, 0, 2.695, 0.036 );
	AddSFacIsotope( "21Ne", 21, 6.66, 0.6, 5.6, 0.05, 5.7, 0.67 );
	AddSFacIsotope( "22Ne", 22, 3.87, 0, 1.88, 0, 1.88, 0.046 );

	AddSFacElement( "Na", 11, 4.763, 3.174, 1.267, 1.113, 3.285, 8.842, 0.314, 129.424, 0.676 );
	AddSFacIsotope( "Na", 0, 3.63, 3.59, 1.66, 1.62, 3.28, 0.53 );

	AddSFacElement( "Mg", 12, 5.42, 2.174, 1.227, 2.307, 2.828, 79.261, 0.381, 7.194, 0.858 );
	AddSFacIsotope( "Mg", 0, 5.375, 0, 3.631, 0.08, 3.71, 0.063 );
	AddSFacIsotope( "24Mg", 24, 5.66, 0, 4.03, 0, 4.03, 0.05 );
	AddSFacIsotope( "25Mg", 25, 3.62, 1.48, 1.65, 0.28, 1.93, 0.19 );
	AddSFacIsotope( "26Mg", 26, 4.89, 0, 3, 0, 3, 0.0382 );

	AddSFacElement( "Al", 13, 6.42, 1.9, 1.594, 1.965, 3.039, 0.743, 31.547, 85.089, 1.115 );
	AddSFacIsotope( "Al", 0, 3.449, 0.256, 1.495, 0.0082, 1.503, 0.231 );

	AddSFacElement( "Si", 14, 6.292, 3.035, 1.989, 1.541, 2.439, 32.334, 0.678, 81.694, 1.141 );
	AddSFacIsotope( "Si", 0, 4.1491, 0, 2.163, 0.004, 2.167, 0.171 );
	AddSFacIsotope( "28Si", 28, 4.107, 0, 2.12, 0, 2.12, 0.177 );
	AddSFacIsotope( "29Si", 29, 4.7, 0.09, 2.78, 0.001, 2.78, 0.101 );
	AddSFacIsotope( "30Si", 30, 4.58, 0, 2.64, 0, 2.64, 0.107 );

	AddSFacElement( "P", 15, 6.435, 4.179, 1.78, 1.491, 1.907, 27.157, 0.526, 68.164, 1.115 );
	AddSFacIsotope( "P", 0, 5.13, 0.2, 3.307, 0.005, 3.312, 0.172 );

	AddSFacElement( "S", 16, 6.905, 5.203, 1.438, 1.586, 1.468, 22.215, 0.254, 56.172, 0.867 );
	AddSFacIsotope( "S", 0, 2.847, 0, 1.0186, 0.007, 1.026, 0.53 );
	AddSFacIsotope( "32S", 32, 2.804, 0, 0.988, 0, 0.988, 0.54 );
	AddSFacIsotope( "33S", 33, 4.74, 1.5, 2.8, 0.3, 3.1, 0.54 );
	AddSFacIsotope( "34S", 34, 3.48, 0, 1.52, 0, 1.52, 0.227 );
	AddSFacIsotope( "36S", 36, 3, 0, 1.1, 0, 1.1, 0.15 );

	AddSFacElement( "Cl", 17, 11.46, 7.196, 6.256, 1.645, 0.01, 1.166, 18.519, 47.778, -9.557 );
	AddSFacIsotope( "Cl", 0, 9.577, 0, 11.5257, 5.3, 16.8, 33.5 );
	AddSFacIsotope( "35Cl", 35, 11.65, 6.1, 17.06, 4.7, 21.8, 44.1 );
	AddSFacIsotope( "37Cl", 37, 3.08, 0.1, 1.19, 0.001, 1.19, 0.433 );

	AddSFacElement( "Ar", 18, 7.484, 6.772, 0.654, 1.644, 0.907, 14.841, 43.898, 33.393, 1.444 );
	AddSFacIsotope( "Ar", 0, 1.909, 0, 0.458, 0.225, 0.683, 0.675 );
	AddSFacIsotope( "36Ar", 36, 24.9, 0, 77.9, 0, 77.9, 5.2 );
	AddSFacIsotope( "38Ar", 38, 3.5, 0, 1.5, 0, 1.5, 0.8 );
	AddSFacIsotope( "40Ar", 40, 1.83, 0, 0.421, 0, 0.421, 0.66 );

	AddSFacElement( "K", 19, 8.219, 7.44, 1.052, 0.866, 12.795, 0.775, 213.187, 41.684, 1.423 );
	AddSFacIsotope( "K", 0, 3.67, 0, 1.69, 0.27, 1.96, 2.1 );
	AddSFacIsotope( "39K", 39, 3.74, 1.4, 1.76, 0.25, 2.01, 2.1 );
	AddSFacIsotope( "40K", 40, 3, 0, 1.1, 0.5, 1.6, 35 );
	AddSFacIsotope( "41K", 41, 2.69, 1.5, 0.91, 0.3, 1.2, 1.46 );

	AddSFacElement( "Ca", 20, 8.627, 7.387, 1.59, 1.021, 10.442, 0.66, 85.748, 178.437, 1.375 );
	AddSFacIsotope( "Ca", 0, 4.7, 0, 2.78, 0.05, 2.83, 0.43 );
	AddSFacIsotope( "40Ca", 40, 4.8, 0, 2.9, 0, 2.9, 0.41 );
	AddSFacIsotope( "42Ca", 42, 3.36, 0, 1.42, 0, 1.42, 0.68 );
	AddSFacIsotope( "43Ca", 43, -1.56, 0, 0.31, 0.5, 0.8, 6.2 );
	AddSFacIsotope( "44Ca", 44, 1.42, 0, 0.25, 0, 0.25, 0.88 );
	AddSFacIsotope( "46Ca", 46, 3.6, 0, 1.6, 0, 1.6, 0.74 );
	AddSFacIsotope( "48Ca", 48, 0.39, 0, 0.019, 0, 0.019, 1.09 );

	AddSFacElement( "Sc", 21, 9.189, 7.368, 1.641, 1.468, 9.021, 0.573, 136.108, 51.353, 1.333 );
	AddSFacIsotope( "Sc", 0, 12.29, -6, 19, 4.5, 23.5, 27.5 );

	AddSFacElement( "Ti", 22, 9.759, 7.356, 1.699, 1.902, 7.851, 0.5, 35.634, 116.105, 1.281 );
	AddSFacIsotope( "Ti", 0, -3.438, 0, 1.485, 2.87, 4.35, 6.09 );
	AddSFacIsotope( "46Ti", 46, 4.93, 0, 3.05, 0, 3.05, 0.59 );
	AddSFacIsotope( "47Ti", 47, 3.63, -3.5, 1.66, 1.5, 3.2, 1.7 );
	AddSFacIsotope( "48Ti", 48, -6.08, 0, 4.65, 0, 4.65, 7.84 );
	AddSFacIsotope( "49Ti", 49, 1.04, 5.1, 0.14, 3.3, 3.4, 2.2 );
	AddSFacIsotope( "50Ti", 50, 6.18, 0, 4.8, 0, 4.8, 0.179 );

	AddSFacElement( "V", 23, 10.297, 7.351, 2.07, 2.057, 6.866, 0.438, 26.894, 102.478, 1.22 );
	AddSFacIsotope( "V", 0, -0.3824, 0, 0.0184, 5.08, 5.1, 5.08 );
	AddSFacIsotope( "50V", 50, 7.6, 0, 7.3, 0.5, 7.8, 60 );
	AddSFacIsotope( "51V", 51, -0.402, 6.35, 0.0203, 5.07, 5.09, 4.9 );

	AddSFacElement( "Cr", 24, 10.641, 7.354, 3.324, 1.492, 6.104, 0.392, 20.263, 98.74, 1.183 );
	AddSFacIsotope( "Cr", 0, 3.635, 0, 1.66, 1.83, 3.49, 3.05 );
	AddSFacIsotope( "50Cr", 50, -4.5, 0, 2.54, 0, 2.54, 15.8 );
	AddSFacIsotope( "52Cr", 52, 4.92, 0, 3.042, 0, 3.042, 0.76 );
	AddSFacIsotope( "53Cr", 53, -4.2, 6.87, 2.22, 5.93, 8.15, 18.1 );
	AddSFacIsotope( "54Cr", 54, 4.55, 0, 2.6, 0, 2.6, 0.36 );

	AddSFacElement( "Mn", 25, 11.282, 7.357, 3.019, 2.244, 5.341, 0.343, 17.867, 83.754, 1.09 );
	AddSFacIsotope( "Mn", 0, -3.73, 1.79, 1.75, 0.4, 2.15, 13.3 );

	AddSFacElement( "Fe", 26, 11.769, 7.357, 3.522, 2.305, 4.761, 0.307, 15.354, 76.881, 1.037 );
	AddSFacIsotope( "Fe", 0, 9.45, 0, 11.22, 0.4, 11.62, 2.56 );
	AddSFacIsotope( "54Fe", 54, 4.2, 0, 2.2, 0, 2.2, 2.25 );
	AddSFacIsotope( "56Fe", 56, 9.94, 0, 12.42, 0, 12.42, 2.59 );
	AddSFacIsotope( "57Fe", 57, 2.3, 0, 0.66, 0.3, 1, 2.48 );
	AddSFacIsotope( "58Fe", 58, 15, 0, 28, 0, 28, 1.28 );

	AddSFacElement( "Co", 27, 12.284, 7.341, 4.003, 2.349, 4.279, 0.278, 13.536, 71.169, 1.012 );
	AddSFacIsotope( "Co", 0, 2.49, -6.2, 0.779, 4.8, 5.6, 37.18 );

	AddSFacElement( "Ni", 28, 12.838, 7.292, 4.444, 2.38, 3.878, 0.257, 12.176, 66.342, 1.034 );
	AddSFacIsotope( "Ni", 0, 10.3, 0, 13.3, 5.2, 18.5, 4.49 );
	AddSFacIsotope( "58Ni", 58, 14.4, 0, 26.1, 0, 26.1, 4.6 );
	AddSFacIsotope( "60Ni", 60, 2.8, 0, 0.99, 0, 0.99, 2.9 );
	AddSFacIsotope( "61Ni", 61, 7.6, 3.9, 7.26, 1.9, 9.2, 2.5 );
	AddSFacIsotope( "62Ni", 62, -8.7, 0, 9.5, 0, 9.5, 14.5 );
	AddSFacIsotope( "64Ni", 64, -0.37, 0, 0.017, 0, 0.017, 1.52 );

	AddSFacElement( "Cu", 29, 13.338, 7.168, 5.616, 1.673, 3.583, 0.247, 11.397, 64.813, 1.191 );
	AddSFacIsotope( "Cu", 0, 7.718, 0, 7.485, 0.55, 8.03, 3.78 );
	AddSFacIsotope( "63Cu", 63, 6.43, 0.22, 5.2, 0.006, 5.2, 4.5 );
	AddSFacIsotope( "65Cu", 65, 10.61, 1.79, 14.1, 0.4, 14.5, 2.17 );

	AddSFacElement( "Zn", 30, 14.074, 7.032, 5.165, 2.41, 3.266, 0.233, 10.316, 58.71, 1.304 );
	AddSFacIsotope( "Zn", 0, 5.68, 0, 4.054, 0.077, 4.131, 1.11 );
	AddSFacIsotope( "64Zn", 64, 5.22, 0, 3.42, 0, 3.42, 0.93 );
	AddSFacIsotope( "66Zn", 66, 5.97, 0, 4.48, 0, 4.48, 0.62 );
	AddSFacIsotope( "67Zn", 67, 7.56, -1.5, 7.18, 0.28, 7.46, 6.8 );
	AddSFacIsotope( "68Zn", 68, 6.03, 0, 4.57, 0, 4.57, 1.1 );
	AddSFacIsotope( "70Zn", 70, 6, 0, 4.5, 0, 4.5, 0.092 );

	AddSFacElement( "Ga", 31, 15.235, 6.701, 4.359, 2.962, 3.067, 0.241, 10.781, 61.414, 1.719 );
	AddSFacIsotope( "Ga", 0, 7.288, 0, 6.675, 0.16, 6.83, 2.75 );
	AddSFacIsotope( "69Ga", 69, 7.88, -0.85, 7.8, 0.091, 7.89, 2.18 );
	AddSFacIsotope( "71Ga", 71, 6.4, -0.82, 5.15, 0.084, 5.23, 3.61 );

	AddSFacElement( "Ge", 32, 16.082, 6.375, 3.707, 3.683, 2.851, 0.252, 11.447, 54.763, 2.131 );
	AddSFacIsotope( "Ge", 0, 8.185, 0, 8.42, 0.18, 8.6, 2.2 );
	AddSFacIsotope( "70Ge", 70, 10, 0, 12.6, 0, 12.6, 3 );
	AddSFacIsotope( "72Ge", 72, 8.51, 0, 9.1, 0, 9.1, 0.8 );
	AddSFacIsotope( "73Ge", 73, 5.02, 3.4, 3.17, 1.5, 4.7, 15.1 );
	AddSFacIsotope( "74Ge", 74, 7.58, 0, 7.2, 0, 7.2, 0.4 );
	AddSFacIsotope( "76Ge", 76, 8.2, 0, 8, 0, 8, 0.16 );

	AddSFacElement( "As", 33, 16.672, 6.07, 3.431, 4.278, 2.635, 0.265, 12.948, 47.797, 2.531 );
	AddSFacIsotope( "As", 0, 6.58, -0.69, 5.44, 0.06, 5.5, 4.5 );

	AddSFacElement( "Se", 34, 17.001, 5.82, 3.973, 4.354, 2.41, 0.273, 15.237, 43.816, 2.841 );
	AddSFacIsotope( "Se", 0, 7.97, 0, 7.98, 0.32, 8.3, 11.7 );
	AddSFacIsotope( "74Se", 74, 0.8, 0, 0.1, 0, 0.1, 51.8 );
	AddSFacIsotope( "76Se", 76, 12.2, 0, 18.7, 0, 18.7, 85 );
	AddSFacIsotope( "77Se", 77, 8.25, 0.6, 8.6, 0.05, 8.65, 42 );
	AddSFacIsotope( "78Se", 78, 8.24, 0, 8.5, 0, 8.5, 0.43 );
	AddSFacIsotope( "80Se", 80, 7.48, 0, 7.03, 0, 7.03, 0.61 );
	AddSFacIsotope( "82Se", 82, 6.34, 0, 5.05, 0, 5.05, 0.044 );

	AddSFacElement( "Br", 35, 17.179, 5.236, 5.638, 3.985, 2.172, 16.58, 0.261, 41.433, 2.956 );
	AddSFacIsotope( "Br", 0, 6.795, 0, 5.8, 0.1, 5.9, 6.9 );
	AddSFacIsotope( "79Br", 79, 6.8, -1.1, 5.81, 0.15, 5.96, 11 );
	AddSFacIsotope( "81Br", 81, 6.79, 0.6, 5.79, 0.05, 5.84, 2.7 );

	AddSFacElement( "Kr", 36, 17.355, 6.729, 5.549, 3.537, 1.938, 16.562, 0.226, 39.397, 2.825 );
	AddSFacIsotope( "Kr", 0, 7.81, 0, 7.67, 0.01, 7.68, 25 );
	AddSFacIsotope( "78Kr", 78, 0, 0, 0, 0, 0, 6.4 );
	AddSFacIsotope( "80Kr", 80, 0, 0, 0, 0, 0, 11.8 );
	AddSFacIsotope( "82Kr", 82, 0, 0, 0, 0, 0, 29 );
	AddSFacIsotope( "83Kr", 83, 0, 0, 0, 0, 0, 185 );
	AddSFacIsotope( "84Kr", 84, 0, 0, 0, 0, 6.6, 0.113 );
	AddSFacIsotope( "86Kr", 86, 8.1, 0, 8.2, 0, 8.2, 0.003 );

	AddSFacElement( "Rb", 37, 17.178, 9.644, 5.14, 1.529, 1.789, 17.315, 0.275, 164.934, 3.487 );
	AddSFacIsotope( "Rb", 0, 7.09, 0, 6.32, 0.5, 6.8, 0.38 );
	AddSFacIsotope( "85Rb", 85, 7.03, 0, 6.2, 0.5, 6.7, 0.48 );
	AddSFacIsotope( "87Rb", 87, 7.23, 0, 6.6, 0.5, 7.1, 0.12 );

	AddSFacElement( "Sr", 38, 17.566, 9.818, 5.422, 2.669, 1.556, 14.099, 0.166, 132.376, 2.506 );
	AddSFacIsotope( "Sr", 0, 7.02, 0, 6.19, 0.06, 6.25, 1.28 );
	AddSFacIsotope( "84Sr", 84, 7, 0, 6, 0, 6, 0.87 );
	AddSFacIsotope( "86Sr", 86, 5.67, 0, 4.04, 0, 4.04, 1.04 );
	AddSFacIsotope( "87Sr", 87, 7.4, 0, 6.88, 0.5, 7.4, 16 );
	AddSFacIsotope( "88Sr", 88, 7.15, 0, 6.42, 0, 6.42, 0.058 );

	AddSFacElement( "Y", 39, 17.776, 10.295, 5.726, 3.266, 1.403, 12.801, 0.126, 104.354, 1.912 );
	AddSFacIsotope( "Y", 0, 7.75, 1.1, 7.55, 0.15, 7.7, 1.28 );

	AddSFacElement( "Zr", 40, 17.876, 10.948, 5.417, 3.657, 1.276, 11.916, 0.118, 87.663, 2.069 );
	AddSFacIsotope( "Zr", 0, 7.16, 0, 6.44, 0.02, 6.46, 0.185 );
	AddSFacIsotope( "90Zr", 90, 6.4, 0, 5.1, 0, 5.1, 0.011 );
	AddSFacIsotope( "91Zr", 91, 8.7, -1.08, 9.5, 0.15, 9.7, 1.17 );
	AddSFacIsotope( "92Zr", 92, 7.4, 0, 6.9, 0, 6.9, 0.22 );
	AddSFacIsotope( "94Zr", 94, 8.2, 0, 8.4, 0, 8.4, 0.0499 );
	AddSFacIsotope( "96Zr", 96, 5.5, 0, 3.8, 0, 3.8, 0.0229 );

	AddSFacElement( "Nb", 41, 17.614, 12.014, 4.042, 3.533, 1.189, 11.766, 0.205, 69.796, 3.756 );
	AddSFacIsotope( "Nb", 0, 7.054, -0.139, 6.253, 0.0024, 6.255, 1.15 );

	AddSFacElement( "Mo", 42, 3.703, 17.236, 12.888, 3.743, 0.277, 1.096, 11.004, 61.658, 4.387 );
	AddSFacIsotope( "Mo", 0, 6.715, 0, 5.67, 0.04, 5.71, 2.48 );
	AddSFacIsotope( "92Mo", 92, 6.91, 0, 6, 0, 6, 0.019 );
	AddSFacIsotope( "94Mo", 94, 6.8, 0, 5.81, 0, 5.81, 0.015 );
	AddSFacIsotope( "95Mo", 95, 6.91, 0, 6, 0.5, 6.5, 13.1 );
	AddSFacIsotope( "96Mo", 96, 6.2, 0, 4.83, 0, 4.83, 0.5 );
	AddSFacIsotope( "97Mo", 97, 7.24, 0, 6.59, 0.5, 7.1, 2.5 );
	AddSFacIsotope( "98Mo", 98, 6.58, 0, 5.44, 0, 5.44, 0.127 );
	AddSFacIsotope( "100Mo", 100, 6.73, 0, 5.69, 0, 5.69, 0.4 );

	AddSFacElement( "Tc", 43, 19.13, 11.095, 4.649, 2.713, 0.864, 8.145, 21.571, 86.847, 5.404 );
	AddSFacIsotope( "Tc", 0, 6.8, 0, 5.8, 0.5, 6.3, 20 );

	AddSFacElement( "Ru", 44, 19.267, 12.918, 4.863, 1.568, 0.809, 8.435, 24.8, 94.293, 5.379 );
	AddSFacIsotope( "Ru", 0, 7.03, 0, 6.21, 0.4, 6.6, 2.56 );
	AddSFacIsotope( "96Ru", 96, 0, 0, 0, 0, 0, 0.28 );
	AddSFacIsotope( "98Ru", 98, 0, 0, 0, 0, 0, 8 );
	AddSFacIsotope( "99Ru", 99, 0, 0, 0, 0, 0, 6.9 );
	AddSFacIsotope( "100Ru", 100, 0, 0, 0, 0, 0, 4.8 );
	AddSFacIsotope( "101Ru", 101, 0, 0, 0, 0, 0, 3.3 );
	AddSFacIsotope( "102Ru", 102, 0, 0, 0, 0, 144.8, 1.17 );
	AddSFacIsotope( "104Ru", 104, 0, 0, 0, 0, 4.483, 0.31 );

	AddSFacElement( "Rh", 45, 19.296, 14.35, 4.734, 1.289, 0.752, 8.218, 25.875, 98.606, 5.328 );
	AddSFacIsotope( "Rh", 0, 5.88, 0, 4.34, 0.3, 4.6, 144.8 );

	AddSFacElement( "Pd", 46, 19.332, 15.502, 5.295, 0.606, 0.699, 7.989, 25.205, 76.899, 5.266 );
	AddSFacIsotope( "Pd", 0, 5.91, 0, 4.39, 0.093, 4.48, 6.9 );
	AddSFacIsotope( "102Pd", 102, 7.77, 0, 7.5, 0, 7.5, 3.4 );
	AddSFacIsotope( "104Pd", 104, 7.77, 0, 7.5, 0, 7.5, 0.6 );
	AddSFacIsotope( "105Pd", 105, 5.5, -2.6, 3.8, 0.8, 4.6, 20 );
	AddSFacIsotope( "106Pd", 106, 6.4, 0, 5.1, 0, 5.1, 0.304 );
	AddSFacIsotope( "108Pd", 108, 4.1, 0, 2.1, 0, 2.1, 8.55 );
	AddSFacIsotope( "110Pd", 110, 7.77, 0, 7.5, 0, 7.5, 0.226 );

	AddSFacElement( "Ag", 47, 19.281, 16.688, 4.805, 1.046, 0.645, 7.473, 24.66, 99.816, 5.179 );
	AddSFacIsotope( "Ag", 0, 5.922, 0, 4.407, 0.58, 4.99, 63.3 );
	AddSFacIsotope( "107Ag", 107, 7.555, 1, 7.17, 0.13, 7.3, 37.6 );
	AddSFacIsotope( "109Ag", 109, 4.165, -1.6, 2.18, 0.32, 2.5, 91 );

	AddSFacElement( "Cd", 48, 19.221, 17.644, 4.461, 1.603, 0.595, 6.909, 24.701, 87.482, 5.069 );
	AddSFacIsotope( "Cd", 0, 4.87, 0, 3.04, 3.46, 6.5, 2520 );
	AddSFacIsotope( "106Cd", 106, 5, 0, 3.1, 0, 3.1, 1 );
	AddSFacIsotope( "108Cd", 108, 5.4, 0, 3.7, 0, 3.7, 1.1 );
	AddSFacIsotope( "110Cd", 110, 5.9, 0, 4.4, 0, 4.4, 11 );
	AddSFacIsotope( "111Cd", 111, 6.5, 0, 5.3, 0.3, 5.6, 24 );
	AddSFacIsotope( "112Cd", 112, 6.4, 0, 5.1, 0, 5.1, 2.2 );
	AddSFacIsotope( "113Cd", 113, -8, 0, 12.1, 0.3, 12.4, 20600 );
	AddSFacIsotope( "114Cd", 114, 7.5, 0, 7.1, 0, 7.1, 0.34 );
	AddSFacIsotope( "116Cd", 116, 6.3, 0, 5, 0, 5, 0.075 );

	AddSFacElement( "In", 49, 19.162, 18.56, 4.295, 2.04, 0.548, 6.378, 25.85, 92.803, 4.939 );
	AddSFacIsotope( "In", 0, 4.065, 0, 2.08, 0.54, 2.62, 193.8 );
	AddSFacIsotope( "113In", 113, 5.39, 0.017, 3.65, 0.000037, 3.65, 12 );
	AddSFacIsotope( "115In", 115, 4.01, -2.1, 2.02, 0.55, 2.57, 202 );

	AddSFacElement( "Sn", 50, 19.189, 19.101, 4.458, 2.466, 5.83, 0.503, 26.891, 83.957, 4.782 );
	AddSFacIsotope( "Sn", 0, 6.225, 0, 4.871, 0.022, 4.892, 0.626 );
	AddSFacIsotope( "112Sn", 112, 6, 0, 4.5, 0, 4.5, 1 );
	AddSFacIsotope( "114Sn", 114, 6.2, 0, 4.8, 0, 4.8, 0.114 );
	AddSFacIsotope( "115Sn", 115, 6, 0, 4.5, 0.3, 4.8, 30 );
	AddSFacIsotope( "116Sn", 116, 5.93, 0, 4.42, 0, 4.42, 0.14 );
	AddSFacIsotope( "117Sn", 117, 6.48, 0, 5.28, 0.3, 5.6, 2.3 );
	AddSFacIsotope( "118Sn", 118, 6.07, 0, 4.63, 0, 4.63, 0.22 );
	AddSFacIsotope( "119Sn", 119, 6.12, 0, 4.71, 0.3, 5, 2.2 );
	AddSFacIsotope( "120Sn", 120, 6.49, 0, 5.29, 0, 5.29, 0.14 );
	AddSFacIsotope( "122Sn", 122, 5.74, 0, 4.14, 0, 4.14, 0.18 );
	AddSFacIsotope( "124Sn", 124, 5.97, 0, 4.48, 0, 4.48, 0.133 );

	AddSFacElement( "Sb", 51, 19.642, 19.045, 5.037, 2.683, 5.303, 0.461, 27.907, 75.283, 4.591 );
	AddSFacIsotope( "Sb", 0, 5.57, 0, 3.9, 0.007, 3.9, 4.91 );
	AddSFacIsotope( "121Sb", 121, 5.71, -0.05, 4.1, 0.0003, 4.1, 5.75 );
	AddSFacIsotope( "123Sb", 123, 5.38, -0.1, 3.64, 0.001, 3.64, 3.8 );

	AddSFacElement( "Te", 52, 19.964, 19.014, 6.145, 2.524, 4.817, 0.421, 28.528, 70.84, 4.352 );
	AddSFacIsotope( "Te", 0, 5.8, 0, 4.23, 0.09, 4.32, 4.7 );
	AddSFacIsotope( "120Te", 120, 5.3, 0, 3.5, 0, 3.5, 2.3 );
	AddSFacIsotope( "122Te", 122, 3.8, 0, 1.8, 0, 1.8, 3.4 );
	AddSFacIsotope( "123Te", 123, -0.05, -2.04, 0.002, 0.52, 0.52, 418 );
	AddSFacIsotope( "124Te", 124, 7.96, 0, 8, 0, 8, 6.8 );
	AddSFacIsotope( "125Te", 125, 5.02, -0.26, 3.17, 0.008, 3.18, 1.55 );
	AddSFacIsotope( "126Te", 126, 5.56, 0, 3.88, 0, 3.88, 1.04 );
	AddSFacIsotope( "128Te", 128, 5.89, 0, 4.36, 0, 4.36, 0.215 );
	AddSFacIsotope( "130Te", 130, 6.02, 0, 4.55, 0, 4.55, 0.29 );

	AddSFacElement( "I", 53, 20.147, 18.995, 7.514, 2.273, 4.347, 0.381, 27.766, 66.878, 4.071 );
	AddSFacIsotope( "I", 0, 5.28, 1.58, 3.5, 0.31, 3.81, 6.15 );

	AddSFacElement( "Xe", 54, 20.293, 19.03, 8.977, 1.99, 3.928, 0.344, 26.466, 64.266, 3.712 );
	AddSFacIsotope( "Xe", 0, 4.92, 3.04, 2.96, 0, 0, 23.9 );
	AddSFacIsotope( "124Xe", 124, 0, 0, 0, 0, 0, 165 );
	AddSFacIsotope( "126Xe", 126, 0, 0, 0, 0, 0, 3.5 );
	AddSFacIsotope( "128Xe", 128, 0, 0, 0, 0, 0, 8 );
	AddSFacIsotope( "129Xe", 129, 0, 0, 0, 0, 0, 21 );
	AddSFacIsotope( "130Xe", 130, 0, 0, 0, 0, 0, 26 );
	AddSFacIsotope( "131Xe", 131, 0, 0, 0, 0, 0, 85 );
	AddSFacIsotope( "132Xe", 132, 0, 0, 0, 0, 0, 0.45 );
	AddSFacIsotope( "134Xe", 134, 0, 0, 0, 0, 0, 0.265 );
	AddSFacIsotope( "136Xe", 136, 0, 0, 0, 0, 0, 0.26 );

	AddSFacElement( "Cs", 55, 20.389, 19.106, 10.662, 1.495, 3.569, 0.311, 24.388, 213.904, 3.335 );
	AddSFacIsotope( "Cs", 0, 5.42, 1.29, 3.69, 0.21, 3.9, 29 );

	AddSFacElement( "Ba", 56, 20.336, 19.297, 10.888, 2.696, 3.216, 0.276, 20.207, 167.202, 2.773 );
	AddSFacIsotope( "Ba", 0, 5.07, 0, 3.23, 0.15, 3.38, 1.1 );
	AddSFacIsotope( "130Ba", 130, -3.6, 0, 1.6, 0, 1.6, 30 );
	AddSFacIsotope( "132Ba", 132, 7.8, 0, 7.6, 0, 7.6, 7 );
	AddSFacIsotope( "134Ba", 134, 5.7, 0, 4.08, 0, 4.08, 2 );
	AddSFacIsotope( "135Ba", 135, 4.67, 0, 2.74, 0.5, 3.2, 5.8 );
	AddSFacIsotope( "136Ba", 136, 4.91, 0, 3.03, 0, 3.03, 0.68 );
	AddSFacIsotope( "137Ba", 137, 6.83, 0, 5.86, 0.5, 6.4, 3.6 );
	AddSFacIsotope( "138Ba", 138, 4.84, 0, 2.94, 0, 2.94, 0.27 );

	AddSFacElement( "La", 57, 20.578, 19.599, 11.373, 3.287, 2.948, 0.244, 18.773, 133.124, 2.147 );
	AddSFacIsotope( "La", 0, 8.24, 0, 8.53, 1.13, 9.66, 8.97 );
	AddSFacIsotope( "138La", 138, 8, 0, 8, 0.5, 8.5, 57 );
	AddSFacIsotope( "139La", 139, 8.24, 3, 8.53, 1.13, 9.66, 8.93 );

	AddSFacElement( "Ce", 58, 21.167, 19.77, 11.851, 3.33, 2.812, 0.227, 17.608, 127.113, 1.863 );
	AddSFacIsotope( "Ce", 0, 4.84, 0, 2.94, 0.001, 2.94, 0.63 );
	AddSFacIsotope( "136Ce", 136, 5.8, 0, 4.23, 0, 4.23, 7.3 );
	AddSFacIsotope( "138Ce", 138, 6.7, 0, 5.64, 0, 5.64, 1.1 );
	AddSFacIsotope( "140Ce", 140, 4.84, 0, 2.94, 0, 2.94, 0.57 );
	AddSFacIsotope( "142Ce", 142, 4.75, 0, 2.84, 0, 2.84, 0.95 );

	AddSFacElement( "Pr", 59, 22.044, 19.67, 12.386, 2.824, 2.774, 0.222, 16.767, 143.644, 2.058 );
	AddSFacIsotope( "Pr", 0, 4.58, -0.35, 2.64, 0.015, 2.66, 11.5 );

	AddSFacElement( "Nd", 60, 22.684, 19.685, 12.774, 2.851, 2.662, 0.211, 15.885, 137.903, 1.985 );
	AddSFacIsotope( "Nd", 0, 7.69, 0, 7.43, 9.2, 16.6, 50.5 );
	AddSFacIsotope( "142Nd", 142, 7.7, 0, 7.5, 0, 7.5, 18.7 );
	AddSFacIsotope( "143Nd", 143, 14, 21, 25, 55, 80, 337 );
	AddSFacIsotope( "144Nd", 144, 2.8, 0, 1, 0, 1, 3.6 );
	AddSFacIsotope( "145Nd", 145, 14, 0, 25, 5, 30, 42 );
	AddSFacIsotope( "146Nd", 146, 8.7, 0, 9.5, 0, 9.5, 1.4 );
	AddSFacIsotope( "148Nd", 148, 5.7, 0, 4.1, 0, 4.1, 2.5 );
	AddSFacIsotope( "150Nd", 150, 5.3, 0, 3.5, 0, 3.5, 1.2 );

	AddSFacElement( "Pm", 61, 23.34, 19.61, 13.123, 2.875, 2.563, 0.202, 15.101, 132.721, 2.029 );
	AddSFacIsotope( "Pm", 0, 12.6, 3.2, 20, 1.3, 21.3, 168.4 );

	AddSFacElement( "Sm", 62, 24.004, 19.426, 13.44, 2.896, 2.473, 0.196, 14.4, 128.007, 2.21 );
	AddSFacIsotope( "Sm", 0, 0.8, 0, 0.422, 39, 39, 5922 );
	AddSFacIsotope( "144Sm", 144, -3, 0, 1, 0, 1, 0.7 );
	AddSFacIsotope( "147Sm", 147, 14, 11, 25, 143, 39, 57 );
	AddSFacIsotope( "148Sm", 148, -3, 0, 1, 0, 1, 2.4 );
	AddSFacIsotope( "149Sm", 149, -19.2, 31.4, 63.5, 137, 200, 42080 );
	AddSFacIsotope( "150Sm", 150, 14, 0, 25, 0, 25, 104 );
	AddSFacIsotope( "152Sm", 152, -5, 0, 3.1, 0, 3.1, 206 );
	AddSFacIsotope( "154Sm", 154, 9.3, 0, 11, 0, 11, 8.4 );

	AddSFacElement( "Eu", 63, 24.627, 19.089, 13.76, 2.923, 2.388, 0.194, 13.755, 123.174, 2.575 );
	AddSFacIsotope( "Eu", 0, 7.22, 0, 6.57, 2.5, 9.2, 4530 );
	AddSFacIsotope( "151Eu", 151, 6.13, 4.5, 5.5, 3.1, 8.6, 9100 );
	AddSFacIsotope( "153Eu", 153, 8.22, 3.2, 8.5, 1.3, 9.8, 312 );

	AddSFacElement( "Gd", 64, 25.071, 19.08, 13.852, 3.545, 2.253, 0.182, 12.933, 101.398, 2.42 );
	AddSFacIsotope( "Gd", 0, 6.5, 0, 29.3, 151, 180, 49700 );
	AddSFacIsotope( "152Gd", 152, 10, 0, 13, 0, 13, 735 );
	AddSFacIsotope( "154Gd", 154, 10, 0, 13, 0, 13, 85 );
	AddSFacIsotope( "155Gd", 155, 6, 5, 40.8, 25, 66, 61100 );
	AddSFacIsotope( "156Gd", 156, 6.3, 0, 5, 0, 5, 1.5 );
	AddSFacIsotope( "157Gd", 157, -1.14, 5, 650, 394, 1044, 259000 );
	AddSFacIsotope( "158Gd", 158, 9, 0, 10, 0, 10, 2.2 );
	AddSFacIsotope( "160Gd", 160, 9.15, 0, 10.52, 0, 10.52, 0.77 );

	AddSFacElement( "Tb", 65, 25.898, 18.219, 14.317, 2.954, 2.243, 0.196, 12.665, 115.362, 3.583 );
	AddSFacIsotope( "Tb", 0, 7.38, -0.17, 6.84, 0.004, 6.84, 23.4 );

	AddSFacElement( "Dy", 66, 26.507, 17.638, 14.56, 2.966, 2.18, 0.202, 12.19, 111.874, 4.297 );
	AddSFacIsotope( "Dy", 0, 16.9, 0, 35.9, 54.4, 90.3, 994 );
	AddSFacIsotope( "156Dy", 156, 6.1, 0, 4.7, 0, 4.7, 33 );
	AddSFacIsotope( "158Dy", 158, 6, 0, 5, 0, 5, 43 );
	AddSFacIsotope( "160Dy", 160, 6.7, 0, 5.6, 0, 5.6, 56 );
	AddSFacIsotope( "161Dy", 161, 10.3, 4.9, 13.3, 3, 16, 600 );
	AddSFacIsotope( "162Dy", 162, -1.4, 0, 0.25, 0, 0.25, 194 );
	AddSFacIsotope( "163Dy", 163, 5, 1.3, 3.1, 0.21, 3.3, 124 );
	AddSFacIsotope( "164Dy", 164, 49.4, 0, 307, 0, 307, 2840 );

	AddSFacElement( "Ho", 67, 26.905, 17.294, 14.558, 3.638, 2.071, 0.198, 11.441, 92.657, 4.568 );
	AddSFacIsotope( "Ho", 0, 8.01, -1.7, 8.06, 0.36, 8.42, 64.7 );

	AddSFacElement( "Er", 68, 27.656, 16.428, 14.978, 2.982, 2.074, 0.224, 11.36, 105.703, 5.92 );
	AddSFacIsotope( "Er", 0, 7.79, 0, 7.63, 1.1, 8.7, 159 );
	AddSFacIsotope( "162Er", 162, 8.8, 0, 9.7, 0, 9.7, 19 );
	AddSFacIsotope( "164Er", 164, 8.2, 0, 8.4, 0, 8.4, 13 );
	AddSFacIsotope( "166Er", 166, 10.6, 0, 14.1, 0, 14.1, 19.6 );
	AddSFacIsotope( "167Er", 167, 3, 1, 1.1, 0.13, 1.2, 659 );
	AddSFacIsotope( "168Er", 168, 7.4, 0, 6.9, 0, 6.9, 2.74 );
	AddSFacIsotope( "170Er", 170, 9.6, 0, 11.6, 0, 11.6, 5.8 );

	AddSFacElement( "Tm", 69, 28.182, 15.885, 15.154, 2.987, 2.029, 0.239, 10.998, 102.961, 6.756 );
	AddSFacIsotope( "Tm", 0, 7.07, 0.9, 6.28, 0.1, 6.38, 100 );

	AddSFacElement( "Yb", 70, 28.664, 15.434, 15.309, 2.99, 1.989, 0.257, 10.665, 100.417, 7.567 );
	AddSFacIsotope( "Yb", 0, 12.43, 0, 19.42, 4, 23.4, 34.8 );
	AddSFacIsotope( "168Yb", 168, -4.07, 0, 2.13, 0, 2.13, 2230 );
	AddSFacIsotope( "170Yb", 170, 6.77, 0, 5.8, 0, 5.8, 11.4 );
	AddSFacIsotope( "171Yb", 171, 9.66, -5.59, 11.7, 3.9, 15.6, 48.6 );
	AddSFacIsotope( "172Yb", 172, 9.43, 0, 11.2, 0, 11.2, 0.8 );
	AddSFacIsotope( "173Yb", 173, 9.56, -5.3, 11.5, 3.5, 15, 17.1 );
	AddSFacIsotope( "174Yb", 174, 19.3, 0, 46.8, 0, 46.8, 69.4 );
	AddSFacIsotope( "176Yb", 176, 8.72, 0, 9.6, 0, 9.6, 2.85 );

	AddSFacElement( "Lu", 71, 28.948, 15.221, 15.1, 3.716, 1.902, 9.985, 0.261, 84.33, 7.976 );
	AddSFacIsotope( "Lu", 0, 7.21, 0, 6.53, 0.7, 7.2, 74 );
	AddSFacIsotope( "175Lu", 175, 7.24, 2.2, 6.59, 0.6, 7.2, 21 );
	AddSFacIsotope( "176Lu", 176, 6.1, 3, 4.7, 1.2, 5.9, 2065 );

	AddSFacElement( "Hf", 72, 29.144, 15.173, 14.759, 4.3, 1.833, 9.6, 0.275, 72.029, 8.582 );
	AddSFacIsotope( "Hf", 0, 7.7, 0, 7.6, 2.6, 10.2, 104.1 );
	AddSFacIsotope( "174Hf", 174, 10.9, 0, 15, 0, 15, 561 );
	AddSFacIsotope( "176Hf", 176, 6.61, 0, 5.5, 0, 5.5, 23.5 );
	AddSFacIsotope( "177Hf", 177, 0.8, 0.9, 0.1, 0.1, 0.2, 373 );
	AddSFacIsotope( "178Hf", 178, 5.9, 0, 4.4, 0, 4.4, 84 );
	AddSFacIsotope( "179Hf", 179, 7.46, 1.06, 7, 0.14, 7.1, 41 );
	AddSFacIsotope( "180Hf", 180, 13.2, 0, 21.9, 0, 21.9, 13.04 );

	AddSFacElement( "Ta", 73, 29.202, 15.229, 14.514, 4.765, 1.773, 9.37, 0.296, 63.364, 9.244 );
	AddSFacIsotope( "Ta", 0, 6.91, 0, 6, 0.01, 6.01, 20.6 );
	AddSFacIsotope( "180Ta", 180, 7, 0, 6.2, 0.5, 7, 563 );
	AddSFacIsotope( "181Ta", 181, 6.91, -0.29, 6, 0.011, 6.01, 20.5 );

	AddSFacElement( "W", 74, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
	AddSFacIsotope( "W", 0, 4.86, 0, 2.97, 1.63, 4.6, 18.3 );
	AddSFacIsotope( "180W", 180, 5, 0, 3, 0, 3, 30 );
	AddSFacIsotope( "182W", 182, 6.97, 0, 6.1, 0, 6.1, 20.7 );
	AddSFacIsotope( "183W", 183, 6.53, 0, 5.36, 0.3, 5.7, 10.1 );
	AddSFacIsotope( "184W", 184, 7.48, 0, 7.03, 0, 7.03, 1.7 );
	AddSFacIsotope( "186W", 186, -0.72, 0, 0.065, 0, 0.065, 37.9 );

	AddSFacElement( "Re", 75, 28.762, 15.719, 14.556, 5.442, 1.672, 9.092, 0.35, 52.086, 10.472 );
	AddSFacIsotope( "Re", 0, 9.2, 0, 10.6, 0.9, 11.5, 89.7 );
	AddSFacIsotope( "185Re", 185, 9, 2, 10.2, 0.5, 10.7, 112 );
	AddSFacIsotope( "187Re", 187, 9.3, 2.8, 10.9, 1, 11.9, 76.4 );

	AddSFacElement( "Os", 76, 28.189, 16.155, 14.931, 5.676, 1.629, 8.979, 0.383, 48.165, 11 );
	AddSFacIsotope( "Os", 0, 10.7, 0, 14.4, 0.3, 14.7, 16 );
	AddSFacIsotope( "184Os", 184, 10, 0, 13, 0, 13, 3000 );
	AddSFacIsotope( "186Os", 186, 11.6, 0, 17, 0, 17, 80 );
	AddSFacIsotope( "187Os", 187, 10, 0, 13, 0.3, 13, 320 );
	AddSFacIsotope( "188Os", 188, 7.6, 0, 7.3, 0, 7.3, 4.7 );
	AddSFacIsotope( "189Os", 189, 10.7, 0, 14.4, 0.5, 14.9, 25 );
	AddSFacIsotope( "190Os", 190, 11, 0, 15.2, 0, 15.2, 13.1 );
	AddSFacIsotope( "192Os", 192, 11.5, 0, 16.6, 0, 16.6, 2 );

	AddSFacElement( "Ir", 77, 27.305, 16.73, 15.611, 5.834, 1.593, 8.866, 0.418, 45.001, 11.472 );
	AddSFacIsotope( "Ir", 0, 10.6, 0, 14.1, 0, 14, 425 );
	AddSFacIsotope( "191Ir", 191, 0, 0, 0, 0, 0, 954 );
	AddSFacIsotope( "193Ir", 193, 0, 0, 0, 0, 0, 111 );

	AddSFacElement( "Pt", 78, 27.006, 17.764, 15.713, 5.784, 1.513, 8.812, 0.425, 38.61, 11.688 );
	AddSFacIsotope( "Pt", 0, 9.6, 0, 11.58, 0.13, 11.71, 10.3 );
	AddSFacIsotope( "190Pt", 190, 9, 0, 10, 0, 10, 152 );
	AddSFacIsotope( "192Pt", 192, 9.9, 0, 12.3, 0, 12.3, 10 );
	AddSFacIsotope( "194Pt", 194, 10.55, 0, 14, 0, 14, 1.44 );
	AddSFacIsotope( "195Pt", 195, 8.83, -1, 9.8, 0.13, 9.9, 27.5 );
	AddSFacIsotope( "196Pt", 196, 9.89, 0, 12.3, 0, 12.3, 0.72 );
	AddSFacIsotope( "198Pt", 198, 7.8, 0, 7.6, 0, 7.6, 3.66 );

	AddSFacElement( "Au", 79, 16.882, 18.591, 25.558, 5.86, 0.461, 8.622, 1.483, 36.396, 12.066 );
	AddSFacIsotope( "Au", 0, 7.63, -1.84, 7.32, 0.43, 7.75, 98.65 );

	AddSFacElement( "Hg", 80, 20.681, 19.042, 21.657, 5.968, 0.545, 8.448, 1.573, 38.325, 12.609 );
	AddSFacIsotope( "Hg", 0, 12.692, 0, 20.24, 6.6, 26.8, 372.3 );
	AddSFacIsotope( "196Hg", 196, 30.3, 0, 115, 0, 115, 3080 );
	AddSFacIsotope( "198Hg", 198, 0, 0, 0, 0, 0, 2 );
	AddSFacIsotope( "199Hg", 199, 16.9, 15.5, 36, 30, 66, 2150 );
	AddSFacIsotope( "200Hg", 200, 0, 0, 0, 0, 0, 60 );
	AddSFacIsotope( "201Hg", 201, 0, 0, 0, 0, 0, 7.8 );
	AddSFacIsotope( "202Hg", 202, 0, 0, 0, 0, 9.828, 4.89 );
	AddSFacIsotope( "204Hg", 204, 0, 0, 0, 0, 0, 0.43 );

	AddSFacElement( "Tl", 81, 27.545, 19.158, 15.538, 5.526, 0.655, 8.708, 1.963, 45.815, 13.175 );
	AddSFacIsotope( "Tl", 0, 8.776, 0, 9.678, 0.21, 9.89, 3.43 );
	AddSFacIsotope( "203Tl", 203, 6.99, 1.06, 6.14, 0.14, 6.28, 11.4 );
	AddSFacIsotope( "205Tl", 205, 9.52, -0.242, 11.39, 0.007, 11.4, 0.104 );

	AddSFacElement( "Pb", 82, 31.062, 13.064, 18.442, 5.97, 0.69, 2.358, 8.618, 47.258, 13.412 );
	AddSFacIsotope( "Pb", 0, 9.405, 0, 11.115, 0.003, 11.118, 0.171 );
	AddSFacIsotope( "204Pb", 204, 9.9, 0, 12.3, 0, 12.3, 0.65 );
	AddSFacIsotope( "206Pb", 206, 9.22, 0, 10.68, 0, 10.68, 0.03 );
	AddSFacIsotope( "207Pb", 207, 9.28, 0.14, 10.82, 0.002, 10.82, 0.699 );
	AddSFacIsotope( "208Pb", 208, 9.5, 0, 11.34, 0, 11.34, 0.00048 );

	AddSFacElement( "Bi", 83, 33.369, 12.951, 16.588, 6.469, 0.704, 2.924, 8.794, 48.009, 13.578 );
	AddSFacIsotope( "Bi", 0, 8.532, 0, 9.148, 0.0084, 9.156, 0.0338 );

	AddSFacElement( "Po", 84, 34.673, 15.473, 13.114, 7.026, 0.701, 3.551, 9.556, 47.005, 13.677 );
	AddSFacIsotope( "Po", 0, 0, 0.259, 0, 0, 0, 0 );

	AddSFacElement( "At", 85, 35.316, 19.021, 9.499, 7.425, 0.686, 3.975, 11.382, 45.472, 13.711 );
	AddSFacIsotope( "At", 0, 0, 0, 0, 0, 0, 0 );

	AddSFacElement( "Rn", 86, 35.563, 21.282, 8.004, 7.443, 0.663, 4.069, 14.042, 44.247, 13.691 );
	AddSFacIsotope( "Rn", 0, 0, 0, 0, 0, 12.6, 0 );

	AddSFacElement( "Fr", 87, 35.93, 23.055, 12.144, 2.113, 0.646, 4.176, 23.105, 150.645, 13.725 );
	AddSFacIsotope( "Fr", 0, 0, 0, 0, 0, 0, 0 );

	AddSFacElement( "Ra", 88, 35.763, 22.906, 12.474, 3.211, 0.616, 3.871, 19.989, 142.325, 13.621 );
	AddSFacIsotope( "Ra", 0, 10, 0, 13, 0, 13, 12.8 );

	AddSFacElement( "Ac", 89, 35.66, 23.103, 12.598, 4.087, 0.589, 3.652, 18.599, 117.02, 13.527 );
	AddSFacIsotope( "Ac", 0, 0, 0, 0, 0, 0, 0 );

	AddSFacElement( "Th", 90, 35.564, 23.422, 12.747, 4.807, 0.563, 3.462, 17.831, 99.172, 13.431 );
	AddSFacIsotope( "Th", 0, 10.31, 0, 13.36, 0, 13.36, 7.37 );

	AddSFacElement( "Pa", 91, 35.885, 23.295, 14.189, 4.173, 0.548, 3.415, 16.924, 105.251, 13.429 );
	AddSFacIsotope( "Pa", 0, 9.1, 0, 10.4, 0.1, 10.5, 200.6 );

	AddSFacElement( "U", 92, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
	AddSFacIsotope( "U", 0, 8.417, 0, 8.903, 0.005, 8.908, 7.57 );
	AddSFacIsotope( "233U", 233, 10.1, 1, 12.8, 0.1, 12.9, 574.7 );
	AddSFacIsotope( "234U", 234, 12.4, 0, 19.3, 0, 19.3, 100.1 );
	AddSFacIsotope( "235U", 235, 10.47, 1.3, 13.78, 0.2, 14, 680.9 );
	AddSFacIsotope( "238U", 238, 8.402, 0, 8.871, 0, 8.871, 2.68 );

	AddSFacElement( "Np", 93, 36.187, 23.596, 15.64, 4.186, 0.512, 3.254, 15.362, 97.491, 13.357 );
	AddSFacIsotope( "Np", 0, 10.55, 0, 14, 0.5, 14.5, 175.9 );

	AddSFacElement( "Pu", 94, 36.526, 23.808, 16.771, 3.479, 0.499, 3.264, 14.946, 105.98, 13.381 );
	AddSFacIsotope( "Pu", 0, 0, 0, 0, 0, 0, 0 );
	AddSFacIsotope( "238Pu", 238, 14.1, 0, 25, 0, 25, 558 );
	AddSFacIsotope( "239Pu", 239, 7.7, 1.3, 7.5, 0.2, 7.7, 1017.3 );
	AddSFacIsotope( "240Pu", 240, 3.5, 0, 1.54, 0, 1.54, 289.6 );
	AddSFacIsotope( "242Pu", 242, 8.1, 0, 8.2, 0, 8.2, 18.5 );

	AddSFacElement( "Am", 95, 36.671, 24.099, 17.341, 3.493, 0.484, 3.206, 14.314, 102.273, 13.359 );
	AddSFacIsotope( "Am", 0, 8.3, 2, 8.7, 0.3, 9, 75.3 );

	AddSFacElement( "Cm", 96, 36.649, 24.41, 17.399, 4.217, 0.465, 3.09, 13.435, 88.483, 13.289 );
	AddSFacIsotope( "Cm", 0, 0, 0, 0, 0, 0, 0 );
	AddSFacIsotope( "244Cm", 244, 9.5, 0, 11.3, 0, 11.3, 16.2 );
	AddSFacIsotope( "246Cm", 246, 9.3, 0, 10.9, 0, 10.9, 1.36 );
	AddSFacIsotope( "248Cm", 248, 7.7, 0, 7.5, 0, 7.5, 3 );


	
/*
	AddIsotope(    "H",   -3.7390,  0.493,   0.323, 0.140, 0.041, 10.511, 26.126, 3.142, 57.800, 0.003 ); } catch(...) { isotope = NULL; }
	AddIsotope(   "1H",   -3.7406,  0.493,   0.323, 0.140, 0.041, 10.511, 26.126, 3.142, 57.800, 0.003 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "D",    6.671,   0.493,   0.323, 0.140, 0.041, 10.511, 26.126, 3.142, 57.800, 0.003 ); } catch(...) { isotope = NULL; }
	AddIsotope(   "2H",    6.671,   0.493,   0.323, 0.140, 0.041, 10.511, 26.126, 3.142, 57.800, 0.003 ); } catch(...) { isotope = NULL; }
	AddIsotope(   "3H",    4.792,   0.493,   0.323, 0.140, 0.041, 10.511, 26.126, 3.142, 57.800, 0.003 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "Li",  -1.90,    1.128,   0.751, 0.618, 0.465, 3.955, 1.052, 85.391, 168.261, 0.038 ); } catch(...) { isotope = NULL; }
	AddIsotope(   "6Li",   2.00,    1.128,   0.751, 0.618, 0.465, 3.955, 1.052, 85.391, 168.261, 0.038 ); } catch(...) { isotope = NULL; }
	AddIsotope(   "7Li",  -2.22,    1.128,   0.751, 0.618, 0.465, 3.955, 1.052, 85.391, 168.261, 0.038 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "B",    5.30,    2.055,   1.333, 1.098, 0.707, 23.219, 1.021, 60.350, 0.140, -0.193 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "10B",   -0.1,     2.055,   1.333, 1.098, 0.707, 23.219, 1.021, 60.350, 0.140, -0.193 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "11B",    6.65,    2.055,   1.333, 1.098, 0.707, 23.219, 1.021, 60.350, 0.140, -0.193 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "C",    6.6460,  2.310,   1.020, 1.589, 0.865, 20.844, 10.208, 0.569, 51.651, 0.216 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "12C",    6.6511,  2.310,   1.020, 1.589, 0.865, 20.844, 10.208, 0.569, 51.651, 0.216 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "13C",    6.19,    2.310,   1.020, 1.589, 0.865, 20.844, 10.208, 0.569, 51.651, 0.216 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "N",    9.36,   12.213,   3.132, 2.013, 1.166, 0.006, 9.893, 28.997, 0.583, -11.529 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "14N",    9.37,   12.213,   3.132, 2.013, 1.166, 0.006, 9.893, 28.997, 0.583, -11.529 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "15N",    6.44,   12.213,   3.132, 2.013, 1.166, 0.006, 9.893, 28.997, 0.583, -11.529 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "O",    5.803,   3.049,   2.287, 1.546, 0.867, 13.277, 5.701, 0.324, 32.909, 0.251 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "16O",    5.803,   3.049,   2.287, 1.546, 0.867, 13.277, 5.701, 0.324, 32.909, 0.251 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "17O",    5.78,    3.049,   2.287, 1.546, 0.867, 13.277, 5.701, 0.324, 32.909, 0.251 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "18O",    5.84,    3.049,   2.287, 1.546, 0.867, 13.277, 5.701, 0.324, 32.909, 0.251 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "F",    5.654,   3.539,   2.641, 1.517, 1.024, 10.283, 4.294, 0.262, 26.148, 0.278 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "P",    5.13,    6.435,   4.179, 1.780, 1.491, 1.907, 27.157, 0.526, 68.164, 1.115 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "S",    2.847,   6.905,   5.203, 1.438, 1.586, 1.468, 22.215, 0.254, 56.172, 0.867 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "32S",    2.804,   6.905,   5.203, 1.438, 1.586, 1.468, 22.215, 0.254, 56.172, 0.867 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "33S",    4.74,    6.905,   5.203, 1.438, 1.586, 1.468, 22.215, 0.254, 56.172, 0.867 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "34S",    3.48,    6.905,   5.203, 1.438, 1.586, 1.468, 22.215, 0.254, 56.172, 0.867 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "36S",    3.1,     6.905,   5.203, 1.438, 1.586, 1.468, 22.215, 0.254, 56.172, 0.867 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "Cl",   9.577,  11.460,   7.196, 6.256, 1.645, 0.010, 1.166, 18.519, 47.778, -9.557 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "35Cl",  11.65,   11.460,   7.196, 6.256, 1.645, 0.010, 1.166, 18.519, 47.778, -9.557 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "37Cl",   3.08,   11.460,   7.196, 6.256, 1.645, 0.010, 1.166, 18.519, 47.778, -9.557 ); } catch(...) { isotope = NULL; }
	AddIsotope(    "Br",   6.795,  17.179,   5.236, 5.638, 3.985, 2.172, 16.580, 0.261, 41.433, -2.956 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "79Br",   6.80,   17.179,   5.236, 5.638, 3.985, 2.172, 16.580, 0.261, 41.433, -2.956 ); } catch(...) { isotope = NULL; }
	AddIsotope(  "81Br",   6.79,   17.179,   5.236, 5.638, 3.985, 2.172, 16.580, 0.261, 41.433, -2.956 ); } catch(...) { isotope = NULL; }
*/
}


static void deleteIsotopeList() {
	int i;
	for(i = 0; i < g_oaSFacIsotopes.GetSize(); i++)
		delete (CSFacIsotope *)g_oaSFacIsotopes[i];
	for(i = 0; i < g_oaSFacElements.GetSize(); i++)
		delete (CSFacElement *)g_oaSFacElements[i];
}


struct StructureFactorAtomKind: public CxObject
{
	int atomType;
	CxObArray isotopeList;
};


struct StructureFactorMolecule: public CxObject
{
	int moleculeType;
	CxObArray atomKinds;
};



CSFacElement::CSFacElement( const char *label, int ord, double cma1, double cma2, double cma3, double cma4, double cmb1, double cmb2, double cmb3, double cmb4, double cmc ) {

	m_sLabel = label;
	m_iOrd = ord;
	m_fCMa[0] = cma1;
	m_fCMa[1] = cma2;
	m_fCMa[2] = cma3;
	m_fCMa[3] = cma4;
	m_fCMb[0] = cmb1;
	m_fCMb[1] = cmb2;
	m_fCMb[2] = cmb3;
	m_fCMb[3] = cmb4;
	m_fCMc    = cmc;
}



CSFacIsotope::CSFacIsotope( CSFacElement *elem, int iso, const char *label, double Coh_b, double Inc_b, double Coh_xs, double Inc_xs, double Scatt_xs, double Abs_xs ) {

	m_pElement = elem;
	m_iIsotope = iso;
	m_sLabel = label;

	m_fCoh_b = Coh_b;
	m_fInc_b = Inc_b;
	m_fCoh_xs = Coh_xs;
	m_fInc_xs = Inc_xs;
	m_fScatt_xs = Scatt_xs;
	m_fAbs_xs = Abs_xs;
}



double CSFacElement::xrayFactor(double q) {

	double x = q * 100.0 / 4.0 / Pi;
	double factor = 0.0;
	int i;

	for(i = 0; i < 4; i++)
		factor += m_fCMa[i] * exp(-m_fCMb[i] * x * x);
	factor += m_fCMc;
	return factor;
}



double CSFacIsotope::xrayFactor(double q) {
	return m_pElement->xrayFactor(q);
}



CStructureFactorGroup::CStructureFactorGroup(bool global, CxObArray &isotopeAssignList) {

	int i, j, k, l;


	if (global) {

		for (i = 0; i < g_oaMolecules.GetSize(); i++) {
			CAtomGroup *ag;
			try { ag = new CAtomGroup(); } catch(...) { ag = NULL; }
			if (ag == NULL) NewException((double)sizeof(CAtomGroup), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			if(!ag->ParseAtoms((CMolecule *)g_oaMolecules[i], "*")) {
				eprintf("CStructureFactorGroup::CStructureFactorGroup(): Internal error.\n");
				abort();
			}
			m_atomGroupList.Add(ag);
		}
		m_sepInterIntra = AskYesNo("    Separate intramolecular and intermolecular contributions in the total structure factor (y/n)? [no] ", false);
		mprintf("\n");

	} else {

		CxString buf, buf2;

		while (true) {
			buf.sprintf("      Take atoms from which molecule (");
			for (i = 0; i < g_oaMolecules.GetSize(); i++) {
				buf2.sprintf("%s=%d", ((CMolecule *)g_oaMolecules[i])->m_sName, i+1);
				buf.strcat(buf2);
				if (i < g_oaMolecules.GetSize() - 1) {
					buf.strcat(", ");
				}
			}
			buf.strcat(")? ");
			
			int mol = AskRangeInteger_ND("%s", 1, g_oaMolecules.GetSize(),(const char*)buf) - 1;
			
			CAtomGroup *ag;
			try { ag = new CAtomGroup(); } catch(...) { ag = NULL; }
			if (ag == NULL) NewException((double)sizeof(CAtomGroup), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			
			while (true) {
				if (((CMolecule *)g_oaMolecules[mol])->m_iAtomGesNoVirt == 1) {
					mprintf("      %s is only one atom, there is no choice.\n", ((CMolecule *)g_oaMolecules[mol])->m_sName);
					ag->Reset();
					ag->m_pMolecule = (CMolecule *)g_oaMolecules[mol];
					ag->AddAtom(0, 0, false);
					ag->SortAtoms();
					ag->BuildName();
				} else {
					AskString("      Which atom(s) to take from molecule %s (e.g. \"C1,C3-5,H\", \"*\"=all)? [*] ", &buf, "*", ((CMolecule*)g_oaMolecules[mol])->m_sName);
					if(!ag->ParseAtoms((CMolecule *)g_oaMolecules[mol], buf)) {
						continue;
					}
					bool containsVirt = false;
					for (i = 0; i < ag->m_baAtomType.GetSize(); i++) {
						if (ag->m_baAtomType[i] == g_iVirtAtomType) {
							containsVirt = true;
							break;
						}
					}
					if (containsVirt) {
						eprintf("The selection must not contain virtual atoms.\n");
						continue;
					}
				}
				break;
			}
			m_atomGroupList.Add(ag);
			
			if (!AskYesNo("\n      Add atoms from another molecule (y/n)? [no] ", false))
				break;
			mprintf("\n");
		}
		mprintf("\n");
		
		m_sepInterIntra = AskYesNo("      Separate intramolecular and intermolecular contributions within this group (y/n)? [no] ", false);
		mprintf("\n");
	}
	
	if (global) {
		m_name.sprintf("total");
	} else {
		CxString temp;
		for (i = 0; i < m_atomGroupList.GetSize(); i++) {
			if (i > 0)
				temp.strcat("__");
			temp.strcat(((CAtomGroup *)m_atomGroupList[i])->m_pMolecule->m_sName);
			if (((CAtomGroup *)m_atomGroupList[i])->m_pMolecule->m_iAtomGes > 1) {
				temp.strcat("_");
				temp.strcat(((CAtomGroup *)m_atomGroupList[i])->m_sName);
			}
		}
		
		m_name.sprintf("[%s]", (const char *)temp);
	}
	
	for (i = 0; i < m_atomGroupList.GetSize(); i++) {
		CAtomGroup *ag = (CAtomGroup *)m_atomGroupList[i];
		CMolecule *mol = ag->m_pMolecule;
		for (j = 0; j < ag->m_baAtomType.GetSize(); j++) {
			CxIntArray *a = (CxIntArray *)ag->m_oaAtoms[j];
			for (k = 0; k < a->GetSize(); k++) {
				CSFacIsotope *isotope = (CSFacIsotope *)((StructureFactorAtomKind *)((StructureFactorMolecule *)isotopeAssignList.GetAt(mol->m_iIndex))->atomKinds[ag->m_baAtomType[j]])->isotopeList[k];
				int isotopeIndex = -1;
				for (l = 0; l < m_isotopeTypeList.GetSize(); l++) {
					if((CSFacIsotope *)m_isotopeTypeList[l] == isotope) {
						isotopeIndex = l;
						break;
					}
				}
				if (isotopeIndex == -1) {
					isotopeIndex = m_isotopeTypeList.GetSize();
					m_isotopeTypeList.Add(isotope);
					m_isotopeTypeCount.Add(0);
				}
				for (l = 0; l < mol->m_laSingleMolIndex.GetSize(); l++) {
					CSingleMolecule *sm = (CSingleMolecule *)g_oaSingleMolecules[mol->m_laSingleMolIndex[l]];
					m_atomIndexList.Add(((CxIntArray *)sm->m_oaAtomOffset[ag->m_baAtomType[j]])->GetAt(a->GetAt(k)));
					m_singleMolList.Add(mol->m_laSingleMolIndex[l]);
					m_isotopeList.Add(isotopeIndex);
					m_isotopeTypeCount[isotopeIndex]++;
				}
			}
		}
	}
	
	m_isotopeTypeTotalCount.SetSize(m_isotopeTypeCount.GetSize());
	for (i = 0; i < m_isotopeTypeTotalCount.GetSize(); i++)
		m_isotopeTypeTotalCount[i] = 0;
	
	for (i = 0; i < isotopeAssignList.GetSize(); i++) {
		StructureFactorMolecule *smol = (StructureFactorMolecule *)isotopeAssignList[i];
		for (j = 0; j < smol->atomKinds.GetSize(); j++) {
			StructureFactorAtomKind *satom = (StructureFactorAtomKind *)smol->atomKinds[j];
			for (k = 0; k < satom->isotopeList.GetSize(); k++) {
				CSFacIsotope *isotope = (CSFacIsotope *)satom->isotopeList[k];
				int isotopeIndex = -1;
				for (l = 0; l < m_isotopeTypeList.GetSize(); l++) {
					if ((CSFacIsotope *)m_isotopeTypeList[l] == isotope) {
						isotopeIndex = l;
						break;
					}
				}
				if (isotopeIndex != -1) {
					m_isotopeTypeTotalCount[isotopeIndex] += ((CMolecule *)g_oaMolecules[i])->m_laSingleMolIndex.GetSize();
				}
			}
		}
	}
	
	m_global = global;
}


CStructureFactorGroup::~CStructureFactorGroup() {
	int i;
	for (i = 0; i < m_atomGroupList.GetSize(); i++)
		delete (CAtomGroup *)m_atomGroupList[i];
	for (i = 0; i < m_rdfList.GetSize(); i++)
		delete (CDF *)m_rdfList[i];
	for (i = 0; i < m_rdfIntraList.GetSize(); i++)
		delete (CDF *)m_rdfIntraList[i];
	for (i = 0; i < m_rdfInterList.GetSize(); i++)
		delete (CDF *)m_rdfInterList[i];
}


void CStructureFactorGroup::initialize(double rdfMax, int rdfRes) {
	int i;
	mprintf("      Creating %d RDFs\n", m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2);
	for (i = 0; i < m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2; i++) {
		CDF *df;
		try { df = new CDF(); } catch(...) { df = NULL; }
		if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
		df->m_fMinVal = 0.0;
		df->m_fMaxVal = rdfMax;
		df->m_iResolution = rdfRes;
		df->SetLabelX("Distance / pm");
		df->SetLabelY("g(r)");
		df->Create();
		m_rdfList.Add(df);
	}
	
	if (m_sepInterIntra) {
		mprintf("      Creating %d intramolecular RDFs\n", m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2);
		for (i = 0; i < m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2; i++) {
			CDF *df;
			try { df = new CDF(); } catch(...) { df = NULL; }
			if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			df->m_fMinVal = 0.0;
			df->m_fMaxVal = rdfMax;
			df->m_iResolution = rdfRes;
			df->SetLabelX("Distance / pm");
			df->SetLabelY("g(r)");
			df->Create();
			m_rdfIntraList.Add(df);
		}
		mprintf("      Creating %d intermolecular RDFs\n", m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2);
		for (i = 0; i < m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2; i++) {
			CDF *df;
			try { df = new CDF(); } catch(...) { df = NULL; }
			if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			df->m_fMinVal = 0.0;
			df->m_fMaxVal = rdfMax;
			df->m_iResolution = rdfRes;
			df->SetLabelX("Distance / pm");
			df->SetLabelY("g(r)");
			df->Create();
			m_rdfInterList.Add(df);
		}
	}
//>>>OMP
#ifdef USE_OMP
	m_tempLists.resize(omp_get_max_threads());
	for ( int j=0; j < omp_get_max_threads(); j++ )
	{
		m_tempLists[j].resize(m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2);
		for (i = 0; i < m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2; i++) 
		{
			CDF *df;
			try { df = new CDF(); } catch(...) { df = NULL; }
			if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			df->m_fMinVal = 0.0;
			df->m_fMaxVal = rdfMax;
			df->m_iResolution = rdfRes;
			df->SetLabelX("Distance / pm");
			df->SetLabelY("g(r)");
			df->Create();
			m_tempLists[j][i] = df;
		}
	}
	if (m_sepInterIntra) 
	{
		m_tempInterLists.resize(omp_get_max_threads());
		m_tempIntraLists.resize(omp_get_max_threads());
		for ( int j=0; j < omp_get_max_threads(); j++ )
		{
			m_tempInterLists[j].resize(m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2);
			m_tempIntraLists[j].resize(m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2);
			for (i = 0; i < m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2; i++) 
			{
				CDF *df;
				try { df = new CDF(); } catch(...) { df = NULL; }
				if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
				df->m_fMinVal = 0.0;
				df->m_fMaxVal = rdfMax;
				df->m_iResolution = rdfRes;
				df->SetLabelX("Distance / pm");
				df->SetLabelY("g(r)");
				df->Create();
				m_tempInterLists[j][i] = df;
			}
			for (i = 0; i < m_isotopeTypeList.GetSize() * (m_isotopeTypeList.GetSize() + 1) / 2; i++) 
			{
				CDF *df;
				try { df = new CDF(); } catch(...) { df = NULL; }
				if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
				df->m_fMinVal = 0.0;
				df->m_fMaxVal = rdfMax;
				df->m_iResolution = rdfRes;
				df->SetLabelX("Distance / pm");
				df->SetLabelY("g(r)");
				df->Create();
				m_tempIntraLists[j][i] = df;
			}
		}
	}
#endif
//<<<OMP
}


void CStructureFactorGroup::process(CTimeStep *ts) {
	int i, j, a, b, index;
	double dist;
//>>>OMP
#ifdef USE_OMP
#pragma omp parallel for private(i,j,a,b,index,dist)
#endif
//<<<OMP
	for (i = 0; i < m_atomIndexList.GetSize(); i++) {
		//if ((i%100) == 0)
		//	mprintf("\n@Group i=%d",i);
		for (j = i+1; j < m_atomIndexList.GetSize(); j++) {
			dist = FoldedLength(ts->m_vaCoords[m_atomIndexList[i]] - ts->m_vaCoords[m_atomIndexList[j]]);
			a = m_isotopeList[i];
			b = m_isotopeList[j];
			if (a < b)
				index = (m_isotopeTypeList.GetSize()-1)*a - a*(a-1)/2 + b;
			else
				index = (m_isotopeTypeList.GetSize()-1)*b - b*(b-1)/2 + a;
//>>>OMP
#ifdef USE_OMP
			m_tempLists[omp_get_thread_num()][index]->AddToBin(dist);
			if (m_sepInterIntra) 
			{
				if (m_singleMolList[i] == m_singleMolList[j])
					m_tempIntraLists[omp_get_thread_num()][index]->AddToBin(dist);
				else
					m_tempInterLists[omp_get_thread_num()][index]->AddToBin(dist);
			}
#else
//<<<OMP
			((CDF *)m_rdfList[index])->AddToBin(dist);
			if (m_sepInterIntra) {
				if (m_singleMolList[i] == m_singleMolList[j])
					((CDF *)m_rdfIntraList[index])->AddToBin(dist);
				else
					((CDF *)m_rdfInterList[index])->AddToBin(dist);
			}
//>>>OMP
#endif
//<<<OMP
		}
	}
}


void CStructureFactorGroup::finalize(CDF *sfac, CDF *xray, CDF *neutron, bool saveIntermediate, bool m_bLorch, bool kuehnelong) {
	int i, j, k, l;
	CxString filename;

//>>>OMP
#ifdef USE_OMP
	for ( i=0; i < (int)m_tempLists.size(); i++ )
		for ( j=0; j < (int)m_tempLists[i].size(); j++ )
			((CDF *)m_rdfList[j])->AddFrom(m_tempLists[i][j]);
	for ( i=0; i < (int)m_tempInterLists.size(); i++ )
		for ( j=0; j < (int)m_tempInterLists[i].size(); j++ )
			((CDF *)m_rdfInterList[j])->AddFrom(m_tempInterLists[i][j]);
	for ( i=0; i < (int)m_tempIntraLists.size(); i++ )
		for ( j=0; j < (int)m_tempIntraLists[i].size(); j++ )
			((CDF *)m_rdfIntraList[j])->AddFrom(m_tempIntraLists[i][j]);
#endif
//<<<OMP
	
	CDF *sfacTemp;
	try { sfacTemp = new CDF(); } catch(...) { sfacTemp = NULL; }
	if(sfacTemp == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	sfacTemp->m_fMinVal = sfac->m_fMinVal;
	sfacTemp->m_fMaxVal = sfac->m_fMaxVal;
	sfacTemp->m_iResolution = sfac->m_iResolution;
	sfacTemp->SetLabelX("Wave vector modulus / nm^-1");
	sfacTemp->SetLabelY("Intensity");
	sfacTemp->Create();
	
	for (i = 0; i < m_isotopeTypeList.GetSize(); i++) {
		for (j = i; j < m_isotopeTypeList.GetSize(); j++) {
			mprintf("      Processing partial structure factor %s-%s\n", ((CSFacIsotope *)m_isotopeTypeList[i])->label(), ((CSFacIsotope *)m_isotopeTypeList[j])->label());
			CDF *df = (CDF *)m_rdfList[(m_isotopeTypeList.GetSize()-1)*i - i*(i-1)/2 + j];
			
			df->MultiplyBin(1.0 / g_iSteps * g_iStride);

			if (i == j)
				df->MultiplyBin(2.0);

			if (kuehnelong)
				df->CorrectRadialDistKuehne();
			else
				df->CorrectRadialDist();

			if (g_bBoxNonOrtho)
				df->MultiplyBin(g_fBoxVolume * 1000000.0 / (4.0/3.0 * Pi) / ((double)m_isotopeTypeTotalCount[i]) / ((double)m_isotopeTypeTotalCount[j]));
			else
				df->MultiplyBin(g_fBoxX * g_fBoxY * g_fBoxZ / (4.0/3.0 * Pi) / ((double)m_isotopeTypeTotalCount[i]) / ((double)m_isotopeTypeTotalCount[j]));

			if (g_bDoubleBox)
				df->MultiplyBin(g_iDoubleBoxFactor);
			
			if (saveIntermediate) {
// 				df->Integrate(true, (4.0f/3.0f * Pi) * m_isotopeTypeTotalCount[i] * m_isotopeTypeTotalCount[j] / (g_fBoxX * g_fBoxY * g_fBoxZ) / m_isotopeTypeCount[i]);
				filename.sprintf("sfac_%s%s_rdf_%s_%s.csv", m_global ? "" : "self_", (const char *)m_name, (const char *)(((CSFacIsotope *)m_isotopeTypeList[i])->label()), (const char *)(((CSFacIsotope *)m_isotopeTypeList[j])->label()));
				mprintf("      Writing RDF to %s...\n", (const char *)filename);
				df->Write("", filename, "", false);
			}
			
			double shift = ((double)m_isotopeTypeCount[i]) * ((double)m_isotopeTypeCount[j]) / (((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]));

	/*		mprintf("@ m_isotopeTypeCount[i] = %d\n",m_isotopeTypeCount[i]);
			mprintf("@ m_isotopeTypeCount[j] = %d\n",m_isotopeTypeCount[j]);
			mprintf("@ m_isotopeTypeTotalCount[i] = %d\n",m_isotopeTypeTotalCount[i]);
			mprintf("@ m_isotopeTypeTotalCount[j] = %d\n",m_isotopeTypeTotalCount[j]);
			mprintf("@ shift = %.10G\n",shift);*/

			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = 0;
				for (l = 0; l < df->m_iResolution; l++) {
					double r = (0.5 + l) / df->m_fFac;
//>>> SG 27.08.2019
					if ( m_bLorch )
						f += r * (df->m_pBin[l] - shift) / q * sin(r * q) * sin(M_PI * r / df->m_iResolution) * df->m_iResolution / (M_PI * r);
					else
//<<< SG 27.08.2019
					f += r * (df->m_pBin[l] - shift) / q * sin(r * q);
				}
				sfacTemp->m_pBin[k] = f / df->m_fFac;
			}
			
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				sfac->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount);
				neutron->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_isotopeTypeList[i])->neutronFactor() * ((CSFacIsotope *)m_isotopeTypeList[j])->neutronFactor();
				xray->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_isotopeTypeList[i])->xrayFactor(q) * ((CSFacIsotope *)m_isotopeTypeList[j])->xrayFactor(q);
			}
			
			if (saveIntermediate) {
				if (g_bBoxNonOrtho)
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / g_fBoxVolume / 1000000.0);
				else
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / (g_fBoxX * g_fBoxY * g_fBoxZ));
				filename.sprintf("sfac_%s%s_sfac_%s_%s.csv", m_global ? "" : "self_", (const char *)m_name, (const char *)((CSFacIsotope *)m_isotopeTypeList[i])->label(), (const char *)((CSFacIsotope *)m_isotopeTypeList[j])->label());
				mprintf("      Writing Structure Factor to %s...\n", (const char *)filename);
				sfacTemp->Write("", filename, "", false);
			}
			
			sfacTemp->ZeroBin();
		}
	}
	
	delete sfacTemp;
}


void CStructureFactorGroup::finalizeIntra(CDF *sfac, CDF *xray, CDF *neutron, bool saveIntermediate, bool m_bLorch, bool kuehnelong) {
	int i, j, k, l;
	CxString filename;
	
	CDF *sfacTemp;
	try { sfacTemp = new CDF(); } catch(...) { sfacTemp = NULL; }
	if(sfacTemp == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	sfacTemp->m_fMinVal = sfac->m_fMinVal;
	sfacTemp->m_fMaxVal = sfac->m_fMaxVal;
	sfacTemp->m_iResolution = sfac->m_iResolution;
	sfacTemp->SetLabelX("Wave vector modulus / nm^-1");
	sfacTemp->SetLabelY("Intensity");
	sfacTemp->Create();
	
	for (i = 0; i < m_isotopeTypeList.GetSize(); i++) {
		for (j = i; j < m_isotopeTypeList.GetSize(); j++) {
			mprintf("      Processing intramolecular partial structure factor %s-%s\n", ((CSFacIsotope *)m_isotopeTypeList[i])->label(), ((CSFacIsotope *)m_isotopeTypeList[j])->label());
			CDF *df = (CDF *)m_rdfIntraList[(m_isotopeTypeList.GetSize()-1)*i - i*(i-1)/2 + j];
			
			df->MultiplyBin(1.0 / g_iSteps * g_iStride);

			if (i == j)
				df->MultiplyBin(2.0);

			if (kuehnelong)
				df->CorrectRadialDistKuehne();
			else
				df->CorrectRadialDist();

			if (g_bBoxNonOrtho)
				df->MultiplyBin(g_fBoxVolume * 1000000.0 / (4.0/3.0 * Pi) / ((double)m_isotopeTypeTotalCount[i]) / ((double)m_isotopeTypeTotalCount[j]));
			else
				df->MultiplyBin(g_fBoxX * g_fBoxY * g_fBoxZ / (4.0/3.0 * Pi) / ((double)m_isotopeTypeTotalCount[i]) / ((double)m_isotopeTypeTotalCount[j]));

			if (g_bDoubleBox)
				df->MultiplyBin(g_iDoubleBoxFactor);
			
			if (saveIntermediate) {
				filename.sprintf("sfac_self_%s_rdf_%s_%s_intra.csv", (const char *)m_name, (const char *)(((CSFacIsotope *)m_isotopeTypeList[i])->label()), (const char *)(((CSFacIsotope *)m_isotopeTypeList[j])->label()));
				mprintf("      Writing RDF to %s...\n", (const char *)filename);
				df->Write("", filename, "", false);
			}
			
			double shift = 0.0;
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = 0;
				for (l = 0; l < df->m_iResolution; l++) {
					double r = (0.5 + l) / df->m_fFac;
//>>> SG 27.08.2019
					if ( m_bLorch )
						f += r * (df->m_pBin[l] - shift) / q * sin(r * q) * sin(M_PI * r / df->m_iResolution) * df->m_iResolution / (M_PI * r);
					else
//<<< SG 27.08.2019
					f += r * (df->m_pBin[l] - shift) / q * sin(r * q);
				}
				sfacTemp->m_pBin[k] = f / df->m_fFac;
			}
			
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				sfac->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount);
				neutron->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_isotopeTypeList[i])->neutronFactor() * ((CSFacIsotope *)m_isotopeTypeList[j])->neutronFactor();
				xray->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_isotopeTypeList[i])->xrayFactor(q) * ((CSFacIsotope *)m_isotopeTypeList[j])->xrayFactor(q);
			}
			
			if (saveIntermediate) {
				if (g_bBoxNonOrtho)
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / g_fBoxVolume / 1000000.0);
				else
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / (g_fBoxX * g_fBoxY * g_fBoxZ));
				filename.sprintf("sfac_self_%s_sfac_%s_%s_intra.csv", (const char *)m_name, (const char *)((CSFacIsotope *)m_isotopeTypeList[i])->label(), (const char *)((CSFacIsotope *)m_isotopeTypeList[j])->label());
				mprintf("      Writing Structure Factor to %s...\n", (const char *)filename);
				sfacTemp->Write("", filename, "", false);
			}
			
			sfacTemp->ZeroBin();
		}
	}
	
	delete sfacTemp;
}


void CStructureFactorGroup::finalizeInter(CDF *sfac, CDF *xray, CDF *neutron, bool saveIntermediate, bool m_bLorch, bool kuehnelong) {
	int i, j, k, l;
	CxString filename;
	
	CDF *sfacTemp;
	try { sfacTemp = new CDF(); } catch(...) { sfacTemp = NULL; }
	if(sfacTemp == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	sfacTemp->m_fMinVal = sfac->m_fMinVal;
	sfacTemp->m_fMaxVal = sfac->m_fMaxVal;
	sfacTemp->m_iResolution = sfac->m_iResolution;
	sfacTemp->SetLabelX("Wave vector modulus / nm^-1");
	sfacTemp->SetLabelY("Intensity");
	sfacTemp->Create();
	
	for (i = 0; i < m_isotopeTypeList.GetSize(); i++) {
		for (j = i; j < m_isotopeTypeList.GetSize(); j++) {
			mprintf("      Processing intermolecular partial structure factor %s-%s\n", ((CSFacIsotope *)m_isotopeTypeList[i])->label(), ((CSFacIsotope *)m_isotopeTypeList[j])->label());
			CDF *df = (CDF *)m_rdfInterList[(m_isotopeTypeList.GetSize()-1)*i - i*(i-1)/2 + j];
			
			df->MultiplyBin(1.0 / g_iSteps * g_iStride);

			if (i == j)
				df->MultiplyBin(2.0);

			if (kuehnelong)
				df->CorrectRadialDistKuehne();
			else
				df->CorrectRadialDist();

			if (g_bBoxNonOrtho)
				df->MultiplyBin(g_fBoxVolume * 1000000.0 / (4.0/3.0 * Pi) / ((double)m_isotopeTypeTotalCount[i]) / ((double)m_isotopeTypeTotalCount[j]));
			else
				df->MultiplyBin(g_fBoxX * g_fBoxY * g_fBoxZ / (4.0/3.0 * Pi) / ((double)m_isotopeTypeTotalCount[i]) / ((double)m_isotopeTypeTotalCount[j]));

			if (g_bDoubleBox)
				df->MultiplyBin(g_iDoubleBoxFactor);
			
			if (saveIntermediate) {
				filename.sprintf("sfac_self_%s_rdf_%s_%s_inter.csv", (const char *)m_name, (const char *)(((CSFacIsotope *)m_isotopeTypeList[i])->label()), (const char *)(((CSFacIsotope *)m_isotopeTypeList[j])->label()));
				mprintf("      Writing RDF to %s...\n", (const char *)filename);
				df->Write("", filename, "", false);
			}
			
			//double shift = (double)m_isotopeTypeCount[i] * m_isotopeTypeCount[j] / (m_isotopeTypeTotalCount[i] * m_isotopeTypeTotalCount[j]);
			double shift = ((double)m_isotopeTypeCount[i]) * ((double)m_isotopeTypeCount[j]) / (((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]));
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = 0;
				for (l = 0; l < df->m_iResolution; l++) {
					double r = (0.5 + l) / df->m_fFac;
//>>> SG 27.08.2019
					if ( m_bLorch )
						f += r * (df->m_pBin[l] - shift) / q * sin(r * q) * sin(M_PI * r / df->m_iResolution) * df->m_iResolution / (M_PI * r);
					else
//<<< SG 27.08.2019
					f += r * (df->m_pBin[l] - shift) / q * sin(r * q);
				}
				sfacTemp->m_pBin[k] = f / df->m_fFac;
			}
			
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				sfac->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount);
				neutron->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_isotopeTypeList[i])->neutronFactor() * ((CSFacIsotope *)m_isotopeTypeList[j])->neutronFactor();
				xray->m_pBin[k] += sfacTemp->m_pBin[k] * ((i == j) ? 1.0 : 2.0) * ((double)m_isotopeTypeTotalCount[i]) * ((double)m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_isotopeTypeList[i])->xrayFactor(q) * ((CSFacIsotope *)m_isotopeTypeList[j])->xrayFactor(q);
			}
			
			if (saveIntermediate) {
				if (g_bBoxNonOrtho)
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / g_fBoxVolume / 1000000.0);
				else
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / (g_fBoxX * g_fBoxY * g_fBoxZ));
				filename.sprintf("sfac_self_%s_sfac_%s_%s_inter.csv", (const char *)m_name, (const char *)((CSFacIsotope *)m_isotopeTypeList[i])->label(), (const char *)((CSFacIsotope *)m_isotopeTypeList[j])->label());
				mprintf("      Writing Structure Factor to %s...\n", (const char *)filename);
				sfacTemp->Write("", filename, "", false);
			}
			
			sfacTemp->ZeroBin();
		}
	}
	
	delete sfacTemp;
}


CStructureFactorCross::CStructureFactorCross(CStructureFactorGroup *sfacGroup1, CStructureFactorGroup *sfacGroup2) {
	m_sfacGroup1 = sfacGroup1;
	m_sfacGroup2 = sfacGroup2;
	m_name.sprintf("%s_%s", (const char *)sfacGroup1->getName(), (const char *)sfacGroup2->getName());
	m_sepInterIntra = false;
}


CStructureFactorCross::~CStructureFactorCross() {
	int i;
	for (i = 0; i < m_rdfList.GetSize(); i++)
		delete (CDF *)m_rdfList[i];
	for (i = 0; i < m_rdfIntraList.GetSize(); i++)
		delete (CDF *)m_rdfIntraList[i];
	for (i = 0; i < m_rdfInterList.GetSize(); i++)
		delete (CDF *)m_rdfInterList[i];
}


void CStructureFactorCross::initialize(double rdfMax, int rdfRes) {
	int i;
	mprintf("      Creating %d RDFs\n", m_sfacGroup1->m_isotopeTypeList.GetSize() * m_sfacGroup2->m_isotopeTypeList.GetSize());
	for (i = 0; i < m_sfacGroup1->m_isotopeTypeList.GetSize() * m_sfacGroup2->m_isotopeTypeList.GetSize(); i++) {
		CDF *df;
		try { df = new CDF(); } catch(...) { df = NULL; }
		if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
		df->m_fMinVal = 0.0;
		df->m_fMaxVal = rdfMax;
		df->m_iResolution = rdfRes;
		df->SetLabelX("Distance / pm");
		df->SetLabelY("g(r)");
		df->Create();
		m_rdfList.Add(df);
	}
	
	if (m_sepInterIntra) {
		mprintf("      Creating %d intramolecular RDFs\n", m_sfacGroup1->m_isotopeTypeList.GetSize() * m_sfacGroup2->m_isotopeTypeList.GetSize());
		for (i = 0; i < m_sfacGroup1->m_isotopeTypeList.GetSize() * m_sfacGroup2->m_isotopeTypeList.GetSize(); i++) {
			CDF *df;
			try { df = new CDF(); } catch(...) { df = NULL; }
			if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			df->m_fMinVal = 0.0;
			df->m_fMaxVal = rdfMax;
			df->m_iResolution = rdfRes;
			df->SetLabelX("Distance / pm");
			df->SetLabelY("g(r)");
			df->Create();
			m_rdfIntraList.Add(df);
		}
		mprintf("      Creating %d intermolecular RDFs\n", m_sfacGroup1->m_isotopeTypeList.GetSize() * m_sfacGroup2->m_isotopeTypeList.GetSize());
		for (i = 0; i < m_sfacGroup1->m_isotopeTypeList.GetSize() * m_sfacGroup2->m_isotopeTypeList.GetSize(); i++) {
			CDF *df;
			try { df = new CDF(); } catch(...) { df = NULL; }
			if (df == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			df->m_fMinVal = 0.0;
			df->m_fMaxVal = rdfMax;
			df->m_iResolution = rdfRes;
			df->SetLabelX("Distance / pm");
			df->SetLabelY("g(r)");
			df->Create();
			m_rdfInterList.Add(df);
		}
	}
}


void CStructureFactorCross::process(CTimeStep* ts) {
	int i, j;
	for(i = 0; i < m_sfacGroup1->m_atomIndexList.GetSize(); i++) {
		//if ((i%100) == 0)
		//	mprintf("\n@Cross i=%d",i);
		for(j = 0; j < m_sfacGroup2->m_atomIndexList.GetSize(); j++) {
			double dist = FoldedLength(ts->m_vaCoords[m_sfacGroup1->m_atomIndexList[i]] - ts->m_vaCoords[m_sfacGroup2->m_atomIndexList[j]]);
			int a = m_sfacGroup1->m_isotopeList[i];
			int b = m_sfacGroup2->m_isotopeList[j];
			((CDF *)m_rdfList[a * m_sfacGroup2->m_isotopeTypeList.GetSize() + b])->AddToBin(dist);
			if (m_sepInterIntra) {
				if (m_sfacGroup1->m_singleMolList[i] == m_sfacGroup2->m_singleMolList[j])
					((CDF *)m_rdfIntraList[a * m_sfacGroup2->m_isotopeTypeList.GetSize() + b])->AddToBin(dist);
				else
					((CDF *)m_rdfInterList[a * m_sfacGroup2->m_isotopeTypeList.GetSize() + b])->AddToBin(dist);
			}
		}
	}
}


void CStructureFactorCross::finalize(CDF *sfac, CDF *xray, CDF *neutron, bool saveIntermediate, bool m_bLorch, bool kuehnelong) {
	int i, j, k, l;
	CxString filename;
	
	CDF *sfacTemp;
	try { sfacTemp = new CDF(); } catch(...) { sfacTemp = NULL; }
	if(sfacTemp == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	sfacTemp->m_fMinVal = sfac->m_fMinVal;
	sfacTemp->m_fMaxVal = sfac->m_fMaxVal;
	sfacTemp->m_iResolution = sfac->m_iResolution;
	sfacTemp->SetLabelX("Wave vector modulus / nm^-1");
	sfacTemp->SetLabelY("Intensity");
	sfacTemp->Create();
	
	for (i = 0; i < m_sfacGroup1->m_isotopeTypeList.GetSize(); i++) {
		for (j = 0; j < m_sfacGroup2->m_isotopeTypeList.GetSize(); j++) {
			mprintf("      Processing partial structure factor %s-%s\n", ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label(), ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label());
			CDF *df = (CDF *)m_rdfList[i * m_sfacGroup2->m_isotopeTypeList.GetSize() + j];
			
			df->MultiplyBin(1.0 / g_iSteps * g_iStride);

			if ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])
				df->MultiplyBin(2.0);

			if (kuehnelong)
				df->CorrectRadialDistKuehne();
			else
				df->CorrectRadialDist();

			if (g_bBoxNonOrtho)
				df->MultiplyBin(g_fBoxVolume * 1000000.0 / (4.0/3.0 * Pi) / ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) / ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));
			else
				df->MultiplyBin(g_fBoxX * g_fBoxY * g_fBoxZ / (4.0/3.0 * Pi) / ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) / ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));

			if (g_bDoubleBox)
				df->MultiplyBin(g_iDoubleBoxFactor);
			
			if (saveIntermediate) {
				filename.sprintf("sfac_cross_%s_rdf_%s_%s.csv", (const char *)m_name, (const char *)(((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label()), (const char *)(((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label()));
				mprintf("      Writing RDF to %s...\n", (const char *)filename);
				df->Write("", filename, "", false);
			}
			
			double shift = ((double)m_sfacGroup1->m_isotopeTypeCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeCount[j]) / (((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));
			if ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])
				shift *= 2.0;
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = 0;
				for (l = 0; l < df->m_iResolution; l++) {
					double r = (0.5 + l) / df->m_fFac;
//>>> SG 27.08.2019
					if ( m_bLorch )
						f += r * (df->m_pBin[l] - shift) / q * sin(r * q) * sin(M_PI * r / df->m_iResolution) * df->m_iResolution / (M_PI * r);
					else
//<<< SG 27.08.2019
					f += r * (df->m_pBin[l] - shift) / q * sin(r * q);
				}
				sfacTemp->m_pBin[k] = f / df->m_fFac;
			}
			
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = (CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j] ? 1.0 : 2.0;
				sfac->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount);
				neutron->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->neutronFactor() * ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->neutronFactor();
				xray->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->xrayFactor(q) * ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->xrayFactor(q);
			}
			
			if (saveIntermediate) {
				if (g_bBoxNonOrtho)
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / g_fBoxVolume / 1000000.0);
				else
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / (g_fBoxX * g_fBoxY * g_fBoxZ));
				filename.sprintf("sfac_cross_%s_sfac_%s_%s.csv", (const char *)m_name, (const char *)((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label(), (const char *)((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label());
				mprintf("      Writing Structure Factor to %s...\n", (const char *)filename);
				sfacTemp->Write("", filename, "", false);
			}
			
			sfacTemp->ZeroBin();
		}
	}
	
	delete sfacTemp;
}


void CStructureFactorCross::finalizeIntra(CDF *sfac, CDF *xray, CDF *neutron, bool saveIntermediate, bool m_bLorch, bool kuehnelong) {
	int i, j, k, l;
	CxString filename;
	
	CDF *sfacTemp;
	try { sfacTemp = new CDF(); } catch(...) { sfacTemp = NULL; }
	if(sfacTemp == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	sfacTemp->m_fMinVal = sfac->m_fMinVal;
	sfacTemp->m_fMaxVal = sfac->m_fMaxVal;
	sfacTemp->m_iResolution = sfac->m_iResolution;
	sfacTemp->SetLabelX("Wave vector modulus / nm^-1");
	sfacTemp->SetLabelY("Intensity");
	sfacTemp->Create();
	
	for (i = 0; i < m_sfacGroup1->m_isotopeTypeList.GetSize(); i++) {
		for (j = 0; j < m_sfacGroup2->m_isotopeTypeList.GetSize(); j++) {
			mprintf("      Processing intramolecular partial structure factor %s-%s\n", ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label(), ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label());
			CDF *df = (CDF *)m_rdfIntraList[i * m_sfacGroup2->m_isotopeTypeList.GetSize() + j];
			
			df->MultiplyBin(1.0 / g_iSteps * g_iStride);

			if ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])
				df->MultiplyBin(2.0);

			if (kuehnelong)
				df->CorrectRadialDistKuehne();
			else
				df->CorrectRadialDist();

			if (g_bBoxNonOrtho)
				df->MultiplyBin(g_fBoxVolume * 1000000.0 / (4.0/3.0 * Pi) / ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) / ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));
			else
				df->MultiplyBin(g_fBoxX * g_fBoxY * g_fBoxZ / (4.0/3.0 * Pi) / ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) / ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));

			if (g_bDoubleBox)
				df->MultiplyBin(g_iDoubleBoxFactor);
			
			if (saveIntermediate) {
				filename.sprintf("sfac_cross_%s_rdf_%s_%s_intra.csv", (const char *)m_name, (const char *)(((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label()), (const char *)(((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label()));
				mprintf("      Writing RDF to %s...\n", (const char *)filename);
				df->Write("", filename, "", false);
			}
			
			double shift = 0.0;
			if ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])
				shift *= 2.0;
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = 0;
				for (l = 0; l < df->m_iResolution; l++) {
					double r = (0.5 + l) / df->m_fFac;
//>>> SG 27.08.2019
					if ( m_bLorch )
						f += r * (df->m_pBin[l] - shift) / q * sin(r * q) * sin(M_PI * r / df->m_iResolution) * df->m_iResolution / (M_PI * r);
					else
//<<< SG 27.08.2019
					f += r * (df->m_pBin[l] - shift) / q * sin(r * q);
				}
				sfacTemp->m_pBin[k] = f / df->m_fFac;
			}
			
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = (CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j] ? 1.0 : 2.0;
				sfac->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount);
				neutron->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->neutronFactor() * ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->neutronFactor();
				xray->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->xrayFactor(q) * ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->xrayFactor(q);
			}
			
			if (saveIntermediate) {
				if (g_bBoxNonOrtho)
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / g_fBoxVolume / 1000000.0);
				else
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / (g_fBoxX * g_fBoxY * g_fBoxZ));
				filename.sprintf("sfac_cross_%s_sfac_%s_%s_intra.csv", (const char *)m_name, (const char *)((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label(), (const char *)((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label());
				mprintf("      Writing Structure Factor to %s...\n", (const char *)filename);
				sfacTemp->Write("", filename, "", false);
			}
			
			sfacTemp->ZeroBin();
		}
	}
	
	delete sfacTemp;
}


void CStructureFactorCross::finalizeInter(CDF *sfac, CDF *xray, CDF *neutron, bool saveIntermediate, bool m_bLorch, bool kuehnelong) {
	int i, j, k, l;
	CxString filename;
	
	CDF *sfacTemp;
	try { sfacTemp = new CDF(); } catch(...) { sfacTemp = NULL; }
	if(sfacTemp == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	sfacTemp->m_fMinVal = sfac->m_fMinVal;
	sfacTemp->m_fMaxVal = sfac->m_fMaxVal;
	sfacTemp->m_iResolution = sfac->m_iResolution;
	sfacTemp->SetLabelX("Wave vector modulus / nm^-1");
	sfacTemp->SetLabelY("Intensity");
	sfacTemp->Create();
	
	for (i = 0; i < m_sfacGroup1->m_isotopeTypeList.GetSize(); i++) {
		for (j = 0; j < m_sfacGroup2->m_isotopeTypeList.GetSize(); j++) {
			mprintf("      Processing intermolecular partial structure factor %s-%s\n", ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label(), ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label());
			CDF *df = (CDF *)m_rdfInterList[i * m_sfacGroup2->m_isotopeTypeList.GetSize() + j];
			
			df->MultiplyBin(1.0 / g_iSteps * g_iStride);

			if ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])
				df->MultiplyBin(2.0);

			if (kuehnelong)
				df->CorrectRadialDistKuehne();
			else
				df->CorrectRadialDist();

			if (g_bBoxNonOrtho)
				df->MultiplyBin(g_fBoxVolume * 1000000.0 / (4.0/3.0 * Pi) / ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) / ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));
			else
				df->MultiplyBin(g_fBoxX * g_fBoxY * g_fBoxZ / (4.0/3.0 * Pi) / ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) / ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));

			if (g_bDoubleBox)
				df->MultiplyBin(g_iDoubleBoxFactor);
			
			if (saveIntermediate) {
				filename.sprintf("sfac_cross_%s_rdf_%s_%s_inter.csv", (const char *)m_name, (const char *)(((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label()), (const char *)(((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label()));
				mprintf("      Writing RDF to %s...\n", (const char *)filename);
				df->Write("", filename, "", false);
			}
			
			double shift = ((double)m_sfacGroup1->m_isotopeTypeCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeCount[j]) / (((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]));
			if ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])
				shift *= 2.0;
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = 0;
				for (l = 0; l < df->m_iResolution; l++) {
					double r = (0.5 + l) / df->m_fFac;
//>>> SG 27.08.2019
					if ( m_bLorch )
						f += r * (df->m_pBin[l] - shift) / q * sin(r * q) * sin(M_PI * r / df->m_iResolution) * df->m_iResolution / (M_PI * r);
					else
//<<< SG 27.08.2019
					f += r * (df->m_pBin[l] - shift) / q * sin(r * q);
				}
				sfacTemp->m_pBin[k] = f / df->m_fFac;
			}
			
			for (k = 0; k < sfacTemp->m_iResolution; k++) {
				double q = (sfacTemp->m_fMinVal + (0.5 + k) / sfacTemp->m_fFac) / 1000.0;
				double f = (CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i] == (CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j] ? 1.0 : 2.0;
				sfac->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount);
				neutron->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->neutronFactor() * ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->neutronFactor();
				xray->m_pBin[k] += sfacTemp->m_pBin[k] * f * ((double)m_sfacGroup1->m_isotopeTypeTotalCount[i]) * ((double)m_sfacGroup2->m_isotopeTypeTotalCount[j]) / ((double)g_iGesAtomCount) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->xrayFactor(q) * ((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->xrayFactor(q);
			}
			
			if (saveIntermediate) {
				if (g_bBoxNonOrtho)
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / g_fBoxVolume / 1000000.0);
				else
					sfacTemp->MultiplyBin(4.0 * Pi * g_iGesAtomCount / (g_fBoxX * g_fBoxY * g_fBoxZ));
				filename.sprintf("sfac_cross_%s_sfac_%s_%s_inter.csv", (const char *)m_name, (const char *)((CSFacIsotope *)m_sfacGroup1->m_isotopeTypeList[i])->label(), (const char *)((CSFacIsotope *)m_sfacGroup2->m_isotopeTypeList[j])->label());
				mprintf("      Writing Structure Factor to %s...\n", (const char *)filename);
				sfacTemp->Write("", filename, "", false);
			}
			
			sfacTemp->ZeroBin();
		}
	}
	
	delete sfacTemp;
}



void CStructureFactor::PrintAllScatteringFactors() {

	int i, j;
	CSFacElement *el;
	CSFacIsotope *isotope;

	mprintf("\n    The following scattering factors are available in TRAVIS:\n\n");
	mprintf(WHITE,"    Name    neutron       a1       a2       a3       a4       b1       b2       b3       b4        c\n");
	mprintf(WHITE,"    ------------------------------------------------------------------------------------------------\n");
	CxObArray tlist;
	for (i = 0; i < g_oaSFacElements.GetSize(); i++) {
		el = (CSFacElement*)g_oaSFacElements[i];
		for (j=0;j<(int)el->m_oaIsotopes.size();j++) {
			isotope = el->m_oaIsotopes[j];
			if (j == 0)
				mprintf("    %-6s %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
					isotope->m_sLabel.c_str(),
					isotope->neutronFactor(),
					isotope->m_pElement->m_fCMa[0],
					isotope->m_pElement->m_fCMa[1],
					isotope->m_pElement->m_fCMa[2],
					isotope->m_pElement->m_fCMa[3],
					isotope->m_pElement->m_fCMb[0],
					isotope->m_pElement->m_fCMb[1],
					isotope->m_pElement->m_fCMb[2],
					isotope->m_pElement->m_fCMb[3],
					isotope->m_pElement->m_fCMc
				);
			else
				mprintf("    %-6s %8.3f\n",
					isotope->m_sLabel.c_str(),
					isotope->neutronFactor()
				);
		}
	}
	mprintf("\n\n");
}



void CStructureFactor::PrintScatteringFactors() {

	int i, j, k;

	mprintf("\n    The following scattering factors are set up:\n\n");
	mprintf(WHITE,"    Name    neutron       a1       a2       a3       a4       b1       b2       b3       b4        c\n");
	mprintf(WHITE,"    ------------------------------------------------------------------------------------------------\n");
	CxObArray tlist;
	for (i = 0; i < isotopeAssignList.GetSize(); i++) {
		StructureFactorMolecule *smol = (StructureFactorMolecule *)isotopeAssignList[i];
		for (j = 0; j < smol->atomKinds.GetSize(); j++) {
			StructureFactorAtomKind *satom = (StructureFactorAtomKind *)smol->atomKinds[j];
			for (k = 0; k < satom->isotopeList.GetSize(); k++) {
				CSFacIsotope *isotope = (CSFacIsotope *)satom->isotopeList[k];
				bool tfound = false;
				int tl;
				for (tl = 0; tl < tlist.GetSize(); tl++) {
					if ((CSFacIsotope *)tlist[tl] == isotope) {
						tfound = true;
						break;
					}
				}
				if (!tfound) {
					mprintf("    %-6s %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
						isotope->m_sLabel.c_str(),
						isotope->neutronFactor(),
						isotope->m_pElement->m_fCMa[0],
						isotope->m_pElement->m_fCMa[1],
						isotope->m_pElement->m_fCMa[2],
						isotope->m_pElement->m_fCMa[3],
						isotope->m_pElement->m_fCMb[0],
						isotope->m_pElement->m_fCMb[1],
						isotope->m_pElement->m_fCMb[2],
						isotope->m_pElement->m_fCMb[3],
						isotope->m_pElement->m_fCMc
					);
					tlist.Add(isotope);
				}
			}
		}
	}
	mprintf("\n");
}



CStructureFactor::CStructureFactor() {

	int i, j, k;
	CxString buf, buf2, temp;
	

	if (g_bAdvanced2)
		PrintAllScatteringFactors();

	#ifdef _OPENMP
		#ifdef USE_OMP
			mprintf(WHITE,"    ####  OpenMP  ####\n");
			mprintf(WHITE,"    # ");
			mprintf("This analysis can be parallelized via OpenMP.\n");
			if (omp_get_max_threads() > 1) {
				mprintf(WHITE,"    # ");
				mprintf(GREEN,"OpenMP is active, max_threads=%d.\n", omp_get_max_threads() );
				mprintf(WHITE,"    # ");
				mprintf(GREEN,"Running in parallel on %d local CPU cores.\n", omp_get_max_threads() );
			} else {
				mprintf(WHITE,"    # ");
				mprintf(RED,"OpenMP is active, but max_threads=%d. Set the OMP_NUM_THREADS environment variable.\n", omp_get_max_threads() );
				mprintf(WHITE,"    # ");
				mprintf( RED, "Not using OpenMP, running serially.\n" );
			}
			mprintf(WHITE,"    ##################\n");
		#else
			mprintf(WHITE,"    ####  OpenMP  ####\n");
			mprintf(WHITE,"    # ");
			mprintf("This analysis can be parallelized via OpenMP.\n");
			mprintf(WHITE,"    # ");
			mprintf( RED, "Compiled with OpenMP, but USE_OMP not switched on in \"config.h\"!\n" );
			mprintf(WHITE,"    # ");
			mprintf( RED, "Not using OpenMP, running serially.\n" );
			mprintf(WHITE,"    ##################\n");
		#endif
	#else
		#ifdef USE_OMP
			mprintf(WHITE,"    ####  OpenMP  ####\n");
			mprintf(WHITE,"    # ");
			mprintf("This analysis can be parallelized via OpenMP.\n");
			mprintf(WHITE,"    # ");
			mprintf( RED, "USE_OMP is switched on, but code not compiled with -fopenmp!\n" );
			mprintf(WHITE,"    # ");
			mprintf( RED, "Not using OpenMP, running serially.\n" );
			mprintf(WHITE,"    ##################\n");
		#else
			mprintf(WHITE,"    ####  OpenMP  ####\n");
			mprintf(WHITE,"    # ");
			mprintf("This analysis can be parallelized via OpenMP.\n");
			mprintf(WHITE,"    # ");
			mprintf( RED, "USE_OMP not switched on in \"config.h\", and code is not compiled with -fopenmp!\n" );
			mprintf(WHITE,"    # ");
			mprintf( RED, "Not using OpenMP, running serially.\n" );
			mprintf(WHITE,"    ##################\n");
		#endif
	#endif

	mprintf("\n");


	for (i = 0; i < g_oaMolecules.GetSize(); i++) {
		CMolecule *mol = (CMolecule *)g_oaMolecules[i];
		StructureFactorMolecule *smol;
		try { smol = new StructureFactorMolecule; } catch(...) { smol = NULL; }
		if (smol == NULL) NewException((double)sizeof(StructureFactorMolecule), __FILE__, __LINE__, __PRETTY_FUNCTION__);
		smol->moleculeType = i;
		for (j = 0; j < mol->m_baAtomIndex.GetSize(); j++) {
			if (mol->m_baAtomIndex[j] == g_iVirtAtomType)
				continue;
			StructureFactorAtomKind *satom;
			try { satom = new StructureFactorAtomKind; } catch(...) { satom = NULL; }
			if (satom == NULL) NewException((double)sizeof(StructureFactorAtomKind), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			satom->atomType = mol->m_baAtomIndex[j];
			CSFacIsotope *isotope = NULL;
			for (k = 0; k < g_oaSFacIsotopes.GetSize(); k++) {
				if (mystricmp(((CAtom *)g_oaAtoms[mol->m_baAtomIndex[j]])->m_sName, ((CSFacIsotope *)g_oaSFacIsotopes[k])->label()) == 0) {
					isotope = (CSFacIsotope *)g_oaSFacIsotopes[k];
					break;
				}
			}
			if (isotope == NULL) {
				mprintf(RED, "Warning: no isotope data for \"%s\" found. Setting all scattering factors to 0.\n", (const char*)((CAtom *)g_oaAtoms[mol->m_baAtomIndex[j]])->m_sName);
				try { isotope = new CSFacIsotope( new CSFacElement( (const char*)((CAtom *)g_oaAtoms[mol->m_baAtomIndex[j]])->m_sName, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ), 0, (const char*)((CAtom *)g_oaAtoms[mol->m_baAtomIndex[j]])->m_sName, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ); } catch(...) { isotope = NULL; }
				if (isotope == NULL) NewException((double)sizeof(CSFacIsotope), __FILE__, __LINE__, __PRETTY_FUNCTION__);
				g_oaSFacIsotopes.Add(isotope);
			}
			for (k = 0; k < mol->m_waAtomCount[j]; k++) {
				satom->isotopeList.Add(isotope);
			}
			smol->atomKinds.Add(satom);
		}
		isotopeAssignList.Add(smol);
	}
	
	if (g_bAdvanced2) {

		PrintScatteringFactors();

		if (!AskYesNo("    Use standard atom data (y) or specify isotopes (n)? [yes] ", true)) {
			while (true) {
				buf.sprintf("\n    Change isotopes in which molecule (");
				for(i = 0; i < g_oaMolecules.GetSize(); i++) {
					buf2.sprintf("%s=%d", ((CMolecule *)g_oaMolecules[i])->m_sName, i+1);
					buf.strcat(buf2);
					if(i < g_oaMolecules.GetSize() - 1)
						buf.strcat(", ");
				}
				buf.strcat(")? ");
				int mol = AskRangeInteger_ND("%s", 1, g_oaMolecules.GetSize(),(const char*)buf) - 1;
				CMolecule *m = (CMolecule *)g_oaMolecules[mol];
				
				while (true) {
					mprintf("\n    The following isotopes are set up:\n");
					
					for (i = 0; i < m->m_baAtomIndex.GetSize(); i++) {
						if (m->m_baAtomIndex[i] == g_iVirtAtomType)
							continue;
						for (j = 0; j < m->m_waAtomCount[i]; j++) {
							mprintf("      %2s%-2d: %-4s\n", (const char*)((CAtom *)g_oaAtoms[m->m_baAtomIndex[i]])->m_sName, j+1, ((CSFacIsotope *)((StructureFactorAtomKind *)((StructureFactorMolecule *)isotopeAssignList[mol])->atomKinds[i])->isotopeList[j])->label());
						}
					}
					mprintf("\n\n");
					
					int ca, cb, cc;
					ca = 0;
					cc = 0;
					do {
						AskString("    Change isotope for which atom? [done] ", &buf, "");
						if (buf.GetLength() == 0)
							break;
					} while (!ParseAtom(buf, mol, ca, cb, cc));
					if (buf.GetLength() == 0)
						break;

					CSFacElement *el = NULL;

					mprintf("\n");
					mprintf("    The following isotopes are available for element \"%s\":\n", (const char*)((CAtom*)g_oaAtoms[cb])->m_sName );
					for (i=0;i<g_oaSFacElements.GetSize();i++) {
						if (mystricmp( ((CSFacElement*)g_oaSFacElements[i])->m_sLabel.c_str(), (const char*)((CAtom*)g_oaAtoms[cb])->m_sName ) == 0) {
							el = (CSFacElement*)g_oaSFacElements[i];
							break;
						}
					}

					if (el != NULL) {
						for (i=0;i<(int)el->m_oaIsotopes.size();i++)
							mprintf("      %s\n", el->m_oaIsotopes[i]->m_sLabel.c_str() );
					} else
						mprintf( "      (none)\n");
					mprintf( "\n");
					
					while (true) {
						AskString_ND("    Which isotope to set for %s (e.g. \"13C\")? ", &buf2, (const char *)buf);
						int isotopeIndex = -1;
						for (i = 0; i < g_oaSFacIsotopes.GetSize(); i++) {
							if(mystricmp(((CSFacIsotope *)g_oaSFacIsotopes[i])->label(), buf2) == 0) {
								isotopeIndex = i;
								break;
							}
						}
						if (isotopeIndex != -1) {
							((StructureFactorAtomKind *)((StructureFactorMolecule *)isotopeAssignList[mol])->atomKinds[ca])->isotopeList[cc] = (CSFacIsotope *)g_oaSFacIsotopes[isotopeIndex];
							break;
						}
						mprintf("\n    No isotope data for \"%s\" found.\n", (const char *)buf2);
						if (AskYesNo("    Enter data for \"%s\" (y/n)? [yes] ", true, (const char *)buf2)) {
							double nf = AskFloat_ND("    Enter neutron scattering factor: ");
							double cma1 = AskFloat_ND("    Enter Cromer-Mann coefficient a1: ");
							double cma2 = AskFloat_ND("    Enter Cromer-Mann coefficient a2: ");
							double cma3 = AskFloat_ND("    Enter Cromer-Mann coefficient a3: ");
							double cma4 = AskFloat_ND("    Enter Cromer-Mann coefficient a4: ");
							double cmb1 = AskFloat_ND("    Enter Cromer-Mann coefficient b1: ");
							double cmb2 = AskFloat_ND("    Enter Cromer-Mann coefficient b2: ");
							double cmb3 = AskFloat_ND("    Enter Cromer-Mann coefficient b3: ");
							double cmb4 = AskFloat_ND("    Enter Cromer-Mann coefficient b4: ");
							double cmc = AskFloat_ND("    Enter Cromer-Mann coefficient c: ");
							CSFacIsotope *isotope;

							try { isotope = new CSFacIsotope( new CSFacElement( buf2, 0, cma1, cma2, cma3, cma4, cmb1, cmb2, cmb3, cmb4, cmc ), 0, buf2, nf, 0.0, 0.0, 0.0, 0.0, 0.0 ); } catch(...) { isotope = NULL; }
							if (isotope == NULL) NewException((double)sizeof(CSFacIsotope), __FILE__, __LINE__, __PRETTY_FUNCTION__);
							g_oaSFacIsotopes.Add(isotope);
							((StructureFactorAtomKind *)((StructureFactorMolecule *)isotopeAssignList[mol])->atomKinds[ca])->isotopeList[cc] = isotope;
							break;
						} else {
							mprintf("\n");
						}
					}
				}
				
				if (!AskYesNo("\n    Change isotopes in another molecule (y/n)? [no] ", false))
					break;
			}
			mprintf("\n");
		} else {
			mprintf("\n");
		}
		
		if (AskYesNo("    Change the predefined scattering factors (y/n)? [no] ", false)) {
			CxObArray isotopeTypeList;
			for (i = 0; i < isotopeAssignList.GetSize(); i++) {
				StructureFactorMolecule *smol = (StructureFactorMolecule *)isotopeAssignList[i];
				for (j = 0; j < smol->atomKinds.GetSize(); j++) {
					StructureFactorAtomKind *satom = (StructureFactorAtomKind *)smol->atomKinds[j];
					for (k = 0; k < satom->isotopeList.GetSize(); k++) {
						CSFacIsotope *isotope = (CSFacIsotope *)satom->isotopeList[k];
						bool found = false;
						int l;
						for (l = 0; l < isotopeTypeList.GetSize(); l++) {
							if ((CSFacIsotope *)isotopeTypeList[l] == isotope) {
								found = true;
								break;
							}
						}
						if (!found) {
							isotopeTypeList.Add(isotope);
						}
					}
				}
			}
			
			while (true) {
				mprintf("\n    The following scattering factors are set up:\n\n");
				mprintf("    Name    neutron       a1       a2       a3       a4       b1       b2       b3       b4        c\n");
				for (i = 0; i < isotopeTypeList.GetSize(); i++) {
					CSFacIsotope *isotope = (CSFacIsotope *)isotopeTypeList[i];
					mprintf("    %-6s %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
						isotope->m_sLabel.c_str(),
						isotope->neutronFactor(),
						isotope->m_pElement->m_fCMa[0],
						isotope->m_pElement->m_fCMa[1],
						isotope->m_pElement->m_fCMa[2],
						isotope->m_pElement->m_fCMa[3],
						isotope->m_pElement->m_fCMb[0],
						isotope->m_pElement->m_fCMb[1],
						isotope->m_pElement->m_fCMb[2],
						isotope->m_pElement->m_fCMb[3],
						isotope->m_pElement->m_fCMc
					);
				}
				mprintf("\n");
				CSFacIsotope *isotope = NULL;
				while (true) {
					AskString("    Change scattering factors of which isotope? [done] ", &buf, "");
					if (buf.GetLength() == 0)
						break;
					for (i = 0; i < isotopeTypeList.GetSize(); i++) {
						if (mystricmp(((CSFacIsotope *)isotopeTypeList[i])->label(), buf) == 0) {
							isotope = (CSFacIsotope *)isotopeTypeList[i];
							break;
						}
					}
					if (isotope != NULL)
						break;
					eprintf("The system does not contain isotope \"%s\".\n", (const char *)buf);
				}
				if (buf.GetLength() == 0)
					break;
				isotope->m_fCoh_b = AskFloat_ND("    Enter neutron scattering factor: ");
				isotope->m_pElement->m_fCMa[0] = AskFloat_ND("    Enter Cromer-Mann coefficient a1: ");
				isotope->m_pElement->m_fCMa[1] = AskFloat_ND("    Enter Cromer-Mann coefficient a2: ");
				isotope->m_pElement->m_fCMa[2] = AskFloat_ND("    Enter Cromer-Mann coefficient a3: ");
				isotope->m_pElement->m_fCMa[3] = AskFloat_ND("    Enter Cromer-Mann coefficient a4: ");
				isotope->m_pElement->m_fCMb[0] = AskFloat_ND("    Enter Cromer-Mann coefficient b1: ");
				isotope->m_pElement->m_fCMb[1] = AskFloat_ND("    Enter Cromer-Mann coefficient b2: ");
				isotope->m_pElement->m_fCMb[2] = AskFloat_ND("    Enter Cromer-Mann coefficient b3: ");
				isotope->m_pElement->m_fCMb[3] = AskFloat_ND("    Enter Cromer-Mann coefficient b4: ");
				isotope->m_pElement->m_fCMc = AskFloat_ND("    Enter Cromer-Mann coefficient c: ");
			}
			mprintf("\n");
		} else {
			mprintf("\n");
		}
	}

	PrintScatteringFactors();

	if (!g_bAdvanced2)
		mprintf("\n    To specify isotopes or change the scattering cross sections, use the advanced mode.\n\n");
	
	try { m_globalSFac = new CStructureFactorGroup(true, isotopeAssignList); } catch(...) { m_globalSFac = NULL; }
	if (m_globalSFac == NULL) NewException((double)sizeof(CStructureFactorGroup), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	
	if (AskYesNo("    Compute partial structure factors of specific atom groups (y/n)? [no] ", false)) {
		while (true) {
			mprintf(WHITE, "\n    > Group %d >\n\n", m_sFacGroups.GetSize() + 1);
			CStructureFactorGroup *sfac;
			try { sfac = new CStructureFactorGroup(false, isotopeAssignList); } catch(...) { sfac = NULL; }
			if (sfac == NULL) NewException((double)sizeof(CStructureFactorGroup), __FILE__, __LINE__, __PRETTY_FUNCTION__);
			m_sFacGroups.Add(sfac);
			AskString("      Which label to use for this atom group? [%s] ",&buf,(const char*)sfac->getName(),(const char*)sfac->getName());
			sfac->getName() = (const char*)buf;
			mprintf("\n");
			mprintf(WHITE, "    < End of Group %d <\n\n", m_sFacGroups.GetSize());
			if (!AskYesNo("    Add another group (y/n)? [no] ", false))
				break;
		}
	}
	mprintf("\n");
	
	if (m_sFacGroups.GetSize() > 1) {
		if (AskYesNo("    Compute all cross terms of the defined atom groups (y) or select certain combinations (n)? [yes] ", true)) {
			mprintf("\n");
			int count = 0;
			for (i = 0; i < m_sFacGroups.GetSize(); i++) {
				for (j = i + 1; j < m_sFacGroups.GetSize(); j++) {
					CStructureFactorCross *sfac;
					try { sfac = new CStructureFactorCross((CStructureFactorGroup *)m_sFacGroups[i], (CStructureFactorGroup *)m_sFacGroups[j]); } catch(...) { sfac = NULL; }
					if (sfac == NULL) NewException((double)sizeof(CStructureFactorGroup), __FILE__, __LINE__, __PRETTY_FUNCTION__);
					m_sFacCrosses.Add(sfac);
					mprintf("    Cross term %d: Group %d - Group %d\n", ++count, i + 1, j + 1);
				}
			}
		} else {
			mprintf("    The following groups are defined:\n\n");
			for (i = 0; i < m_sFacGroups.GetSize(); i++) {
				mprintf("    %3d - %s\n", i + 1, (const char *)((CStructureFactorGroup *)m_sFacGroups[i])->getName());
			}
			mprintf("\n    Enter each combination as a comma-separated pair of numbers (e.g. 1,1)\n\n");
			CxWordArray wa;
			while (true) {
				wa.RemoveAll_KeepSize();
				AskString("    Enter combination (return=finished): ", &buf, "");
				if (buf.GetLength() == 0)
					break;
				ParseIntList(buf, &wa);
				if (wa.GetSize() != 2) {
					eprintf("Invalid input. Please enter exactly two numbers separated by a comma.\n");
					continue;
				}
				if ((wa[0] < 1) || (wa[1] < 1)) {
					eprintf("Invalid input. Please enter positive numbers.\n");
					continue;
				}
				if ((wa[0] > m_sFacGroups.GetSize()) || (wa[1] > m_sFacGroups.GetSize())) {
					eprintf("Invalid input. There are only %d groups.\n", m_sFacGroups.GetSize());
					continue;
				}
				if (wa[0] == wa[1]) {
					eprintf("Invalid input. Please enter two different numbers.\n");
					continue;
				}
				CStructureFactorCross *sfac;
				try { sfac = new CStructureFactorCross((CStructureFactorGroup *)m_sFacGroups[wa[0] - 1], (CStructureFactorGroup *)m_sFacGroups[wa[1] - 1]); } catch(...) { sfac = NULL; }
				if (sfac == NULL) NewException((double)sizeof(CStructureFactorGroup), __FILE__, __LINE__, __PRETTY_FUNCTION__);
				m_sFacCrosses.Add(sfac);
			}
		}
		mprintf("\n");
	}
	
	if (m_sFacCrosses.GetSize() > 0) {
		if (AskYesNo("    Separate intramolecular and intermolecular contributions in the cross terms (y/n)? [no] ", false))
			for (i = 0; i < m_sFacCrosses.GetSize(); i++)
				((CStructureFactorCross *)m_sFacCrosses[i])->setSepInterIntra(true);
		mprintf("\n");
	}

	m_fNormalizationFactor = 1.0;

	if (g_bAdvanced2) {
		mprintf("    Standard RDFs can be computed up to half of the smallest box diameter:      %5d pm\n",HalfBox());
		mprintf("    Long-range RDFs via Roehrig's & Kuehne's formalism can have a range up to:  %5.0f pm\n",sqrt(SQR(g_fBoxX)+SQR(g_fBoxY)+SQR(g_fBoxZ))/2.0);
		mprintf("\n");
		m_bKuehneLong = AskYesNo("    Use formalism of Roehrig & Kuehne for longer-range RDFs (y/n)? [no] ",false);
		mprintf("\n");
	} else
		m_bKuehneLong = false;

	if (m_bKuehneLong) {
		//m_rdfMax = AskFloat("    Enter maximum RDF distance to observe (in pm): [%.0f] ", floor(sqrt(SQR(g_fBoxX)+SQR(g_fBoxY)+SQR(g_fBoxZ))/2.0*0.97), floor(sqrt(SQR(g_fBoxX)+SQR(g_fBoxY)+SQR(g_fBoxZ))/2.0*0.97) );
		m_rdfMax = AskFloat("    Enter maximum RDF distance to observe (in pm): [%d] ", (double)HalfBox(), HalfBox());
		g_bKuehneLong = true; // For the literature reference
	} else
		m_rdfMax = AskFloat("    Enter maximum RDF distance to observe (in pm): [%d] ", (double)HalfBox(), HalfBox());

	m_rdfRes = AskUnsignedInteger("    Enter RDF binning resolution: [%d] ", 2 * HalfBox(), 2 * HalfBox());
	m_sfacMax = AskFloat("    Enter maximum wave vector modulus (nm^-1): [200] ", 200.0);
	m_sfacRes = AskUnsignedInteger("    Enter Structure Factor resolution: [2000] ", 2000);
	
	mprintf("\n    The following normalization factors are available:\n");
	mprintf("    (1) [Sum_i x_i*f_i(q)]^2\n");
	mprintf("    (2) Sum_i x_i*[f_i(q)]^2\n");
	mprintf("    (3) manual normalization factor\n");
	mprintf("    (4) 1 (no normalization)\n\n");

	mprintf("    They will all be written to the output files as consecutive columns.\n\n");

	m_fNormalizationFactor = AskFloat("    Enter manual normalization factor for (3): [%.5f] ",0.00714,0.00714);
	
	if (g_bAdvanced2) {
		mprintf("\n");
		m_saveIntermediate = AskYesNo("    Save all intermediate data (RDFs, etc.) (y/n)? [no] ", false);
	} else {
		mprintf("    To save intermediate data (RDFs, etc.), please activate the advanced mode.\n");
		m_saveIntermediate = false;
	}

	mprintf("\n");
	
	m_sharpening = AskYesNo("    Apply sharpening factor (y/n)? [no] ", false);
	if (m_sharpening) {
		while (true) {
			AskString_ND("    Which isotope to use as sharpening atom (e.g. \"N\" or \"14N\")? ", &buf);
			int isotopeIndex = -1;
			for (i = 0; i < g_oaSFacIsotopes.GetSize(); i++) {
				if(mystricmp(((CSFacIsotope *)g_oaSFacIsotopes[i])->label(), buf) == 0) {
					isotopeIndex = i;
					break;
				}
			}
			if(isotopeIndex != -1) {
				m_sharpeningIsotope = (CSFacIsotope *)g_oaSFacIsotopes[isotopeIndex];
				break;
			}
			eprintf("Isotope data for \"%s\" not found.\n", (const char *)buf);
		}
	} else {
		m_sharpeningIsotope = NULL;
	}
	mprintf("\n");

//>>> SG 27.08.2019
	m_bLorch = AskYesNo("    Apply Lorch type window function (y/n)? [no] ", false);
//<<< SG 27.08.2019
}


CStructureFactor::~CStructureFactor() {
	int i;
	delete m_globalSFac;
	for (i = 0; i < m_sFacGroups.GetSize(); i++)
		delete (CStructureFactorGroup *)m_sFacGroups[i];
	for (i = 0; i < m_sFacCrosses.GetSize(); i++)
		delete (CStructureFactorCross *)m_sFacCrosses[i];
}


void CStructureFactor::initialize() {
	int i;
	mprintf("  Initializing structure factor\n");
	mprintf(WHITE, "\n    > Total >\n\n");
	m_globalSFac->initialize(m_rdfMax, m_rdfRes);
	mprintf(WHITE, "\n    < End of Total <\n");
	for (i = 0; i < m_sFacGroups.GetSize(); i++) {
		mprintf(WHITE, "\n    > Group %d >\n\n", i + 1);
		((CStructureFactorGroup *)m_sFacGroups[i])->initialize(m_rdfMax, m_rdfRes);
		mprintf(WHITE, "\n    < End of Group %d <\n", i + 1);
	}
	for (i = 0; i < m_sFacCrosses.GetSize(); i++) {
		mprintf(WHITE, "\n    > Cross Term %d >\n\n", i + 1);
		((CStructureFactorCross *)m_sFacCrosses[i])->initialize(m_rdfMax, m_rdfRes);
		mprintf(WHITE, "\n    < End of Cross Term %d <\n", i + 1);
	}
	#ifdef _OPENMP
		#ifdef USE_OMP
			mprintf( "\n  OpenMP is active, max_threads=%d\n\n", omp_get_max_threads() );
		#else
			mprintf( RED, "\n  Compiled with OpenMP, but USE_OMP not switched on in \"config.h\"!\n\n" );
		#endif
	#else
		#ifdef USE_OMP
			mprintf( RED, "\n  USE_OMP is switched on, but code not compiled with -fopenmp!\n\n" );
		#endif
	#endif
}


void CStructureFactor::process(CTimeStep *ts) {
	int i;
	m_globalSFac->process(ts);
	for (i = 0; i < m_sFacGroups.GetSize(); i++) {
		((CStructureFactorGroup *)m_sFacGroups[i])->process(ts);
	}
	for (i = 0; i < m_sFacCrosses.GetSize(); i++) {
		((CStructureFactorCross *)m_sFacCrosses[i])->process(ts);
	}
}



void CStructureFactor::HandleGroup( const char *name, CStructureFactorGroup *sfgroup, CStructureFactorCross *sfcross, int mode ) {

	int i, z, z2, z3;
	CDF *sfac, *xray, *neutron, *dfwork;
	double *workbin, sf, xf, nf, q;
	CxString modesuffix, filename, clabel;


	try { sfac = new CDF(); } catch(...) { sfac = NULL; }
	if (sfac == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	sfac->m_fMinVal = 2.0 * Pi / m_rdfMax * 1000.0;
	sfac->m_fMaxVal = m_sfacMax;
	sfac->m_iResolution = m_sfacRes;
	sfac->SetLabelX("Wave vector modulus / nm^-1");
	sfac->SetLabelY("Intensity (normalization 1)");
	sfac->Create();

	try { xray = new CDF(); } catch(...) { xray = NULL; }
	if (xray == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	xray->m_fMinVal = 2.0 * Pi / m_rdfMax * 1000.0;
	xray->m_fMaxVal = m_sfacMax;
	xray->m_iResolution = m_sfacRes;
	xray->SetLabelX("Wave vector modulus / nm^-1");
	xray->SetLabelY("Intensity (normalization 1)");
	xray->Create();

	try { neutron = new CDF(); } catch(...) { neutron = NULL; }
	if (neutron == NULL) NewException((double)sizeof(CDF), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	neutron->m_fMinVal = 2.0 * Pi / m_rdfMax * 1000.0;
	neutron->m_fMaxVal = m_sfacMax;
	neutron->m_iResolution = m_sfacRes;
	neutron->SetLabelX("Wave vector modulus / nm^-1");
	neutron->SetLabelY("Intensity (normalization 1)");
	neutron->Create();
	
	switch(mode) {

		case 0: // Standard
			modesuffix = "";
			if (sfgroup != NULL)
				sfgroup->finalize( sfac, xray, neutron, m_saveIntermediate, m_bLorch, m_bKuehneLong );
			else if (sfcross != NULL)
				sfcross->finalize( sfac, xray, neutron, m_saveIntermediate, m_bLorch, m_bKuehneLong );
			else {
				eprintf("CStructureFactor::HandleGroup(): Internal error.\n");
				abort();
			}
			break;

		case 1: // Intra
			modesuffix.Format("_intra");
			if (sfgroup != NULL)
				sfgroup->finalizeIntra( sfac, xray, neutron, m_saveIntermediate, m_bLorch, m_bKuehneLong );
			else if (sfcross != NULL)
				sfcross->finalizeIntra( sfac, xray, neutron, m_saveIntermediate, m_bLorch, m_bKuehneLong );
			else {
				eprintf("CStructureFactor::HandleGroup(): Internal error.\n");
				abort();
			}
			break;

		case 2: // Inter
			modesuffix.Format("_inter");
			if (sfgroup != NULL)
				sfgroup->finalizeInter( sfac, xray, neutron, m_saveIntermediate, m_bLorch, m_bKuehneLong );
			else if (sfcross != NULL)
				sfcross->finalizeInter( sfac, xray, neutron, m_saveIntermediate, m_bLorch, m_bKuehneLong );
			else {
				eprintf("CStructureFactor::HandleGroup(): Internal error.\n");
				abort();
			}
			break;
	}

	if (m_bKuehneLong)
		modesuffix += "_long";

	for (i=0;i<3;i++) {

		switch(i) {
			case 0:
				dfwork = sfac;
				break;
			case 1:
				dfwork = xray;
				break;
			case 2:
				dfwork = neutron;
				break;
			default:
				eprintf("CStructureFactor::HandleGroup(): Internal error.\n");
				abort();
		}

		if (g_bBoxNonOrtho) {
			double f = 4.0 * Pi * g_iGesAtomCount / (g_fBoxVolume * 1000000.0);
			dfwork->MultiplyBin(f);
		} else {
			double f = 4.0 * Pi * g_iGesAtomCount / (g_fBoxX * g_fBoxY * g_fBoxZ);
			dfwork->MultiplyBin(f);
		}

		dfwork->m_iAdditionalSets = 3;

		try { dfwork->m_pAdditionalSets = new double*[dfwork->m_iAdditionalSets]; } catch(...) { dfwork->m_pAdditionalSets = NULL; }
		if (dfwork->m_pAdditionalSets == NULL) NewException((double)dfwork->m_iAdditionalSets*sizeof(double*),__FILE__,__LINE__,__PRETTY_FUNCTION__);
		
		try { dfwork->m_pAdditionalSetLabels = new char*[dfwork->m_iAdditionalSets]; } catch(...) { dfwork->m_pAdditionalSetLabels = NULL; }
		if (dfwork->m_pAdditionalSetLabels == NULL) NewException((double)dfwork->m_iAdditionalSets*sizeof(char*),__FILE__,__LINE__,__PRETTY_FUNCTION__);
		
		for (z=0;z<dfwork->m_iAdditionalSets;z++) {

			try { dfwork->m_pAdditionalSets[z] = new double[dfwork->m_iResolution]; } catch(...) { dfwork->m_pAdditionalSets[z] = NULL; }
			if (dfwork->m_pAdditionalSets[z] == NULL) NewException((double)dfwork->m_iResolution*sizeof(double),__FILE__,__LINE__,__PRETTY_FUNCTION__);

			for (z2=0;z2<dfwork->m_iResolution;z2++)
				dfwork->m_pAdditionalSets[z][z2] = dfwork->m_pBin[z2];

			switch(z) {
				case 0:
					clabel.sprintf("Intensity (normalization 2)");
					break;
				case 1:
					clabel.sprintf("Intensity (manual normalization by %.8f)",m_fNormalizationFactor);
					break;
				case 2:
					clabel.sprintf("Intensity (no normalization)");
					break;
			}

			try { dfwork->m_pAdditionalSetLabels[z] = new char[strlen((const char*)clabel)+1]; } catch(...) { dfwork->m_pAdditionalSetLabels[z] = NULL; }
			if (dfwork->m_pAdditionalSetLabels[z] == NULL) NewException((double)strlen((const char*)clabel)+1,__FILE__,__LINE__,__PRETTY_FUNCTION__);
			strcpy( dfwork->m_pAdditionalSetLabels[z], (const char*)clabel );
		}

		for (z=0;z<4;z++) {

			if (z == 0)
				workbin = dfwork->m_pBin;
			else
				workbin = dfwork->m_pAdditionalSets[z-1];

			switch(z) {

				case 0: // Normalization factor 1
					switch(i) {
						case 0: // SFac
							sf = 0.0;
							for (z2=0;z2<m_globalSFac->getIsotopeTypeList().GetSize();z2++)
								sf += ((double)m_globalSFac->getIsotopeTypeTotalCount().GetAt(z2)) / ((double)g_iGesAtomCount);
							for (z2=0;z2<dfwork->m_iResolution;z2++)
								workbin[z2] *= 1.0 / (sf * sf);
							break;

						case 1: // Xray
							for (z2=0;z2<dfwork->m_iResolution;z2++) {
								q = (dfwork->m_fMinVal + (0.5 + z2) / dfwork->m_fFac) / 1000.0;
								xf = 0.0;
								for (z3=0;z3<m_globalSFac->getIsotopeTypeList().GetSize();z3++)
									xf += ((double)m_globalSFac->getIsotopeTypeTotalCount().GetAt(z3)) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_globalSFac->getIsotopeTypeList().GetAt(z3))->xrayFactor(q);
								workbin[z2] *= 1.0 / (xf * xf);
							}
							break;
					
						case 2: // Neutron
							nf = 0.0;
							for (z2=0;z2<m_globalSFac->getIsotopeTypeList().GetSize();z2++)
								nf += ((double)m_globalSFac->getIsotopeTypeTotalCount().GetAt(z2)) / ((double)g_iGesAtomCount) * ((CSFacIsotope *)m_globalSFac->getIsotopeTypeList().GetAt(z2))->neutronFactor();
							for (z2=0;z2<dfwork->m_iResolution;z2++)
								workbin[z2] *= 1.0 / (nf * nf);
							break;
					}
					break;

				case 1: // Normalization factor 2
					switch(i) {
						case 0: // SFac
							sf = 0.0;
							for (z2=0;z2<m_globalSFac->getIsotopeTypeList().GetSize();z2++)
								sf += ((double)m_globalSFac->getIsotopeTypeTotalCount().GetAt(z2)) / ((double)g_iGesAtomCount);
							for (z2=0;z2<dfwork->m_iResolution;z2++)
								workbin[z2] *= 1.0 / sf;
							break;

						case 1: // Xray
							for (z2=0;z2<dfwork->m_iResolution;z2++) {
								q = (dfwork->m_fMinVal + (0.5 + z2) / dfwork->m_fFac) / 1000.0;
								xf = 0.0;
								for (z3=0;z3<m_globalSFac->getIsotopeTypeList().GetSize();z3++)
									xf += ((double)m_globalSFac->getIsotopeTypeTotalCount().GetAt(z3)) / ((double)g_iGesAtomCount) * ((CSFacIsotope*)m_globalSFac->getIsotopeTypeList().GetAt(z3))->xrayFactor(q) * ((CSFacIsotope*)m_globalSFac->getIsotopeTypeList().GetAt(z3))->xrayFactor(q);
								workbin[z2] *= 1.0 / xf;
							}
							break;
					
						case 2: // Neutron
							nf = 0.0;
							for (z2=0;z2<m_globalSFac->getIsotopeTypeList().GetSize();z2++)
								nf += ((double)m_globalSFac->getIsotopeTypeTotalCount().GetAt(z2)) / ((double)g_iGesAtomCount) * ((CSFacIsotope*)m_globalSFac->getIsotopeTypeList().GetAt(z2))->neutronFactor() * ((CSFacIsotope*)m_globalSFac->getIsotopeTypeList().GetAt(z2))->neutronFactor();
							for (z2=0;z2<dfwork->m_iResolution;z2++)
								workbin[z2] *= 1.0 / nf;
							break;
					}
					break;

				case 2: // Manual Normalization
					for (z2=0;z2<dfwork->m_iResolution;z2++)
						workbin[z2] *= m_fNormalizationFactor;
					break;

				case 3: // No Normalization
					// Do nothing
					break;
			}
		}
	}

	mprintf("\n");
	filename.sprintf( "%s_unweighted%s.csv", name, (const char*)modesuffix );
	mprintf( "      Writing unweighted structure factor to %s ...\n", (const char *)filename );
	sfac->Write( "", filename, "", false );
	filename.sprintf( "%s_xray%s.csv", name, (const char*)modesuffix );
	mprintf( "      Writing X-ray scattering function to %s ...\n", (const char *)filename );
	xray->Write( "", filename, "", false );
	filename.sprintf( "%s_neutron%s.csv", name, (const char*)modesuffix );
	mprintf( "      Writing neutron scattering function to %s ...\n", (const char *)filename );
	neutron->Write( "", filename, "", false );
	
	if (m_sharpening) {

		for (i=0;i<xray->m_iResolution;i++) {
			q = (xray->m_fMinVal + (0.5 + i) / xray->m_fFac) / 1000.0;
			nf = q * exp(-0.01 * q * q);
			xf = q * exp(-0.01 * q * q) * m_sharpeningIsotope->xrayFactor(0.0) * m_sharpeningIsotope->xrayFactor(0.0) / m_sharpeningIsotope->xrayFactor(q) / m_sharpeningIsotope->xrayFactor(q);
			neutron->m_pBin[i] *= nf;
			xray->m_pBin[i] *= xf;
			for (z=0;z<3;z++) {
				neutron->m_pAdditionalSets[z][i] *= nf;
				xray->m_pAdditionalSets[z][i] *= xf;
			}
		}
		
		filename.sprintf( "%s_neutron%s_sharpened.csv", name,(const char*)modesuffix );
		mprintf( "      Writing sharpened neutron scattering function to %s ...\n", (const char *)filename );
		neutron->Write( "", filename, "", false );
		filename.sprintf( "%s_xray%s_sharpened.csv", name, (const char*)modesuffix );
		mprintf( "      Writing sharpened X-ray scattering function to %s ...\n", (const char *)filename );
		xray->Write( "", filename, "", false );
	}

	mprintf("\n");

	delete sfac;
	delete xray;
	delete neutron;
}



void CStructureFactor::finalize() {

	int i;
	CxString name;


	mprintf("  Finalizing structure factor\n");
	
	mprintf(WHITE, "\n    > Total >\n\n");
	
	HandleGroup( "sfac_total", m_globalSFac, NULL, 0 );

	if (m_globalSFac->sepInterIntra()) {
		HandleGroup( "sfac_total", m_globalSFac, NULL, 1 );
		HandleGroup( "sfac_total", m_globalSFac, NULL, 2 );
	}
		
	mprintf(WHITE, "    < End of Total <\n");
	
	for (i=0;i<m_sFacGroups.GetSize();i++) {

		mprintf(WHITE, "\n    > Group %d >\n\n", i + 1);

		name.sprintf( "sfac_self_%s", (const char*)((CStructureFactorGroup*)m_sFacGroups[i])->getName() );

		HandleGroup( (const char*)name, (CStructureFactorGroup*)m_sFacGroups[i], NULL, 0 );

		if (((CStructureFactorGroup*)m_sFacGroups[i])->sepInterIntra()) {
			HandleGroup( (const char*)name, (CStructureFactorGroup*)m_sFacGroups[i], NULL, 1 );
			HandleGroup( (const char*)name, (CStructureFactorGroup*)m_sFacGroups[i], NULL, 2 );
		}

		mprintf(WHITE, "    < End of Group %d <\n", i + 1);
	}

	for (i=0;i<m_sFacCrosses.GetSize();i++) {

		mprintf(WHITE, "\n    > Cross Term %d >\n\n", i + 1);

		name.sprintf( "sfac_cross_%s", (const char*)((CStructureFactorCross*)m_sFacCrosses[i])->getName() );

		HandleGroup( (const char*)name, NULL, (CStructureFactorCross*)m_sFacCrosses[i], 0 );

		if (((CStructureFactorGroup*)m_sFacGroups[i])->sepInterIntra()) {
			HandleGroup( (const char*)name, NULL, (CStructureFactorCross*)m_sFacCrosses[i], 1 );
			HandleGroup( (const char*)name, NULL, (CStructureFactorCross*)m_sFacCrosses[i], 2 );
		}

		mprintf(WHITE, "    < End of Cross Term %d <\n", i + 1);
	}
}


bool gatherStructureFactor() {
	createIsotopeList();
	
	try { g_structureFactor = new CStructureFactor(); } catch(...) { g_structureFactor = NULL; }
	if (g_structureFactor == NULL) NewException((double)sizeof(CStructureFactor), __FILE__, __LINE__, __PRETTY_FUNCTION__);
	
	return true;
}


bool initializeStructureFactor() {
	g_structureFactor->initialize();
	return true;
}


void processStructureFactor(CTimeStep *ts) {
	g_structureFactor->process(ts);
}


void finalizeStructureFactor() {
	g_structureFactor->finalize();
	delete g_structureFactor;
	deleteIsotopeList();
}

