Changed how default PML parameters are used

这个提交包含在:
Craig Warren
2022-11-10 14:06:00 +00:00
父节点 4e2079db59
当前提交 8de75446d0
共有 10 个文件被更改,包括 129 次插入132 次删除

查看文件

@@ -28,9 +28,8 @@ from .cmds_multiuse import (PMLCFS, AddDebyeDispersion, AddDrudeDispersion,
Material, Rx, RxArray, Snapshot, SoilPeplinski,
TransmissionLine, VoltageSource, Waveform)
from .cmds_singleuse import (Discretisation, Domain, ExcitationFile,
OMPThreads, PMLCells, PMLFormulation,
RxSteps, SrcSteps, TimeStepStabilityFactor,
TimeWindow, Title)
OMPThreads, PMLProps, RxSteps, SrcSteps,
TimeStepStabilityFactor, TimeWindow, Title)
from .gprMax import run as run
from .hash_cmds_file import user_libs_fn_to_scene_obj
from .scene import Scene

查看文件

@@ -106,16 +106,16 @@ class Domain(UserObjectSingle):
# Calculate time step at CFL limit; switch off appropriate PMLs for 2D
if G.nx == 1:
config.get_model_config().mode = '2D TMx'
G.pmlthickness['x0'] = 0
G.pmlthickness['xmax'] = 0
G.pmls['thickness']['x0'] = 0
G.pmls['thickness']['xmax'] = 0
elif G.ny == 1:
config.get_model_config().mode = '2D TMy'
G.pmlthickness['y0'] = 0
G.pmlthickness['ymax'] = 0
G.pmls['thickness']['y0'] = 0
G.pmls['thickness']['ymax'] = 0
elif G.nz == 1:
config.get_model_config().mode = '2D TMz'
G.pmlthickness['z0'] = 0
G.pmlthickness['zmax'] = 0
G.pmls['thickness']['z0'] = 0
G.pmls['thickness']['zmax'] = 0
else:
config.get_model_config().mode = '3D'
G.calculate_dt()
@@ -261,11 +261,15 @@ class TimeStepStabilityFactor(UserObjectSingle):
logger.info(f'Time step (modified): {G.dt:g} secs')
class PMLFormulation(UserObjectSingle):
"""Specifies the formulation (type) of the PML to be used.
class PMLProps(UserObjectSingle):
"""Specifies the formulation used, and controls the number of cells
(thickness) of PML that are used on the six sides of the model domain.
Attributes:
pml: string specifying formulation of PML.
formulation: string specifying formulation to be used for all PMLs.
thickness or x0, y0, z0, xmax, ymax, zmax: ints for thickness of PML
on all 6 sides or individual
sides of the model domain.
"""
def __init__(self, **kwargs):
@@ -274,58 +278,40 @@ class PMLFormulation(UserObjectSingle):
def create(self, G, uip):
try:
pml = self.kwargs['pml']
formulation = self.kwargs['formulation']
except KeyError:
logger.exception(self.__str__() + ' requires exactly one parameter ' +
'to specify the formulation of PML to use')
logger.exception(self.__str__() + ' requires the formulation of PML to use')
raise
if pml not in PML.formulations:
if formulation not in PML.formulations:
logger.exception(self.__str__() + f" requires the value to be one " +
f"of {' '.join(PML.formulations)}")
raise ValueError
G.pmlformulation = pml
G.pmls['formulation'] = formulation
class PMLCells(UserObjectSingle):
"""Controls the number of cells (thickness) of PML that are used on the six
sides of the model domain. Specify either single thickness or thickness
on each side.
Attributes:
thickness: int for thickness of PML on all 6 sides.
x0, y0, z0, xmax, ymax, zmax: ints of thickness of PML on individual
sides of the model domain.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.order = 9
def create(self, G, uip):
try:
thickness = self.kwargs['thickness']
for key in G.pmlthickness.keys():
G.pmlthickness[key] = int(thickness)
for key in G.pmls['thickness'].keys():
G.pmls['thickness'][key] = int(thickness)
except KeyError:
try:
G.pmlthickness['x0'] = int(self.kwargs['x0'])
G.pmlthickness['y0'] = int(self.kwargs['y0'])
G.pmlthickness['z0'] = int(self.kwargs['z0'])
G.pmlthickness['xmax'] = int(self.kwargs['xmax'])
G.pmlthickness['ymax'] = int(self.kwargs['ymax'])
G.pmlthickness['zmax'] = int(self.kwargs['zmax'])
G.pmls['thickness']['x0'] = int(self.kwargs['x0'])
G.pmls['thickness']['y0'] = int(self.kwargs['y0'])
G.pmls['thickness']['z0'] = int(self.kwargs['z0'])
G.pmls['thickness']['xmax'] = int(self.kwargs['xmax'])
G.pmls['thickness']['ymax'] = int(self.kwargs['ymax'])
G.pmls['thickness']['zmax'] = int(self.kwargs['zmax'])
except KeyError:
logger.exception(self.__str__() + ' requires either one or six parameter(s)')
raise
if (2 * G.pmlthickness['x0'] >= G.nx or
2 * G.pmlthickness['y0'] >= G.ny or
2 * G.pmlthickness['z0'] >= G.nz or
2 * G.pmlthickness['xmax'] >= G.nx or
2 * G.pmlthickness['ymax'] >= G.ny or
2 * G.pmlthickness['zmax'] >= G.nz):
if (2 * G.pmls['thickness']['x0'] >= G.nx or
2 * G.pmls['thickness']['y0'] >= G.ny or
2 * G.pmls['thickness']['z0'] >= G.nz or
2 * G.pmls['thickness']['xmax'] >= G.nx or
2 * G.pmls['thickness']['ymax'] >= G.ny or
2 * G.pmls['thickness']['zmax'] >= G.nz):
logger.exception(self.__str__() + ' has too many cells for the domain size')
raise ValueError
@@ -339,7 +325,7 @@ class SrcSteps(UserObjectSingle):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.order = 10
self.order = 9
def create(self, G, uip):
try:
@@ -362,7 +348,7 @@ class RxSteps(UserObjectSingle):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.order = 11
self.order = 10
def create(self, G, uip):
try:
@@ -389,7 +375,7 @@ class ExcitationFile(UserObjectSingle):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.order = 12
self.order = 11
def create(self, G, uip):
try:
@@ -473,7 +459,7 @@ class OutputDir(UserObjectSingle):
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.order = 13
self.order = 12
def create(self, grid, uip):
config.get_model_config().set_output_file_path(self.kwargs['dir'])
@@ -488,7 +474,7 @@ class NumberOfModelRuns(UserObjectSingle):
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.order = 14
self.order = 13
def create(self, grid, uip):
try:

