Source code for PyNucleus_multilevelSolver.geometricMG
###################################################################################
# Copyright 2021 National Technology & Engineering Solutions of Sandia, #
# LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the #
# U.S. Government retains certain rights in this software. #
# If you want to use this code, please refer to the README.rst and LICENSE files. #
###################################################################################
from __future__ import division
import logging
import numpy as np
from PyNucleus_base import INDEX, uninitialized
from PyNucleus_base.linear_operators import LinearOperator
LOGGER = logging.getLogger(__name__)
[docs]
def paramsForSerialMG(noRef, global_params):
symmetric = global_params.get('symmetric', False)
hierarchies = [
{'label': 'fine',
'ranks': set([0]),
'connectorStart': 'input',
'connectorEnd': None,
'params': {'noRef': noRef,
'keepMeshes': 'all' if global_params.get('keepMeshes', False) else 'none',
'keepAllDoFMaps': global_params.get('keepAllDoFMaps', False),
'assemble': 'all',
'symmetric': symmetric,
'solver': 'Chol' if symmetric else 'LU'
}
}]
connectors = {}
return hierarchies, connectors
[docs]
def paramsForMG(noRef, onRanks, global_params, manifold_dim, element, repartitionFactor=0.05,
max_coarse_grid_size=4500):
from . connectors import repartitionConnector
numProcsAvail = len(onRanks)
onRanks = np.array(list(onRanks), dtype=INDEX)
if manifold_dim == 1:
numInitialCells = 2
if element in ('P1', 1):
cells2dofsFactor = 1
elif element in ('P2', 2):
cells2dofsFactor = 2
elif element in ('P3', 3):
cells2dofsFactor = 3
else:
raise NotImplementedError()
elif manifold_dim == 2:
numInitialCells = 8
if element in ('P1', 1):
cells2dofsFactor = 0.5
elif element in ('P2', 2):
cells2dofsFactor = 2
elif element in ('P3', 3):
cells2dofsFactor = 4.5
else:
raise NotImplementedError()
elif manifold_dim == 3:
numInitialCells = 48
if element in ('P1', 1):
cells2dofsFactor = 1./6.
elif element in ('P2', 2):
cells2dofsFactor = 1.35
elif element in ('P3', 3):
cells2dofsFactor = 4.5
else:
raise NotImplementedError()
else:
raise NotImplementedError()
uniformRefinementMutiplier = 2**manifold_dim
numCells = numInitialCells * uniformRefinementMutiplier**np.arange(noRef+1)
cg = 0
while numCells[cg+1]*cells2dofsFactor < max_coarse_grid_size and cg < noRef-1:
cg += 1
cellsPerProc = numCells[-1]/numProcsAvail
numProcs = uninitialized((noRef+1), dtype=int)
numProcs[-1] = numProcsAvail
numProcs[:cg+1] = 1
for i in range(noRef-1, cg, -1):
if numCells[i]/numProcs[i+1] < repartitionFactor * cellsPerProc:
numProcs[i] = int(np.ceil(numCells[i]/cellsPerProc))
else:
numProcs[i] = numProcs[i+1]
buildMass = global_params.get('buildMass', False)
symmetric = global_params.get('symmetric', False)
reaction = global_params.get('reaction', None)
hierarchies = [
{'label': 'seed',
'ranks': set([onRanks[0]]),
'connectorStart': 'input',
'connectorEnd': None,
'params': {'noRef': cg,
'keepMeshes': 'all' if global_params.get('keepMeshes', False) else 'none',
'assemble': 'all',
'symmetric': symmetric,
'reaction': reaction,
'buildMass': buildMass,
'element': element,
'solver': 'Chol' if symmetric else 'LU',
'solver_params': {}
}
}]
lvl = cg+1
hierarchies.append({'label': str(len(hierarchies)),
'ranks': set(onRanks[range(0, numProcs[lvl])]),
'connectorStart': None,
'connectorEnd': None,
'params': {'noRef': 1,
'keepMeshes': 'all' if global_params.get('keepMeshes', False) else 'last',
'assemble': 'all',
'symmetric': symmetric,
'reaction': reaction,
'buildMass': buildMass,
'element': element,
'solver': 'MG',
'solver_params': {
'maxIter': 1,
'tolerance': 0.,
},
}
})
lvl += 1
while lvl < noRef:
if numProcs[lvl] == numProcs[lvl-1]:
hierarchies[-1]['params']['noRef'] += 1
else:
hierarchies.append({'label': str(len(hierarchies)),
'ranks': set(onRanks[range(0, numProcs[lvl])]),
'connectorStart': None,
'connectorEnd': None,
'params': {'noRef': 1,
'keepMeshes': 'all' if global_params.get('keepMeshes', False) else 'last',
'assemble': 'all',
'symmetric': symmetric,
'reaction': reaction,
'buildMass': buildMass,
'element': element,
'solver': 'MG',
'solver_params': {
'maxIter': 1,
'tolerance': 0.,
},
}
})
lvl += 1
if 'tag' in global_params:
for i in range(len(hierarchies)):
h = hierarchies[i]
h['params']['tag'] = global_params['tag']
connectors = {}
for i in range(1, len(hierarchies)):
label = 'breakUp_' + hierarchies[i-1]['label'] + ':' + hierarchies[i]['label']
connectors[label] = {'type': repartitionConnector,
'params': {'partitionerType': global_params.get('coarsePartitioner', global_params.get('partitioner', 'regular')),
'partitionerParams': global_params.get('coarsePartitionerParams', global_params.get('partitionerParams', {})),
'debugOverlaps': global_params.get('debugOverlaps', False)}}
hierarchies[i-1]['connectorEnd'] = label
hierarchies[i]['connectorStart'] = label
return hierarchies, connectors
[docs]
def writeToHDF(filename, levels, mesh):
import h5py
f = h5py.File(filename, 'w')
for i, lvl in enumerate(levels):
for key in lvl:
if key in ('P', 'R', 'A', 'mesh'):
val = lvl[key]
grp = f.create_group(str(i) + '/' + key)
val.HDF5write(grp)
if 'mesh' not in f[str(i)]:
grp = f.create_group(str(i) + '/' + 'mesh')
mesh.HDF5write(grp)
f.flush()
f.close()
[docs]
def readFromHDF(filename):
import h5py
f = h5py.File(filename, 'r')
LOGGER.info('Reading hierarchy from {}'.format(filename))
maxLvl = 0
for lvl in f:
maxLvl = max(maxLvl, int(lvl))
levels = [{} for i in range(maxLvl+1)]
for lvl in f:
for key in f[lvl]:
if key in ('P', 'R', 'A'):
levels[int(lvl)][key] = LinearOperator.HDF5read(f[lvl + '/' + key])
return levels