////////////////////////////////////////////////////////
//  
// Reads an ASCII-matrix and samples observables
// in 1-, 2- or 3-dimensional space. The sampled
// observables can be written to PParticles via
// batch scripting
//
////////////////////////////////////////////////////////

#include "PDensityMatrix.h"
#include "PChannel.h"


PDensityMatrix::PDensityMatrix() {
    projector      = NULL;
    current_matrix = 0;
    x = makeStaticData()->GetBatchValue("_x");
    y = makeStaticData()->GetBatchValue("_y");
    z = makeStaticData()->GetBatchValue("_z");
}

Bool_t PDensityMatrix::IsBorder(Int_t bin) {
    //checks if there is a grid border between bin-1 and bin
    if ((bin % axes_size[0]) == 0) {
	return kTRUE;
    }
    return kFALSE;
}

Bool_t PDensityMatrix::GetBin(Double_t *x, Int_t *bins) {
    bins[0] = bins[1] = bins[2] = 0;

    for (int i=0; i<dimension; i++) {
	bins[i] = 0;
	for (int j=0; j<axes_size[i]; j++) {
	    bins[i] = j;
	    if (x[i] <= (axes[i])[j]) {
		j = axes_size[i];
	    } 
	}
    }
    
    return kTRUE;
}

Bool_t PDensityMatrix::GetBin(Int_t bin, Int_t *bins) {
    bins[0] = bin % axes_size[0];
    if (dimension > 1) 
	bins[1] = ((bin - bins[0]) / axes_size[0]) % axes_size[1];
    if (dimension > 2) 
	bins[2] = ((bin - bins[0] - bins[1]*axes_size[1]) / (axes_size[0] * axes_size[1])) % axes_size[2];
    return kTRUE;
}

Double_t PDensityMatrix::GetBinWidth(Int_t dim, Int_t bin) {
    if (bin <= 0) {
	return ((axes[dim])[1] - (axes[dim])[0]);
    } else if (bin >= axes_size[dim]-1) {
	return ((axes[dim])[axes_size[dim]-1] - (axes[dim])[axes_size[dim]-2]);
    } 
    return ((axes[dim])[bin+1] - (axes[dim])[bin-1]) / 2.0;
}

Int_t PDensityMatrix::GetRandomBin(Int_t num) {
    Int_t lower_bound = -1;
    Int_t upper_bound = matrixsize - 1;    
    Int_t middle_point;

    while ((upper_bound - lower_bound) > 1) {
	middle_point = lower_bound + (upper_bound-lower_bound)/2;

	Double_t frac = 0;

	if (lower_bound < 0)
	    frac = (matrix_integral[num])[middle_point] /
		(matrix_integral[num])[upper_bound];
	else
	    frac = ((matrix_integral[num])[middle_point] - (matrix_integral[num])[lower_bound]) /
		((matrix_integral[num])[upper_bound] - (matrix_integral[num])[lower_bound]);
	
	if (PUtils::sampleFlat() > frac) {
	    lower_bound = middle_point;
	} else {
	    upper_bound = middle_point;
	}
    }
    return lower_bound + 1;
}

Bool_t PDensityMatrix::Do(const char *command) {

    if (!projector) projector = new PProjector();
    return projector->AddCommand(command);

    return kTRUE;
}

