diff --git a/hysop/backend/host/python/operator/multiresolution_filter.py b/hysop/backend/host/python/operator/multiresolution_filter.py index 6ab6fdee6d7466e7e22a2cac6f0918af599994e1..6d7fba0412010eb997070bb3eb64774fe9e64aa2 100755 --- a/hysop/backend/host/python/operator/multiresolution_filter.py +++ b/hysop/backend/host/python/operator/multiresolution_filter.py @@ -11,8 +11,9 @@ from hysop.tools.decorators import debug class PythonMultiresolutionFilter(RedistributeOperatorBase): - """Interpolation between topologies when topology - differs only by global resolution + """ + Interpolation between topologies when topology + differs only by global resolution. Source and target must: *be CartesianTopology topologies with a target diff --git a/hysop/core/graph/computational_node.py b/hysop/core/graph/computational_node.py index d05ec1619e9064e7e9343af5a0f729ddae7fc1c5..833cbe66ec32e378c4a4a41979b283e2e5bb3e38 100644 --- a/hysop/core/graph/computational_node.py +++ b/hysop/core/graph/computational_node.py @@ -275,6 +275,20 @@ class ComputationalGraphNode(OperatorBase): """Return True if this node has no input nor output fields.""" return (not self.input_fields) and (not self.output_fields) is_domainless = property(_get_is_domainless) + + @classmethod + def expand_tensor_fields(fields): + scalar_fields = () + tensor_fields = () + for field in fields: + if (field is None): + scalar_fields += (None,) + elif field.is_tensor: + scalar_fields += field.fields + tensor_fields += (field,) + else: + scalar_fields += (field,) + return (scalar_fields, tensor_fields) @debug def _setup_method(self, topgraph_method): @@ -866,8 +880,8 @@ class ComputationalGraphNode(OperatorBase): @base_initialized def iter_output_fields(self, with_scalars=True, - with_tensors=True, - as_scalars=False): + with_tensors=True, + as_scalars=False): """ Iterate over all output fields. By default iterate over all tensors and scalars unless diff --git a/hysop/operator/base/spatial_filtering.py b/hysop/operator/base/spatial_filtering.py new file mode 100644 index 0000000000000000000000000000000000000000..f160158e53735f5d2f18bd0df3055f4521135ef2 --- /dev/null +++ b/hysop/operator/base/spatial_filtering.py @@ -0,0 +1,52 @@ +""" +@file advection.py +LowpassFilter operator generator. +""" +from hysop.constants import Implementation +from hysop.tools.types import check_instance, to_list, first_not_None +from hysop.tools.decorators import debug +from hysop.fields.continuous_field import Field +from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors +from hysop.parameters.scalar_parameter import ScalarParameter +from hysop.core.graph.node_generator import ComputationalGraphNodeGenerator +from hysop.core.graph.computational_node_fronted import ComputationalGraphNodeFrontend + + +class LowpassFilterBase(object): + """ + Base implementation for lowpass spatial filtering: small grid -> coarse grid + """ + + def __init__(self, input_field, output_field, + input_topo, output_topo, + **kwds): + + check_instance(input_field, ScalarField) + check_instance(output_field, ScalarField) + check_instance(input_topo, CartesianTopologyDescriptors) + check_instance(output_topo, CartesianTopologyDescriptors) + + super(LowpassFilterBase, self).__init__( + input_fields={input_field: input_topo}, + output_fields={output_field: output_topo}, + **kwds) + + self.Fin = input_field + self.Fout = output_field + + + @debug + def discretize(self): + if self.discretized: + return + super(LowpassFilterBase, self).discretize() + dFin = self.get_input_discrete_field(self.Fin) + dFout = self.get_output_discrete_field(self.Fout) + + import sys + sys.exit(1) + + self.dFin, self.dFout = dFin, dFout + + + diff --git a/hysop/operator/spatial_filtering.py b/hysop/operator/spatial_filtering.py new file mode 100644 index 0000000000000000000000000000000000000000..c9b79d3c612b59fa754d7341f6b75916ba86ae80 --- /dev/null +++ b/hysop/operator/spatial_filtering.py @@ -0,0 +1,153 @@ +""" +@file advection.py +LowpassFilter operator generator. +""" +from hysop.constants import Implementation +from hysop.tools.types import check_instance, to_list, first_not_None +from hysop.tools.decorators import debug +from hysop.fields.continuous_field import Field +from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors +from hysop.parameters.scalar_parameter import ScalarParameter +from hysop.core.graph.node_generator import ComputationalGraphNodeGenerator +from hysop.core.graph.computational_node_fronted import ComputationalGraphNodeFrontend + + +class LowpassFilterFrontend(ComputationalGraphNodeFrontend): + """ + Interface for lowpass spatial filtering: small grid -> coarse grid + Available implementations are: + *Python using remeshing kernels + """ + @classmethod + def implementations(cls): + from hysop.backend.host.python.operator.spatial_filtering import \ + PythonLowpassFilter + _implementations = { + Implementation.PYTHON: PythonLowpassFilter + } + return _implementations + + @classmethod + def default_implementation(cls): + return Implementation.PYTHON + + def __init__(self, input_variable, output_variable, + implementation=None, + base_kwds=None, + **kwds): + """ + Initialize a LowpassFilter operator. + + Parameters + ---------- + input_variable: ScalarField + Input field on fine grid as a tuple (ScalarField, CartesianTopologyDescriptor). + output_variable: ScalarField + Output field on coarse grid as a tuple (ScalarField, CartesianTopologyDescriptor). + implementation: implementation, optional, defaults to None + target implementation, should be contained in available_implementations(). + If None, implementation will be set to default_implementation(). + base_kwds: dict, optional, defaults to None + Base class keywords arguments. + If None, an empty dict will be passed. + kwds: + Extra parameters passed to generated operator. + + Notes + ----- + An implementation should at least support the LowpassFilterBase interface. + """ + check_instance(input_variable, tuple, size=2) + check_instance(output_variable, tuple, size=2) + input_field, input_topo = input_variable + output_field, output_topo = output_variable + + check_instance(input_field, ScalarField) + check_instance(output_field, ScalarField) + check_instance(input_topo, CartesianTopologyDescriptors) + check_instance(output_topo, CartesianTopologyDescriptors) + check_instance(base_kwds, dict, keys=str) + assert (input_topo != output_topo), "Same topology for input and output." + + super(LowpassFilterFrontend, self).__init__(input_field=input_field, input_topo=input_topo, + output_field=output_field, output_topo=output_topo, + implementation=implementation, base_kwds=base_kwds, **kwds) + + + +class LowpassFilter(ComputationalGraphNodeGenerator): + """ + Graphnode generator to lowpass filter multiple fields at once. + """ + @debug + def __init__(self, input_variables, output_variables=None, + implementation=None, + base_kwds=None, + **kwds): + """ + Initialize a LowpassFilter operator generator. + + Parameters + ---------- + intput_variables: dict + Input fields on fine grid. + Dictionary of continuous fields as keys and topologies as values. + output_variables: dict + Output fields on coarse grid, default to input_fields. + Dictionary of continuous fields as keys and topologies as values. + implementation: implementation, optional, defaults to None + target implementation, should be contained in available_implementations(). + If None, implementation will be set to default_implementation(). + base_kwds: dict, optional, defaults to None + Base class keywords arguments. + If None, an empty dict will be passed. + kwds: + Extra parameters passed to generated operators. + """ + input_fields = list(self.expand_tensor_fields(input_variables.keys())[0]) + assert len(set(input_fields)) == len(input_fields) + if (output_variables is None): + output_variables = input_variables + output_fields = list(self.expand_tensor_fields(output_variables.keys())[0]) + assert len(input_fields) == len(output_fields) + for i, field in enumerate(output_fields): + if (field is None): + output_fields[i] = input_fields[i] + + input_fields = tuple(input_fields) + output_fields = tuple(output_fields) + base_kwds = first_not_None(base_kwds, {}) + + check_instance(input_fields, tuple, values=ScalarField) + check_instance(output_fields, tuple, values=ScalarField) + check_instance(input_variables, dict, keys=Field, values=CartesianTopologyDescriptors) + check_instance(output_variables, dict, keys=Field, values=CartesianTopologyDescriptors) + check_instance(base_kwds, dict, keys=str) + + super(LowpassFilter, self).__init__(**base_kwds) + + self._input_fields = input_fields + self._output_fields = output_fields + self._input_variables = input_variables + self._output_variables = output_variables + self._impl = implementation + self._kwds = kwds + + @debug + def _generate(self): + nodes = [] + for (ifield, ofield) in zip(self._input_fields, self._output_fields): + stopo = self.get_topo_descriptor(self._input_variables, ifield) + ttopo = self.get_topo_descriptor(self._output_variables, ofield) + impl = self._impl + kwds = self._kwds.copy() + + # if source topology is destination topology there is nothing to be done + if (ttopo == stopo): + continue + + # else we build a lowpass filter operator + node = LowpassFilterFrontend(input_field=(ifield,stopo) output_field=(ofield,ttopo), + implementation=impl, **kwds) + nodes.append(node) + return nodes diff --git a/hysop/operators.py b/hysop/operators.py index 3399f0e45e0ce7eadff1856f73c463e294e02b7e..50cd5db0e1d7edec5cc3c0797396a432ae6e0ac4 100644 --- a/hysop/operators.py +++ b/hysop/operators.py @@ -23,10 +23,11 @@ from hysop.operator.integrate import Integrate from hysop.operator.penalization import PenalizeVorticity from hysop.operator.flowrate_correction import FlowRateCorrection from hysop.operator.vorticity_absorption import VorticityAbsorption -from hysop.operator.multiresolution_filter import MultiresolutionFilter from hysop.operator.dummy import Dummy from hysop.operator.custom import CustomOperator from hysop.operator.convergence import Convergence +from hysop.operator.multiresolution_filter import MultiresolutionFilter +from hysop.operator.spatial_filtering import LowpassFilter from hysop.operator.derivative import SpaceDerivative, \ SpectralSpaceDerivative, \