查看文件

@@ -150,7 +150,7 @@ def write_grid(basegrp, G, is_subgrid=False):
# Write additional meta data about subgrid
basegrp.attrs['is_os_sep'] = G.is_os_sep
basegrp.attrs['pml_separation'] = G.pml_separation
basegrp.attrs['subgrid_pml_thickness'] = G.pmlthickness['x0']
basegrp.attrs['subgrid_pml_thickness'] = G.pml['thickness']['x0']
basegrp.attrs['filter'] = G.filter
basegrp.attrs['ratio'] = G.ratio
basegrp.attrs['interpolation'] = G.interpolation

查看文件

@@ -16,13 +16,6 @@
# You should have received a copy of the GNU General Public License
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
# TODO
# subgrids geometry export
# user specifies subgrid in main grid coordinates
# if grid.pmlthickness['x0'] - self.geoview.vtk_xscells > 0:
# if dx not 1 this above will break - fix
import json
import logging
import sys
@@ -288,7 +281,7 @@ class Comments():
# Write information on PMLs, sources, and receivers
if not self.materials_only:
# Information on PML thickness
if self.grid.pmls:
if self.grid.pmls['slabs']:
comments['PMLthickness'] = self.pml_gv_comment()
srcs = self.grid.get_srcs()
if srcs:
@@ -303,21 +296,21 @@ class Comments():
grid = self.grid
# Only render PMLs if they are in the geometry view
pmlstorender = dict.fromkeys(grid.pmlthickness, 0)
pmlstorender = dict.fromkeys(grid.pmls['thickness'], 0)
# Casting to int required as json does not handle numpy types
if grid.pmlthickness['x0'] - self.gv.xs > 0:
pmlstorender['x0'] = int(grid.pmlthickness['x0'] - self.gv.xs)
if grid.pmlthickness['y0'] - self.gv.ys > 0:
pmlstorender['y0'] = int(grid.pmlthickness['y0'] - self.gv.ys)
if grid.pmlthickness['z0'] - self.gv.zs > 0:
pmlstorender['z0'] = int(grid.pmlthickness['z0'] - self.gv.zs)
if self.gv.xf > grid.nx - grid.pmlthickness['xmax']:
pmlstorender['xmax'] = int(self.gv.xf - (grid.nx - grid.pmlthickness['xmax']))
if self.gv.yf > grid.ny - grid.pmlthickness['ymax']:
pmlstorender['ymax'] = int(self.gv.yf - (grid.ny - grid.pmlthickness['ymax']))
if self.gv.zf > grid.nz - grid.pmlthickness['zmax']:
pmlstorender['zmax'] = int(self.gv.zf - (grid.nz - grid.pmlthickness['zmax']))
if grid.pmls['thickness']['x0'] - self.gv.xs > 0:
pmlstorender['x0'] = int(grid.pmls['thickness']['x0'] - self.gv.xs)
if grid.pmls['thickness']['y0'] - self.gv.ys > 0:
pmlstorender['y0'] = int(grid.pmls['thickness']['y0'] - self.gv.ys)
if grid.pmls['thickness']['z0'] - self.gv.zs > 0:
pmlstorender['z0'] = int(grid.pmls['thickness']['z0'] - self.gv.zs)
if self.gv.xf > grid.nx - grid.pmls['thickness']['xmax']:
pmlstorender['xmax'] = int(self.gv.xf - (grid.nx - grid.pmls['thickness']['xmax']))
if self.gv.yf > grid.ny - grid.pmls['thickness']['ymax']:
pmlstorender['ymax'] = int(self.gv.yf - (grid.ny - grid.pmls['thickness']['ymax']))
if self.gv.zf > grid.nz - grid.pmls['thickness']['zmax']:
pmlstorender['zmax'] = int(self.gv.zf - (grid.nz - grid.pmls['thickness']['zmax']))
return list(pmlstorender.values())

