void VectorVectorConvolution_Simple::execute(const VectorMatrix &rhs, Matrix &res)
{
	VectorMatrix::const_accessor S_acc(lhs);
	VectorMatrix::const_accessor M_acc(rhs); 
	Matrix::      accessor phi_acc(res);

	// phi(r) = int S(r-r')*M(r') dr'
	// phi = Sx*Mx + Sy*My + Sz*Mz

	for (int z=0; z<dim_z; ++z)
	for (int y=0; y<dim_y; ++y)
	for (int x=0; x<dim_x; ++x) 
	{
		double sum = 0.0;

		for (int o=0; o<dim_z; ++o)
		for (int n=0; n<dim_y; ++n)
		for (int m=0; m<dim_x; ++m) 
		{
			// (X,Y,Z): position in demag tensor field matrix
			const int X = (x-m+exp_x) % exp_x;
			const int Y = (y-n+exp_y) % exp_y;
			const int Z = (z-o+exp_z) % exp_z;

			const Vector3d &S = S_acc.get(X, Y, Z);
			const Vector3d &M = M_acc.get(m, n, o);

			sum = S.x*M.x + S.y*M.y + S.z*M.z;
		}

		phi_acc.at(x, y, z) = sum;
	}
}
Esempio n. 2
0
Matrix GeneratePhiDemagTensor(
	int dim_x, int dim_y, int dim_z, 
	double delta_x, double delta_y, double delta_z, 
	bool periodic_x, bool periodic_y, bool periodic_z, int periodic_repeat,
	int padding,
	const char *cache_dir)
{
	int exp_x = round_tensor_dimension(dim_x, periodic_x, padding);
	int exp_y = round_tensor_dimension(dim_y, periodic_y, padding);
	int exp_z = round_tensor_dimension(dim_z, periodic_z, padding);

	// also pad if exp_i = 1
	if (exp_x == 1) exp_x = 2;
	if (exp_y == 1) exp_y = 2;
	if (exp_z == 1) exp_z = 2;

	LOG_INFO  << "Preparing scalar potential tensor.";
	LOG_DEBUG << "  Magn. size: " << dim_x << "x" << dim_y << "x" << dim_z;
	LOG_DEBUG << "  Zeropadded: " << exp_x << "x" << exp_y << "x" << exp_z;
	LOG_DEBUG << "Periodic boundary conditions:";
	LOG_DEBUG << "  Dimensions : " << (periodic_x ? "x" : "") << (periodic_y ? "y" : "") << (periodic_z ? "z" : "");
	LOG_DEBUG << "  Repetitions: " << periodic_repeat;

	if (periodic_x || periodic_y || periodic_z) {
		throw std::runtime_error("Demag potential tensor field calculation for periodic boundary conditions not yet supported");
	}

	Matrix S(Shape(3, exp_x, exp_y, exp_z));
	S.clear();

	if (std::getenv("MAGNUM_DEMAG_GARBAGE")) {
		LOG_INFO << "Skipping phi tensor generation ('MAGNUM_GARBAGE' environment variable is set!)";
		return S;
	}

	LOG_DEBUG<< "Generating...";

	Matrix::wo_accessor S_acc(S);

	int cnt = 0, percent = 0;
	for (int z=0; z<exp_z; ++z)
	for (int y=0; y<exp_y; ++y) {
		for (int x=0; x<exp_x; ++x) {
			// position delta (in number of cells)
			const int dx = x - dim_x + 1;
			const int dy = y - dim_y + 1;
			const int dz = z - dim_z + 1;

			/*if (dx >= dim_x+1) continue;
			if (dy >= dim_y+1) continue;
			if (dz >= dim_z+1) continue;*/

			// position delta (in nanometer)
			const double diff_x = dx * delta_x - 0.5*delta_x;
			const double diff_y = dy * delta_y - 0.5*delta_y;
			const double diff_z = dz * delta_z - 0.5*delta_z;
			
			// store Nij at modulo position
			const int X = (dx + 2*exp_x) % exp_x;
			const int Y = (dy + 2*exp_y) % exp_y;
			const int Z = (dz + 2*exp_z) % exp_z;

			// insert components (all real)
			Vector3d S_i(
				- demag_phi_coeff::getS<long double>(0, diff_x, diff_y, diff_z, delta_x, delta_y, delta_z),
				- demag_phi_coeff::getS<long double>(1, diff_x, diff_y, diff_z, delta_x, delta_y, delta_z),
				- demag_phi_coeff::getS<long double>(2, diff_x, diff_y, diff_z, delta_x, delta_y, delta_z)
			);
			S_acc.at(0, X, Y, Z) = S_i.x;
			S_acc.at(1, X, Y, Z) = S_i.y;
			S_acc.at(2, X, Y, Z) = S_i.z;
		}

		cnt += 1;
		if (100 * cnt / (exp_y*exp_z) > percent) {
			LOG_DEBUG << " * " << percent << "%";
			percent += 10;
		}
	}

	LOG_INFO << "Done.";
	return S;
}