Пример #1
0
    def __init__(self, conf=None, props=None):
        """ Input:  conf = output properties
                    props = input properties """

        NodeSet.__init__(self)
        ElementSet.__init__(self)
        self.groups = []
        self.groupNames = IndexedOrderedDict()
        self.ngroups = 0

        if conf and props:
            # Get Props
            myProps = props.getProps("mesh")
            myConf = conf.makeProps("mesh")

            self.path = myProps.get("file")
            self.type = myProps.get("type", "Gmsh")
            self.rank = myProps.get("rank", 2)
            self.doElemGroups = myProps.get("doElemGroups", False)

            myConf.set("file", self.path)
            myConf.set("type", self.type)
            myConf.set("rank", self.rank)
            myConf.set("doElemGroups", self.doElemGroups)

            # Read Mesh
            self.readMesh(self.type, self.path, self.rank, self.doElemGroups)

            # Initialize DofSpace
            DofSpace.__init__(self, self.nnod, self.rank)
Пример #2
0
 def __init__(self, verbose=False, handle_errors=False):
     """See help(AnalysisHandler)."""
     self.fns_to_run = []
     self.fn_params_list = []
     self.fn_kwargs_list = []
     self.results = IndexedOrderedDict()
     self.verbose = verbose
     self.handle_errors = handle_errors
     self._was_error = False
Пример #3
0
    def __init__(self, year_of_advent, calendar="ACNA_BCP2019"):

        self.calendar = Calendar.objects.filter(abbreviation=calendar).first()

        self.start_year = year_of_advent
        self.end_year = year_of_advent + 1

        self.dates = IndexedOrderedDict()

        start_date = advent(year_of_advent)
        end_date = advent(year_of_advent + 1) - timedelta(days=1)

        self.start_date = start_date
        self.end_date = end_date

        self.seasons = self._get_seasons()
        self.season_tracker = None
        # create each date
        for single_date in self.daterange(start_date, end_date):
            name = single_date.strftime("%Y-%m-%d")
            self.dates[name] = CalendarDate(single_date,
                                            calendar=self.calendar,
                                            year=self)

        # add commemorations to date
        commemorations = (Commemoration.objects.select_related(
            "rank", "cannot_occur_after__rank").filter(
                calendar__abbreviation=calendar).all())
        already_added = []
        for commemoration in commemorations:

            if not commemoration.can_occur_in_year(self.start_year):
                continue

            try:
                self.dates[commemoration.initial_date_string(
                    self.start_year)].add_commemoration(commemoration)
                already_added.append(commemoration.pk)

            except KeyError:
                pass

        for key, calendar_date in self.dates.items():

            # seasons
            self._set_season(calendar_date)

            # apply transfers
            transfers = calendar_date.apply_rules()
            new_date = (calendar_date.date +
                        timedelta(days=1)).strftime("%Y-%m-%d")
            if new_date in self.dates.keys():
                self.dates[new_date].required = transfers + self.dates[
                    new_date].required

        SetNamesAndCollects(self)
Пример #4
0
def unique_pattern_counter(reading):
    """Returns an IndexedOrderedDict of unique sub-patterns in a reading"""
    counter = IndexedOrderedDict()
    idx = 0
    for row in reading:
        if counter.get(str(idx) + '_' + convert_row_to_key(row)):
            counter[str(idx) + '_' + convert_row_to_key(row)] += 1
        else:
            idx += 1
            counter[str(idx) + '_' + convert_row_to_key(row)] = 1
    return counter
Пример #5
0
    def __init__(self, ordering=None):
        """
        Constructs a HashedParameterArray

        Args:
            ordering (list): initial ordering of hashable
                objects to be stored in the array
        """
        # Construct IndexedOrderedDict
        self._iod = IndexedOrderedDict()
        if ordering:
            self.extend(ordering)