查看文件

@@ -50,16 +50,17 @@ class FDTDGrid:
self.iterations = 0
self.timewindow = 0
self.pmls = {}
self.pmls['formulation'] = None
self.pmls['cfs'] = []
self.pmls['slabs'] = []
# Ordered dictionary required so that PMLs are always updated in the
# same order. The order itself does not matter, however, if must be the
# same from model to model otherwise the numerical precision from adding
# the PML corrections will be different.
self.pmlthickness = OrderedDict((key, 10) for key in PML.boundaryIDs)
# Default PML CFS parameters will be used if none are provided by user.
self.cfs = []
self.pmls = []
self.pmlformulation = 'HORIPML'
self.pmls['thickness'] = OrderedDict((key, None) for key in PML.boundaryIDs)
self.materials = []
self.mixingmodels = []
self.averagevolumeobjects = True
@@ -112,12 +113,12 @@ class FDTDGrid:
return p_r
def within_pml(self, p):
if (p[0] < self.pmlthickness['x0'] or
p[0] > self.nx - self.pmlthickness['xmax'] or
p[1] < self.pmlthickness['y0'] or
p[1] > self.ny - self.pmlthickness['ymax'] or
p[2] < self.pmlthickness['z0'] or
p[2] > self.nz - self.pmlthickness['zmax']):
if (p[0] < self.pmls['thickness']['x0'] or
p[0] > self.nx - self.pmls['thickness']['xmax'] or
p[1] < self.pmls['thickness']['y0'] or
p[1] > self.ny - self.pmls['thickness']['ymax'] or
p[2] < self.pmls['thickness']['z0'] or
p[2] > self.nz - self.pmls['thickness']['zmax']):
return True
else:
return False
@@ -185,7 +186,7 @@ class FDTDGrid:
self.initialise_dispersive_arrays()
# Clear arrays for fields in PML
for pml in self.pmls:
for pml in self.pmls['slabs']:
pml.initialise_field_arrays()
def mem_est_basic(self):
@@ -206,7 +207,7 @@ class FDTDGrid:
# PML arrays
pmlarrays = 0
for (k, v) in self.pmlthickness.items():
for (k, v) in self.pmls['thickness'].items():
if v > 0:
if 'x' in k:
pmlarrays += ((v + 1) * self.ny * (self.nz + 1))

