diff --git a/spatialpy/core/boundarycondition.py b/spatialpy/core/boundarycondition.py index 32f25ae7..8c833c2a 100644 --- a/spatialpy/core/boundarycondition.py +++ b/spatialpy/core/boundarycondition.py @@ -87,6 +87,8 @@ def __init__(self, xmin=None, xmax=None, ymin=None, ymax=None, zmin=None, zmax=N if type_id is not None and not isinstance(type_id, (int, str)): raise BoundaryConditionError("Type-ID must be of type int.") elif type_id is not None: + if "UnAssigned" in type_id: + raise BoundaryConditionError("'UnAssigned' is not a valid type_id") type_id = f"type_{type_id}" if target is None or not (isinstance(target, (str, Species)) or type(target).__name__ == 'Species' or property in ('nu', 'rho', 'v')): diff --git a/spatialpy/core/domain.py b/spatialpy/core/domain.py index cdb033bf..e2a2f49d 100644 --- a/spatialpy/core/domain.py +++ b/spatialpy/core/domain.py @@ -68,13 +68,13 @@ def __init__(self, numpoints, xlim, ylim, zlim, rho0=1.0, c0=10, P0=None, gravit self.vol = numpy.zeros((numpoints), dtype=float) self.mass = numpy.zeros((numpoints), dtype=float) - self.type_id = numpy.array([None] * numpoints, dtype=object) + self.type_id = numpy.array(["type_UnAssigned"] * numpoints, dtype=object) self.nu = numpy.zeros((numpoints), dtype=float) self.c = numpy.zeros((numpoints), dtype=float) self.rho = numpy.zeros((numpoints), dtype=float) self.fixed = numpy.zeros((numpoints), dtype=bool) self.listOfTypeIDs = [] - self.typeNdxMapping = OrderedDict() + self.typeNdxMapping = OrderedDict({"type_UnAssigned": 0}) self.typeNameMapping = None self.rho0 = rho0 @@ -136,7 +136,7 @@ def compile_prep(self): :raises DomainError: If a type_id is not set or rho=0 for a particle. """ - if self.type_id.tolist().count(None) > 0: + if self.type_id.tolist().count("type_UnAssigned") > 0: raise DomainError(f"Particles must be assigned a type_id.") if numpy.count_nonzero(self.rho) < len(self.rho): raise DomainError(f"Rho must be a positive value.") @@ -184,7 +184,10 @@ def add_point(self, point, vol=0, mass=0, type_id=1, nu=0, fixed=False, rho=None if (char in string.punctuation and char != "_") or char == " ": raise DomainError(f"Type_id cannot contain {char}") if type_id not in self.typeNdxMapping: - self.typeNdxMapping[type_id] = len(self.typeNdxMapping) + 1 + if "UnAssigned" in type_id: + self.typeNdxMapping[type_id] = 0 + else: + self.typeNdxMapping[type_id] = len(self.typeNdxMapping) if rho is None: rho = mass / vol @@ -240,7 +243,10 @@ def set_properties(self, geometry_ivar, type_id, vol=None, mass=None, nu=None, r if (char in string.punctuation and char != "_") or char == " ": raise DomainError(f"Type_id cannot contain '{char}'") if type_id not in self.typeNdxMapping: - self.typeNdxMapping[type_id] = len(self.typeNdxMapping) + 1 + if "UnAssigned" in type_id: + self.typeNdxMapping[type_id] = 0 + else: + self.typeNdxMapping[type_id] = len(self.typeNdxMapping) # apply the type to all points, set type for any points that match count = 0 on_boundary = self.find_boundary_points() @@ -807,7 +813,10 @@ def read_stochss_subdomain_file(self, filename, type_ids=None): if (char in string.punctuation and char != "_") or char == " ": raise DomainError(f"Type_id cannot contain {char}") if type_id not in self.typeNdxMapping: - self.typeNdxMapping[type_id] = len(self.typeNdxMapping) + 1 + if "UnAssigned" in type_id: + self.typeNdxMapping[type_id] = 0 + else: + self.typeNdxMapping[type_id] = len(self.typeNdxMapping) self.type_id[int(ndx)] = type_id @@ -834,13 +843,15 @@ def read_stochss_domain(cls, filename): obj = Domain(0, tuple(domain['x_lim']), tuple(domain['y_lim']), tuple(domain['z_lim']), rho0=domain['rho_0'], c0=domain['c_0'], P0=domain['p_0'], gravity=domain['gravity']) - for particle in domain['particles']: + for i, particle in enumerate(domain['particles']): try: type_id = list(filter( lambda d_type, t_ndx=particle['type']: d_type['typeID'] == t_ndx, domain['types'] ))[0]['name'] except IndexError: type_id = particle['type'] + if type_id == "Un-Assigned" or type_id == 0: + type_id = "UnAssigned" # StochSS backward compatability check for rho rho = None if "rho" not in particle.keys() else particle['rho'] # StochSS backward compatability check for c diff --git a/spatialpy/core/reaction.py b/spatialpy/core/reaction.py index d0404734..cad800c9 100644 --- a/spatialpy/core/reaction.py +++ b/spatialpy/core/reaction.py @@ -623,6 +623,8 @@ def validate(self, coverage="build", reactants=None, products=None, propensity_f raise ReactionError("Type ids in restrict_to must be of type int or str.") if type_id == "": raise ReactionError("Type ids in restrict_to can't be an empty string.") + if isinstance(type_id, str) and "UnAssigned" in type_id: + raise ReactionError("'UnAssigned' is not a valid type_id.") if coverage in ("all", "initialized"): if not isinstance(type_id, str): raise ReactionError("Type ids in restrict_to must be of type str.") diff --git a/spatialpy/solvers/solver.py b/spatialpy/solvers/solver.py index 5d46bfe9..c2da3a26 100644 --- a/spatialpy/solvers/solver.py +++ b/spatialpy/solvers/solver.py @@ -312,9 +312,9 @@ def __get_param_defs(self): def __get_particle_inits(self, num_chem_species): init_particles = "" if self.model.domain.type_id is None: - self.model.domain.type_id = ["type 1"] * self.model.domain.get_num_voxels() + self.model.domain.type_id = ["type_1"] * self.model.domain.get_num_voxels() for i, type_id in enumerate(self.model.domain.type_id): - if type_id is None: + if "UnAssigned" in type_id: errmsg = "Not all particles have been defined in a type. Mass and other properties must be defined" raise SimulationError(errmsg) x = self.model.domain.coordinates()[i, 0] diff --git a/spatialpy/stochss/stochss_export.py b/spatialpy/stochss/stochss_export.py index 7fe2c545..5d7d586d 100644 --- a/spatialpy/stochss/stochss_export.py +++ b/spatialpy/stochss/stochss_export.py @@ -173,12 +173,13 @@ def __build_element(stoich_species): def __get_particles(domain): s_particles = [] for i, point in enumerate(domain.vertices): + type_id = domain.typeNdxMapping[domain.type_id[i]] s_particle = {"fixed":bool(domain.fixed[i]), "mass":domain.mass[i], "nu":domain.nu[i], "particle_id":i, "point":list(point), - "type":int(domain.type_id[i]), + "type":type_id, "volume":domain.vol[i]} s_particles.append(s_particle)