Пример #6
0
class PaletteParser():

    paletteDict = IndexedOrderedDict()

    regexp = r"\D+(?P<shadeNumber>\d)\D+#(?P<hexValue>\S{6})\D+(?P<rgbValue>\d+\D+\d+\D+\d+)\D+(?P<rgbaValue>\d+\D+\d+\D+\d+\D+\d+)"

    def parseDocument(self, filePath):
        paletteFile = open(filePath, 'r')

        prog = re.compile(self.regexp)

        paletteDict = IndexedOrderedDict()
        sectionDict = IndexedOrderedDict()
        shadeDict = IndexedOrderedDict()

        section = ''
        shade = ''

        for line in paletteFile:
            if "*** Primary color:" in line:
                section = 'primary'

                sectionDict = IndexedOrderedDict()

            elif "*** Secondary color (1):" in line:
                section = 'secondary_1'

                sectionDict = IndexedOrderedDict()

            elif "*** Secondary color (2):" in line:
                section = 'secondary_2'

                sectionDict = IndexedOrderedDict()

            elif "*** Complement color:" in line:
                section = 'complementary'

                sectionDict = IndexedOrderedDict()

            # only if a section has been detected, the line is not empty and it's not a comment
            elif line != "" and "#####" not in line:
                res = prog.match(line)

                if res:
                    shadeNum = res.group('shadeNumber')

                    shadeDict['hex'] = res.group('hexValue')
                    shadeDict['rgb'] = res.group('rgbValue')
                    shadeDict['rgba'] = res.group('rgbaValue')

                    sectionDict[shadeNum] = shadeDict

                    shadeDict = IndexedOrderedDict()

            if section != "":
                paletteDict[section] = sectionDict

        # store changes
        self.paletteDict = paletteDict
Пример #7
0
 def performance_iodict_build():
     #tag access
     global dt_root, max_items
     dt = IndexedOrderedDict()
     #append itertree with items
     for i in range(max_items):
         dt['%i' % i] = 0
     dt_root = dt
Пример #8
0
def f_jumping_modulo(n, m=10):
    idxs = list(range(1, n*m+1))
    # vals_mod = np.arange(0, n) % m
    vals = IndexedOrderedDict([(i, -1) for i in range(1, n*m+1)]) # {i: -1 for i in range(1, n*m+1)}

    vals_mod = [i for j in range(1, 30+1) for i in range(0, j)]

    smallest_idx = 0
    largest_idx = 0
    idx_now = 0
    # for i, v in enumerate(vals_mod[:50]):
    j = 1
    max_reached = False
    while not max_reached:
        for v in range(j-1, -1, -1):
        # for v in range(0, j):
            if v > idx_now:
                idx_now += v
            else:
                idx_now -= v
            if idx_now >= len(idxs):
                max_reached = True
                break
            idx = idxs.pop(idx_now)
            vals[idx] = v
            
            print("idx_now: {}, idx: {}, v: {}".format(idx_now, idx, v))
            
            if smallest_idx < idxs[0]:
                smallest_idx = idxs[0]
            # if largest_idx < idx:
            #     largest_idx = idx
            # lst_temp = list(vals.values())[:largest_idx]
            # print("i: {}, lst_temp:\n{}".format(i, lst_temp))
        j += 1
    lst = list(vals.values())[:smallest_idx-1]
    # print("lst: {}".format(lst))
    # print("idxs: {}".format(idxs))
    # arr = np.array(lst[:smallest_idx-1]) # % m
    # arr = np.array(lst[:smallest_idx-1]) # % m

    return lst
Пример #9
0
def treatment_create(request):
    if request.method == 'POST':
        form = TxAttendanceForm(request.POST)
    else:
        form = TxAttendanceForm()
    context = IndexedOrderedDict()
    context['treatment'] = form.instance
    context = add_forms_to_context((form,), context)
    return save_ajax_form(request, context=context,
                          form_template='treatment/includes/partial_treatment_create.html',
                          list_template='treatment/includes/partial_treatment_list.html')
