diff --git a/demos/Wiener_Filter.ipynb b/demos/Wiener_Filter.ipynb index 26f5e402851e21ab9fc4e2bab9fe5a88f9a3e730..1754210855c62bbedd755e0db45f734f626cab0e 100644 --- a/demos/Wiener_Filter.ipynb +++ b/demos/Wiener_Filter.ipynb @@ -427,12 +427,12 @@ "\n", "mask = np.full(s_space.shape, 1.)\n", "mask[l:h] = 0\n", - "mask = ift.Field.from_arr(s_space, mask)\n", + "mask = ift.Field.from_raw(s_space, mask)\n", "\n", "R = ift.DiagonalOperator(mask)(HT)\n", - "n = n.val.copy()\n", + "n = n.val_rw()\n", "n[l:h] = 0\n", - "n = ift.Field.from_arr(s_space, n)\n", + "n = ift.Field.from_raw(s_space, n)\n", "\n", "d = R(sh) + n" ] @@ -501,7 +501,7 @@ "m_data = HT(m).val\n", "m_var_data = m_var.val\n", "uncertainty = np.sqrt(m_var_data)\n", - "d_data = d.val.copy()\n", + "d_data = d.val_rw()\n", "\n", "# Set lost data to NaN for proper plotting\n", "d_data[d_data == 0] = np.nan" @@ -583,12 +583,12 @@ "\n", "mask = np.full(s_space.shape, 1.)\n", "mask[l:h,l:h] = 0.\n", - "mask = ift.Field.from_arr(s_space, mask)\n", + "mask = ift.Field.from_raw(s_space, mask)\n", "\n", "R = ift.DiagonalOperator(mask)(HT)\n", - "n = n.val.copy()\n", + "n = n.val_rw()\n", "n[l:h, l:h] = 0\n", - "n = ift.Field.from_arr(s_space, n)\n", + "n = ift.Field.from_raw(s_space, n)\n", "curv = Curvature(R=R, N=N, Sh=Sh)\n", "D = curv.inverse\n", "\n", diff --git a/demos/bernoulli_demo.py b/demos/bernoulli_demo.py index 19e82af32ede0fd54febdb17e9abf1077ba991b6..4cd8dbc1d0ee3003e28a3015b0fec1990e8663af 100644 --- a/demos/bernoulli_demo.py +++ b/demos/bernoulli_demo.py @@ -63,7 +63,7 @@ if __name__ == '__main__': mock_position = ift.from_random('normal', harmonic_space) tmp = p(mock_position).val.astype(np.float64) data = np.random.binomial(1, tmp) - data = ift.Field.from_arr(R.target, data) + data = ift.Field.from_raw(R.target, data) # Compute likelihood and Hamiltonian position = ift.from_random('normal', harmonic_space) diff --git a/demos/find_amplitude_parameters.py b/demos/find_amplitude_parameters.py index e96c06615d227c072f6547f73ef0a054769daa21..90cdfd29390173ec8bd9a6e9a14d6bd709b64964 100644 --- a/demos/find_amplitude_parameters.py +++ b/demos/find_amplitude_parameters.py @@ -57,7 +57,7 @@ if __name__ == '__main__': for _ in range(n_samps): fld = pspec(ift.from_random('normal', pspec.domain)) klengths = fld.domain[0].k_lengths - ycoord = fld.val.copy() + ycoord = fld.val_rw() ycoord[0] = ycoord[1] ax.plot(klengths, ycoord, alpha=1) diff --git a/demos/getting_started_1.py b/demos/getting_started_1.py index b0277a7504b1baf2e2b55f6e1b22151a2c118132..3698549a02ba2640b895fdf6019824a90c8f7537 100644 --- a/demos/getting_started_1.py +++ b/demos/getting_started_1.py @@ -95,7 +95,7 @@ if __name__ == '__main__': # and harmonic transformaion # Masking operator to model that parts of the field have not been observed - mask = ift.Field.from_arr(position_space, mask) + mask = ift.Field.from_raw(position_space, mask) Mask = ift.MaskOperator(mask) # The response operator consists of diff --git a/demos/getting_started_2.py b/demos/getting_started_2.py index 62f2e9351b58f039fbc49febf8eb66f3bf0affd6..17b4e05158567bd61685e3504d40b23774f14096 100644 --- a/demos/getting_started_2.py +++ b/demos/getting_started_2.py @@ -40,7 +40,7 @@ def exposure_2d(): exposure[:, x_shape*4//5:x_shape] *= .1 exposure[:, x_shape//2:x_shape*3//2] *= 3. - return ift.Field.from_arr(position_space, exposure) + return ift.Field.from_raw(position_space, exposure) if __name__ == '__main__': @@ -95,7 +95,7 @@ if __name__ == '__main__': mock_position = ift.from_random('normal', domain) data = lamb(mock_position) data = np.random.poisson(data.val.astype(np.float64)) - data = ift.Field.from_arr(d_space, data) + data = ift.Field.from_raw(d_space, data) likelihood = ift.PoissonianEnergy(data)(lamb) # Settings for minimization diff --git a/demos/polynomial_fit.py b/demos/polynomial_fit.py index dcc3a47e1de6439335470c5c5b2c40d1baadf168..be51daf0c06cff26f1c7a01f7e306bf4ebe3dd9c 100644 --- a/demos/polynomial_fit.py +++ b/demos/polynomial_fit.py @@ -71,7 +71,7 @@ class PolynomialResponse(ift.LinearOperator): def apply(self, x, mode): self._check_input(x, mode) - val = x.val.copy() + val = x.val_rw() if mode == self.TIMES: # FIXME Use polynomial() here out = self._mat.dot(val) diff --git a/nifty6/domains/lm_space.py b/nifty6/domains/lm_space.py index ad5799bfdea370d80a74b103d5d8369f44906619..d3e9723d03b62344fac28ea42ef32c27687978bb 100644 --- a/nifty6/domains/lm_space.py +++ b/nifty6/domains/lm_space.py @@ -87,7 +87,7 @@ class LMSpace(StructuredDomain): for m in range(1, mmax+1): ldist[idx:idx+2*(lmax+1-m)] = tmp[2*m:] idx += 2*(lmax+1-m) - return Field.from_arr(self, ldist) + return Field.from_raw(self, ldist) def get_unique_k_lengths(self): return np.arange(self.lmax+1, dtype=np.float64) @@ -123,7 +123,7 @@ class LMSpace(StructuredDomain): lm0 = gl.get_default_codomain() theta = pyHealpix.GL_thetas(gl.nlat) # evaluate the kernel function at the required thetas - kernel_sphere = Field.from_arr(gl, func(theta)) + kernel_sphere = Field.from_raw(gl, func(theta)) # normalize the kernel such that the integral over the sphere is 4pi kernel_sphere = kernel_sphere * (4 * np.pi / kernel_sphere.integrate()) # compute the spherical harmonic coefficients of the kernel @@ -131,7 +131,7 @@ class LMSpace(StructuredDomain): kernel_lm = op.adjoint_times(kernel_sphere.weight(1)).val # evaluate the k lengths of the harmonic space k_lengths = self.get_k_length_array().val.astype(np.int) - return Field.from_arr(self, kernel_lm[k_lengths]) + return Field.from_raw(self, kernel_lm[k_lengths]) @property def lmax(self): diff --git a/nifty6/domains/power_space.py b/nifty6/domains/power_space.py index f5774e3fd90019710c7ef4be311eaf2f859accde..13b73cdb858a4a44485537b292217170580175e4 100644 --- a/nifty6/domains/power_space.py +++ b/nifty6/domains/power_space.py @@ -240,7 +240,7 @@ class PowerSpace(StructuredDomain): @property def pindex(self): - """data_object : bin indices + """numpy.ndarray : bin indices Bin index for every pixel in the harmonic partner. """ diff --git a/nifty6/domains/rg_space.py b/nifty6/domains/rg_space.py index 3301d2e68495ee78d6fb3153e24c6e555441e598..7b41ff75438b385aea45677cee60adbd4b14da62 100644 --- a/nifty6/domains/rg_space.py +++ b/nifty6/domains/rg_space.py @@ -97,14 +97,14 @@ class RGSpace(StructuredDomain): res = np.arange(self.shape[0], dtype=np.float64) res = np.minimum(res, self.shape[0]-res)*self.distances[0] if len(self.shape) == 1: - return Field.from_arr(self, res) + return Field.from_raw(self, res) res *= res for i in range(1, len(self.shape)): tmp = np.arange(self.shape[i], dtype=np.float64) tmp = np.minimum(tmp, self.shape[i]-tmp)*self.distances[i] tmp *= tmp res = np.add.outer(res, tmp) - return Field.from_arr(self, np.sqrt(res)) + return Field.from_raw(self, np.sqrt(res)) def get_k_length_array(self): if (not self.harmonic): diff --git a/nifty6/field.py b/nifty6/field.py index 1adb5143c8ab60c3ffc65aaaf903519898470838..00cb2923d50ca3b392c3d71a0e11ff36d91d9146 100644 --- a/nifty6/field.py +++ b/nifty6/field.py @@ -32,8 +32,8 @@ class Field(object): ---------- domain : DomainTuple The domain of the new Field. - val : data_object - This object's global shape must match the domain shape + val : numpy.ndarray + This object's shape must match the domain shape After construction, the object will no longer be writeable! Notes @@ -93,7 +93,7 @@ class Field(object): return Field(domain, val) @staticmethod - def from_arr(domain, arr): + def from_raw(domain, arr): """Returns a Field constructed from `domain` and `arr`. Parameters @@ -148,15 +148,19 @@ class Field(object): @property def val(self): - """numpy.ndarray : the data object storing the field's entries. + """numpy.ndarray : the array storing the field's entries. Notes ----- - This property is intended for low-level, internal use only. Do not use - from outside of NIFTy's core; there should be better alternatives. + The returned array is read-only. """ return self._val + def val_rw(self): + """numpy.ndarray : a copy of the array storing the field's entries. + """ + return self._val.copy() + @property def dtype(self): """type : the data type of the field's entries""" @@ -241,7 +245,7 @@ class Field(object): Field The weighted field. """ - aout = self.val.copy() + aout = self.val_rw() spaces = utilities.parse_spaces(spaces, len(self._domain)) diff --git a/nifty6/library/correlated_fields.py b/nifty6/library/correlated_fields.py index a6a8a019bdd06556fc34436f3bb6f8c082ff10b1..ba348cac0365e3cee1c29e76d449520e14612f9b 100644 --- a/nifty6/library/correlated_fields.py +++ b/nifty6/library/correlated_fields.py @@ -179,7 +179,7 @@ class _TwoLogIntegrations(LinearOperator): res[from_third] = (res[from_third] + res[no_border])/2*self._log_vol[extender_sl] + x[first] res[from_third] = np.cumsum(res[from_third], axis=axis) else: - x = x.val.copy() + x = x.val_rw() res = np.zeros(self._domain.shape) x[from_third] = np.cumsum(x[from_third][reverse], axis=axis)[reverse] res[first] += x[from_third] @@ -199,7 +199,7 @@ class _Normalization(Operator): pd = PowerDistributor(hspace, power_space=self._domain[space], space=space) - mode_multiplicity = pd.adjoint(full(pd.target, 1.)).val.copy() + mode_multiplicity = pd.adjoint(full(pd.target, 1.)).val_rw() zero_mode = (slice(None),)*self._domain.axes[space][0] + (0,) mode_multiplicity[zero_mode] = 0 self._mode_multiplicity = makeField(self._domain, diff --git a/nifty6/library/los_response.py b/nifty6/library/los_response.py index 25e05de1995178fa7f3685213c415d37867af2d8..bd8e65c12f1ff3ce0e67b3e030ea37da38067958 100644 --- a/nifty6/library/los_response.py +++ b/nifty6/library/los_response.py @@ -172,12 +172,11 @@ class LOSResponse(LinearOperator): "getting negative distances") real_ends = starts + diffs*real_distances dist = np.array(self.domain[0].distances).reshape((-1, 1)) - localized_pixel_starts = starts/dist + 0.5 - localized_pixel_ends = real_ends/dist + 0.5 + pixel_starts = starts/dist + 0.5 + pixel_ends = real_ends/dist + 0.5 - # get the shape of the local data slice - w_i = _comp_traverse(localized_pixel_starts, - localized_pixel_ends, + w_i = _comp_traverse(pixel_starts, + pixel_ends, self.domain[0].shape, np.array(self.domain[0].distances), 1./(1./difflen+truncation*sigmas), @@ -229,6 +228,6 @@ class LOSResponse(LinearOperator): if mode == self.TIMES: result_arr = self._smat.matvec(x.val.reshape(-1)) return Field(self._target, result_arr) - local_input_data = x.val.reshape(-1) - res = self._smat.rmatvec(local_input_data).reshape(self.domain[0].shape) + input_data = x.val.reshape(-1) + res = self._smat.rmatvec(input_data).reshape(self.domain[0].shape) return Field(self._domain, res) diff --git a/nifty6/linearization.py b/nifty6/linearization.py index 10141ca6561579b5e1de587e53ffa1e65cd94b11..d62d5b402fb7731874c73cbc5966011192ef25a2 100644 --- a/nifty6/linearization.py +++ b/nifty6/linearization.py @@ -321,7 +321,7 @@ class Linearization(object): tmp = self._val.sinc() tmp2 = ((np.pi*self._val).cos()-tmp)/self._val ind = self._val.val == 0 - loc = tmp2.val.copy() + loc = tmp2.val_rw() loc[ind] = 0 tmp2 = Field(tmp.domain, loc) return self.new(tmp, makeOp(tmp2)(self._jac)) @@ -371,7 +371,7 @@ class Linearization(object): tmp2 = self._val.sign() ind = self._val.val == 0 - loc = tmp2.val.copy().astype(float) + loc = tmp2.val_rw().astype(float) loc[ind] = np.nan tmp2 = Field(tmp.domain, loc) diff --git a/nifty6/minimization/metric_gaussian_kl_mpi.py b/nifty6/minimization/metric_gaussian_kl_mpi.py index f0dc1ce58177c417587f2fbe3f6ba92976bb99f1..9de0866af69a9631255cceeb1fe31532514498f9 100644 --- a/nifty6/minimization/metric_gaussian_kl_mpi.py +++ b/nifty6/minimization/metric_gaussian_kl_mpi.py @@ -188,7 +188,7 @@ class MetricGaussianKL_MPI(Energy): for s in self._samples: tmp = self._hamiltonian(self._lin+s) if v is None: - v = tmp.val.val.copy() + v = tmp.val.val_rw() g = tmp.gradient else: v += tmp.val.val diff --git a/nifty6/minimization/scipy_minimizer.py b/nifty6/minimization/scipy_minimizer.py index fcba4863108dbbd49e5288c702ed80da7955cef1..353006869ca522dc52670c628a2c64687422025b 100644 --- a/nifty6/minimization/scipy_minimizer.py +++ b/nifty6/minimization/scipy_minimizer.py @@ -48,7 +48,7 @@ def _toArray(fld): def _toArray_rw(fld): if isinstance(fld, Field): - return fld.val.copy().reshape(-1) + return fld.val_rw().reshape(-1) return _multiToArray(fld) diff --git a/nifty6/multi_field.py b/nifty6/multi_field.py index b78caa5a0da725605ee9a4773ad229996a481c4f..66d655505f172bed31d89c530e621de5a714d220 100644 --- a/nifty6/multi_field.py +++ b/nifty6/multi_field.py @@ -132,12 +132,17 @@ class MultiField(object): return MultiField(domain, tuple(Field(dom, val) for dom in domain._domains)) - def to_global_data(self): + @property + def val(self): return {key: val.val for key, val in zip(self._domain.keys(), self._val)} + def val_rw(self): + return {key: val.val_rw() + for key, val in zip(self._domain.keys(), self._val)} + @staticmethod - def from_global_data(domain, arr): + def from_raw(domain, arr): return MultiField( domain, tuple(Field(domain[key], arr[key]) for key in domain.keys())) diff --git a/nifty6/operator_spectrum.py b/nifty6/operator_spectrum.py index 53336afc6e89c21afd2b37162a48f334f59b0fb1..cb0a8a3ef4207e340e275e9452ae4a07583e09e7 100644 --- a/nifty6/operator_spectrum.py +++ b/nifty6/operator_spectrum.py @@ -56,7 +56,7 @@ class _DomRemover(LinearOperator): def apply(self, x, mode): self._check_input(x, mode) self._check_float_dtype(x) - x = x.to_global_data() + x = x.val if isinstance(self._domain, DomainTuple): res = x.ravel() if mode == self.TIMES else x.reshape( self._domain.shape) diff --git a/nifty6/operators/distributors.py b/nifty6/operators/distributors.py index ee7e102ef498d6705dc7b8be22b37f3fac57490c..bcd413ad3ebcc4c512f692f8ed5082c0337918a5 100644 --- a/nifty6/operators/distributors.py +++ b/nifty6/operators/distributors.py @@ -74,7 +74,7 @@ class DOFDistributor(LinearOperator): wgt = np.bincount(dofdex.val.ravel(), minlength=nbin) wgt = wgt*partner.scalar_dvol else: - dvol = Field.from_arr(partner, partner.dvol).val + dvol = Field.from_raw(partner, partner.dvol).val wgt = np.bincount(dofdex.val.ravel(), minlength=nbin, weights=dvol) # The explicit conversion to float64 is necessary because bincount @@ -108,7 +108,7 @@ class DOFDistributor(LinearOperator): oarr = np.zeros(self._hshape, dtype=x.dtype) oarr = special_add_at(oarr, 1, self._dofdex, arr) oarr = oarr.reshape(self._domain.shape) - res = Field.from_arr(self._domain, oarr) + res = Field.from_raw(self._domain, oarr) return res def _times(self, x): diff --git a/nifty6/plot.py b/nifty6/plot.py index 574a54587ae2d93707949910f42d9dc8cb305fcd..8e84cd6742b92f0718e240199e7f201a4fc2ed9e 100644 --- a/nifty6/plot.py +++ b/nifty6/plot.py @@ -310,7 +310,7 @@ def _plot1D(f, ax, **kwargs): plt.yscale(kwargs.pop("yscale", "log")) xcoord = dom.k_lengths for i, fld in enumerate(f): - ycoord = fld.val.copy() + ycoord = fld.val_rw() ycoord[0] = ycoord[1] plt.plot(xcoord, ycoord, label=label[i], linewidth=linewidth[i], alpha=alpha[i]) diff --git a/nifty6/probing.py b/nifty6/probing.py index f99b8d3863d44d9dc312aec4d2d7b9a78604810d..337e239a1d6f5826bea481cf670a1a60a9921cef 100644 --- a/nifty6/probing.py +++ b/nifty6/probing.py @@ -144,7 +144,7 @@ def approximation2endo(op, nsamples): approx = sc.var dct = approx.to_dict() for kk in dct: - foo = dct[kk].to_global_data_rw() + foo = dct[kk].val_rw() foo[foo == 0] = 1 dct[kk] = makeField(dct[kk].domain, foo) return MultiField.from_dict(dct) diff --git a/nifty6/sugar.py b/nifty6/sugar.py index 973b989d0f0cd9f3f7b550583545a93aee316f5c..2a568eac9d75021e5beaad68d60107f092ad430f 100644 --- a/nifty6/sugar.py +++ b/nifty6/sugar.py @@ -297,8 +297,8 @@ def makeField(domain, arr): The newly created random field """ if isinstance(domain, (dict, MultiDomain)): - return MultiField.from_global_data(domain, arr) - return Field.from_arr(domain, arr) + return MultiField.from_raw(domain, arr) + return Field.from_raw(domain, arr) def makeDomain(domain): diff --git a/test/test_minimizers.py b/test/test_minimizers.py index 83c8d89864a92971c9512f3201c60ba93a00869b..e0c6641808cea8db0a95ba936ab8cb3fa1bdcfc0 100644 --- a/test/test_minimizers.py +++ b/test/test_minimizers.py @@ -131,11 +131,11 @@ def test_rosenbrock(minimizer): @property def value(self): - return rosen(self._position.val.copy()) + return rosen(self._position.val_rw()) @property def gradient(self): - inp = self._position.val.copy() + inp = self._position.val_rw() out = ift.Field(space, rosen_der(inp)) return out @@ -143,13 +143,13 @@ def test_rosenbrock(minimizer): def metric(self): class RBCurv(ift.EndomorphicOperator): def __init__(self, loc): - self._loc = loc.val.copy() + self._loc = loc.val_rw() self._capability = self.TIMES self._domain = space def apply(self, x, mode): self._check_input(x, mode) - inp = x.val.copy() + inp = x.val_rw() out = ift.Field( space, rosen_hess_prod(self._loc.copy(), inp)) return out @@ -159,8 +159,8 @@ def test_rosenbrock(minimizer): return ift.InversionEnabler(RBCurv(self._position), t1) def apply_metric(self, x): - inp = x.val.copy() - pos = self._position.val.copy() + inp = x.val_rw() + pos = self._position.val_rw() return ift.Field(space, rosen_hess_prod(pos, inp)) try: diff --git a/test/test_multi_field.py b/test/test_multi_field.py index 9c1a7c0815d17c1648899dcea2d189e7d6d9f605..e29fd31873b1d03fcd83e60a195d3dce7d44c946 100644 --- a/test/test_multi_field.py +++ b/test/test_multi_field.py @@ -44,7 +44,7 @@ def test_multifield_field_consistency(): def test_dataconv(): f1 = ift.full(dom, 27) - f2 = ift.makeField(dom, f1.to_global_data()) + f2 = ift.makeField(dom, f1.val) for key, val in f1.items(): assert_equal(val.val, f2[key].val) if "d1" not in f2: diff --git a/test/test_operators/test_adjoint.py b/test/test_operators/test_adjoint.py index 0f3b2622a6ae219cbf5c47d5682e13febb1f18e4..c55f6b986c3f76fd250a8134ab15a2e853b95ec7 100644 --- a/test/test_operators/test_adjoint.py +++ b/test/test_operators/test_adjoint.py @@ -127,7 +127,7 @@ def testDOFDistributor(sp, dtype): if sp.size < 4: return dofdex = np.arange(sp.size).reshape(sp.shape) % 3 - dofdex = ift.Field.from_arr(sp, dofdex) + dofdex = ift.Field.from_raw(sp, dofdex) op = ift.DOFDistributor(dofdex) ift.extra.consistency_check(op, dtype, dtype) @@ -174,7 +174,7 @@ def testMask(sp, dtype): f = ift.from_random('normal', sp).val mask = np.zeros_like(f) mask[f > 0] = 1 - mask = ift.Field.from_arr(sp, mask) + mask = ift.Field.from_raw(sp, mask) # Test MaskOperator op = ift.MaskOperator(mask) ift.extra.consistency_check(op, dtype, dtype) diff --git a/test/test_operators/test_representation.py b/test/test_operators/test_representation.py index efa87b8486a7892c3daa8989c8994d0c15d7f4dc..b817b18be6e5c60f27cc4391ec92cf57ae8cca4d 100644 --- a/test/test_operators/test_representation.py +++ b/test/test_operators/test_representation.py @@ -102,7 +102,7 @@ def testDOFDistributor(sp, dtype): if sp.size < 4: return dofdex = np.arange(sp.size).reshape(sp.shape) % 3 - dofdex = ift.Field.from_arr(sp, dofdex) + dofdex = ift.Field.from_raw(sp, dofdex) _check_repr(ift.DOFDistributor(dofdex)) @@ -140,7 +140,7 @@ def testMask(sp, dtype): f = ift.from_random('normal', sp).val mask = np.zeros_like(f) mask[f > 0] = 1 - mask = ift.Field.from_arr(sp, mask) + mask = ift.Field.from_raw(sp, mask) # Test MaskOperator _check_repr(ift.MaskOperator(mask)) diff --git a/test/test_operators/test_smoothing_operator.py b/test/test_operators/test_smoothing_operator.py index 71ce7b825e8347759ad5bcdc3674b0a1b36cda56..3bebbc419f43283c5d34bb086498058bd4001239 100644 --- a/test/test_operators/test_smoothing_operator.py +++ b/test/test_operators/test_smoothing_operator.py @@ -56,7 +56,7 @@ def test_times(space, sigma): op = ift.HarmonicSmoothingOperator(space, sigma=sigma) fld = np.zeros(space.shape, dtype=np.float64) fld[0] = 1. - rand1 = ift.Field.from_arr(space, fld) + rand1 = ift.Field.from_raw(space, fld) tt1 = op.times(rand1) assert_allclose(1, tt1.sum())