def _toc_tree(obj, prefix=""): ret = colorize(obj.__str__(), "blue") prefix = prefix + 4*" " for key in sorted(obj.__dict__.keys(), key=str.casefold): if key.startswith("_"): continue val = obj.__dict__[key] ret += "\n{}- {}: ".format( prefix, colorize(key, "blue")) if isinstance(val, Group): ret += _toc_tree(val, prefix=prefix) else: ret += val.__str__() return ret
def __repr__(self): ret = self.__str__() + "\n" ret += "-" * (len(ret) - 1) + "\n" ret += " Data directory : {}\n".format(self.datadir) ret += " File names : {}\n".format(self._getfilename(0)) ret += " Overwrite : {}\n".format( colorize(self.overwrite, "yellow") if self.overwrite else self. overwrite) ret += " Dumping : {}\n".format( colorize(self.dumping, "yellow") if not self.dumping else self. dumping) ret += " Options : {}\n".format(self.options) ret += " Verbosity : {}".format(self.verbosity) return ret
def write(self, owner, i, forceoverwrite, filename=""): """Writes output to file Parameters ---------- owner : Frame Parent ``Frame`` object i : int Number of output forceoverwrite : boolean If ``True`` it will forces and overwrite of the file if it exists independent of the writer attribute filename : string If this is not "" the writer will use this filename instead of the standard scheme""" if filename == "": filename = self._getfilename(i) self.checkdatadir(createdir=True) if not forceoverwrite: if not self.overwrite: if os.path.isfile(filename): raise RuntimeError( "File {} already exists.".format(filename)) self._func(owner, filename, **self.options) if self.verbosity > 0: msg = "Writing file {}".format(colorize(filename, "blue")) print(msg) if self.dumping: self.writedump(owner)
def __repr__(self): ret = self.__str__() + "\n" ret += "-" * (len(ret) - 1) + "\n" ret += " Data directory : {}\n".format(self.datadir) ret += " Dumping : {}\n".format( colorize(self.dumping, "yellow") if not self.dumping else self. dumping) ret += " Verbosity : {}".format(self.verbosity) return ret
def writedump(self, frame, filename=""): """Writes the ``Frame`` to dump file Parameters ---------- frame : object object to be written to file filename : str, optional, default : "" path to file to be written if not set, filename will be <writer.datadir>/frame.dmp.""" filename = os.path.join(self.datadir, "frame.dmp") if filename == "" else filename self.checkdatadir(createdir=True) if self.verbosity > 0: msg = "Writing dump file {}".format(colorize(filename, "blue")) print(msg) writedump(frame, filename)
def run(self): """This functions runs the simulation.""" # Print welcome message if self.verbosity > 0: msg = "" msg += "\nDustPy v{}".format(self.__version__) msg += "\n" msg += "\nDocumentation: {}".format( "https://stammler.github.io/dustpy/") msg += "\nPyPI: {}".format( "https://pypi.org/project/dustpy/") msg += "\nGitHub: {}".format( "https://github.com/stammler/dustpy/") msg += "\n" msg += colorize("\nPlease cite Stammler & Birnstiel (2022).", "blue") print(msg) # Check for mass conserbation self.checkmassconservation() # Actually run the simulation super().run()
def condition(self, val): msg = "{} Use <Boundary>.setcondition() to set boundary condition.".format( colorize("Warning:", color="yellow")) print(msg)
def __str__(self): ret = AbstractGroup.__str__(self) if self.constant: ret += ", {}".format(colorize("constant", "purple")) return ret
def setdustintegrator(self, scheme="explicit", method="cash-karp"): """Function sets the dust integrator. Parameters ---------- scheme : string, optional, default : "explicit" Possible values {"explicit", "implicit"} method : string, optional, default : "cash-karp" Possible values for explicit integration {"cash-karp"} Possible values for implicit integration {"direct", "gmres", "bicgstab}""" if not isinstance(self.grid.Nm, Field) or not isinstance(self.grid.Nr, Field): raise RuntimeError( "The simulation frame has to be initialized before calling setdustimplicit().") # Get index of dust instruction for i, inst in enumerate(self.integrator.instructions): if inst.Y is self.dust.Sigma: break if scheme == "implicit": shape2ravel = (int(self.grid.Nr*self.grid.Nm)) # Hidden fields # We store the old values of the surface density in a hidden field # to calculate the fluxes through the boundaries in case of implicit integration. self.dust._SigmaOld = Field( self, self.dust.Sigma, description="Previous value of surface density [g/cm²]") # The right-hand side of the matrix equation is stored in a hidden field self.dust._rhs = Field(self, np.zeros( shape2ravel), description="Right-hand side of matrix equation [g/cm²]") # Setting the Jacobinator self.dust.Sigma.jacobinator = std.dust.jacobian # Time step routine self.t.updater = std.sim.dt # Updaters self.dust.v.updater = ["frag", "driftmax", "rel"] self.dust.updater = ["delta", "rhos", "fill", "a", "St", "H", "rho", "backreaction", "v", "D", "eps", "kernel", "p", "S"] self.dust.S.updater = ["ext", "tot"] # Preparation/Finalization self.integrator.preparator = std.sim.prepare_implicit_dust self.integrator.finalizer = std.sim.finalize_implicit_dust # Integrator if method == "direct": inst = Instruction(std.dust.impl_1_direct, self.dust.Sigma, controller={"rhs": self.dust._rhs }, description="Dust: implicit 1st-order direct solver" ) self.integrator.instructions[i] = inst elif method == "gmres": raise NotImplementedError( "GMRES method is not implemented, yet.") elif method == "bicgstab": raise NotImplementedError("BiCGSTAB is not implemented, yet.") else: raise RuntimeError("Invalid method for implicit integration.") elif scheme == "explicit": # Remove hidden fields if they exist if hasattr(self.dust, "_SigmaOld"): del self.dust._SigmaOld if hasattr(self.dust, "_rhs"): del self.dust._rhs # Unset Jacobian self.dust.Sigma.jacobinator = None # Updaters self.dust.v.updater = ["frag", "driftmax", "rad", "rel"] self.dust.updater = ["delta", "rhos", "fill", "a", "St", "H", "rho", "backreaction", "v", "D", "eps", "Fi", "kernel", "p", "S"] self.dust.S.updater = ["coag", "hyd", "ext", "tot"] # Preparation/Finalization self.integrator.preparator = std.sim.prepare_explicit_dust self.integrator.finalizer = std.sim.finalize_explicit_dust if method == "cash-karp": # Adaptive time step routine self.t.updater = std.sim.dt_adaptive # Instruction inst = Instruction(schemes.expl_5_cash_karp_adptv, self.dust.Sigma, controller={"dYdx": self.dust.S.tot, "eps": 0.1, "S": 0.9, }, description="Dust: explicit 5th-order adaptive Cash-Karp method" ) self.integrator.instructions[i] = inst self.t.suggest(1.*c.year) else: raise RuntimeError("Invalid method for explicit integration.") else: raise RuntimeError("Unknown integration scheme.") self.integrator._finalize() self.update() if self.verbosity > 0: msg = "Setting dust integrator\n scheme: {}\n method: {}".format( colorize(scheme, "blue"), colorize(method, "blue")) print(msg)
def checkmassconservation(self): """Function checks for mass conservation and prints the maximum relative mass error.""" # Check if required fields are present if self.dust.coagulation.stick is None: raise RuntimeError( "'Simulation.dust.coagulation.stick' is not set.") if self.dust.coagulation.stick_ind is None: raise RuntimeError( "'Simulation.dust.coagulation.stick_ind' is not set.") if self.dust.coagulation.A is None: raise RuntimeError( "'Simulation.dust.coagulation.A' is not set.") if self.dust.coagulation.eps is None: raise RuntimeError( "'Simulation.dust.coagulation.eps' is not set.") if self.dust.coagulation.lf_ind is None: raise RuntimeError( "'Simulation.dust.coagulation.lf_ind' is not set.") if self.dust.coagulation.rm_ind is None: raise RuntimeError( "'Simulation.dust.coagulation.rm_ind' is not set.") if self.dust.coagulation.phi is None: raise RuntimeError( "'Simulation.dust.coagulation.phi' is not set.") if self.grid.m is None: raise RuntimeError("'sim.grid.m' is not set.") if self.verbosity > 0: # Maximum acceptable error erracc = 1.e-13 # Checking for sticking error msg = "\n" msg += colorize("Checking for mass conservation...\n", color="yellow") print(msg) msg = colorize(" - Sticking:", color="yellow") print(msg) errmax, i, j = std.dust_f.check_mass_conservation_sticking( self.dust.coagulation.stick, self.dust.coagulation.stick_ind, self.grid.m) tup = (j, i) color = "red" if(errmax < erracc): color = "green" error = "{:9.2e}".format(errmax) msg = " max. rel. error: {:}\n".format( colorize(error, color=color)) msg += " for particle collision\n" msg += " m[{:d}] = {:9.2e} g with\n".format( tup[0], self.grid.m[tup[0]]) msg += " m[{:d}] = {:9.2e} g".format( tup[1], self.grid.m[tup[1]]) msg = colorize(msg) print(msg) # Checking for full fragmentation error msg = colorize(" - Full fragmentation:", color="yellow") print(msg) A = self.dust.coagulation.A eps = self.dust.coagulation.eps klf = self.dust.coagulation.lf_ind krm = self.dust.coagulation.rm_ind m = self.grid.m phi = self.dust.coagulation.phi errmax, i, j = std.dust_f.check_mass_conservation_full_fragmentation( A, klf, m, phi) tup = (j, i) color = "red" if(errmax < erracc): color = "green" error = "{:9.2e}".format(errmax) msg = " max. rel. error: {:}\n".format( colorize(error, color=color)) msg += " for particle collision\n" msg += " m[{:d}] = {:9.2e} g with\n".format( tup[0], self.grid.m[tup[0]]) msg += " m[{:d}] = {:9.2e} g".format( tup[1], self.grid.m[tup[1]]) msg = colorize(msg) print(msg) # Checking for erosion error msg = colorize(" - Erosion:", color="yellow") print(msg) errmax, i, j = std.dust_f.check_mass_conservation_erosion( A, eps, klf, krm, m, phi) tup = (j, i) color = "red" if(errmax < erracc): color = "green" error = "{:9.2e}".format(errmax) msg = " max. rel. error: {:}\n".format( colorize(error, color=color)) msg += " for particle collision\n" msg += " m[{:d}] = {:9.2e} g with\n".format( tup[0], self.grid.m[tup[0]]) msg += " m[{:d}] = {:9.2e} g\n".format( tup[1], self.grid.m[tup[1]]) msg = colorize(msg) print(msg)
def __repr__(self): """Function to have good looking overview of the members of the group.""" fields = {} groups = {} misc = {} # return value ret = "" for key, val in self.__dict__.items(): # Don't show private attributes if key.startswith("_"): continue # Sort attributes by group, field and else if isinstance(val, Field): fields[key] = val elif isinstance(val, Group): groups[key] = val else: misc[key] = val # Underlined headline. The length of the underline is off if there are hidden characters, like color. ret += self.__str__() + "\n" ret += "-" * (len(ret) - 1) + "\n" # Printing all groups alphanumerically sorted by name if len(groups) > 0: for key in sorted(groups.keys(), key=str.casefold): if len(key) > 12: name = key[:9] + "..." else: name = key ret += " {:12s} : {}\n".format(name, groups[key]) ret += " -----\n" # Printing all fields alphanumerically sorted by name if len(fields) > 0: for key in sorted(fields.keys(), key=str.casefold): if len(key) > 12: name = key[:9] + "..." else: name = key ret += " {:12s} : {}\n".format(name, fields[key].__str__()) ret += " -----\n" # Printing everything else alphanumerically sorted if len(misc) > 0: for key in sorted(misc.keys(), key=str.casefold): if len(key) > 12: name = key[:9] + "..." else: name = key ret += " {:12s} : {}\n".format(name, type(misc[key]).__name__) ret += " -----\n" # The Frame object should have an integrator and writer which are displayed separately. # If the object has an integrator if "_integrator" in self.__dict__.keys(): integrator = self.__dict__["_integrator"] # If not set, print warning txt = colorize("not specified", "yellow") if integrator is not None: txt = integrator.__str__() ret += " {:12s} : {}".format("Integrator", txt) ret += "\n" # If the object has a writer if "_writer" in self.__dict__.keys(): writer = self.__dict__["_writer"] # If not set print warning txt = colorize("not specified", "yellow") if writer is not None: txt = writer.__str__() ret += " {:12s} : {}".format("Writer", txt) ret += "\n" return ret
def run(self): """This method starts the simulation. An ``Integrator`` has to be set beforehand.""" if not isinstance(self.integrator, Integrator): raise RuntimeError("No integrator set.") # Check if integration variable is set if not isinstance(self.integrator.var, IntVar): raise RuntimeError( "No integration variable assigned to integrator.") # If there are no snapshots set if not len(self.integrator.var.snapshots): raise RuntimeError( "No snapshots set. At least one snapshot has to be given.") # If integration variable passed maximum value of snapshots if self.integrator.var >= self.integrator.var.snapshots[-1]: raise RuntimeError( "Integration variable already passed the largest snapshot.") # Timekeeping tini = monotonic() # Write initial conditions if self.integrator.var < self.integrator.var.snapshots[0]: self.writeoutput(0) # Staring index of snapshots starting_index = np.argmin( self.integrator.var >= self.integrator.var.snapshots) # Starting value of integration variable startingvalue = self.integrator.var.copy() for i in range(starting_index, len(self.integrator.var.snapshots)): # Nextsnapshot cannot be referenced directly, because it dynamically changes. nextsnapshot = self.integrator.var.nextsnapshot prevsnapshot = self.integrator.var.prevsnapshot if self.integrator.var.prevsnapshot is not None else startingvalue while self.integrator.var < nextsnapshot: if self.verbosity > 1: self.progressbar(self.integrator.var, prevsnapshot, nextsnapshot, startingvalue, self.integrator.var.snapshots[-1]) self.integrator.integrate() self.integrator.var += self.integrator.var._prevstepsize self.update() if self.verbosity > 1: self.progressbar._reset() self.writeoutput(i + 1) # Timekeeping tfin = monotonic() t_exec = timedelta(seconds=int(tfin - tini)) if self.verbosity > 0: msg = "Execution time: {}".format(colorize(t_exec, color="blue")) print(msg)
def update(self): """Not used for ``IntVar``.""" msg = "{}: {}".format( colorize("Warning", "yellow"), "Do not update the integration variable by hand.") print(msg)
def __str__(self): ret = "{}".format(str(self.__name__)) ret = super().__str__() ret += ", {}".format(colorize("Integration variable", "purple")) return ret