Пример #10
0
def treatment_update(request, pk):
    treatment = get_object_or_404(TxAttendance, pk=pk)
    if request.method == 'POST':
        form = TxAttendanceForm(request.POST, instance=treatment)
    else:
        form = TxAttendanceForm(instance=treatment)

    context = IndexedOrderedDict()
    context['treatment'] = form.instance
    context = add_forms_to_context((form,), context)
    return save_ajax_form(request, context=context,
                          form_template='treatment/includes/partial_treatment_update.html',
                          list_template='treatment/includes/partial_treatment_list.html')
    def calculate_rgb_pixs(self):
        print("Getting all data in pix_float array")
        shape = self.arr_xy_real_imag.shape + (3, )
        self.pixs1_dict = IndexedOrderedDict([
            ("f", np.ones(shape)),
            ("f_mod", np.ones(shape)),
            ("angle", np.ones(shape)),
            ("abs", np.ones(shape)),
            ("abs_mod", np.ones(shape)),
            ("x", np.ones(shape)),
            ("x_mod", np.ones(shape)),
            ("y", np.ones(shape)),
            ("y_mod", np.ones(shape)),
        ])

        self.pixs1_dict["f"][:, :, 0] = self.arrs["angle"]
        self.pixs1_dict["f"][:, :, 2] = self.arrs["abs"] * 1 / 3 + 2 / 3

        self.pixs1_dict["f_mod"][:, :, 0] = self.arrs["angle"]
        self.pixs1_dict["f_mod"][:, :, 2] = self.arrs["abs_mod"]

        keys = ["angle", "abs", "abs_mod", "x", "x_mod", "y", "y_mod"]
        for key in keys:
            self.pixs1_dict[key][:, :, 0] = self.arrs[key]

        hsv_to_rgb_vectorized = np.vectorize(colorsys.hsv_to_rgb)

        print("Convert hsv to rgb and convert to uint8")

        self.pixs1_dict_rgb = IndexedOrderedDict()
        for key, value in self.pixs1_dict.items():
            pix_float_rgb = np.dstack(
                hsv_to_rgb_vectorized(value[..., 0], value[..., 1], value[...,
                                                                          2]))
            self.pixs1_dict_rgb[key] = (pix_float_rgb * 255.9).astype(np.uint8)

        self.pixs1 = [v for v in self.pixs1_dict_rgb.values()]

        self.imgs_orig = [Image.fromarray(pix.copy()) for pix in self.pixs1]
Пример #12
0
    def __init__(self, datasets, variable_activities=False):
        self.samples = IndexedOrderedDict()
        self.samples_file_descriptors = []
        self.variable_activities = variable_activities
        for i, dataset in enumerate(datasets, start=1):
            self.samples_file_descriptors.append(open(dataset, 'r'))
            d = csv.reader(self.samples_file_descriptors[i - 1])
            self.header = next(d)
            self.samples['sample' + str(i)] = d

        self.extract_all_labels()
        self.reset_file_descriptors()
        self.attach_readings_to_labels()
Пример #13
0
def objective_update(request, pk):
    objectives = get_object_or_404(Objectives, pk=pk)
    if request.method == 'POST':
        form = ObjectivesForm(request.POST, instance=objectives)
    else:
        form = ObjectivesForm(instance=objectives)

    context = IndexedOrderedDict()
    context['objectives'] = form.instance
    context = add_forms_to_context((form,), context)
    return save_ajax_form(request, context=context,
                          form_template='treatment/includes/partial_objectives_update.html',
                          list_template='treatment/includes/partial_objectives_list.html')
