Ejemplo n.º 1
0
    def test_pythonize_name_dict(self):

        names = ["energy", "rho[0]"]

        pyth_dict = ad.pythonize_name_dict(names)

        self.assertEqual(pyth_dict.energy, "energy")
        self.assertEqual(pyth_dict.rho[0], "rho[0]")
Ejemplo n.º 2
0
    def __init__(self, allfiles, reduction_type):
        """Constructor.

        :param allfiles: List of all the files
        :type allfiles: list of str
        :param reduction_type: Type of reduction.
        :type reduction_type: str

        """
        self.reduction_type = str(reduction_type)

        # TODO: Is it necessary to have the folder level?
        # Probably not, so remove it

        # _vars_readers is like _vars_readers['variable']['folder'] ->
        # OneScalar(f) _vars_readers['variable'] is a dictionary with as keys
        # the folders where to find the files associated to the variable and the
        # reduction reduction_type
        #
        # OneScalar objects act as readers.
        self._vars_readers = {}
        for file_ in allfiles:
            # We only save those that variables are well-behaved
            try:
                cactusascii_file = OneScalar(file_)
                if cactusascii_file.reduction_type == reduction_type:
                    for var in list(cactusascii_file.keys()):
                        # We add to the _vars_readers dictionary the mapping:
                        # [var][folder] to OneScalar(f)
                        folder = cactusascii_file.folder
                        self._vars_readers.setdefault(
                            var, {})[folder] = cactusascii_file
            except RuntimeError:
                try:
                    cactusascii_file = TwoScalar(file_)
                    if cactusascii_file.reduction_type == reduction_type:
                        for var in list(cactusascii_file.keys()):
                            # We add to the _vars dictionary the mapping:
                            # [var][folder] to OneScalar(f)
                            folder = cactusascii_file.folder
                            self._vars_readers.setdefault(
                                var, {})[folder] = cactusascii_file
                except RuntimeError:
                    pass

        # We cache the results in _vars, a dictionary with keys the variables
        # and values the timeseries.
        self._vars = {}

        # What pythonize_name_dict does is to make the various variables
        # accessible as attributes, e.g. self.fields.rho
        self.fields = pythonize_name_dict(list(self.keys()), self.__getitem__)
Ejemplo n.º 3
0
    def __init__(self, sd):
        """Constructor.

        :param sd: Simulation directory.
        :type sd: :py:class:`~.SimDir`
        """
        # self._vars is a dictionary. For _vars_ascii, the keys are the
        # variables  and the items are sets of tuples of the form
        # (multipole_l,  multipole_m, radius, filename) for text files.
        #
        # For _vars_h5 they are sets (since we have to read the content
        # to find the l and m)
        self._vars_ascii = {}
        self._vars_h5 = {}

        # First, we need to find the multipole files.
        # There are text files and h5 files
        #
        # We use a regular expressions on the name
        # The structure is like mp_Psi4_l_m2_r110.69.asc
        #
        # Let's understand the regexp:
        # 0. ^ and $ means that we match the entire name
        # 1. We match mp_ followed my the variable name, which is
        #    any combination of characters
        # 2. We match _l with a number
        # 3. We match _m with possibly a minus sign and a number
        # 4. We match _r with any combination of numbers with possibly
        #    dots
        # 5. We possibly match a compression
        rx_ascii = re.compile(
            r"""^
        mp_([a-zA-Z0-9\[\]_]+)
        _l(\d+)
        _m([-]?\d+)
        _r([0-9.]+)
        .asc
        (?:.bz2|.gz)?
        $""",
            re.VERBOSE,
        )

        # For h5 files is easy: it is just the var name
        rx_h5 = re.compile(r"^mp_([a-zA-Z0-9\[\]_]+).h5$")

        for f in sd.allfiles:
            filename = os.path.split(f)[1]
            matched_h5 = rx_h5.match(filename)
            matched_ascii = rx_ascii.match(filename)
            if matched_h5 is not None:
                variable_name = matched_h5.group(1).lower()
                var_list = self._vars_h5.setdefault(variable_name, set())
                # We are flagging that this h5
                var_list.add(f)
            elif matched_ascii is not None:
                variable_name = matched_ascii.group(1).lower()
                mult_l = int(matched_ascii.group(2))
                mult_m = int(matched_ascii.group(3))
                radius = float(matched_ascii.group(4))
                var_list = self._vars_ascii.setdefault(variable_name, set())
                var_list.add((mult_l, mult_m, radius, f))

        # What pythonize_name_dict does is to make the various variables
        # accessible as attributes, e.g. self.fields.rho
        self.fields = pythonize_name_dict(list(self.keys()), self.__getitem__)
