class splitSELAFIN(): def __init__(self, SLFfileName, CLMfileName, SEQfileName='', splitCONLIM=False, DOMfileRoot=''): print '\n... Acquiring global files' # ~~> Acquire global CONLIM file print ' +> CONLIM file' self.clm = CONLIM(CLMfileName) self.isCONLIM = splitCONLIM # ~~> Acquire global SELAFIN file print ' +> SELAFIN file' self.slf = SELAFIN(SLFfileName) # ~~> Acquire global SELAFIN file if SEQfileName != '': print ' +> SEQUENCE file' self.NPARTS, self.NSPLIT, self.KSPLIT = self.getSplitFromSequence( np.array(getFileContent(SEQfileName), dtype='<i4')) else: self.NPARTS, self.NSPLIT, self.KSPLIT = self.getSplitFromNodeValues( 'PROCESSORS') print '\n... Split by elements in ', self.NPARTS, ' parts\n' # ~~> Clean inconsistencies in boundary segments self.IPOBO, self.NSPLIT, self.KSPLIT = self.setSplitForBoundaries( self.NSPLIT, self.clm.KFRGL, self.KSPLIT) self.PINTER,self.PNHALO,self.PNODDS = \ self.setSplitForElements( self.IPOBO,self.NPARTS,self.NSPLIT,self.KSPLIT ) self.slfn = self.copyCommonData() # ~~> Optional output file names self.isDOMAIN = DOMfileRoot # Make a copy of common information for sub-meshes def copyCommonData(self): SLFn = SELAFIN('') # Meta data SLFn.TITLE = self.slf.TITLE SLFn.file = self.slf.file SLFn.IPARAM = self.slf.IPARAM # Time SLFn.DATETIME = self.slf.DATETIME SLFn.tags = self.slf.tags # Variables SLFn.NBV1 = self.slf.NBV1 SLFn.VARNAMES = self.slf.VARNAMES SLFn.VARUNITS = self.slf.VARUNITS SLFn.NBV2 = self.slf.NBV2 SLFn.CLDNAMES = self.slf.CLDNAMES SLFn.CLDUNITS = self.slf.CLDUNITS SLFn.NVAR = self.slf.NVAR SLFn.VARINDEX = range(self.slf.NVAR) # Unchanged numbers SLFn.NPLAN = self.slf.NPLAN SLFn.NDP = self.slf.NDP return SLFn # Split based on a sequence of parts, one for each element (result from METIS) def getSplitFromSequence(self, KSPLIT): # ~~> NPARTS is the number of parts /!\ does not check continuity vs. missing parts NPARTS = max(*KSPLIT) NSPLIT = np.zeros(self.slf.NPOIN3, dtype=np.int) for part in range(NPARTS): k = np.compress(KSPLIT == (part + 1), range(len(self.slf.IKLE))) NSPLIT[self.slf.IKLE[k]] = KSPLIT[k] return NPARTS, NSPLIT - 1, KSPLIT - 1 # Split based on the variable PROCESSORS, defined at the nodes def getSplitFromNodeValues(self, var): # ~~> Filter for 'PROCESSORS' as input to the getVariablesAt method i, vn = subsetVariablesSLF(var, self.slf.VARNAMES) if i == []: print '... Could not find ', var, ', you may need another split method' sys.exit() # ~~> NSPLIT is the interger value of the variable PROCESSORS (time frame 0) NSPLIT = np.array( \ getVariablesAt( self.slf.file,self.slf.tags,0,self.slf.NVAR,self.slf.NPOIN3,i )[0], \ dtype=np.int) # ~~> NPARTS is the number of parts /!\ does not check continuity vs. missing parts NPARTS = max(*NSPLIT) + 1 # User numbering NSPLIT starts from 0 KSPLIT = np.minimum(*(NSPLIT[self.slf.IKLE].T)) return NPARTS, NSPLIT, KSPLIT def setSplitForBoundaries(self, NSPLIT, KFRGL, KSPLIT): # ~~> Join up the global boundary nodes with the halo elements IPOBO = np.zeros(self.slf.NPOIN3, dtype=np.int) IPOBO[KFRGL.keys()] = np.array( KFRGL.values(), dtype=np.int) + 1 # this is so the nonzero search is easier # ~~> Cross check partition quality -- step 1 found = True nloop = 0 while found: found = False nloop += 1 for k in range(len(self.slf.IKLE)): e = self.slf.IKLE[k] if KSPLIT[k] != max(NSPLIT[e]): for p1, p2, p3 in zip([0, 1, 2], [1, 2, 0], [2, 0, 1]): if NSPLIT[e[p1]] != KSPLIT[k] and NSPLIT[ e[p2]] != KSPLIT[k]: if IPOBO[e[p1]] != 0 and IPOBO[e[p2]] != 0: print ' ~> correcting boundary segment at iteration: ', nloop, ( e[p1], e[p2]), k, KSPLIT[k], e, NSPLIT[e] NSPLIT[e[p1]] = NSPLIT[e[p3]] NSPLIT[e[p2]] = NSPLIT[e[p3]] KSPLIT[k] = NSPLIT[e[p3]] found = True # ~~> Cross check partition quality -- step 2 found = True nloop = 0 while found: found = False nloop += 1 for k in range(len(self.slf.IKLE)): e = self.slf.IKLE[k] if min(NSPLIT[e]) != max(NSPLIT[e]) and KSPLIT[k] != min( NSPLIT[e]): print ' ~> correcting internal segment at iteration: ', nloop, k, KSPLIT[ k], e, NSPLIT[e] KSPLIT[k] = min(NSPLIT[e]) found = True return IPOBO, NSPLIT, KSPLIT # Split based on the variable PROCESSORS, defined at the nodes def setSplitForElements(self, IPOBO, NPARTS, NSPLIT, KSPLIT): SNHALO = dict([(i, []) for i in range(NPARTS)]) PNODDS = dict([(i, []) for i in range(NPARTS)]) SINTER = dict([(i, []) for i in range(NPARTS)]) # ~~> Internal segments separating parts pbar = ProgressBar(maxval=len(self.slf.IKLE)).start() for k in range(len(self.slf.IKLE)): e = self.slf.IKLE[k] # Case 1: you are at an internal boundary element if KSPLIT[k] != max(NSPLIT[e]): for p1, p2 in zip([0, 1, 2], [1, 2, 0]): if NSPLIT[e[p1]] != KSPLIT[k] and NSPLIT[ e[p2]] != KSPLIT[k]: SINTER[KSPLIT[k]].append((e[p1], e[p2])) SINTER[min(NSPLIT[e[p1]], NSPLIT[e[p2]])].append( (e[p2], e[p1])) # Case 2: you may be at an external boundary element if np.count_nonzero(IPOBO[e]) > 1: for p1, p2 in zip([0, 1, 2], [1, 2, 0]): if IPOBO[e[p1]] != 0 and IPOBO[ e[p2]] != 0: # multiplier is not possible if IPOBO[e[p1]] + 1 == IPOBO[e[p2]]: SNHALO[KSPLIT[k]].append((e[p1], e[p2])) else: PNODDS[KSPLIT[k]].append([e[p1], e[p2]]) pbar.update(k) pbar.finish() # ~~> Clean-up of funny segments looping on themselves for part in range(NPARTS): # ~~> Quickly checking through to remove duplicate segments found = True while found: found = False INTER = np.array(SINTER[part], dtype=[('h', int), ('t', int)]) HEADT = np.argsort(INTER['h']) HLINK = np.searchsorted(INTER['h'][HEADT], INTER['t'][HEADT]) w = 0 while w < len(HLINK): if HLINK[w] < len(HLINK): if INTER['h'][HEADT[w]] == INTER['t'][HEADT[ HLINK[w]]] and INTER['t'][ HEADT[w]] == INTER['h'][HEADT[HLINK[w]]]: print ' ~> Removing dupicate segments in part: ', part, SINTER[ part][HEADT[w]], SINTER[part][HEADT[HLINK[w]]] if HEADT[w] > HEADT[HLINK[w]]: SINTER[part].pop(HEADT[w]) SINTER[part].pop(HEADT[HLINK[w]]) else: SINTER[part].pop(HEADT[HLINK[w]]) SINTER[part].pop(HEADT[w]) found = True break w += 1 return SINTER, SNHALO, PNODDS def getIKLE(self, npart): # ~~> get IKLE for that part ... still with global element numbers GIKLE = np.compress(self.KSPLIT == npart, self.slf.IKLE, axis=0) KELLG = np.compress(self.KSPLIT == npart, range(len(self.slf.IKLE)), axis=0) # ~~> KNOLG(NPOIN3) gives the global node number such that # for i = 1,NPOIN3: Fwrite(i) = Fread(KNOLG(i)) and is ordered KNOLG, indices = np.unique(np.ravel(GIKLE), return_index=True) KNOGL = dict(zip(KNOLG, range(len(KNOLG)))) LIKLE = -np.ones_like(GIKLE, dtype=np.int) pbar = ProgressBar(maxval=len(GIKLE)).start() for k in range(len(GIKLE)): LIKLE[k] = [ KNOGL[GIKLE[k][0]], KNOGL[GIKLE[k][1]], KNOGL[GIKLE[k][2]] ] pbar.update(k) pbar.finish() return LIKLE, KELLG, KNOLG def resetPartition(self, part, PINTER, KSPLIT): MASKER = np.zeros(self.slf.NPOIN3, dtype=np.int) for p in PINTER: MASKER[p] = np.arange(len(p)) + 1 # PINTER is ordered KIKLE = np.compress( np.maximum(*(MASKER[self.slf.IKLE].T)) >= 0, range(len(self.slf.IKLE))) #KIKLE = np.compress(np.count_nonzero(MASKER[self.slf.IKLE],axis=1)>2,range(len(self.slf.IKLE))) # /!\ does not work ? pbar = ProgressBar(maxval=len(KIKLE)).start() for k in KIKLE: e = self.slf.IKLE[k] if np.count_nonzero(MASKER[e]) < 2 or KSPLIT[k] == part: continue for p1, p2 in zip([0, 1, 2], [1, 2, 0]): if MASKER[e[p1]] > 0 and MASKER[e[p2]] > 0 and MASKER[ e[p2]] > MASKER[e[p1]]: print ' ~> Warning for element of part: ', part, '(was:', KSPLIT[ k], ') ', k, e #KSPLIT[k] = part pbar.update(k) pbar.finish() return KSPLIT def joinPairs(self, polyLines): INTER = np.array(polyLines, dtype=[('h', int), ('t', int)]) IDONE = np.ones(len(polyLines), dtype=np.int) polyA = [] polyZ = [] polyL = [] # ~~> Finding the endings HEADT = np.argsort( INTER['h']) # knowing that INTER[HEADT] is sorted by the head HLINK = np.searchsorted( INTER['h'][HEADT], INTER['t'][HEADT]) # INTER['h'][HEADT] is sorted # ... HLINK[w] for w in INTER['t'] gives you the position of INTER['t'][w] in INTER['h'][HEADT] w = min(np.compress(np.not_equal(IDONE, IDONE * 0), range(len(HEADT)))) po = INTER['h'][HEADT[w]] pe = INTER['t'][HEADT[w]] IDONE[w] = 0 polyA.append(po) swapMinMax = True while True: if HLINK[w] < len(INTER): if INTER['t'][HEADT][w] == INTER['h'][HEADT][HLINK[w]]: w = HLINK[w] pe = INTER['t'][HEADT][w] IDONE[w] = 0 if pe not in polyA: if HLINK[w] < len(INTER): if INTER['t'][HEADT][w] != po and INTER['t'][HEADT][ w] == INTER['h'][HEADT][HLINK[w]]: continue if po == pe: polyL.append(pe) else: if pe not in polyZ: polyZ.append(pe) else: polyA.append(po) if np.count_nonzero(IDONE) == 0: break if swapMinMax: w = max( np.compress(np.not_equal(IDONE, IDONE * 0), range(len(HEADT)))) else: w = min( np.compress(np.not_equal(IDONE, IDONE * 0), range(len(HEADT)))) swapMinMax = not swapMinMax po = INTER['h'][HEADT[w]] pe = INTER['t'][HEADT[w]] IDONE[w] = 0 polyA.append(po) # ~~> Finding the sources TAILT = np.argsort( INTER['t']) # knowing that INTER[TAILT] is sorted by the tail TLINK = np.searchsorted( INTER['t'][TAILT], INTER['h'][TAILT]) # INTER['h'][HEADT] is sorted # ... TLINK[w] for w in polyZ gives you the position of polyZ[w] in INTER['t'][TAILT] polyGones = [] # ~~> Finding the sources of non-looping lines TAILS = np.searchsorted(INTER['t'][TAILT], polyZ) for w in TAILS: p = [INTER['t'][TAILT[w]]] while True: if INTER['h'][TAILT][w] == INTER['t'][TAILT][TLINK[w]]: po = [INTER['h'][TAILT][w]] po.extend(p) p = po w = TLINK[w] if TLINK[w] < len(INTER): if INTER['h'][TAILT][w] == INTER['t'][TAILT][TLINK[w]]: continue po = [INTER['h'][TAILT][w]] po.extend(p) p = po break polyGones.append(p) # ~~> Finding the sources of looping lines LOOPS = np.searchsorted(INTER['t'][TAILT], polyL) for w in LOOPS: p = [INTER['t'][TAILT[w]]] while True: if INTER['h'][TAILT][w] == INTER['t'][TAILT][TLINK[w]]: po = [INTER['h'][TAILT][w]] po.extend(p) p = po w = TLINK[w] if INTER['h'][TAILT][w] != p[len(p) - 1]: continue po = [INTER['h'][TAILT][w]] po.extend(p) p = po break polyGones.append(p) return polyGones def joinSegments(self, polyLines): polyGones = [] maxbar = max(len(polyLines), 1) pbar = ProgressBar(maxval=maxbar).start() while polyLines != []: # ~~> starting point e = polyLines[0] le = len(e) a, b = e[0], e[len(e) - 1] # ~~> case of closed line if a == b: polyGones.append( e[0:len(e)]) # /!\ here you keep the duplicated point polyLines.pop(0) continue # ~~> iterative process for ei, iline in zip(polyLines[1:], range(len(polyLines))[1:]): # ~~> merging the two segments if b == ei[0]: polyLines[0] = e[0:len(e)] # copy ! polyLines[0].extend(ei[1:]) polyLines.pop(iline) break if a == ei[len(ei) - 1]: polyLines[0] = ei[0:len(ei)] # copy ! polyLines[0].extend(e[1:]) polyLines.pop(iline) break # ~~> completed search if le == len(polyLines[0]): polyGones.append(e[0:len(e)]) polyLines.pop(0) pbar.update(maxbar - len(polyLines)) pbar.finish() return polyGones def tetrisOddSegments(self, main, odds): polyGones = [] lo = len(odds) while main != []: # ~~> starting point e = main[0] le = len(e) a, b = e[0], e[len(e) - 1] # ~~> case of closed line if a == b: polyGones.append( e[0:len(e)]) # /!\ here you keep the duplicated point main.pop(0) continue # ~~> iterative process for ei, iline in zip(odds, range(len(odds))): # ~~> merging the two segments if b == ei[0]: main[0] = e[0:len(e)] main[0].extend(ei[1:]) odds.pop(iline) break if a == ei[len(ei) - 1]: main[0] = ei[0:len(ei)] main[0].extend(e[1:]) odds.pop(iline) break # ~~> completed search if le == len(main[0]): polyGones.append(e[0:len(e)]) main.pop(0) # ~~> removing the over-constrained elements for p in polyGones: if len(p) > 3: j = 2 while j < len(p): if p[j - 2] == p[j]: p.pop(j - 2) p.pop(j - 2) j += 1 return polyGones # Filter poly according to IPOBO on that part. # ~> gloseg: is the ensemble of either closed islands or # open external boundary segments # Note: filtering now seems to mean that to have done a lot of work for nothing def globalSegments(self, poly): gloseg = [] for p in poly: pA = p[0] pZ = p[len(p) - 1] closed = False if pA == pZ and self.IPOBO[pA] != 0: closed = True iA = 0 iZ = 0 ploseg = [] for i in p: if self.IPOBO[ i] != 0: # moves the counter along for external points iZ += 1 elif iZ != 0: # you have just found the end of an external segment ploseg.append(p[iA:iA + iZ]) iA += iZ + 1 iZ = 0 else: iA += 1 if iZ != 0: if closed and len(ploseg) > 0: i = p[iA:iA + iZ] i.extend(ploseg[0][1:]) # remove duplicate ploseg[0] = i else: ploseg.append(p[iA:iA + iZ]) gloseg.extend(ploseg) return gloseg def putContent(self): # ~~> Extension for parallel file names fmtn = '00000' + str(self.NPARTS - 1) fmtn = fmtn[len(fmtn) - 5:] print '\n... Split the boundary connectivity' # ~~> Assemble internal and external segments polyCLOSED = dict([(i, []) for i in range(self.NPARTS)]) polyFILTER = dict([(i, []) for i in range(self.NPARTS)]) polyGLOSED = [] for part in range(self.NPARTS): # this could be done in parallel print ' +> Joining up boundary segments for part: ', part + 1 # ~~> Joining up boundaries for sub-domains print ' ~> main internal segments' self.PINTER[part] = self.joinPairs(self.PINTER[part]) print ' ~> main external segments' polyHALO = self.joinPairs(self.PNHALO[part]) polyHALO.extend(self.PINTER[part]) polyHALO = self.joinSegments(polyHALO) print ' ~> odd segments' polyODDS = self.joinSegments(self.PNODDS[part]) print ' ~> stitching with the odd ones' polyGones = self.tetrisOddSegments(polyHALO, polyODDS) print ' ~> final closure' polyCLOSED[part] = self.joinSegments(polyGones) # ~~> Building up the entire picture polyFILTER[part] = self.globalSegments(polyCLOSED[part]) polyGLOSED.extend(polyFILTER[part]) # ~~> Joining up boundaries for the global domain (Note: seems counter productive but is not) polyGLOSED = self.joinSegments(polyGLOSED) if self.isDOMAIN != '': print '\n... Printing the domain split into a series of i2s files' # ~~> Convert node numbers into x,y for part in range(self.NPARTS): print ' +> part ', part + 1, ' of ', self.NPARTS polyXY = [] for pg in range(len(polyCLOSED[part])): pxy = [] for pt in range(len(polyCLOSED[part][pg])): n = polyCLOSED[part][pg][pt] pxy.append([self.slf.MESHX[n], self.slf.MESHY[n]]) polyXY.append(pxy) # ~~> Write polygons to double check fmti = '00000' + str(part) fmti = fmti[len(fmti) - 5:] fileName = path.join( path.dirname(self.slf.fileName), self.isDOMAIN + fmtn + '-' + fmti + '.i2s') putInS(fileName, [], 'i2s', polyXY) # ~~> Convert node numbers into x,y polyXY = [] for pg in range(len(polyGLOSED)): pxy = [] for pt in range(len(polyGLOSED[pg])): n = polyGLOSED[pg][pt] pxy.append([self.slf.MESHX[n], self.slf.MESHY[n]]) polyXY.append(pxy) # ~~> Write polygons to double check fileName = path.join(path.dirname(self.slf.fileName), self.isDOMAIN + '.i2s') putInS(fileName, [], 'i2s', polyXY) print '\n... Final check to the element partitioning' for part in range(self.NPARTS): # this could be done in parallel self.KSPLIT = self.resetPartition(part, self.PINTER[part], self.KSPLIT) if self.isDOMAIN != '': # ~~> This is optional print '\n... Printing the domain split into a SELAFIN' fileRoot, fileExts = path.splitext(self.slf.fileName) self.slf.fole = open(fileRoot + '_PROCS' + fileExts, 'wb') putHeaderSLF(self.slf) appendCoreTimeSLF(self.slf, 0) VARSOR = self.slf.getVALUES(0) for v in range(self.slf.NVAR): VARSOR[v] = self.NSPLIT appendCoreVarsSLF(self.slf, VARSOR) self.slf.fole.close() print '\n... Storing the global liquid boundary numbering (NUMLIQ)' # ~~> Implying NUMLIQ and the number NFRLIQ based on the joined-up lines self.clm.setNUMLIQ(polyGLOSED) print '\n... Split the mesh connectivity' # ~~> Preliminary set up for LIKLE, KNOLG and KEMLG by parts LIKLE = dict([(i, []) for i in range(self.NPARTS)]) KELLG = dict([(i, []) for i in range(self.NPARTS)]) KNOLG = dict([(i, []) for i in range(self.NPARTS)]) for part in range(self.NPARTS): print ' +> re-ordering IKLE for part ', part + 1 LIKLE[part], KELLG[part], KNOLG[part] = self.getIKLE(part) # ~~> CONLIM file: Preliminary set up of IFAPAR and ISEG for all parts IFAPAR = dict([(i, {}) for i in range(self.NPARTS)]) ISEG = {} # Organising ISEG for easier call: part 1 for part in range(self.NPARTS): for i in polyFILTER[part]: if i[0] == i[len(i) - 1]: continue # /!\ you are here adding one ! if i[0] in ISEG.keys(): ISEG[i[0]].update({part: i[1] + 1}) else: ISEG.update({i[0]: {part: i[1] + 1}}) if i[len(i) - 1] in ISEG.keys(): ISEG[i[len(i) - 1]].update({part: -i[len(i) - 2] - 1}) else: ISEG.update({i[len(i) - 1]: {part: -i[len(i) - 2] - 1}}) # Switching parts of ISEG for final call: part 2 for i in ISEG.keys(): if len(ISEG[i]) != 2: print '... You have a boundary node surounded with more than two boundary segments: ', i sys.exit() parts = ISEG[i].keys() ISEG[i] = { parts[0]: ISEG[i][parts[1]], parts[1]: ISEG[i][parts[0]] } # ~~> CONLIM file: Preliminary set up of NPTIR for all parts NPTIR = dict([(i, {}) for i in range(self.NPARTS)]) for part in range(self.NPARTS): for p in self.PINTER[part]: NPTIR[part].update(dict([(i, []) for i in p])) parts = range(self.NPARTS) while parts != []: part = parts[0] parts.pop(0) for ip in NPTIR[part].keys(): for ipart in parts: if ip in NPTIR[ipart].keys(): NPTIR[part][ip].append(ipart) NPTIR[ipart][ip].append(part) print '... Split of the SELAFIN file' for part in range(self.NPARTS): fmti = '00000' + str(part) fmti = fmti[len(fmti) - 5:] print ' +> part ', part + 1, ' of ', self.NPARTS self.slfn.IKLE = LIKLE[part] self.slfn.NELEM3 = len(LIKLE[part]) self.slfn.NPOIN3 = len(KNOLG[part]) # ~~> IPARAM has two new values: 8:NPTFR and 9:NPTIR self.slfn.IPARAM[7] = len( np.unique(np.concatenate(polyFILTER[part]))) self.slfn.IPARAM[8] = len(NPTIR[part]) # ~~> IPOBO (or IRAND) converted into KNOLG[part] self.slfn.IPOBO = KNOLG[part] + 1 print ' ~> filtering the MESH' # ~~> GEO file: MESH coordinates self.slfn.MESHX = np.zeros(self.slfn.NPOIN3, dtype=np.float32) self.slfn.MESHY = np.zeros(self.slfn.NPOIN3, dtype=np.float32) self.slfn.MESHX = self.slf.MESHX[KNOLG[part]] self.slfn.MESHY = self.slf.MESHY[KNOLG[part]] # ~~> GEO file: File names fileRoot, fileExts = path.splitext(self.slf.fileName) self.slfn.fileName = fileRoot + fmtn + '-' + fmti + fileExts # ~~> GEO file: Printing print ' ~> printing: ', self.slfn.fileName self.slfn.fole = open(self.slfn.fileName, 'wb') putHeaderSLF(self.slfn) LVARSOR = np.zeros((self.slfn.NVAR, self.slfn.NPOIN3), dtype=np.float32) for t in range(len(self.slf.tags['times'])): appendCoreTimeSLF(self.slfn, t) VARSOR = self.slf.getVALUES(t) for v in range(self.slfn.NVAR): LVARSOR[v] = VARSOR[v][KNOLG[part]] appendCoreVarsSLF(self.slfn, LVARSOR) self.slfn.fole.close() if not self.isCONLIM: return print '\n... Connect elements across internal boundaries (IFAPAR)' for part in range(self.NPARTS): print ' +> part ', part + 1, ' of ', self.NPARTS # ~~> CONLIM file: Preliminary set up of PEHALO elements accross internal boundaries PEHALO = {} SEHALO = {} # Step 1: find out about the primary elements and loop through IKLE self.NSPLIT *= 0 MASKER = NPTIR[part].keys() self.NSPLIT[MASKER] += 1 print ' ~> Assembling primary elements with other side' # Sub Step 1: Assembling all edges from the other sides maxbar = 0 ibar = 0 for ip in range(self.NPARTS): maxbar += len(LIKLE[ip]) pbar = ProgressBar(maxval=maxbar).start() for otherpart in range(self.NPARTS): if otherpart == part: continue # all parts are still positive at this stage for k in range(len(LIKLE[otherpart])): ibar += 1 e = self.slf.IKLE[KELLG[otherpart][k]] if np.count_nonzero(self.NSPLIT[e]) < 2: continue for p1, p2 in zip([1, 2, 0], [ 0, 1, 2 ]): # reverse order because looking from the other side if self.NSPLIT[e[p1]] > 0 and self.NSPLIT[e[p2]] > 0: if not PEHALO.has_key((e[p1], e[p2])): PEHALO.update({(e[p1], e[p2]): [0, []]}) PEHALO[(e[p1], e[p2])][1].append(k) PEHALO[(e[p1], e[p2])][1].append(otherpart) pbar.update(ibar) # Sub Step 2: Assembling all edges from the primary side (there are three times more of them) for k in range(len(LIKLE[part])): ibar += 1 j = KELLG[part][k] e = self.slf.IKLE[j] if np.count_nonzero(self.NSPLIT[e]) < 2: continue for p1, p2, p3 in zip([0, 1, 2], [1, 2, 0], [2, 0, 1]): if self.NSPLIT[e[p1]] > 0 and self.NSPLIT[e[p2]] > 0: if PEHALO.has_key( (e[p1], e[p2])): # the good side opposes the dark side PEHALO[(e[p1], e[p2])][0] = k if self.NSPLIT[e[p3]] == 0: self.NSPLIT[e[p3]] = -1 if self.NSPLIT[e[p3]] == -1: if not SEHALO.has_key((e[p1], e[p3])): SEHALO.update({(e[p1], e[p3]): []}) SEHALO[(e[p1], e[p3])].append(k) if not SEHALO.has_key((e[p2], e[p3])): SEHALO.update({(e[p2], e[p3]): []}) SEHALO[(e[p2], e[p3])].append(k) else: # self.NSPLIT[e[p3]] must be 2 ! if not SEHALO.has_key((e[p3], e[p1])): SEHALO.update({(e[p3], e[p1]): []}) if k not in SEHALO[(e[p3], e[p1])]: SEHALO[(e[p3], e[p1])].append(k) if not SEHALO.has_key((e[p2], e[p3])): SEHALO.update({(e[p2], e[p3]): []}) if k not in SEHALO[(e[p2], e[p3])]: SEHALO[(e[p2], e[p3])].append(k) if self.KSPLIT[j] >= 0: self.KSPLIT[j] = -( self.KSPLIT[j] + 1 ) # /!\ This is very dangerous but necessary pbar.update(ibar) pbar.finish() # Sub Step 3: Final clean up of the other side ? no need but check later for (ei)[0] == 0 # Step 2: find out about the secondary elements on IKLE ( local LIKLE ? ) print ' ~> Assembling secondary elements of that side' pbar = ProgressBar(maxval=len(LIKLE[part])).start() for k in range(len(LIKLE[part])): j = KELLG[part][k] e = self.slf.IKLE[j] if self.KSPLIT[j] != part: continue if np.count_nonzero(self.NSPLIT[e]) < 2: continue for i in [0, 1, 2]: ii = (i + 1) % 3 if self.NSPLIT[e[i]] > 0 and self.NSPLIT[ e[ii]] < 0 and SEHALO.has_key((e[i], e[ii])): SEHALO[(e[i], e[ii])].append(k) # correct orientation if self.NSPLIT[e[i]] > 0 and self.NSPLIT[ e[ii]] > 0 and SEHALO.has_key((e[ii], e[i])): SEHALO[(e[ii], e[i])].append(k) # opposite orientation ii = (i + 2) % 3 if self.NSPLIT[e[i]] > 0 and self.NSPLIT[ e[ii]] < 0 and SEHALO.has_key((e[i], e[ii])): SEHALO[(e[i], e[ii])].append(k) # correct orientation if self.NSPLIT[e[i]] > 0 and self.NSPLIT[ e[ii]] > 0 and SEHALO.has_key((e[i], e[ii])): SEHALO[(e[i], e[ii])].append(k) # opposite orientation if self.KSPLIT[j] < 0: self.KSPLIT[ j] = -self.KSPLIT[j] - 1 # /!\ back to a safe place pbar.update(k) pbar.finish() # Step 3: finally cross reference information between SEHALO and PEHALO print ' ~> Combining sides surrounding the halo-elements' for ie in PEHALO.keys(): if PEHALO[ie][0] == 0: continue k = PEHALO[ie][0] # element number in its local part numbering if not IFAPAR[part].has_key(k): IFAPAR[part].update({k: [-2, -1, -2, -1, -2, -1]}) j = KELLG[part][k] e = self.slf.IKLE[j] for p1, p2 in zip([0, 1, 2], [1, 2, 0]): if SEHALO.has_key((e[p1], e[p2])): if len(SEHALO[(e[p1], e[p2])]) > 1: if SEHALO[(e[p1], e[p2])][0] == k: IFAPAR[part][k][2 * p1] = SEHALO[(e[p1], e[p2])][1] if SEHALO[(e[p1], e[p2])][1] == k: IFAPAR[part][k][2 * p1] = SEHALO[(e[p1], e[p2])][0] IFAPAR[part][k][1 + 2 * p1] = part if SEHALO.has_key((e[p2], e[p1])): if len(SEHALO[(e[p2], e[p1])]) > 1: if SEHALO[(e[p2], e[p1])][0] == k: IFAPAR[part][k][2 * p1] = SEHALO[(e[p2], e[p1])][1] if SEHALO[(e[p2], e[p1])][1] == k: IFAPAR[part][k][2 * p1] = SEHALO[(e[p2], e[p1])][0] IFAPAR[part][k][1 + 2 * p1] = part if ie == (e[p1], e[p2]): IFAPAR[part][k][2 * p1] = PEHALO[ie][1][0] IFAPAR[part][k][1 + 2 * p1] = PEHALO[ie][1][1] # ~~> CONLIM file: Write to file ... pfuuuuuh ... this is it ! print '\n... Split of the CONLIM files' for part in range(self.NPARTS): fmti = '00000' + str(part) fmti = fmti[len(fmti) - 5:] print ' +> part: ', part + 1, ' of ', self.NPARTS # ~~> CONLIM file: Set the filter INDEX = np.zeros_like(self.clm.INDEX, dtype=np.int) for contour in polyFILTER[part]: # ~~> Closed contour: no need to change ISEG if contour[0] == contour[len(contour) - 1]: for c in contour[1:]: INDEX[self.clm.KFRGL[c]] = self.clm.KFRGL[c] + 1 # ~~> Open contour: need to change ISEG with neighbours else: for c in contour[0:]: INDEX[self.clm.KFRGL[c]] = self.clm.KFRGL[c] + 1 iA = self.clm.KFRGL[contour[0]] self.clm.POR['is'][iA] = ISEG[contour[0]][part] self.clm.POR['xs'][iA] = self.slf.MESHX[abs( ISEG[contour[0]][part]) - 1] # /!\ MESHX start at 0 self.clm.POR['ys'][iA] = self.slf.MESHY[abs( ISEG[contour[0]][part]) - 1] # /!\ MESHY start at 0 iA = self.clm.KFRGL[contour[len(contour) - 1]] self.clm.POR['is'][iA] = ISEG[contour[len(contour) - 1]][part] self.clm.POR['xs'][iA] = self.slf.MESHX[ abs(ISEG[contour[len(contour) - 1]][part]) - 1] self.clm.POR['ys'][iA] = self.slf.MESHY[ abs(ISEG[contour[len(contour) - 1]][part]) - 1] self.clm.INDEX = INDEX # ~~> CONLIM file: Set the NPTIR and CUTs self.clm.NPTIR = NPTIR[part] # ~~> CONLIM file: Set the IFAPAR self.clm.IFAPAR = IFAPAR[part] # ~~> CONLIM file fileRoot, fileExts = path.splitext(self.clm.fileName) print ' ~> printing: ', fileRoot + fmtn + '-' + fmti + fileExts self.clm.putContent(fileRoot + fmtn + '-' + fmti + fileExts) return