Пример #14
0
class TaburuState(State):
    def __init__(self):
        self.parameters = IndexedOrderedDict()
        self.methods = IndexedOrderedDict()

    def apply(self, event):
        if isinstance(event, ParametersAdded):
            if event.table_name in self.parameters:
                self.parameters[event.table_name].append(event.parameters)
            else:
                self.parameters[event.table_name] = ParameterTable(
                    event.parameters)
        elif isinstance(event, MethodAdded):
            if self.methods.get(event.name) is None:
                self.methods[event.name] = event.parameter_indices
            else:
                print("Method name already exists")
                return False
        return True

    def __str__(self):
        return self.__repr__()

    def __repr__(self):
        parameters = [
            '{} {}: {}'.format(n, parameter_name, len(table))
            for n, (parameter_name,
                    table) in enumerate(self.parameters.items())
        ]
        methods = [
            "{}: {}".format(method_name, parameters)
            for method_name, parameters in self.methods.items()
        ]
        output = "Parameters:\n   "
        output += "\n   ".join(parameters)
        output += "\nMethods:\n   "
        output += "\n   ".join(methods)
        return output
Пример #15
0
def court_date_create(request):
    if request.method == 'POST':
        form = CourtDateForm(request.POST)
    else:
        form = CourtDateForm()
    context = IndexedOrderedDict()
    context['court_date'] = form.instance
    context = add_forms_to_context((form, ), context)

    return save_ajax_form(
        request,
        context=context,
        list_template='court/includes/partial_court_list.html',
        form_template='court/includes/partial_court_create.html')
Пример #16
0
def court_date_update(request, pk):
    court = get_object_or_404(CourtDates, pk=pk)

    if request.method == 'POST':
        form = CourtDateForm(request.POST, instance=court)
    else:
        form = CourtDateForm(instance=court)
    context = IndexedOrderedDict()
    context['court_date'] = form.instance
    context = add_forms_to_context((form, ), context)
    return save_ajax_form(
        request,
        context=context,
        list_template='court/includes/partial_court_list.html',
        form_template='court/includes/partial_court_update.html')
Пример #17
0
    def __init__(self, year):

        first_year = year - 1
        second_year = year

        first_year = ChurchYear(first_year)
        second_year = ChurchYear(second_year)

        dates = IndexedOrderedDict(
            list(first_year.dates.items()) + list(second_year.dates.items()))

        base = datetime(year, 1, 1)
        date_list = [base + timedelta(days=x) for x in range(0, 365)]

        self.dates = [dates[date.strftime("%Y-%m-%d")] for date in date_list]
Пример #18
0
def client_note(request, pk):

    client = get_object_or_404(Client, pk=pk)
    if request.method == 'POST':
        form = NoteForm(request.POST, initial={'note_type': 'General'})
    else:
        form = NoteForm(initial={'note_type': 'General'})
    context = IndexedOrderedDict()
    context['client'] = client
    context['forms'] = {'note_form': form}

    return save_ajax_form(
        request,
        list_template='intake/includes/partial_client_list.html',
        form_template='intake/includes/partial_client_note.html',
        context=context)
    def calculate_arrs(self):
        print("Calculate self.arr_f and self.arr_scales")
        self.arr_f, self.arr_scales = np.vectorize(self.f)(
            self.arr_xy_real_imag)

        print("Calculate arr")
        arr_angle = np.angle(self.arr_f)
        idx = arr_angle < 0
        arr_angle[idx] = arr_angle[idx] + np.pi * 2

        print("np.min(arr_angle): {}".format(np.min(arr_angle)))
        print("np.max(arr_angle): {}".format(np.max(arr_angle)))

        arr_angle_norm = arr_angle / (np.pi * 2)
        print("np.min(arr_angle_norm): {}".format(np.min(arr_angle_norm)))
        print("np.max(arr_angle_norm): {}".format(np.max(arr_angle_norm)))

        print("Calculate abs")
        arr_abs = np.abs(self.arr_f)
        arr_abs_mod = arr_abs * self.arr_scales

        arr_abs_norm = arr_abs / np.max(arr_abs)
        arr_abs_mod_norm = arr_abs_mod / np.max(arr_abs_mod)

        print("Calculate x and y")
        f_norm_axis = lambda v: (lambda v2: v / np.max(v))(v - np.min(v))

        arr_x = self.arr_f.real
        arr_y = self.arr_f.imag
        arr_x_mod = arr_x * self.arr_scales
        arr_y_mod = arr_y * self.arr_scales

        arr_x_norm = f_norm_axis(arr_x)
        arr_y_norm = f_norm_axis(arr_y)
        arr_x_mod_norm = f_norm_axis(arr_x_mod)
        arr_y_mod_norm = f_norm_axis(arr_y_mod)

        self.arrs = IndexedOrderedDict([
            ("angle", arr_angle_norm),
            ("abs", arr_abs_norm),
            ("abs_mod", arr_abs_mod_norm),
            ("x", arr_x_norm),
            ("x_mod", arr_x_mod_norm),
            ("y", arr_y_norm),
            ("y_mod", arr_y_mod_norm),
        ])