Ejemplo n.º 4
0
    def __init__(self, qlm_vars, ah_vars, shape_files):
        """Constructor.

        :param qlm_vars: Dictionary that maps the name of the QLM variable with
                         the associated :py:class:`~.TimeSeries`.
        :type qlm_vars: dict
        :param ah_vars: Dictionary that maps the name of the AH variable with
                        the associated :py:class:`~.TimeSeries`.
        :type ah_vars: dict
        :param shape_files: Dictionary that maps the iteration to the files where
                            to find the shape at that iteration.
        :type shape_files: dict

        """
        self._qlm_vars = qlm_vars
        self._ah_vars = ah_vars

        # We turn the var_dictionary into attributes
        for var, timeseries in self._qlm_vars.items():
            # With this we can access properties in the following way
            # horizon.mass
            setattr(self, var, timeseries)

        # Here we compute some interesting and useful quantities, if we have
        # qlm data
        if self._qlm_vars:
            self.mass_final = self.mass.y[-1]
            self.spin_final = self.spin.y[-1]
            self.dimensionless_spin_final = (self.spin_final /
                                             self.mass_final**2)
        else:
            self.mass_final = None
            self.spin_final = None
            self.dimensionless_spin_final = None

        # We put the AH vars under the ah attribute, they are accessed in the
        # same way as qlm_vars (as attribute). This is achieved using
        # pythonize_name_dict. The second argument is how we access the data.
        # Here we use the method get_ah_property that peeks into self._ah_vars.
        self.ah = pythonize_name_dict(ah_vars, self.get_ah_property)

        # We read the formation time from a variable in AH
        if self._ah_vars:
            self.formation_time = self.ah.area.tmin
        else:
            self.formation_time = None

        # Now we deal with the shape. Shape files is a dictionary that maps
        # iteration to the associated file
        self._shape_files = shape_files

        self.shape_available = self._shape_files != {}

        if self.shape_available:
            # We sort the iterations
            self.shape_iterations = np.array(
                sorted(s for s in self._shape_files))

            self.shape_iteration_min = self.shape_iterations[0]
            self.shape_iteration_max = self.shape_iterations[-1]

            # To convert between time and iteration, we need the AH data If we
            # don't have that, we will assume time = iteration.
            #
            if self._ah_vars:
                # Now we find the associated times using ah.cctk_iteration
                # self.ah.cctk_iteration is a function time vs iteration, we
                # want the opposite. We define a new timeseries in which we swap
                # t and y
                times_iterations = TimeSeries(self.ah.cctk_iteration.y,
                                              self.ah.cctk_iteration.t)
                self.shape_times = times_iterations(self.shape_iterations)
                self.shape_time_min = self.shape_times[0]
                self.shape_time_max = self.shape_times[-1]
            else:
                warnings.warn(
                    "AH data not found, so it is impossible to convert"
                    " between iteration number to time.\nManually set"
                    " shape_times or methods involving shape and time"
                    " will not work")
                self.shape_times = None
                self.shape_time_min = None
                self.shape_time_max = None

            # We will save all the shape patches and their origin that we read in
            # this dictionary
            self._patches = {}
