void gradient(RawArray<const T,2> x, RawArray<T,2> grad) const { // Temporary arrays and views GEODE_ASSERT(x.sizes()==vec(n+3,d) && grad.sizes()==x.sizes()); const auto sx = smallx.flat.raw(), sv = smallv.flat.raw(); // Collect quadrature points const int e = 4*d; Array<T,3> tq( n,quads,e,uninit); Array<T,4> xq(vec(n,quads,e,d),uninit); Array<T,4> vq(vec(n,quads,e,d),uninit); for (int i=0;i<n;i++) { T_INFO(i) for (int q=0;q<quads;q++) { const T s = samples[q], t = t1+dt*s; for (int j=0;j<e;j++) tq(i,q,j) = t; SPLINE_INFO(s) for (int a=0;a<d;a++) { X_INFO(i,a) const T x = a0*x0+a1*x1+a2*x2+a3*x3, v = b0*x0+b1*x1+b2*x2+b3*x3; for (int j=0;j<e;j++) { xq(i,q,j,a) = x; vq(i,q,j,a) = v; } } for (int a=0;a<d;a++) { xq(i,q,4*a ,a) -= sx[a]; xq(i,q,4*a+1,a) += sx[a]; vq(i,q,4*a+2,a) -= sv[a]; vq(i,q,4*a+3,a) += sv[a]; } } } // Compute energies const auto Uq_ = U(tq.reshape_own(n*quads*e),NdArray<const T>(q2shape,xq.flat),NdArray<const T>(q2shape,vq.flat)); GEODE_ASSERT(Uq_.size()==n*quads*e); const auto Uq = Uq_.reshape(n,quads,e); // Accumulate grad.fill(0); const auto inv_2s = GEODE_RAW_ALLOCA(d,Vector<T,2>); for (int a=0;a<d;a++) inv_2s[a] = vec(.5/sx[a],.5/sv[a]); for (int i=0;i<n;i++) { T_INFO(i) for (int q=0;q<quads;q++) { const T s = samples[q], w = dt*weights[q]; SPLINE_INFO(s) for (int a=0;a<d;a++) { const T wx = w*inv_2s[a].x*(Uq(i,q,4*a+1)-Uq(i,q,4*a )), wv = w*inv_2s[a].y*(Uq(i,q,4*a+3)-Uq(i,q,4*a+2)); grad(i ,a) += a0*wx+b0*wv; grad(i+1,a) += a1*wx+b1*wv; grad(i+2,a) += a2*wx+b2*wv; grad(i+3,a) += a3*wx+b3*wv; } } } }