Пример #20
0
def court_date_note(request, pk):

    client = get_object_or_404(Client, pk=pk)
    initial = {'client': client, 'note_type': 'Court'}
    if request.method == 'POST':
        form = NoteForm(request.POST, initial=initial)
    else:
        form = NoteForm(initial=initial)
    context = IndexedOrderedDict()
    context['court_date'] = form.instance
    context['client'] = client
    context = add_forms_to_context((form, ), context)
    return save_ajax_form(
        request,
        context=context,
        list_template='court/includes/partial_court_list.html',
        form_template='intake/includes/partial_client_note.html')
Пример #21
0
def client_create(request):
    """
        Handle GET/POST requests and instantiate forms.
    """

    if request.method == 'POST':
        client_form = ClientForm(request.POST)
        referral_form = ReferralForm(request.POST)
    else:
        client_form = ClientForm()
        referral_form = ReferralForm()

    forms = (client_form, referral_form)
    context = IndexedOrderedDict()
    context['client'] = client_form.instance
    context = add_forms_to_context(forms, context)

    return save_ajax_form(
        request,
        context=context,
        list_template='intake/includes/partial_client_list.html',
        form_template='intake/includes/partial_client_create.html')
Пример #22
0
def parse_video_list(video_list_file):
        """
        This function parses the video list.
        We assume the video list is in the following format.
        So there should be not be any space in the video directory names
        =======
        num_videos
        video_0_directory video_0_num_frames (video_0_label)
        video_1_directory video_1_num_frames (video_1_label)
        video_2_directory video_2_num_frames (video_2_label)
        ...
        ...
        =======

        (labels) are optional
        """
        video_dict = IndexedOrderedDict()
        if hasattr(video_list_file, 'read'):
            lst_file = video_list_file.read().split('\n')
        elif isinstance(video_list_file, str):
            lst_file = open(video_list_file)
        else:
            raise TypeError('incorrect type of video list file!')
        items = [x.strip().split() for x in lst_file]
        print(items[0])
        num_videos = int(items[0][0])

        for it in items[1:]:
            video_key = it[0]
            video_num_frame = int(it[1])
            video_path = video_key

            # write the video record to the indexedOrderedDict
            video_dict[video_key] = (video_path, video_num_frame)

        assert num_videos == len(video_dict)
        print("all videos indexed. got {} videos".format(len(video_dict)))
        return video_dict
Пример #23
0
def client_evaluate(request, pk):
    """
    """

    referral = get_object_or_404(Referral, pk=pk)
    decisions = referral.decisions

    if request.method == 'POST':

        forms = (DecisionForm(request.POST, instance=decision)
                 for decision in decisions)
    else:
        forms = (DecisionForm(instance=decision) for decision in decisions)
    context = IndexedOrderedDict()
    context['client'] = referral.client
    context['referral'] = referral
    context['forms'] = forms

    return save_ajax_form(
        request,
        context=context,
        list_template='intake/includes/partial_client_list.html',
        form_template='intake/includes/partial_client_evaluate.html')