Ejemplo n.º 5
0
    def __init__(self, sd):
        """Constructor.

        :param sd: Simulation directory.
        :type sd: :py:class:`~.SimDir`
        """
        # self._vars_*_files are dictionary. For _vars_ascii_files, the keys are
        # the variables and the items are sets of tuples of the form
        # (multipole_l, multipole_m, radius, filename) for text files.
        #

        # For example:
        # self._vars_ascii_files =
        # {'psi4': {(2, 2, 110.69, 'output-0000/mp_Psi4_l_m2_r110.69.asc'),
        #           (2, 2, 110.69, 'output-0001/mp_Psi4_l_m2_r110.69.asc')}}

        self._vars_ascii_files = {}

        # For _vars_h5_files, the keys are still the variables, but values are
        # sets with only the files (and not tuples), since we have to read the
        # content to find the l and m
        #
        # For example
        # self._vars_h5_files =
        # {'psi4': {'output-0000/mp_Psi4.h5', 'output-0001/mp_Psi4.h5'}}
        self._vars_h5_files = {}

        # For _vars_IL_files, I did things similarly to in the ascii case,
        # because I didn't appreciate the fact that the h5 files were really
        # closer to what I needed for the IL code files, since in both cases
        # one must open the files in order to know what modes it contains.
        # The only difference from the ascii case is that this time the whole
        # set of multipoles contains the *same* file. I then overload the
        # reading method to figure out which column of the file to pull from
        # when reading. Hacky & inelegant, but hey, it works!
        self._vars_IL_files = {}

        # self._vars is the dictionary where we cache the results. The keys are
        # the variables, the values are the corresponding MultipoleAllDets
        # objects. We fill this with __getitem__
        self._vars = {}

        # First, we need to find the multipole files.
        # There are text files and h5 files
        #
        # We use a regular expressions on the name
        # The structure is like mp_Psi4_l_m2_r110.69.asc
        #
        # Let's understand the regexp:
        # 0. ^ and $ means that we match the entire name
        # 1. We match mp_ followed my the variable name, which is
        #    any combination of characters
        # 2. We match _l with a number
        # 3. We match _m with possibly a minus sign and a number
        # 4. We match _r with any combination of numbers with possibly
        #    dots
        # 5. We possibly match a compression
        rx_ascii = re.compile(
            r"""^
        mp_([a-zA-Z0-9\[\]_]+)
        _l(\d+)
        _m([-]?\d+)
        _r([0-9.]+)
        .asc
        (?:.bz2|.gz)?
        $""",
            re.VERBOSE,
        )

        # For h5 files is easy: it is just the var name
        rx_h5 = re.compile(r"^mp_([a-zA-Z0-9\[\]_]+).h5$")

        # For IL code Psi4 files, it is even easier: it's just these files,
        rx_IL = re.compile('^Psi4_rad\.mon\.([0-9]+)$')

        for f in sd.allfiles:
            filename = os.path.split(f)[1]
            matched_h5 = rx_h5.match(filename)
            matched_ascii = rx_ascii.match(filename)
            matched_IL = rx_IL.match(filename)
            if matched_h5 is not None:
                variable_name = matched_h5.group(1).lower()
                var_list = self._vars_h5_files.setdefault(variable_name, set())
                # We are flagging that this h5
                var_list.add(f)
            elif matched_ascii is not None:
                variable_name = matched_ascii.group(1).lower()
                mult_l = int(matched_ascii.group(2))
                mult_m = int(matched_ascii.group(3))
                radius = float(matched_ascii.group(4))
                var_list = self._vars_ascii_files.setdefault(
                    variable_name, set())
                var_list.add((mult_l, mult_m, radius, f))
            elif matched_IL is not None:
                variable_name = "psi4"  # all keys must be lower-case
                var_list = self._vars_IL_files.setdefault(variable_name, set())
                data = np.genfromtxt(
                    f
                )  # Unfortunately there's no way to check this without opening the file
                radius = data[0, -4]
                if (data.shape[1] - 5) % 2 != 0:
                    raise RuntimeError('Wrong format')
                nmodes = (data.shape[1] - 5) // 2
                # Loop through all the modes in the file
                l = 2
                i = 1
                while (i <= nmodes):
                    m = l
                    while (m >= -l and i <= nmodes):
                        var_list.add((l, m, radius, f))
                        m = m - 1
                        i = i + 1
                    l = l + 1

        # What pythonize_name_dict does is to make the various variables
        # accessible as attributes, e.g. self.fields.rho
        self.fields = pythonize_name_dict(list(self.keys()), self.__getitem__)