Пример #1
0
func (plan *MaxwellPlan) init() {
	if plan.initialized {
		return
	}
	plan.initialized = true
	e := GetEngine()
	dataSize := e.GridSize()
	logicSize := e.PaddedSize()
	Assert(len(dataSize) == 3)
	Assert(len(logicSize) == 3)

	// init size
	copy(plan.dataSize[:], dataSize)
	copy(plan.logicSize[:], logicSize)

	// init fft
	fftOutputSize := gpu.FFTOutputSize(logicSize)
	plan.fftBuf = gpu.NewArray(3, fftOutputSize)
	plan.fftPlan = gpu.NewDefaultFFT(dataSize, logicSize)

	// init M
	plan.M = gpu.NewArray(3, dataSize)

	// init fftKern
	copy(plan.fftKernSize[:], gpu.FFTOutputSize(logicSize))
	plan.fftKernSize[2] = plan.fftKernSize[2] / 2 // store only non-redundant parts
}
Пример #2
0
// Derived quantities are averages, components, etc. of existing quantities.
// They are added to the engine on-demand.
// Syntax:
//	"<q>"  		: average of q
//	"q.x"  		: x-component of q, must be vector
//	"q.xx" 		: xx-component of q, must be tensor
//	"<q.x>"		: average of x-component of q.
//  "fft(q)" 	: fft of q
func (e *Engine) addDerivedQuant(name string) {
	// fft
	if strings.HasPrefix(name, "fft(") && strings.HasSuffix(name, ")") {
		in := name[len("fft(") : len(name)-1]
		Debug(in)
		qin := e.Quant(in)
		if qin.kind == VALUE {
			panic(InputErrF(qin.Name(), "is not space-dependent, fft is meaningless."))
		}
		e.AddQuant(NewQuant(name, qin.nComp, gpu.FFTOutputSize(e.GridSize()), qin.kind, qin.unit, false, "fft of "+qin.desc))
		Debug(name)
		qout := e.Quant(name)
		qout.updater = NewFFTUpdater(qin, qout)
		return
	}
	// average
	if strings.HasPrefix(name, "<") && strings.HasSuffix(name, ">") {
		origname := name[1 : len(name)-1]
		original := e.Quant(origname)
		if original.kind == VALUE {
			panic(InputErrF(original.Name(), "is not space-dependent, can not take its average."))
		}
		e.AddNewQuant(name, original.nComp, VALUE, original.unit)
		derived := e.Quant(name)
		e.Depends(name, origname)
		derived.updater = NewAverageUpdater(original, derived)
		return
	}
	// component
	if strings.Contains(name, ".") {
		split := strings.Split(name, ".")
		if len(split) != 2 {
			e.panicNoSuchQuant(name)
			//panic(InputErr("engine: undefined quantity: " + name))
		}
		origname, compname := split[0], strings.ToLower(split[1])
		orig := e.Quant(origname)

		// parse component string ("X" -> 0)
		comp := -1
		ok := false
		switch orig.nComp {
		default:
			panic(InputErr(orig.Name() + " has no component " + compname))
		case 3:
			comp, ok = VectorIndex[strings.ToUpper(compname)]
			comp = SwapIndex(comp, 3)
		case 6:
			comp, ok = TensorIndex[strings.ToUpper(compname)]
			comp = SwapIndex(comp, 6)
		case 9:
			comp, ok = TensorIndex[strings.ToUpper(compname)]
			comp = SwapIndex(comp, 9)
		}
		if !ok {
			panic(InputErr("invalid component:" + compname))
		}

		derived := orig.Component(comp)
		derived.name = orig.name + "." + strings.ToLower(compname) // hack, graphviz can't handle "."
		e.AddQuant(derived)
		e.Depends(derived.name, origname)
		return
	}
	e.panicNoSuchQuant(name)
	//panic(InputErr("engine: undefined quantity: " + name))
}
Пример #3
0
//// Loads a sub-kernel at position pos in the 3x3 global kernel matrix.
//// The symmetry and real/imaginary/complex properties are taken into account to reduce storage.
func (plan *MaxwellPlan) LoadKernel(kernel *host.Array, matsymm int, realness int) {

	//	for i := range kernel.Array {
	//		Debug("kernel", TensorIndexStr[i], ":", kernel.Array[i], "\n\n\n")
	//	}

	//Assert(kernel.NComp() == 9) // full tensor
	if kernel.NComp() > 3 {
		testedsymm := MatrixSymmetry(kernel)
		Debug("matsymm", testedsymm)
		// TODO: re-enable!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		//Assert(matsymm == testedsymm)
	}
	Assert(matsymm == SYMMETRIC || matsymm == ANTISYMMETRIC || matsymm == NOSYMMETRY || matsymm == DIAGONAL)

	//if FFT'd kernel is pure real or imag,
	//store only relevant part and multiply by scaling later
	scaling := [3]complex128{complex(1, 0), complex(0, 1), complex(0, 0)}[realness]
	Debug("scaling=", scaling)

	// FFT input on GPU
	logic := plan.logicSize[:]
	devIn := gpu.NewArray(1, logic)
	defer devIn.Free()

	// FFT output on GPU
	devOut := gpu.NewArray(1, gpu.FFTOutputSize(logic))
	defer devOut.Free()
	fullFFTPlan := gpu.NewDefaultFFT(logic, logic)
	defer fullFFTPlan.Free()

	// Maximum of all elements gives idea of scale.
	max := maxAbs(kernel.List)

	// FFT all components
	for k := 0; k < 9; k++ {
		i, j := IdxToIJ(k) // fills diagonal first, then upper, then lower

		// ignore off-diagonals of vector (would go out of bounds)
		if k > ZZ && matsymm == DIAGONAL {
			Debug("break", TensorIndexStr[k], "(off-diagonal)")
			break
		}

		// elements of diagonal kernel are stored in one column
		if matsymm == DIAGONAL {
			i = 0
		}

		// clear data first
		AssertMsg(plan.fftKern[i][j] == nil, "I'm afraid I can't let you overwrite that")
		AssertMsg(plan.fftMul[i][j] == 0, "Likewise")

		// auto-fill lower triangle if possible
		if k > XY {
			if matsymm == SYMMETRIC {
				plan.fftKern[i][j] = plan.fftKern[j][i]
				plan.fftMul[i][j] = plan.fftMul[j][i]
				continue
			}
			if matsymm == ANTISYMMETRIC {
				plan.fftKern[i][j] = plan.fftKern[j][i]
				plan.fftMul[i][j] = -plan.fftMul[j][i]
				continue
			}
		}

		// ignore zeros
		if k < kernel.NComp() && IsZero(kernel.Comp[k], max) {
			Debug("kernel", TensorIndexStr[k], " == 0")
			plan.fftKern[i][j] = gpu.NilArray(1, []int{plan.fftKernSize[X], plan.fftKernSize[Y], plan.fftKernSize[Z]})
			continue
		}

		// calculate FFT of kernel elementx
		Debug("use", TensorIndexStr[k])
		devIn.CopyFromHost(kernel.Component(k))
		fullFFTPlan.Forward(devIn, devOut)
		hostOut := devOut.LocalCopy()

		// extract real part of the kernel from the first quadrant (other parts are redundunt due to the symmetry properties)
		hostFFTKern := extract(hostOut)
		rescale(hostFFTKern, 1/float64(gpu.FFTNormLogic(logic)))
		plan.fftKern[i][j] = gpu.NewArray(1, hostFFTKern.Size3D)
		plan.fftKern[i][j].CopyFromHost(hostFFTKern)
		plan.fftMul[i][j] = scaling
	}

}