Пример #24
0
def client_update(request, pk):
    """
    """

    client = get_object_or_404(Client, pk=pk)
    if request.method == 'POST':
        client_form = ClientForm(request.POST, instance=client)
        referral_form = ReferralForm(request.POST, instance=client.referral)

    else:  # GET Request (loadForm)

        client_form = ClientForm(instance=client)
        referral_form = ReferralForm(instance=client.referral)

    forms = (client_form, referral_form)
    context = IndexedOrderedDict()
    context['client'] = client
    context = add_forms_to_context(forms, context)

    return save_ajax_form(
        request,
        context=context,
        list_template='intake/includes/partial_client_list.html',
        form_template='intake/includes/partial_client_update.html')
Пример #25
0
 def __init__(self):
     self.parameters = IndexedOrderedDict()
     self.methods = IndexedOrderedDict()
Пример #26
0
import os
from indexed import IndexedOrderedDict
clear = lambda :os.system('cls')
d={1:'One',2:'Two',3:'Three'}
ix = IndexedOrderedDict(sorted(d.items(),key=lambda t:t[0]))
 def generateIndexedOrderedDict(self):
     return IndexedOrderedDict(
         sorted(self.rom_val_dict.items(), key=lambda t: t[0]))
Пример #28
0
 def reset_results(self):
     """Reset the results."""
     self.results = IndexedOrderedDict()
Пример #29
0
import sqlalchemy as sql
import sqlalchemy.orm as orm
from sqlalchemy.ext.declarative import declarative_base

DeclarativeBase = declarative_base()


NIB_URL = 'https://kartverket.maplytic.no/tile/_nib/{zoom}/{x}/{y}.jpeg'
TOPO4_URL = 'https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=topo4&zoom={zoom}&x={x}&y={y}'


PROJECTS = IndexedOrderedDict([
    ('DTM50', projects.DigitalHeightModel(key='DTM50', name='Terrain model (50 m)')),
    ('DTM10', projects.DigitalHeightModel(key='DTM10', name='Terrain model (10 m)')),
    ('DTM1',  projects.DigitalHeightModel(key='DTM1',  name='Terrain model (1 m)')),
    ('DOM50', projects.DigitalHeightModel(key='DOM50', name='Object model (50 m)')),
    ('DOM10', projects.DigitalHeightModel(key='DOM10', name='Object model (10 m)')),
    ('DOM1',  projects.DigitalHeightModel(key='DOM1',  name='Object model (1 m)')),
    ('NIB',   projects.TiledImageModel(key='NIB', name='Norge i bilder', url=NIB_URL)),
    ('TOPO4', projects.TiledImageModel(key='TOPO4', name='Karverket Topo4', url=TOPO4_URL)),
])

filesystem.create_directories(project.key for project in PROJECTS.values())


class Polygon(DeclarativeBase):
    """ORM representation of a polygon."""

    __tablename__ = 'polygon'

    id = sql.Column(sql.Integer, primary_key=True)
    name = sql.Column(sql.String, nullable=False)