Bool_t PDensityMatrix::ReadDensityMatrix(const char *filename, Int_t dim, Bool_t use_bin_width,
					 Double_t min_selection, Double_t max_selection) {
    //Reads a density matrix which must be organized in one of the the two following way
    //
    //Method 1:
    //x [y] [z] f1 f2 f3 ....
    //
    //The first column contains the bin center on the x-axis, the following
    //columns the values of 1 or more matrices. Optionally, for 2- and 3-dimensional
    //matrixes, the first colum might be followed by the y- and z-value of the bin center
    //
    //The matrixes support variable bin width, the flag "use_bin_width" should be used
    //to select of the sample statistics should be corrected by the bin width
    //
    //Method 2:
    //"section value 1"
    //x [y] [z] f0 f1 f2 ....
    //...
    //"section value 2"
    //x [y] [z] f0 f1 f2 ....
    //...
    //
    //Here, the syntax is like in method 1, but if lines have only one number, 
    //they are considered to be a "selection number". Which of the sections should be read
    //and used to fill the internal matrix, can be selected by "min_selection" and "max_selection"
    //The section is used if "min_selection" <= "section value" <= "max_selection"
    //
    //In your macro, to select one of the matrixes, use
    //  matrix->SetMatrix(N);
    //where N corresponds to fN, e.g.
    //  matrix->SetMatrix(2);
    //uses the values f2 as defined above

    Info("ReadDensityMatrix", "Analysing the file...");

    Double_t  numbers[16];
    dimension = dim;

    for (int i=0; i<dim; i++) {
	axes[i]      = new Double_t[DENSITYMATRIX_MAX];
	axes_size[i] = 0;
    }

    Bool_t found_selection      = kFALSE;
    Bool_t found_single_numbers = kFALSE;
    FILE * file                 = fopen(filename,"r");
    Int_t  line_number = 0;

    if (!file) {
	Error("ReadDensityMatrix", "File '%s' not found", filename);
	return kFALSE;
    }
    
    Int_t numargs = 0;
    char line [1024];
    
    while(!found_selection && (fgets (line, sizeof line, file) != NULL)) {
	line_number++;
	numargs = sscanf(line, "%le %le %le %le %le %le %le %le %le %le %le %le %le %le %le %le\n",
			 &(numbers[0]), &(numbers[1]), &(numbers[2]), &(numbers[3]), &(numbers[4]), 
			 &(numbers[5]), &(numbers[6]), &(numbers[7]), &(numbers[8]), &(numbers[9]), 
			 &(numbers[10]), &(numbers[11]), &(numbers[12]), &(numbers[13]), &(numbers[14]), 
			 &(numbers[15]));
	
	if (numargs == 1) {
	    found_single_numbers = kTRUE;
	    if (numbers[0] >= min_selection && numbers[0] <= max_selection)
		found_selection = kTRUE;
	}
    }

    if (!found_single_numbers) { //no selection at all
	fclose(file);
	file = fopen(filename,"r");
	line_number = 0;
    } 

    Int_t num_matrices = 0;

    //continuing with reading dimensions of matrix
    while(fgets (line, sizeof line, file) != NULL) {
	line_number++;
	numargs = sscanf(line, "%le %le %le %le %le %le %le %le %le %le %le %le %le %le %le %le\n",
			 &(numbers[0]), &(numbers[1]), &(numbers[2]), &(numbers[3]), &(numbers[4]), 
			 &(numbers[5]), &(numbers[6]), &(numbers[7]), &(numbers[8]), &(numbers[9]), 
			 &(numbers[10]), &(numbers[11]), &(numbers[12]), &(numbers[13]), &(numbers[14]), 
			 &(numbers[15]));
	
	if (numargs == 1) {
	    if (numbers[0] >= min_selection && numbers[0] <= max_selection)
		found_selection = kTRUE;
	    else
		found_selection = kFALSE;
	} else if (found_selection && numargs > 1 ) {
	    if (numargs <= dim) {
		Error("ReadDensityMatrix", "Not enough values found");
		cout << "Line number " << line_number << ": " << line << endl;;
		return kFALSE;
	    }
	    for (int i=0; i<dim; i++) {
		if (!axes_size[i] || numbers[i] > (axes[i])[axes_size[i]-1]) {
		    if (axes_size[i] == DENSITYMATRIX_MAX) {
			Error("ReadDensityMatrix", "Size too small for dimension %i", i);
			return kFALSE;
		    }
		    (axes[i])[axes_size[i]] = numbers[i];
		    axes_size[i]++;		    
		}
	    }
	    if (!num_matrices) {
		num_matrices = numargs - dim;
	    } else if (num_matrices && num_matrices != numargs - dim) {
		Error("ReadDensityMatrix", "Number of matrices do not match, it was %i, and is now %i",
		      num_matrices, numargs - dim);
		cout << "Line number " << line_number << ": " << line << endl;;
		return kFALSE;
	    }
	}
    }

    if (!found_single_numbers) 
	Info("ReadDensityMatrix", "...done (no sections found)");
    else
	Info("ReadDensityMatrix", "...done");

    Info("ReadDensityMatrix", "Dimension 1 (_x) has %i bins within the range [%f,%f]", 
	 axes_size[0], (axes[0])[0], (axes[0])[axes_size[0]-1]);
    if (dimension > 1)
	Info("ReadDensityMatrix", "Dimension 2 (_y) has %i bins within the range [%f,%f]", 
	     axes_size[1], (axes[1])[0], (axes[1])[axes_size[1]-1]);
    if (dimension > 2)
	Info("ReadDensityMatrix", "Dimension 3 (_z) has %i bins within the range [%f,%f]", 
	     axes_size[2], (axes[2])[0], (axes[2])[axes_size[2]-1]);

    //TODO: check axis size against dim and DENSITYMATRIX_MAX_MATRICES

    fclose(file);

    Double_t x[3];
    Int_t    bins[3];

    //based on the dimensions, let's create the matrices
    matrixsize = 0;
    for (int i=0; i<num_matrices; i++) {
	if (dim == 1)
	    matrixsize = axes_size[0];
	else if (dim == 2)
	    matrixsize = axes_size[0]*axes_size[1];
	else 
	    matrixsize = axes_size[0]*axes_size[1]*axes_size[2];
	matrix[i] = new Double_t[matrixsize];
	for (int j=0; j<matrixsize; j++) {
	    (matrix[i])[j] = 0;
	}
    }

    //now filling the content
    file = fopen(filename,"r");
    while(fgets (line, sizeof line, file) != NULL) {
	line_number = 0;
	numargs = sscanf(line, "%le %le %le %le %le %le %le %le %le %le %le %le %le %le %le %le\n",
			 &(numbers[0]), &(numbers[1]), &(numbers[2]), &(numbers[3]), &(numbers[4]), 
			 &(numbers[5]), &(numbers[6]), &(numbers[7]), &(numbers[8]), &(numbers[9]), 
			 &(numbers[10]), &(numbers[11]), &(numbers[12]), &(numbers[13]), &(numbers[14]), 
			 &(numbers[15]));
	
	if (numargs == 1) {
	    if (numbers[0] >= min_selection && numbers[0] <= max_selection) {
		Info("ReadDensityMatrix", "Found section [%f], reading...", numbers[0]);
		found_selection = kTRUE;
	    } else {
		Info("ReadDensityMatrix", "Found section [%f], skipped!", numbers[0]);
		found_selection = kFALSE;
	    }
	} else if (found_selection) {
	    for (int i=0; i<dim; i++) {
		x[i] = numbers[i];
	    }
	    GetBin(x, bins);
	    for (int i=0; i<num_matrices; i++) {
		(matrix[i])[bins[0] + bins[1]*axes_size[0] + bins[2]*axes_size[1]*axes_size[0]] += numbers[i+dim];
	    }
	}
    }

    //next step is to fill the integral
    for (int i=0; i<num_matrices; i++) {
	matrix_integral[i] = new Double_t[matrixsize];
	for (int j=0; j<matrixsize; j++) {
	    Double_t bin_content = (matrix[i])[j];
	    if (use_bin_width) {
		//fold with bin area
		Int_t bins[3];
		GetBin(j, bins);

		if (dimension == 1) 
		    bin_content *= GetBinWidth(0, bins[0]);
		else if (dimension == 2) 
		    bin_content *= GetBinWidth(0, bins[0]) * GetBinWidth(1, bins[1]);
		else
		    bin_content *= GetBinWidth(0, bins[0]) * GetBinWidth(1, bins[1]) * GetBinWidth(2, bins[2]);
	    }
	   
	    if (j)
		(matrix_integral[i])[j] = bin_content + (matrix_integral[i])[j-1];
	    else 
		(matrix_integral[i])[j] = bin_content;
	}	
    }

    return kTRUE;
}

