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, )
IDX_COUNT = None prevalences_count = None prevalences_ages_sum = None #### #### STEP 5: Feature scaling (only age: div by age_scaler = 5) #### matrix[:, index_cols[settings.age]] = matrix[:, index_cols[ settings.age]] / settings.age_scaler #scales age to allow better fitting #### #### STEP 6: loop through post_cols #### #loop through post_cols start = False for node in post_cols.keys(): if node == settings.start_icd or settings.start_icd == "": start = True if start: print utils.time() + 'Work on ' + node #### #### STEP 7: calculate node statistics: get possible and real incidents, calc prevalence, incidence, mean_age #### try: if node == "DEATH": possible_incidents = matrix else: possible_incidents = matrix[functions.zero_rows( matrix[:, pre_cols[node]]), :] #rows,cols = matrix.nonzero()
class ChurchYear(object): def __iter__(self): return ChurchYearIterator(self) 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) # print( # "{} = {} - {} {}".format( # calendar_date.season, # calendar_date.date.strftime("%a, %b, %d, %Y"), # calendar_date.primary.__repr__(), # "(Proper {})".format(calendar_date.proper.number) if calendar_date.proper else "", # "+" if calendar_date.day_of_special_commemoration else "", # ) # # ) # print(calendar_date.required, calendar_date.optional) # #print("{} - {} - {}".format(self.mass_year, sself.daily_mass_year, self.office_year)) def _get_seasons(self): seasons = (Season.objects.filter(calendar=Calendar.objects.filter( abbreviation=self.calendar.abbreviation).get()).order_by( "order").all()) season_mapping = {} for season in seasons: season_mapping[season.start_commemoration.name] = season self.seasons = season_mapping # print(self.seasons) def _set_season(self, calendar_date): calendar_date.season = self.season_tracker calendar_date.evening_season = calendar_date.season if not calendar_date.required: return possible_days = [feast.name for feast in calendar_date.required] if not self.seasons: self._get_seasons() if "The Day of Pentecost" in possible_days: calendar_date.season = self.season_tracker for match in self.seasons.keys(): if match in possible_days: self.season_tracker = self.seasons[match] if "The Day of Pentecost" not in possible_days: calendar_date.season = self.season_tracker calendar_date.evening_season = calendar_date.season @staticmethod def daterange(start_date, end_date): for n in range(int((end_date - start_date).days + 1)): yield start_date + timedelta(n) @cached_property def mass_year(self): if self.start_year % 3 == 0: return "A" if self.start_year % 3 == 1: return "B" if self.start_year % 3 == 2: return "C" @cached_property def daily_mass_year(self): return 1 if self.end_year % 2 != 0 else 2 @cached_property def office_year(self): return "I" if self.start_year % 2 == 0 else "II" @cached_property def first_date(self): return self.dates[:1] @cached_property def last_date(self): return self.dates[-1] def get_date(self, date_string): date = to_date(date_string) try: date = self.dates[date.strftime("%Y-%m-%d")] date.year = self return date except KeyError: print(date) print(date.strftime("%Y-%m-%d")) return None
class HashedParameterArray(object): """ This object is an append-only array which composes the IndexedOrderedDict in order to allow for efficient lookup of values and indices, the structure is effectively {"first_key": 0, "second_key": 1, ..., "latest_key": n} such that item inclusion and forwards and backwards (i. e. index->key and key->index) are O(1). Note that items in a HashedParameterArray **must be hashable** Its getitem behavior defaults to access via the index of insertion order, e. g. array[0] returns the first inserted object. """ 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) def __getitem__(self, index): return self._iod.keys()[index] def __contains__(self, item): return item in self._iod.keys() def __len__(self): return len(self._iod) def append(self, item): """ Appends a value to the array Args: item: item to be inserted Returns: (int) index of the item appended, if it's found returns an existing index, if not, returns the index of the inserted (i. e. latest) index """ if item in self._iod.keys(): return self.get_index(item) # Otherwise adds item value = len(self._iod) self._iod[item] = value return value def extend(self, items): """ Appends multiple items to the array Args: items ([]): items to be appended Returns: ([]) indices of appended items in the array """ return [self.append(item) for item in items] def get_index(self, item): """ Fetches the index of a given item Args: item: item to be fetched """ return self._iod[item]
class Mesh(NodeSet, ElementSet, DofSpace): """ Mesh class Static Members: __type__ = "Input is not list or array!" __type_int__ = "Input is not int!" __type_str__ = "Input is not str!" __type_int_list__ = "Input is not int or list!" __type_str_list__ = "Input is not str or list!" __type_dof__ = "Input inod is not int or dof is not str!" __renumber__ = "Erasing dofs: Dof numbers will be renumbered!" Instance Members: coords = list of nodal coordinates nnod = number of nodes connectivity = list of element connectivities nele = number of elements nrow = number of rows (nodes) types = list of dof names dofspace = array of dof indices (idofs) ndof = number of degrees of freedom groups = list of elements in each physical group groupNames = names of physical groups ngroups = number of physical groups path = file path type = file type rank = number of dimensions doElemGroups = bool Public Methods: Mesh(conf, props) readMesh(self, type, path, rank, doElemGroups) readGmsh(self, path, rank, doElemGroups) readXML(self, path, rank) plotMesh(rank) plotDeformed(self, disp, scale, rank) updateGeometry(self, disp) """ # Public: #----------------------------------------------------------------------- # constructor #----------------------------------------------------------------------- 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) #----------------------------------------------------------------------- # readMesh #----------------------------------------------------------------------- def readMesh(self, type, path, rank, doElemGroups): if type == "Gmsh": self.readGmsh(path, rank, doElemGroups) elif type == "XML": self.readXML(path, rank, doElemGroups) else: raise ValueError("type can only be Gmsh or XML!") #----------------------------------------------------------------------- # readGmsh #----------------------------------------------------------------------- def readGmsh(self, path=None, rank=3, doElemGroups=False): """ Input: path = path_to_file """ if path is None: Tk().withdraw() self.path = filedialog.askopenfilename() else: self.path = path fid = open(self.path, "r") line = "start" while line: line = fid.readline() #--------------------------------------------------------------- # Groups #--------------------------------------------------------------- if line.find('$PhysicalNames') == 0: data = fid.readline().split() self.ngroups = int(data[0]) self.groups = [[] for _ in range(self.ngroups)] for _ in range(self.ngroups): line = fid.readline() key = int(line.split()[1]) qstart = line.find('"') + 1 qend = line.find('"', -1, 0) - 1 self.groupNames[key] = line[qstart:qend] #--------------------------------------------------------------- # Nodes #--------------------------------------------------------------- if line.find('$Nodes') == 0: data = fid.readline().split() nnod = int(data[0]) for _ in range(nnod): data = fid.readline().split() coord = [float(x) for x in data[1:rank + 1]] self.addNode(coord) #--------------------------------------------------------------- # Elements #--------------------------------------------------------------- if line.find('$Elements') == 0: data = fid.readline().split() nele = int(data[0]) for iele in range(nele): data = fid.readline().split() ntags = int(data[2]) # number of tags if ntags > 0: key = int(data[3]) if key not in self.groupNames: groupName = 'Group {}'.format(key) self.groupNames[key] = groupName self.ngroups += 1 self.groups.append([]) if doElemGroups is True: idx = self.groupNames.keys().index(key) self.groups[idx].append(iele) else: self.groups[0].append(iele) connect = [int(x) - 1 for x in data[3 + ntags:]] self.addElement(connect) fid.close() # Print nnodes, nele and ngroups if self.ngroups == 1: logging.info( ("Mesh read with {} nodes, {} elements and 1 group: ").format( self.nnod, self.nele)) else: logging.info(( "Mesh read with {} nodes, {} elements and {} groups: ").format( self.nnod, self.nele, self.ngroups)) # Print group names and number of elements for key in self.groupNames: group_name = self.groupNames[key] idx = self.groupNames.keys().index(key) group_nele = len(self.groups[idx]) logging.info( (" {} with {} elements").format(group_name, group_nele)) #----------------------------------------------------------------------- # readXML #----------------------------------------------------------------------- def readXML(self, path=None, rank=3, doElemGroups=False): """ Input: self.path = self.path_to_file """ if path is None: Tk().withdraw() self.path = filedialog.askopenfilename() else: self.path = path if doElemGroups is True: raise NotImplementedError( " readXML does not support doElemGroups!") else: self.groups = [[]] self.ngroups = 1 self.groupNames[0] = 'Group 0' with open(self.path, 'r') as file: flag_n = False flag_e = False for line in file: if line.startswith("<Nodes>"): flag_n = True elif line.startswith("</Nodes>"): flag_n = False elif line.startswith("<Elements>"): flag_e = True elif line.startswith("</Elements>"): flag_e = False data = re.findall(r"[-+]?\d+ *\.\d+|[-+]?\d+", line) if len(data) > 0 and data[0].isdigit(): #------------------------------------------------------- # Nodes #------------------------------------------------------- if flag_n is True: coord = [float(x) for x in data[1:rank + 1]] self.addNode(coord) #------------------------------------------------------- # Elements #------------------------------------------------------- if flag_e is True: connect = [int(x) - 1 for x in data[1:]] self.groups[0].append(int(data[0]) - 1) self.addElement(connect) logging.info(("Mesh read with {} nodes, {} elements.").format( self.nnod, self.nele)) #----------------------------------------------------------------------- # plotMesh #----------------------------------------------------------------------- def plotMesh(self, rank=2): """ Input: rank = number of dimensions """ # Determine whether 2D or 3D plot if rank == 1 or rank == 2: fig = plt.figure(figsize=(6, 6)) ax = fig.add_subplot(111) elif rank == 3: fig = plt.figure(figsize=(6, 6)) ax = fig.add_subplot(111, projection='3d') # Plot Mesh for connect in self.connectivity: iele = connect + [connect[0]] coords = self.getCoords(iele) ax.plot(coords[:, 0], coords[:, 1], linewidth=0.5, color='k') return ax #----------------------------------------------------------------------- # plotDeformed #----------------------------------------------------------------------- def plotDeformed(self, disp, scale, rank=2): """ Input: disp = displacement vector scale = rank = number of dimensions """ # Craft deformed coordinates deformed = self.getCoords() for inod in range(len(self.coords)): idofs = self.getDofIndices(inod) if idofs: # idofs is not empty x = self.getCoords(inod) u = np.array(disp[idofs]) * scale deformed[inod, :] = u + x # Create figure if rank == 1 or rank == 2: fig = plt.figure(figsize=(6, 6)) ax = fig.add_subplot(111) elif rank == 3: fig = plt.figure(figsize=(6, 6)) ax = fig.add_subplot(111, projection='3d') # Plot deformed mesh for connect in self.connectivity: iele = connect + [connect[0]] coords = deformed[np.ix_(iele), :][0] ax.plot(coords[:, 0], coords[:, 1], linewidth=0.5, color='k') plt.show() #----------------------------------------------------------------------- # updateGeometry #----------------------------------------------------------------------- def updateGeometry(self, disp): """ Input: disp = displacement vector """ for inod in range(len(self.coords)): idofs = self.getDofIndices(inod) if idofs: x = [a + b for a, b in zip(self.coords[inod], disp[idofs])] self.coords[inod] = x