Пример #30
0
class AnalysisHandler(object):
    """
    Hold functions to run and the parameters to use for them.

    Attributes
    ----------
    fns_to_run : list of functions
        The functions to run
    fn_param_list : list of tuples
        The arguments to pass to these functions.
        The arguments are passed in order, so these are positional.
    fn_kwargs_list : list of dicts
        Keyword arguments to pass to the functions to run.
    results : indexed.IndexedOrderedDict
        The results of the function calls
    verbose : bool
        Whether to print more information while running the functions.
    handle_errors : bool
        Whether to handle errors during runtime of underlying functions,
        or to crash on error.

    Parameters
    ----------
    verbose : bool, optional
        Sets the value of the verbose attribute, defaults to False.
    handle_errors : bool, optional
        Sets the value of the handle_errors attribute, defaults to False.

    """
    def __init__(self, verbose=False, handle_errors=False):
        """See help(AnalysisHandler)."""
        self.fns_to_run = []
        self.fn_params_list = []
        self.fn_kwargs_list = []
        self.results = IndexedOrderedDict()
        self.verbose = verbose
        self.handle_errors = handle_errors
        self._was_error = False

    def set_handle_errors(self, handle_errors):
        """Set the value of self.handle_errors."""
        self.handle_errors = handle_errors

    def set_verbose(self, verbose):
        """Set the value of self.verbose."""
        self.verbose = verbose

    def get_results(self):
        """Return the results."""
        return self.results

    def run_all(self):
        """Alias for run_all_fns."""
        self.run_all_fns()

    def run_all_fns(self, pbar=False):
        """Run all of the established functions."""
        self._was_error = False
        if pbar:
            pbar_ = tqdm(range(len(self.fns_to_run)))
            for i in pbar_:
                fn = self.fns_to_run[i]
                fn_params = self.fn_params_list[i]
                fn_kwargs = self.fn_kwargs_list[i]
                self._run_fn(fn, *fn_params, **fn_kwargs)
        else:
            fn_zipped = zip(self.fns_to_run, self.fn_params_list,
                            self.fn_kwargs_list)
            for (fn, fn_params, fn_kwargs) in fn_zipped:
                self._run_fn(fn, *fn_params, **fn_kwargs)
        if self._was_error:
            logging.warning("A handled error occurred while running analysis")
        self._was_error = False

    def reset(self):
        """Reset this object, clearing results and function list."""
        self.reset_func_list()
        self.reset_results()

    def reset_func_list(self):
        """Reset all functions and parameters."""
        self.fns_to_run = []
        self.fn_params_list = []
        self.fn_kwargs_list = []

    def reset_results(self):
        """Reset the results."""
        self.results = IndexedOrderedDict()

    def add_fn(self, fn, *args, **kwargs):
        """
        Add the function fn to the list with the given args and kwargs.

        Parameters
        ----------
        fn : function
            The function to add.
        *args : positional arguments
            The positional arguments to run the function with.
        **kwargs : keyword arguments
            The keyword arguments to run the function with.

        Returns
        -------
        None

        """
        self.fns_to_run.append(fn)
        self.fn_params_list.append(args)
        self.fn_kwargs_list.append(kwargs)

    def save_results(self, output_location):
        """
        Save the results of analysis to the given output location.
        
        Parameters
        ----------
        output_location : string
            Path to a csv to save results to.
    
        Returns
        -------
        None

        """
        with open(output_location, "w") as f:
            print("Saving results to {}".format(output_location))
            for k, v in self.results.items():
                f.write(k.replace(" ", "_").replace(",", "_") + "\n")
                o_str = save_mixed_dict_to_csv(v, None, save=False)
                f.write(o_str)

    def _run_fn(self, fn, *args, **kwargs):
        """
        Run the function with *args and **kwargs, not usually publicly called.

        Pass simuran_save_result as a keyword argument to control
        if the result of the function is saved or not.

        Parameters
        ----------
        fn : function
            The function to run.

        Returns
        -------
        object
            The return value of the function

        """
        if self.verbose:
            print("Running {} with params {} kwargs {}".format(
                fn, *args, **kwargs))
        if self.handle_errors:
            try:
                result = fn(*args, **kwargs)
            except BaseException as e:
                log_exception(
                    e,
                    "Running {} with args {} and kwargs {}".format(
                        fn.__name__, args, kwargs),
                )
                self._was_error = True
                result = "SIMURAN-ERROR"
        else:
            result = fn(*args, **kwargs)

        ctr = 1
        save_result = kwargs.get("simuran_save_result", True)
        save_name = str(fn.__name__)
        if save_result:
            while save_name in self.results.keys():
                save_name = str(fn.__name__) + "_{}".format(ctr)
                ctr = ctr + 1
            self.results[save_name] = result

        return result

    def __str__(self):
        """String representation of this class."""
        return "{} with functions:\n {}, args:\n {}, kwargs:\n {}".format(
            self.__class__.__name__,
            self.fns_to_run,
            self.fn_params_list,
            self.fn_kwargs_list,
        )