Bool_t PDensityMatrix::Modify(PParticle **mstack, int *decay_done, int *num, int stacksize) {
    // Read the particles from the defined stack and copy this to the official
    // particle stream

    PEmbeddedParticles::Modify(mstack, decay_done, num, stacksize);
    Int_t bin = GetRandomBin(current_matrix);

    Int_t xb[3];
    if (!GetBin(bin, xb)) return kFALSE;

    Double_t xf[3];
    for (int i=0; i<dimension; i++) {
	xf[i] = (axes[i])[xb[i]];
	xf[i] += GetBinWidth(i, xb[i])*(PUtils::sampleFlat() - 0.5); //avoid binning effects
    }
    
    *x = xf[0];
    if (dimension>1) *y = xf[1];
    if (dimension>2) *z = xf[2];

    projector->Modify(mstack, decay_done, num, stacksize);
			    
    return kTRUE;
}

ClassImp(PDensityMatrix)
 PDensityMatrix.cc:1
 PDensityMatrix.cc:2
 PDensityMatrix.cc:3
 PDensityMatrix.cc:4
 PDensityMatrix.cc:5
 PDensityMatrix.cc:6
 PDensityMatrix.cc:7
 PDensityMatrix.cc:8
 PDensityMatrix.cc:9
 PDensityMatrix.cc:10
 PDensityMatrix.cc:11
 PDensityMatrix.cc:12
 PDensityMatrix.cc:13
 PDensityMatrix.cc:14
 PDensityMatrix.cc:15
 PDensityMatrix.cc:16
 PDensityMatrix.cc:17
 PDensityMatrix.cc:18
 PDensityMatrix.cc:19
 PDensityMatrix.cc:20
 PDensityMatrix.cc:21
 PDensityMatrix.cc:22
 PDensityMatrix.cc:23
 PDensityMatrix.cc:24
 PDensityMatrix.cc:25
 PDensityMatrix.cc:26
 PDensityMatrix.cc:27
 PDensityMatrix.cc:28
 PDensityMatrix.cc:29
 PDensityMatrix.cc:30
 PDensityMatrix.cc:31
 PDensityMatrix.cc:32
 PDensityMatrix.cc:33
 PDensityMatrix.cc:34
 PDensityMatrix.cc:35
 PDensityMatrix.cc:36
 PDensityMatrix.cc:37
 PDensityMatrix.cc:38
 PDensityMatrix.cc:39
 PDensityMatrix.cc:40
 PDensityMatrix.cc:41
 PDensityMatrix.cc:42
 PDensityMatrix.cc:43
 PDensityMatrix.cc:44
 PDensityMatrix.cc:45
 PDensityMatrix.cc:46
 PDensityMatrix.cc:47
 PDensityMatrix.cc:48
 PDensityMatrix.cc:49
 PDensityMatrix.cc:50
 PDensityMatrix.cc:51
 PDensityMatrix.cc:52
 PDensityMatrix.cc:53
 PDensityMatrix.cc:54
 PDensityMatrix.cc:55
 PDensityMatrix.cc:56
 PDensityMatrix.cc:57
 PDensityMatrix.cc:58
 PDensityMatrix.cc:59
 PDensityMatrix.cc:60
 PDensityMatrix.cc:61
 PDensityMatrix.cc:62
 PDensityMatrix.cc:63
 PDensityMatrix.cc:64
 PDensityMatrix.cc:65
 PDensityMatrix.cc:66
 PDensityMatrix.cc:67
 PDensityMatrix.cc:68
 PDensityMatrix.cc:69
 PDensityMatrix.cc:70
 PDensityMatrix.cc:71
 PDensityMatrix.cc:72
 PDensityMatrix.cc:73
 PDensityMatrix.cc:74
 PDensityMatrix.cc:75
 PDensityMatrix.cc:76
 PDensityMatrix.cc:77
 PDensityMatrix.cc:78
 PDensityMatrix.cc:79
 PDensityMatrix.cc:80
 PDensityMatrix.cc:81
 PDensityMatrix.cc:82
 PDensityMatrix.cc:83
 PDensityMatrix.cc:84
 PDensityMatrix.cc:85
 PDensityMatrix.cc:86
 PDensityMatrix.cc:87
 PDensityMatrix.cc:88
 PDensityMatrix.cc:89
 PDensityMatrix.cc:90
 PDensityMatrix.cc:91
 PDensityMatrix.cc:92
 PDensityMatrix.cc:93
 PDensityMatrix.cc:94
 PDensityMatrix.cc:95
 PDensityMatrix.cc:96
 PDensityMatrix.cc:97
 PDensityMatrix.cc:98
 PDensityMatrix.cc:99
 PDensityMatrix.cc:100
 PDensityMatrix.cc:101
 PDensityMatrix.cc:102
 PDensityMatrix.cc:103
 PDensityMatrix.cc:104
 PDensityMatrix.cc:105
 PDensityMatrix.cc:106
 PDensityMatrix.cc:107
 PDensityMatrix.cc:108
 PDensityMatrix.cc:109
 PDensityMatrix.cc:110
 PDensityMatrix.cc:111
 PDensityMatrix.cc:112
 PDensityMatrix.cc:113
 PDensityMatrix.cc:114
 PDensityMatrix.cc:115
 PDensityMatrix.cc:116
 PDensityMatrix.cc:117
 PDensityMatrix.cc:118
 PDensityMatrix.cc:119
 PDensityMatrix.cc:120
 PDensityMatrix.cc:121
 PDensityMatrix.cc:122
 PDensityMatrix.cc:123
 PDensityMatrix.cc:124
 PDensityMatrix.cc:125
 PDensityMatrix.cc:126
 PDensityMatrix.cc:127
 PDensityMatrix.cc:128
 PDensityMatrix.cc:129
 PDensityMatrix.cc:130
 PDensityMatrix.cc:131
 PDensityMatrix.cc:132
 PDensityMatrix.cc:133
 PDensityMatrix.cc:134
 PDensityMatrix.cc:135
 PDensityMatrix.cc:136
 PDensityMatrix.cc:137
 PDensityMatrix.cc:138
 PDensityMatrix.cc:139
 PDensityMatrix.cc:140
 PDensityMatrix.cc:141
 PDensityMatrix.cc:142
 PDensityMatrix.cc:143
 PDensityMatrix.cc:144
 PDensityMatrix.cc:145
 PDensityMatrix.cc:146
 PDensityMatrix.cc:147
 PDensityMatrix.cc:148
 PDensityMatrix.cc:149
 PDensityMatrix.cc:150
 PDensityMatrix.cc:151
 PDensityMatrix.cc:152
 PDensityMatrix.cc:153
 PDensityMatrix.cc:154
 PDensityMatrix.cc:155
 PDensityMatrix.cc:156
 PDensityMatrix.cc:157
 PDensityMatrix.cc:158
 PDensityMatrix.cc:159
 PDensityMatrix.cc:160
 PDensityMatrix.cc:161
 PDensityMatrix.cc:162
 PDensityMatrix.cc:163
 PDensityMatrix.cc:164
 PDensityMatrix.cc:165
 PDensityMatrix.cc:166
 PDensityMatrix.cc:167
 PDensityMatrix.cc:168
 PDensityMatrix.cc:169
 PDensityMatrix.cc:170
 PDensityMatrix.cc:171
 PDensityMatrix.cc:172
 PDensityMatrix.cc:173
 PDensityMatrix.cc:174
 PDensityMatrix.cc:175
 PDensityMatrix.cc:176
 PDensityMatrix.cc:177
 PDensityMatrix.cc:178
 PDensityMatrix.cc:179
 PDensityMatrix.cc:180
 PDensityMatrix.cc:181
 PDensityMatrix.cc:182
 PDensityMatrix.cc:183
 PDensityMatrix.cc:184
 PDensityMatrix.cc:185
 PDensityMatrix.cc:186
 PDensityMatrix.cc:187
 PDensityMatrix.cc:188
 PDensityMatrix.cc:189
 PDensityMatrix.cc:190
 PDensityMatrix.cc:191
 PDensityMatrix.cc:192
 PDensityMatrix.cc:193
 PDensityMatrix.cc:194
 PDensityMatrix.cc:195
 PDensityMatrix.cc:196
 PDensityMatrix.cc:197
 PDensityMatrix.cc:198
 PDensityMatrix.cc:199
 PDensityMatrix.cc:200
 PDensityMatrix.cc:201
 PDensityMatrix.cc:202
 PDensityMatrix.cc:203
 PDensityMatrix.cc:204
 PDensityMatrix.cc:205
 PDensityMatrix.cc:206
 PDensityMatrix.cc:207
 PDensityMatrix.cc:208
 PDensityMatrix.cc:209
 PDensityMatrix.cc:210
 PDensityMatrix.cc:211
 PDensityMatrix.cc:212
 PDensityMatrix.cc:213
 PDensityMatrix.cc:214
 PDensityMatrix.cc:215
 PDensityMatrix.cc:216
 PDensityMatrix.cc:217
 PDensityMatrix.cc:218
 PDensityMatrix.cc:219
 PDensityMatrix.cc:220
 PDensityMatrix.cc:221
 PDensityMatrix.cc:222
 PDensityMatrix.cc:223
 PDensityMatrix.cc:224
 PDensityMatrix.cc:225
 PDensityMatrix.cc:226
 PDensityMatrix.cc:227
 PDensityMatrix.cc:228
 PDensityMatrix.cc:229
 PDensityMatrix.cc:230
 PDensityMatrix.cc:231
 PDensityMatrix.cc:232
 PDensityMatrix.cc:233
 PDensityMatrix.cc:234
 PDensityMatrix.cc:235
 PDensityMatrix.cc:236
 PDensityMatrix.cc:237
 PDensityMatrix.cc:238
 PDensityMatrix.cc:239
 PDensityMatrix.cc:240
 PDensityMatrix.cc:241
 PDensityMatrix.cc:242
 PDensityMatrix.cc:243
 PDensityMatrix.cc:244
 PDensityMatrix.cc:245
 PDensityMatrix.cc:246
 PDensityMatrix.cc:247
 PDensityMatrix.cc:248
 PDensityMatrix.cc:249
 PDensityMatrix.cc:250
 PDensityMatrix.cc:251
 PDensityMatrix.cc:252
 PDensityMatrix.cc:253
 PDensityMatrix.cc:254
 PDensityMatrix.cc:255
 PDensityMatrix.cc:256
 PDensityMatrix.cc:257
 PDensityMatrix.cc:258
 PDensityMatrix.cc:259
 PDensityMatrix.cc:260
 PDensityMatrix.cc:261
 PDensityMatrix.cc:262
 PDensityMatrix.cc:263
 PDensityMatrix.cc:264
 PDensityMatrix.cc:265
 PDensityMatrix.cc:266
 PDensityMatrix.cc:267
 PDensityMatrix.cc:268
 PDensityMatrix.cc:269
 PDensityMatrix.cc:270
 PDensityMatrix.cc:271
 PDensityMatrix.cc:272
 PDensityMatrix.cc:273
 PDensityMatrix.cc:274
 PDensityMatrix.cc:275
 PDensityMatrix.cc:276
 PDensityMatrix.cc:277
 PDensityMatrix.cc:278
 PDensityMatrix.cc:279
 PDensityMatrix.cc:280
 PDensityMatrix.cc:281
 PDensityMatrix.cc:282
 PDensityMatrix.cc:283
 PDensityMatrix.cc:284
 PDensityMatrix.cc:285
 PDensityMatrix.cc:286
 PDensityMatrix.cc:287
 PDensityMatrix.cc:288
 PDensityMatrix.cc:289
 PDensityMatrix.cc:290
 PDensityMatrix.cc:291
 PDensityMatrix.cc:292
 PDensityMatrix.cc:293
 PDensityMatrix.cc:294
 PDensityMatrix.cc:295
 PDensityMatrix.cc:296
 PDensityMatrix.cc:297
 PDensityMatrix.cc:298
 PDensityMatrix.cc:299
 PDensityMatrix.cc:300
 PDensityMatrix.cc:301
 PDensityMatrix.cc:302
 PDensityMatrix.cc:303
 PDensityMatrix.cc:304
 PDensityMatrix.cc:305
 PDensityMatrix.cc:306
 PDensityMatrix.cc:307
 PDensityMatrix.cc:308
 PDensityMatrix.cc:309
 PDensityMatrix.cc:310
 PDensityMatrix.cc:311
 PDensityMatrix.cc:312
 PDensityMatrix.cc:313
 PDensityMatrix.cc:314
 PDensityMatrix.cc:315
 PDensityMatrix.cc:316
 PDensityMatrix.cc:317
 PDensityMatrix.cc:318
 PDensityMatrix.cc:319
 PDensityMatrix.cc:320
 PDensityMatrix.cc:321
 PDensityMatrix.cc:322
 PDensityMatrix.cc:323
 PDensityMatrix.cc:324
 PDensityMatrix.cc:325
 PDensityMatrix.cc:326
 PDensityMatrix.cc:327
 PDensityMatrix.cc:328
 PDensityMatrix.cc:329
 PDensityMatrix.cc:330
 PDensityMatrix.cc:331
 PDensityMatrix.cc:332
 PDensityMatrix.cc:333
 PDensityMatrix.cc:334
 PDensityMatrix.cc:335
 PDensityMatrix.cc:336