// set in regions r1..r2(excl) func (p *inputParam) setRegions(r1, r2 int, v []float64) { util.Argument(len(v) == len(p.cpu_buf)) util.Argument(r1 < r2) // exclusive upper bound for r := r1; r < r2; r++ { p.upd_reg[r] = nil p.bufset_(r, v) } p.invalidate() }
// Copies src (larger) into dst (smaller). // Used to extract demag field after convolution on padded m. func copyUnPad(dst, src *data.Slice, dstsize, srcsize [3]int) { util.Argument(dst.NComp() == 1 && src.NComp() == 1) util.Argument(dst.Len() == prod(dstsize) && src.Len() == prod(srcsize)) cfg := make3DConf(dstsize) k_copyunpad_async(dst.DevPtr(0), dstsize[X], dstsize[Y], dstsize[Z], src.DevPtr(0), srcsize[X], srcsize[Y], srcsize[Z], cfg) }
// For a nanowire magnetized in-plane, with mx = mxLeft on the left end and // mx = mxRight on the right end (both -1 or +1), add a B field needed to compensate // for the surface charges on the left and right edges. // This will mimic an infinitely long wire. func RemoveLRSurfaceCharge(region int, mxLeft, mxRight float64) { SetBusy(true) defer SetBusy(false) util.Argument(mxLeft == 1 || mxLeft == -1) util.Argument(mxRight == 1 || mxRight == -1) bsat := Msat.GetRegion(region) * mag.Mu0 util.AssertMsg(bsat != 0, "RemoveSurfaceCharges: Msat is zero in region "+fmt.Sprint(region)) B_ext.Add(compensateLRSurfaceCharges(Mesh(), mxLeft, mxRight, bsat), nil) }
// dst += prefactor * dot(a, b), as used for energy density func AddDotProduct(dst *data.Slice, prefactor float32, a, b *data.Slice) { util.Argument(dst.NComp() == 1 && a.NComp() == 3 && b.NComp() == 3) util.Argument(dst.Len() == a.Len() && dst.Len() == b.Len()) N := dst.Len() cfg := make1DConf(N) k_dotproduct_async(dst.DevPtr(0), prefactor, a.DevPtr(X), a.DevPtr(Y), a.DevPtr(Z), b.DevPtr(X), b.DevPtr(Y), b.DevPtr(Z), N, cfg) }
// Crop stores in dst a rectangle cropped from src at given offset position. // dst size may be smaller than src. func Crop(dst, src *data.Slice, offX, offY, offZ int) { D := dst.Size() S := src.Size() util.Argument(dst.NComp() == src.NComp()) util.Argument(D[X]+offX <= S[X] && D[Y]+offY <= S[Y] && D[Z]+offZ <= S[Z]) cfg := make3DConf(D) for c := 0; c < dst.NComp(); c++ { k_crop_async(dst.DevPtr(c), D[X], D[Y], D[Z], src.DevPtr(c), S[X], S[Y], S[Z], offX, offY, offZ, cfg) } }
func (p *inputParam) setFunc(r1, r2 int, f func() []float64) { util.Argument(r1 < r2) // exclusive upper bound for r := r1; r < r2; r++ { p.upd_reg[r] = f } p.invalidate() }
// dst += LUT[region], for vectors. Used to add terms to excitation. func RegionAddV(dst *data.Slice, lut LUTPtrs, regions *Bytes) { util.Argument(dst.NComp() == 3) N := dst.Len() cfg := make1DConf(N) k_regionaddv_async(dst.DevPtr(X), dst.DevPtr(Y), dst.DevPtr(Z), lut[X], lut[Y], lut[Z], regions.Ptr, N, cfg) }
// shift dst by shx cells (positive or negative) along X-axis. // new edge value is clampL at left edge or clampR at right edge. func ShiftX(dst, src *data.Slice, shiftX int, clampL, clampR float32) { util.Argument(dst.NComp() == 1 && src.NComp() == 1) util.Assert(dst.Len() == src.Len()) N := dst.Size() cfg := make3DConf(N) k_shiftx_async(dst.DevPtr(0), src.DevPtr(0), N[X], N[Y], N[Z], shiftX, clampL, clampR, cfg) }
// Maximum of the norms of the difference between all vectors (x1,y1,z1) and (x2,y2,z2) // (dx, dy, dz) = (x1, y1, z1) - (x2, y2, z2) // max_i sqrt( dx[i]*dx[i] + dy[i]*dy[i] + dz[i]*dz[i] ) func MaxVecDiff(x, y *data.Slice) float64 { util.Argument(x.Len() == y.Len()) out := reduceBuf(0) k_reducemaxvecdiff2_async(x.DevPtr(0), x.DevPtr(1), x.DevPtr(2), y.DevPtr(0), y.DevPtr(1), y.DevPtr(2), out, 0, x.Len(), reducecfg) return math.Sqrt(float64(copyback(out))) }
func sliceFromList(arr [][]float32, size [3]int) *data.Slice { ptrs := make([]unsafe.Pointer, len(arr)) for i := range ptrs { util.Argument(len(arr[i]) == prod(size)) ptrs[i] = unsafe.Pointer(&arr[i][0]) } return data.SliceFromPtrs(size, data.CPUMemory, ptrs) }
// kernel multiplication for 2D demag convolution on X and Y, exploiting full kernel symmetry. func kernMulRSymm2Dxy_async(fftMx, fftMy, Kxx, Kyy, Kxy *data.Slice, Nx, Ny int) { util.Argument(fftMy.NComp() == 1 && Kxx.NComp() == 1) cfg := make3DConf([3]int{Nx, Ny, 1}) k_kernmulRSymm2Dxy_async(fftMx.DevPtr(0), fftMy.DevPtr(0), Kxx.DevPtr(0), Kyy.DevPtr(0), Kxy.DevPtr(0), Nx, Ny, cfg) }
// Calculate the demag field of m * vol * Bsat, store result in B. // m: magnetization normalized to unit length // vol: unitless mask used to scale m's length, may be nil // Bsat: saturation magnetization in Tesla // B: resulting demag field, in Tesla func (c *DemagConvolution) Exec(B, m, vol *data.Slice, Msat MSlice) { util.Argument(B.Size() == c.inputSize && m.Size() == c.inputSize) if c.is2D() { c.exec2D(B, m, vol, Msat) } else { c.exec3D(B, m, vol, Msat) } }
// kernel multiplication for 3D demag convolution, exploiting full kernel symmetry. func kernMulRSymm3D_async(fftM [3]*data.Slice, Kxx, Kyy, Kzz, Kyz, Kxz, Kxy *data.Slice, Nx, Ny, Nz int) { util.Argument(fftM[X].NComp() == 1 && Kxx.NComp() == 1) cfg := make3DConf([3]int{Nx, Ny, Nz}) k_kernmulRSymm3D_async(fftM[X].DevPtr(0), fftM[Y].DevPtr(0), fftM[Z].DevPtr(0), Kxx.DevPtr(0), Kyy.DevPtr(0), Kzz.DevPtr(0), Kyz.DevPtr(0), Kxz.DevPtr(0), Kxy.DevPtr(0), Nx, Ny, Nz, cfg) }
// Calculate the demag field of m * vol * Bsat, store result in B. // m: magnetization normalized to unit length // vol: unitless mask used to scale m's length, may be nil // Bsat: saturation magnetization in Tesla // B: resulting demag field, in Tesla func (c *DemagConvolution) Exec(B, m, vol *data.Slice, Bsat LUTPtr, regions *Bytes) { util.Argument(B.Size() == c.inputSize && m.Size() == c.inputSize) if c.is2D() { c.exec2D(B, m, vol, Bsat, regions) } else { c.exec3D(B, m, vol, Bsat, regions) } }
// Set Bth to thermal noise (Brown). // see temperature.cu func SetTemperature(Bth, noise *data.Slice, temp_red LUTPtr, k2mu0_VgammaDt float64, regions *Bytes) { util.Argument(Bth.NComp() == 1 && noise.NComp() == 1) N := Bth.Len() cfg := make1DConf(N) k_settemperature_async(Bth.DevPtr(0), noise.DevPtr(0), float32(k2mu0_VgammaDt), unsafe.Pointer(temp_red), regions.Ptr, N, cfg) }
// select the part of src within the specified region, set 0's everywhere else. func RegionSelect(dst, src *data.Slice, regions *Bytes, region byte) { util.Argument(dst.NComp() == src.NComp()) N := dst.Len() cfg := make1DConf(N) for c := 0; c < dst.NComp(); c++ { k_regionselect_async(dst.DevPtr(c), src.DevPtr(c), regions.Ptr, region, N, cfg) } }
// Copies src into dst, which is larger, and multiplies by vol*Bsat. // The remainder of dst is not filled with zeros. // Used to zero-pad magnetization before convolution and in the meanwhile multiply m by its length. func copyPadMul(dst, src, vol *data.Slice, dstsize, srcsize [3]int, Bsat LUTPtr, regions *Bytes) { util.Argument(dst.NComp() == 1 && src.NComp() == 1) util.Assert(dst.Len() == prod(dstsize) && src.Len() == prod(srcsize)) cfg := make3DConf(srcsize) k_copypadmul_async(dst.DevPtr(0), dstsize[X], dstsize[Y], dstsize[Z], src.DevPtr(0), vol.DevPtr(0), srcsize[X], srcsize[Y], srcsize[Z], unsafe.Pointer(Bsat), regions.Ptr, cfg) }
func Crop(parent Quantity, x1, x2, y1, y2, z1, z2 int) *cropped { n := parent.Mesh().Size() util.Argument(x1 < x2 && y1 < y2 && z1 < z2) util.Argument(x1 >= 0 && y1 >= 0 && z1 >= 0) util.Argument(x2 <= n[X] && y2 <= n[Y] && z2 <= n[Z]) name := parent.Name() if x1 != 0 || x2 != n[X] { name += "_xrange" + rangeStr(x1, x2) } if y1 != 0 || y2 != n[Y] { name += "_yrange" + rangeStr(y1, y2) } if z1 != 0 || z2 != n[Z] { name += "_zrange" + rangeStr(z1, z2) } return &cropped{parent, name, x1, x2, y1, y2, z1, z2} }
// Copies src into dst, which is larger, and multiplies by vol*Bsat. // The remainder of dst is not filled with zeros. // Used to zero-pad magnetization before convolution and in the meanwhile multiply m by its length. func copyPadMul(dst, src, vol *data.Slice, dstsize, srcsize [3]int, Msat MSlice) { util.Argument(dst.NComp() == 1 && src.NComp() == 1) util.Assert(dst.Len() == prod(dstsize) && src.Len() == prod(srcsize)) cfg := make3DConf(srcsize) k_copypadmul2_async(dst.DevPtr(0), dstsize[X], dstsize[Y], dstsize[Z], src.DevPtr(0), srcsize[X], srcsize[Y], srcsize[Z], Msat.DevPtr(0), Msat.Mul(0), vol.DevPtr(0), cfg) }
// Dot product. func Dot(a, b *data.Slice) float32 { nComp := a.NComp() util.Argument(nComp == b.NComp()) out := reduceBuf(0) // not async over components for c := 0; c < nComp; c++ { k_reducedot_async(a.DevPtr(c), b.DevPtr(c), out, 0, a.Len(), reducecfg) // all components add to out } return copyback(out) }
// Add effective field of Dzyaloshinskii-Moriya interaction to Beff (Tesla). // According to Bagdanov and Röβler, PRL 87, 3, 2001. eq.8 (out-of-plane symmetry breaking). // See dmi.cu func AddDMI(Beff *data.Slice, m *data.Slice, Aex_red, Dex_red SymmLUT, regions *Bytes, mesh *data.Mesh) { cellsize := mesh.CellSize() N := Beff.Size() util.Argument(m.Size() == N) cfg := make3DConf(N) k_adddmi_async(Beff.DevPtr(X), Beff.DevPtr(Y), Beff.DevPtr(Z), m.DevPtr(X), m.DevPtr(Y), m.DevPtr(Z), unsafe.Pointer(Aex_red), unsafe.Pointer(Dex_red), regions.Ptr, float32(cellsize[X]*1e9), float32(cellsize[Y]*1e9), float32(cellsize[Z]*1e9), N[X], N[Y], N[Z], mesh.PBC_code(), cfg) }
// Set s to the toplogogical charge density s = m · (m/∂x ❌ ∂m/∂y) // See topologicalcharge.cu func SetTopologicalCharge(s *data.Slice, m *data.Slice, mesh *data.Mesh) { cellsize := mesh.CellSize() N := s.Size() util.Argument(m.Size() == N) cfg := make3DConf(N) icxcy := float32(1.0 / (cellsize[X] * cellsize[Y])) k_settopologicalcharge_async(s.DevPtr(X), m.DevPtr(X), m.DevPtr(Y), m.DevPtr(Z), icxcy, N[X], N[Y], N[Z], mesh.PBC_code(), cfg) }
// Set Bth to thermal noise (Brown). // see temperature.cu func SetTemperature(Bth, noise *data.Slice, k2mu0_Mu0VgammaDt float64, Msat, Temp, Alpha MSlice) { util.Argument(Bth.NComp() == 1 && noise.NComp() == 1) N := Bth.Len() cfg := make1DConf(N) k_settemperature2_async(Bth.DevPtr(0), noise.DevPtr(0), float32(k2mu0_Mu0VgammaDt), Msat.DevPtr(0), Msat.Mul(0), Temp.DevPtr(0), Temp.Mul(0), Alpha.DevPtr(0), Alpha.Mul(0), N, cfg) }
// Add uniaxial magnetocrystalline anisotropy field to Beff. // see uniaxialanisotropy.cu func AddUniaxialAnisotropy(Beff, m *data.Slice, k1_red, k2_red LUTPtr, u LUTPtrs, regions *Bytes) { util.Argument(Beff.Size() == m.Size()) N := Beff.Len() cfg := make1DConf(N) k_adduniaxialanisotropy_async(Beff.DevPtr(X), Beff.DevPtr(Y), Beff.DevPtr(Z), m.DevPtr(X), m.DevPtr(Y), m.DevPtr(Z), unsafe.Pointer(k1_red), unsafe.Pointer(k2_red), u[X], u[Y], u[Z], regions.Ptr, N, cfg) }
// x range that needs to be refreshed after shift over dx func shiftDirtyRange(dx int) (x1, x2 int) { nx := Mesh().Size()[X] util.Argument(dx != 0) if dx < 0 { x1 = nx + dx x2 = nx } else { x1 = 0 x2 = dx } return }
// Internal: construct a Slice using bare memory pointers. func SliceFromPtrs(size [3]int, memType int8, ptrs []unsafe.Pointer) *Slice { length := prod(size) nComp := len(ptrs) util.Argument(nComp > 0 && length > 0 && nComp <= MAX_COMP) s := new(Slice) s.ptrs = s.ptr_[:nComp] s.size = size for c := range ptrs { s.ptrs[c] = ptrs[c] } s.memType = memType return s }
// Adds cubic anisotropy field to Beff. // see cubicanisotropy.cu func AddCubicAnisotropy(Beff, m *data.Slice, k1_red, k2_red, k3_red LUTPtr, c1, c2 LUTPtrs, regions *Bytes) { util.Argument(Beff.Size() == m.Size()) N := Beff.Len() cfg := make1DConf(N) k_addcubicanisotropy_async( Beff.DevPtr(X), Beff.DevPtr(Y), Beff.DevPtr(Z), m.DevPtr(X), m.DevPtr(Y), m.DevPtr(Z), unsafe.Pointer(k1_red), unsafe.Pointer(k2_red), unsafe.Pointer(k3_red), c1[X], c1[Y], c1[Z], c2[X], c2[Y], c2[Z], regions.Ptr, N, cfg) }
// Memset sets the Slice's components to the specified values. // To be carefully used on unified slice (need sync) func Memset(s *data.Slice, val ...float32) { if Synchronous { // debug Sync() timer.Start("memset") } util.Argument(len(val) == s.NComp()) for c, v := range val { cu.MemsetD32Async(cu.DevicePtr(uintptr(s.DevPtr(c))), math.Float32bits(v), int64(s.Len()), stream0) } if Synchronous { //debug Sync() timer.Stop("memset") } }
// Re-interpret a contiguous array as a multi-dimensional array of given size. func reshapeBytes(array []byte, size [3]int) [][][]byte { Nx, Ny, Nz := size[X], size[Y], size[Z] util.Argument(Nx*Ny*Nz == len(array)) sliced := make([][][]byte, Nz) for i := range sliced { sliced[i] = make([][]byte, Ny) } for i := range sliced { for j := range sliced[i] { sliced[i][j] = array[(i*Ny+j)*Nx+0 : (i*Ny+j)*Nx+Nx] } } return sliced }
// Add interlayer exchange field to Beff. // see interlayer.cu func AddInterlayerExchange(Beff, m *data.Slice, J1_red, J2_red, toplayer, bottomlayer LUTPtr, direc LUTPtrs, regions *Bytes, mesh *data.Mesh) { cellsize := mesh.CellSize() N := Beff.Size() util.Argument(m.Size() == N) cfg := make3DConf(N) k_addinterlayerexchange_async(Beff.DevPtr(X), Beff.DevPtr(Y), Beff.DevPtr(Z), m.DevPtr(X), m.DevPtr(Y), m.DevPtr(Z), unsafe.Pointer(J1_red), unsafe.Pointer(J2_red), unsafe.Pointer(toplayer), unsafe.Pointer(bottomlayer), direc[X], direc[Y], direc[Z], float32(cellsize[X])*1e9, float32(cellsize[Y])*1e9, float32(cellsize[Z])*1e9, N[X], N[Y], N[Z], regions.Ptr, cfg) }