diff --git a/.gitattributes b/.gitattributes index 18fb6d753473771466372e2c90722cd81ab85532..df50dbe029123b8b20367822981428f91dd3ae34 100755 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,5 @@ tests/keplerian-orbits-2-0.h5 filter=lfs diff=lfs merge=lfs -text tests/esa-trailing-orbits-2-0.h5 filter=lfs diff=lfs merge=lfs -text tests/keplerian-fplan-1-1.h5 filter=lfs diff=lfs merge=lfs -text tests/esa-trailing-fplan-1-1.h5 filter=lfs diff=lfs merge=lfs -text +tests/gws-1-1.h5 filter=lfs diff=lfs merge=lfs -text +tests/gws-2-0-dev.h5 filter=lfs diff=lfs merge=lfs -text diff --git a/lisainstrument/instrument.py b/lisainstrument/instrument.py index e13c032a8d8b7478a7ea5e9e1dca210a16dfca87..144789e57714505ec9d2b61892ed47547c02ed44 100755 --- a/lisainstrument/instrument.py +++ b/lisainstrument/instrument.py @@ -682,10 +682,17 @@ class Instrument: logger.debug("Using GW file version %s", version) if version.is_devrelease: logger.warning("You are using a GW file in a development version") - if version in SpecifierSet('~= 0.1', True) or version in SpecifierSet('~= 1.0', True): - self.gws = ForEachMOSA(lambda mosa: InterpolatedUnivariateSpline( - gwf['t'][:], gwf[f'l_{mosa}'][:], k=5, ext='zeros')(self.physics_t) - ) + if version in SpecifierSet('< 1.1', True): + interpolate = lambda data, t: InterpolatedUnivariateSpline(gwf['t'][:], data, k=5, ext='zeros')(t) + self.gws = ForEachMOSA(lambda mosa: interpolate(gwf[f'l_{mosa}'][:], self.physics_t)) + elif version in SpecifierSet('== 1.1', True): + interpolate = lambda data, t: InterpolatedUnivariateSpline(gwf['t'][:], data, k=5, ext='zeros')(t) + self.gws = ForEachMOSA(lambda mosa: interpolate(gwf[f'tcb/l_{mosa}'][:], self.physics_t)) + elif version in SpecifierSet('== 2.*', True): + times = gwf.attrs['t0'] + np.arange(gwf.attrs['size']) * gwf.attrs['dt'] + interpolate = lambda data, t: InterpolatedUnivariateSpline(times, data, k=5, ext='zeros')(t) + link_index = {'12': 0, '23': 1, '31': 2, '13': 3, '32': 4, '21': 5} + self.gws = ForEachMOSA(lambda mosa: interpolate(gwf['tcb/y'][:, link_index[mosa]], self.physics_t)) else: raise ValueError(f"unsupported GW file version '{version}'") elif gws is None: @@ -792,6 +799,7 @@ class Instrument: self.sc_jitter_eta_asds = ForEachSC(0) self.sc_jitter_theta_asds = ForEachSC(0) self.mosa_jitter_phi_asds = ForEachMOSA(0) + self.mosa_jitter_eta_asds = ForEachMOSA(0) def disable_dopplers(self): """Set proper pseudo-range derivatives to zero to turn off Doppler effects.""" diff --git a/tests/gws-1-1.h5 b/tests/gws-1-1.h5 new file mode 100644 index 0000000000000000000000000000000000000000..c8c5979379be7bd8086f2a833422d0ea251fb248 --- /dev/null +++ b/tests/gws-1-1.h5 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95a12c32a7ab80c75e88d67329e7840760eff990a180a79360da6b1d0f74d150 +size 28672 diff --git a/tests/gws-2-0-dev.h5 b/tests/gws-2-0-dev.h5 new file mode 100644 index 0000000000000000000000000000000000000000..6abce64b1ca22d69e56f7473e8b8d36c60ec901d --- /dev/null +++ b/tests/gws-2-0-dev.h5 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b14f934a46606fffe413bfa4baaf461162ff76346f546b09c5cfb7895d1b8f41 +size 20272 diff --git a/tests/test_gws.py b/tests/test_gws.py new file mode 100644 index 0000000000000000000000000000000000000000..5951f04988b7fe7ec56b7445ac885552aee90f5e --- /dev/null +++ b/tests/test_gws.py @@ -0,0 +1,164 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Test reading of GW response and GW files.""" + +import numpy as np +from pytest import approx +from h5py import File +from lisainstrument import Instrument + + +def test_no_gws(): + """Test that we simulate without GWs.""" + + instru = Instrument(size=100, gws=None) + instru.disable_all_noises() + + assert instru.gw_file is None + for mosa in instru.MOSAS: + assert instru.gws[mosa] == 0 + + instru.simulate() + + for mosa in instru.MOSAS: + assert instru.distant_carrier_fluctuations[mosa] == approx(0) + assert instru.distant_usb_fluctuations[mosa] == approx(0) + assert instru.tps_isi_carrier_fluctuations[mosa] == approx(0) + assert instru.tps_isi_usb_fluctuations[mosa] == approx(0) + assert instru.isi_carrier_fluctuations[mosa] == approx(0) + assert instru.isi_usb_fluctuations[mosa] == approx(0) + +def test_dict_of_gws(): + """Test that we pass link responses in a dictionary.""" + + responses = { + mosa: np.random.normal(size=100 * 16) + for mosa in Instrument.MOSAS + } + + instru = Instrument(size=100, lock='six', gws=responses) + instru.disable_all_noises() + + assert instru.gw_file is None + for mosa in instru.MOSAS: + assert np.all(instru.gws[mosa] == responses[mosa]) + + instru.simulate() + + for mosa in instru.MOSAS: + assert approx(instru.distant_carrier_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_carrier_offsets[mosa]) * responses[mosa] + assert approx(instru.distant_usb_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_usb_offsets[mosa]) * responses[mosa] + assert approx(instru.tps_isi_carrier_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_carrier_offsets[mosa]) * responses[mosa] + assert approx(instru.tps_isi_usb_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_usb_offsets[mosa]) * responses[mosa] + +def test_gw_file_1_1(): + """Test that we can read GW files v1.1 with orbit files v1.0.2. + + Test GW file can be generated using LISA GW Response and the following script. + + from h5py import File + from lisagwresponse import GalacticBinary + + orbits = 'tests/keplerian-orbits-1-0-2.h5' + with File(orbits, 'r') as f: + t0 = f.attrs['t0'] + 10 + + galbin = GalacticBinary( + A=1.0, + f=1E-3, + orbits=orbits, + t0=t0, + size=100, + gw_beta=0, gw_lambda=0, + ) + + galbin.write('tests/gws-1-1.h5') + """ + + gw_file = 'tests/gws-1-1.h5' + gwf = File(gw_file, 'r') + + instru = Instrument( + size=100, + t0=gwf.attrs['t0'], + dt=gwf.attrs['dt'], + physics_upsampling=1, + aafilter=None, + lock='six', + gws=gw_file, + orbits='tests/keplerian-orbits-1-0-2.h5') + instru.disable_all_noises() + + assert instru.gw_file is gw_file + for mosa in instru.MOSAS: + assert instru.gws[mosa] == approx(gwf[f'tcb/l_{mosa}'][:]) + + instru.simulate() + + for mosa in instru.MOSAS: + assert approx(instru.distant_carrier_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:] + assert approx(instru.distant_usb_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:] + assert approx(instru.tps_isi_carrier_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:] + assert approx(instru.tps_isi_usb_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf[f'tcb/l_{mosa}'][:] + +def test_gw_file_2_0_dev(): + """Test that we can read GW files v2.0.dev with orbit files v2.0. + + Test GW file can be generated using LISA GW Response and the following script. + + from h5py import File + from lisagwresponse import GalacticBinary + + orbits = 'tests/keplerian-orbits-2-0.h5' + with File(orbits, 'r') as f: + t0 = f.attrs['t0'] + 10 + + galbin = GalacticBinary( + A=1.0, + f=1E-3, + orbits=orbits, + t0=t0, + size=100, + gw_beta=0, gw_lambda=0, + ) + + galbin.write('tests/gws-2-0-dev.h5') + """ + + gw_file = 'tests/gws-2-0-dev.h5' + gwf = File(gw_file, 'r') + + instru = Instrument( + size=100, + t0=gwf.attrs['t0'], + dt=gwf.attrs['dt'], + physics_upsampling=1, + aafilter=None, + lock='six', + gws=gw_file, + orbits='tests/keplerian-orbits-2-0.h5') + instru.disable_all_noises() + + assert instru.gw_file is gw_file + for imosa, mosa in enumerate(instru.MOSAS): + assert instru.gws[mosa] == approx(gwf['tcb/y'][:, imosa]) + + instru.simulate() + + for imosa, mosa in enumerate(instru.MOSAS): + assert approx(instru.distant_carrier_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf['tcb/y'][:, imosa] + assert approx(instru.distant_usb_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf['tcb/y'][:, imosa] + assert approx(instru.tps_isi_carrier_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_carrier_offsets[mosa]) * gwf['tcb/y'][:, imosa] + assert approx(instru.tps_isi_usb_fluctuations[mosa]) == \ + -(instru.central_freq + instru.local_usb_offsets[mosa]) * gwf['tcb/y'][:, imosa]