查看文件

@@ -19,7 +19,7 @@
import logging
from .cmds_singleuse import (Discretisation, Domain, ExcitationFile,
OMPThreads, OutputDir, PMLCells, RxSteps,
OMPThreads, OutputDir, PMLProps, RxSteps,
SrcSteps, TimeStepStabilityFactor, TimeWindow,
Title)
@@ -117,9 +117,9 @@ def process_singlecmds(singlecmds):
logger.exception(cmd + ' requires either one or six parameter(s)')
raise ValueError
if len(tmp) == 1:
pml_cells = PMLCells(thickness=int(tmp[0]))
pml_cells = PMLProps(thickness=int(tmp[0]))
else:
pml_cells = PMLCells(x0=int(tmp[0]),
pml_cells = PMLProps(x0=int(tmp[0]),
y0=int(tmp[1]),
z0=int(tmp[2]),
xmax=int(tmp[3]),

查看文件

@@ -39,7 +39,7 @@ from .geometry_outputs import save_geometry_views
from .grid import dispersion_analysis
from .hash_cmds_file import parse_hash_commands
from .materials import process_materials
from .pml import build_pml, print_pml_info
from .pml import build_pml, print_pml_info, set_pml_defaults
from .scene import Scene
from .utilities.host_info import mem_check_all, set_omp_threads
from .utilities.utilities import get_terminal_width, human_size
@@ -137,10 +137,12 @@ class ModelBuildRun:
# Combine available grids
grids = [G] + G.subgrids
# Check for dispersive materials and specific type
# Check for dispersive materials (and specific type) and set PML
# defaults (must be done before memory checks)
for grid in grids:
if config.get_model_config().materials['maxpoles'] != 0:
config.get_model_config().materials['drudelorentz'] = any([m for m in grid.materials if 'drude' in m.type or 'lorentz' in m.type])
set_pml_defaults(grid)
# Set data type if any dispersive materials (must be done before memory checks)
if config.get_model_config().materials['maxpoles'] != 0:
@@ -156,7 +158,7 @@ class ModelBuildRun:
gridbuilders = [GridBuilder(grid) for grid in grids]
for gb in gridbuilders:
logger.info(print_pml_info(gb.grid))
if not all(value == 0 for value in gb.grid.pmlthickness.values()):
if not all(value == 0 for value in gb.grid.pmls['thickness'].values()):
gb.build_pmls()
gb.build_components()
gb.tm_grid_update()
@@ -327,11 +329,11 @@ class GridBuilder:
self.grid = grid
def build_pmls(self):
pbar = tqdm(total=sum(1 for value in self.grid.pmlthickness.values() if value > 0),
pbar = tqdm(total=sum(1 for value in self.grid.pmls['thickness'].values() if value > 0),
desc=f'Building PML boundaries [{self.grid.name}]',
ncols=get_terminal_width() - 1, file=sys.stdout,
disable=not config.sim_config.general['progressbars'])
for pml_id, thickness in self.grid.pmlthickness.items():
for pml_id, thickness in self.grid.pmls['thickness'].items():
if thickness > 0:
build_pml(self.grid, pml_id, thickness)
pbar.update()

查看文件

@@ -16,11 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with gprMax. If not, see <http://www.gnu.org/licenses/>.
from collections import OrderedDict
from importlib import import_module
import gprMax.config as config
import numpy as np
import gprMax.config as config
class CFSParameter:
"""Individual CFS parameter (e.g. alpha, kappa, or sigma)."""
@@ -213,10 +215,7 @@ class PML:
self.d = self.G.dz
self.thickness = self.nz
if not self.G.cfs:
self.CFS = [CFS()]
else:
self.CFS = self.G.cfs
self.CFS = []
self.initialise_field_arrays()
@@ -571,26 +570,43 @@ class OpenCLPML(PML):
event.wait()
def set_pml_defaults(G):
"""Set default parameters for PMLs if not provided by user.
Args:
G: FDTDGrid class describing a grid in a model.
"""
if not G.pmls['formulation']:
G.pmls['formulation'] = 'HORIPML'
if not all(G.pmls['thickness'].values()):
G.pmls['thickness'] = OrderedDict.fromkeys(G.pmls['thickness'], 10)
if not G.pmls['cfs']:
G.pmls['cfs'] = [CFS()]
def print_pml_info(G):
"""Information about PMLs.
"""Prints information about PMLs.
Args:
G: FDTDGrid class describing a grid in a model.
"""
# No PML
if all(value == 0 for value in G.pmlthickness.values()):
if all(value == 0 for value in G.pmls['thickness'].values()):
return f'\nPML boundaries [{G.name}]: switched off'
if all(value == G.pmlthickness['x0'] for value in G.pmlthickness.values()):
pmlinfo = str(G.pmlthickness['x0'])
if all(value == G.pmls['thickness']['x0'] for value in G.pmls['thickness'].values()):
pmlinfo = str(G.pmls['thickness']['x0'])
else:
pmlinfo = ''
for key, value in G.pmlthickness.items():
for key, value in G.pmls['thickness'].items():
pmlinfo += f'{key}: {value}, '
pmlinfo = pmlinfo[:-2]
return (f'\nPML boundaries [{G.name}]: {{formulation: {G.pmlformulation}, '
f'order: {len(G.cfs)}, thickness (cells): {pmlinfo}}}')
return (f"\nPML boundaries [{G.name}]: {{formulation: {G.pmls['formulation']}, "
f"order: {len(G.pmls['cfs'])}, thickness (cells): {pmlinfo}}}")
def build_pml(G, key, value):
@@ -621,7 +637,7 @@ def build_pml(G, key, value):
elif key == 'xmax':
pml = pml_type(G, ID=key, direction='xplus',
xs=G.nx - value, xf=G.nx, yf=G.ny, zf=G.nz)
G.pmls.append(pml)
G.pmls['slabs'].append(pml)
for j in range(G.ny):
for k in range(G.nz):
numID = G.solid[pml.xs, j, k]
@@ -638,7 +654,7 @@ def build_pml(G, key, value):
elif key == 'ymax':
pml = pml_type(G, ID=key, direction='yplus',
ys=G.ny - value, xf=G.nx, yf=G.ny, zf=G.nz)
G.pmls.append(pml)
G.pmls['slabs'].append(pml)
for i in range(G.nx):
for k in range(G.nz):
numID = G.solid[i, pml.ys, k]
@@ -655,7 +671,7 @@ def build_pml(G, key, value):
elif key == 'zmax':
pml = pml_type(G, ID=key, direction='zplus',
zs=G.nz - value, xf=G.nx, yf=G.ny, zf=G.nz)
G.pmls.append(pml)
G.pmls['slabs'].append(pml)
for i in range(G.nx):
for j in range(G.ny):
numID = G.solid[i, j, pml.zs]

查看文件

@@ -47,19 +47,19 @@ class SubGridBaseGrid(FDTDGrid):
# Distance from OS to PML or the edge of the grid when PML is off
self.pml_separation = kwargs['pml_separation']
self.pmlthickness['x0'] = kwargs['subgrid_pml_thickness']
self.pmlthickness['y0'] = kwargs['subgrid_pml_thickness']
self.pmlthickness['z0'] = kwargs['subgrid_pml_thickness']
self.pmlthickness['xmax'] = kwargs['subgrid_pml_thickness']
self.pmlthickness['ymax'] = kwargs['subgrid_pml_thickness']
self.pmlthickness['zmax'] = kwargs['subgrid_pml_thickness']
self.pmls['thickness']['x0'] = kwargs['subgrid_pml_thickness']
self.pmls['thickness']['y0'] = kwargs['subgrid_pml_thickness']
self.pmls['thickness']['z0'] = kwargs['subgrid_pml_thickness']
self.pmls['thickness']['xmax'] = kwargs['subgrid_pml_thickness']
self.pmls['thickness']['ymax'] = kwargs['subgrid_pml_thickness']
self.pmls['thickness']['zmax'] = kwargs['subgrid_pml_thickness']
# Number of sub cells to extend the sub grid beyond the IS boundary
d_to_pml = self.s_is_os_sep + self.pml_separation
# Index of the IS
self.n_boundary_cells = d_to_pml + self.pmlthickness['x0']
self.n_boundary_cells_x = d_to_pml + self.pmlthickness['x0']
self.n_boundary_cells_y = d_to_pml + self.pmlthickness['y0']
self.n_boundary_cells_z = d_to_pml + self.pmlthickness['z0']
self.n_boundary_cells = d_to_pml + self.pmls['thickness']['x0']
self.n_boundary_cells_x = d_to_pml + self.pmls['thickness']['x0']
self.n_boundary_cells_y = d_to_pml + self.pmls['thickness']['y0']
self.n_boundary_cells_z = d_to_pml + self.pmls['thickness']['z0']
self.interpolation = kwargs['interpolation']

查看文件

@@ -82,7 +82,7 @@ class CPUUpdates:
def update_magnetic_pml(self):
"""Update magnetic field components with the PML correction."""
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.update_magnetic()
def update_magnetic_sources(self):
@@ -136,7 +136,7 @@ class CPUUpdates:
def update_electric_pml(self):
"""Update electric field components with the PML correction."""
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.update_electric()
def update_electric_sources(self):
@@ -270,7 +270,7 @@ class CUDAUpdates:
# Initialise arrays on GPU, prepare kernels, and get kernel functions
self._set_macros()
self._set_field_knls()
if self.grid.pmls:
if self.grid.pmls['slabs']:
self._set_pml_knls()
if self.grid.rxs:
self._set_rx_knl()
@@ -394,7 +394,7 @@ class CUDAUpdates:
knl_pml_updates_magnetic = import_module('gprMax.cuda_opencl.knl_pml_updates_magnetic_' + self.grid.pmlformulation)
# Initialise arrays on GPU, set block per grid, and get kernel functions
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.htod_field_arrays()
pml.set_blocks_per_grid()
knl_name = 'order' + str(len(pml.CFS)) + '_' + pml.direction
@@ -570,7 +570,7 @@ class CUDAUpdates:
def update_magnetic_pml(self):
"""Update magnetic field components with the PML correction."""
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.update_magnetic()
def update_magnetic_sources(self):
@@ -631,7 +631,7 @@ class CUDAUpdates:
def update_electric_pml(self):
"""Update electric field components with the PML correction."""
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.update_electric()
def update_electric_sources(self):
@@ -776,7 +776,7 @@ class OpenCLUpdates:
# Initialise arrays on device, prepare kernels, and get kernel functions
self._set_field_knls()
if self.grid.pmls:
if self.grid.pmls['slabs']:
self._set_pml_knls()
if self.grid.rxs:
self._set_rx_knl()
@@ -895,7 +895,7 @@ class OpenCLUpdates:
# Set workgroup size, initialise arrays on compute device, and get
# kernel functions
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.set_queue(self.queue)
pml.htod_field_arrays()
knl_name = 'order' + str(len(pml.CFS)) + '_' + pml.direction
@@ -1040,7 +1040,7 @@ class OpenCLUpdates:
def update_magnetic_pml(self):
"""Update magnetic field components with the PML correction."""
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.update_magnetic()
def update_magnetic_sources(self):
@@ -1098,7 +1098,7 @@ class OpenCLUpdates:
def update_electric_pml(self):
"""Update electric field components with the PML correction."""
for pml in self.grid.pmls:
for pml in self.grid.pmls['slabs']:
pml.update_electric()
def update_electric_sources(self):