Changeset 15987
- Timestamp:
- 08/28/13 07:45:22 (12 years ago)
- Location:
- issm/trunk-jpl/src/m
- Files:
-
- 26 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk-jpl/src/m/boundaryconditions/SetMarineIceSheetBC.m
r15946 r15987 27 27 else 28 28 %Guess where the ice front is 29 vertexonfloatingice=zeros(md.mesh.numberofvertices,1); 30 vertexonfloatingice(md.mesh.elements(find(md.mask.elementonfloatingice),:))=1; 29 vertexonfloatingice=(md.mask.groundedice_levelset<0.); 31 30 vertexonicefront=double(md.mesh.vertexonboundary & vertexonfloatingice); 32 31 end … … 97 96 if (length(md.basalforcings.geothermalflux)~=md.mesh.numberofvertices), 98 97 md.basalforcings.geothermalflux=zeros(md.mesh.numberofvertices,1); 99 md.basalforcings.geothermalflux(find(md.mask. vertexongroundedice))=50.*10.^-3; %50mW/m298 md.basalforcings.geothermalflux(find(md.mask.groundedice_levelset>0.))=50.*10.^-3; %50mW/m2 100 99 end 101 100 else -
issm/trunk-jpl/src/m/boundaryconditions/SetMarineIceSheetBC.py
r15946 r15987 31 31 else: 32 32 #Guess where the ice front is 33 vertexonfloatingice=numpy.zeros((md.mesh.numberofvertices),bool) 34 vertexonfloatingice[md.mesh.elements[numpy.nonzero(md.mask.elementonfloatingice),:]-1]=True 33 vertexonfloatingice=numpy.logical(md.mask.groundedice_levelset<0.) 35 34 vertexonicefront=numpy.logical_and(md.mesh.vertexonboundary,vertexonfloatingice) 36 35 … … 104 103 if not isinstance(md.basalforcings.geothermalflux,numpy.ndarray) or not numpy.size(md.basalforcings.geothermalflux,axis=0)==md.mesh.numberofvertices: 105 104 md.basalforcings.geothermalflux=numpy.zeros((md.mesh.numberofvertices,1)) 106 md.basalforcings.geothermalflux[numpy.nonzero(md.mask. vertexongroundedice)]=50.*10.**-3 #50mW/m2105 md.basalforcings.geothermalflux[numpy.nonzero(md.mask.groundedice_levelset>0.)]=50.*10.**-3 #50mW/m2 107 106 else: 108 107 print " no thermal boundary conditions created: no observed temperature found" -
issm/trunk-jpl/src/m/classes/flowequation.m
r15924 r15987 104 104 if ismember(StressbalanceSIAAnalysisEnum(),analyses), 105 105 if any(obj.element_equation==1), 106 if(obj. element_equation & md.mask.elementonfloatingice),106 if(obj.vertex_equation & md.mask.groundedice_levelset<0.), 107 107 disp(sprintf('\n !!! Warning: SIA''s model is not consistent on ice shelves !!!\n')); 108 108 end -
issm/trunk-jpl/src/m/classes/flowequation.py
r15924 r15987 90 90 if StressbalanceSIAAnalysisEnum() in analyses: 91 91 if any(self.element_equation==1): 92 if numpy.any(numpy.logical_and(self. element_equation,md.mask.elementonfloatingice)):92 if numpy.any(numpy.logical_and(self.vertex_equation,md.mask.groundedice_levelset)): 93 93 print "\n !!! Warning: SIA's model is not consistent on ice shelves !!!\n" 94 94 -
issm/trunk-jpl/src/m/classes/groundingline.m
r15131 r15987 35 35 md = checkmessage(md,['requesting grounding line migration, but bathymetry is absent!']); 36 36 end 37 pos=find(md.mask. vertexongroundedice);37 pos=find(md.mask.groundedice_levelset>0.); 38 38 if any(abs(md.geometry.bed(pos)-md.geometry.bathymetry(pos))>10^-10), 39 39 md = checkmessage(md,['bathymetry not equal to bed on grounded ice!']); 40 40 end 41 pos=find(md.mask. vertexonfloatingice);41 pos=find(md.mask.groundedice_levelset<0.); 42 42 if any(md.geometry.bathymetry(pos)-md.geometry.bed(pos)>10^-9), 43 43 md = checkmessage(md,['bathymetry superior to bed on floating ice!']); -
issm/trunk-jpl/src/m/classes/groundingline.py
r15131 r15987 47 47 if numpy.any(numpy.isnan(md.geometry.bathymetry)): 48 48 md.checkmessage("requesting grounding line migration, but bathymetry is absent!") 49 pos=numpy.nonzero(md.mask. vertexongroundedice)49 pos=numpy.nonzero(md.mask.groundedice_levelset>0.) 50 50 if any(numpy.abs(md.geometry.bed[pos]-md.geometry.bathymetry[pos])>10**-10): 51 51 md.checkmessage("bathymetry not equal to bed on grounded ice!") 52 pos=numpy.nonzero(md.mask. vertexonfloatingice)52 pos=numpy.nonzero(md.mask.groundedice_levelset<0.) 53 53 if any(md.geometry.bathymetry[pos]-md.geometry.bed[pos]>10**-9): 54 54 md.checkmessage("bathymetry superior to bed on floating ice!") -
issm/trunk-jpl/src/m/classes/mask.m
r15986 r15987 6 6 classdef mask 7 7 properties (SetAccess=public) 8 elementonfloatingice = NaN;9 elementongroundedice = NaN;10 vertexonfloatingice = NaN;11 vertexongroundedice = NaN;12 vertexonrock = NaN;13 8 groundedice_levelset = NaN; 14 9 ice_levelset = NaN; … … 28 23 function md = checkconsistency(obj,md,solution,analyses) % {{{ 29 24 30 md = checkfield(md,'mask.elementonfloatingice','size',[md.mesh.numberofelements 1],'values',[0 1]);31 md = checkfield(md,'mask.elementongroundedice','size',[md.mesh.numberofelements 1],'values',[0 1]);32 md = checkfield(md,'mask.vertexonfloatingice' ,'size',[md.mesh.numberofvertices 1],'values',[0 1]);33 md = checkfield(md,'mask.vertexongroundedice' ,'size',[md.mesh.numberofvertices 1],'values',[0 1]);34 25 md = checkfield(md,'mask.groundedice_levelset','size',[md.mesh.numberofvertices 1]); 35 26 md = checkfield(md,'mask.ice_levelset' ,'size',[md.mesh.numberofvertices 1]); … … 38 29 error('elements with no ice not implemented yet, each element should have at least one vertex with md.mask.ice_levelset > 0'); 39 30 end 40 %md = checkfield(md,'mask.vertexonrock' ,'size',[md.mesh.numberofvertices 1],'values',[0 1]);41 31 end % }}} 42 32 function disp(obj) % {{{ 43 33 disp(sprintf(' masks:')); 44 34 45 fielddisplay(obj,'elementonfloatingice','element on floating ice flags list');46 fielddisplay(obj,'vertexonfloatingice','vertex on floating ice flags list');47 fielddisplay(obj,'elementongroundedice','element on grounded ice list');48 fielddisplay(obj,'vertexongroundedice','vertex on grounded ice flags list');49 fielddisplay(obj,'vertexonrock','vertex on rock flags list');50 35 fielddisplay(obj,'groundedice_levelset','is ice grounded ? grounded ice if > 0, grounding line position if = 0, floating ice if < 0'); 51 36 fielddisplay(obj,'ice_levelset','presence of ice if > 0, icefront position if = 0, no ice if < 0'); -
issm/trunk-jpl/src/m/classes/mask.py
r15986 r15987 13 13 14 14 def __init__(self): # {{{ 15 self.elementonfloatingice = float('NaN')16 self.elementongroundedice = float('NaN')17 self.vertexonfloatingice = float('NaN')18 self.vertexongroundedice = float('NaN')19 15 self.ice_levelset = float('NaN') 20 16 self.groundedice_levelset = float('NaN') … … 27 23 string=" masks:" 28 24 29 string="%s\n%s"%(string,fielddisplay(self,"elementonfloatingice","element on floating ice flags list"))30 string="%s\n%s"%(string,fielddisplay(self,"vertexonfloatingice","vertex on floating ice flags list"))31 string="%s\n%s"%(string,fielddisplay(self,"elementongroundedice","element on grounded ice list"))32 string="%s\n%s"%(string,fielddisplay(self,"vertexongroundedice","vertex on grounded ice flags list"))33 25 string="%s\n%s"%(string,fielddisplay(self,"groundedice_levelset","is ice grounded ? grounded ice if > 0, grounding line position if = 0, floating ice if < 0")) 34 26 string="%s\n%s"%(string,fielddisplay(self,"ice_levelset","presence of ice if > 0, icefront position if = 0, no ice if < 0")) … … 40 32 def checkconsistency(self,md,solution,analyses): # {{{ 41 33 42 md = checkfield(md,'mask.elementonfloatingice','size',[md.mesh.numberofelements],'values',[0,1])43 md = checkfield(md,'mask.elementongroundedice','size',[md.mesh.numberofelements],'values',[0,1])44 md = checkfield(md,'mask.vertexonfloatingice' ,'size',[md.mesh.numberofvertices],'values',[0,1])45 md = checkfield(md,'mask.vertexongroundedice' ,'size',[md.mesh.numberofvertices],'values',[0,1])46 md = checkfield(md,'mask.groundedice_levelset','size',[md.mesh.numberofvertices])47 34 md = checkfield(md,'mask.ice_levelset' ,'size',[md.mesh.numberofvertices]) 48 35 isice=numpy.array(md.mask.ice_levelset>0,int) -
issm/trunk-jpl/src/m/classes/model/model.m
r15957 r15987 209 209 md.mesh.vertexonboundary=project2d(md,md.mesh.vertexonboundary,1); 210 210 md.mesh.elementconnectivity=project2d(md,md.mesh.elementconnectivity,1); 211 md.mask.elementonfloatingice=project2d(md,md.mask.elementonfloatingice,1);212 md.mask.vertexonfloatingice=project2d(md,md.mask.vertexonfloatingice,1);213 md.mask.elementongroundedice=project2d(md,md.mask.elementongroundedice,1);214 md.mask.vertexongroundedice=project2d(md,md.mask.vertexongroundedice,1);215 if ~isnan(md.mask.vertexonrock)216 md.mask.vertexonrock=project2d(md,md.mask.vertexonrock,1);217 end218 211 md.mask.groundedice_levelset=project2d(md,md.mask.groundedice_levelset,1); 219 212 md.mask.ice_levelset=project2d(md,md.mask.ice_levelset,1); … … 264 257 % Examples: 265 258 % md2=extract(md,'Domain.exp'); 266 % md2=extract(md,md.mask.elementonfloatingice);267 259 % 268 260 % See also: EXTRUDE, COLLAPSE … … 738 730 md.geometry.bathymetry=project3d(md,'vector',md.geometry.bathymetry,'type','node'); 739 731 md.mesh.vertexonboundary=project3d(md,'vector',md.mesh.vertexonboundary,'type','node'); 740 md.mask.elementonfloatingice=project3d(md,'vector',md.mask.elementonfloatingice,'type','element');741 md.mask.vertexonfloatingice=project3d(md,'vector',md.mask.vertexonfloatingice,'type','node');742 md.mask.elementongroundedice=project3d(md,'vector',md.mask.elementongroundedice,'type','element');743 md.mask.vertexongroundedice=project3d(md,'vector',md.mask.vertexongroundedice,'type','node');744 md.mask.vertexonrock=project3d(md,'vector',md.mask.vertexonrock,'type','node');745 732 md.mask.groundedice_levelset=project3d(md,'vector',md.mask.groundedice_levelset,'type','node'); 746 733 md.mask.ice_levelset=project3d(md,'vector',md.mask.ice_levelset,'type','node'); … … 794 781 if isfield(structmd,'gridonsurface'), md.mesh.vertexonsurface=structmd.gridonsurface; end 795 782 if isfield(structmd,'extractedgrids'), md.mesh.extractedvertices=structmd.extractedgrids; end 796 if isfield(structmd,'gridoniceshelf'), md.mask.vertexonfloatingice=structmd.gridoniceshelf; end797 if isfield(structmd,'gridonicesheet'), md.mask.vertexongroundedice=structmd.gridonicesheet; end798 783 if isfield(structmd,'gridonboundary'), md.mesh.vertexonboundary=structmd.gridonboundary; end 799 784 if isfield(structmd,'petscoptions') & ~isempty(structmd.petscoptions), md.toolkits=structmd.petscoptions; end … … 845 830 if isfield(structmd,'rheology_B'), md.materials.rheology_B=structmd.rheology_B; end 846 831 if isfield(structmd,'rheology_n'), md.materials.rheology_n=structmd.rheology_n; end 847 if isfield(structmd,'elementoniceshelf'), md.mask.elementonfloatingice=structmd.elementoniceshelf; end848 if isfield(structmd,'elementonicesheet'), md.mask.elementongroundedice=structmd.elementonicesheet; end849 if isfield(structmd,'nodeoniceshelf'), md.mask.vertexonfloatingice=structmd.nodeoniceshelf; end850 if isfield(structmd,'nodeonicesheet'), md.mask.vertexongroundedice=structmd.nodeonicesheet; end851 832 if isfield(structmd,'spcthickness'), md.balancethickness.spcthickness=structmd.spcthickness; end 852 833 if isfield(structmd,'artificial_diffusivity'), md.balancethickness.stabilization=structmd.artificial_diffusivity; end -
issm/trunk-jpl/src/m/classes/model/model.py
r15960 r15987 185 185 Examples: 186 186 md2=extract(md,'Domain.exp'); 187 md2=extract(md,md.mask.elementonfloatingice);188 187 189 188 See also: EXTRUDE, COLLAPSE … … 637 636 md.geometry.bathymetry=project3d(md,'vector',md.geometry.bathymetry,'type','node') 638 637 md.mesh.vertexonboundary=project3d(md,'vector',md.mesh.vertexonboundary,'type','node') 639 md.mask.elementonfloatingice=project3d(md,'vector',md.mask.elementonfloatingice,'type','element')640 md.mask.vertexonfloatingice=project3d(md,'vector',md.mask.vertexonfloatingice,'type','node')641 md.mask.elementongroundedice=project3d(md,'vector',md.mask.elementongroundedice,'type','element')642 md.mask.vertexongroundedice=project3d(md,'vector',md.mask.vertexongroundedice,'type','node')643 638 md.mask.ice_levelset=project3d(md,'vector',md.mask.ice_levelset,'type','node') 644 639 md.mask.groundedice_levelset=project3d(md,'vector',md.mask.groundedice_levelset,'type','node') -
issm/trunk-jpl/src/m/classes/modellist.m
r15771 r15987 23 23 % 24 24 % Examples: 25 % md_list=modelsextract(md ,md.mask.elementonfloatingice,1000);25 % md_list=modelsextract(md...,,1000); 26 26 % 27 27 % See also: EXTRUDE, COLLAPSE, MODELEXTRACT -
issm/trunk-jpl/src/m/classes/oldclasses/diagnostic.m
r15856 r15987 64 64 obj.rift_penalty_lock=10; 65 65 66 end % }}}67 function md = checkconsistency(obj,md,solution,analyses) % {{{68 69 %Early return70 if ~ismember(StressbalanceAnalysisEnum(),analyses), return; end71 %if ~ismember(StressbalanceAnalysisEnum(),analyses) | (solution==TransientSolutionEnum() & md.transient.isdiagnostic==0), return; end72 73 md = checkfield(md,'diagnostic.spcvx','forcing',1);74 md = checkfield(md,'diagnostic.spcvy','forcing',1);75 if md.mesh.dimension==3, md = checkfield(md,'diagnostic.spcvz','forcing',1); end76 md = checkfield(md,'diagnostic.restol','size',[1 1],'>',0,'NaN',1);77 md = checkfield(md,'diagnostic.reltol','size',[1 1]);78 md = checkfield(md,'diagnostic.abstol','size',[1 1]);79 md = checkfield(md,'diagnostic.isnewton','numel',[1],'values',[0 1 2]);80 md = checkfield(md,'diagnostic.FSreconditioning','size',[1 1],'NaN',1);81 md = checkfield(md,'diagnostic.viscosity_overshoot','size',[1 1],'NaN',1);82 if md.mesh.dimension==2,83 md = checkfield(md,'diagnostic.icefront','size',[NaN 4],'NaN',1);84 else85 md = checkfield(md,'diagnostic.icefront','size',[NaN 6],'NaN',1);86 end87 md = checkfield(md,'diagnostic.icefront(:,end)','values',[0 1 2]);88 md = checkfield(md,'diagnostic.maxiter','size',[1 1],'>=',1);89 md = checkfield(md,'diagnostic.referential','size',[md.mesh.numberofvertices 6]);90 md = checkfield(md,'diagnostic.loadingforce','size',[md.mesh.numberofvertices 3]);91 if ~isempty(md.diagnostic.requested_outputs),92 md = checkfield(md,'diagnostic.requested_outputs','size',[NaN 1]);93 end94 95 %singular solution96 if ~(any(~isnan(md.diagnostic.spcvx)) & any(~isnan(md.diagnostic.spcvy))),97 md = checkmessage(md,['model is not well posed (singular). You need at least one node with fixed velocity!']);98 end99 %CHECK THAT EACH LINES CONTAINS ONLY NAN VALUES OR NO NAN VALUES100 if any(sum(isnan(md.diagnostic.referential),2)~=0 & sum(isnan(md.diagnostic.referential),2)~=6),101 md = checkmessage(md,['Each line of diagnostic.referential should contain either only NaN values or no NaN values']);102 end103 %CHECK THAT THE TWO VECTORS PROVIDED ARE ORTHOGONAL104 if any(sum(isnan(md.diagnostic.referential),2)==0),105 pos=find(sum(isnan(md.diagnostic.referential),2)==0);106 if any(abs(dot(md.diagnostic.referential(pos,1:3),md.diagnostic.referential(pos,4:6),2))>eps),107 md = checkmessage(md,['Vectors in diagnostic.referential (columns 1 to 3 and 4 to 6) must be orthogonal']);108 end109 end110 %CHECK THAT NO rotation specified for FS Grounded ice at base111 if md.mesh.dimension==3 & md.flowequation.isFS,112 pos=find(md.mask.vertexongroundedice & md.mesh.vertexonbed);113 if any(~isnan(md.diagnostic.referential(pos,:))),114 md = checkmessage(md,['no referential should be specified for basal vertices of grounded ice']);115 end116 md = checkfield(md,'diagnostic.FSreconditioning','>',0);117 end118 66 end % }}} 119 67 function disp(obj) % {{{ -
issm/trunk-jpl/src/m/classes/stressbalance.m
r15771 r15987 112 112 %CHECK THAT NO rotation specified for FS Grounded ice at base 113 113 if md.mesh.dimension==3 & md.flowequation.isFS, 114 pos=find(md.mask. vertexongroundedice& md.mesh.vertexonbed);114 pos=find(md.mask.groundedice_levelset>0. & md.mesh.vertexonbed); 115 115 if any(~isnan(md.stressbalance.referential(pos,:))), 116 116 md = checkmessage(md,['no referential should be specified for basal vertices of grounded ice']); -
issm/trunk-jpl/src/m/classes/stressbalance.py
r15771 r15987 147 147 # if md.mesh.dimension==3 & md.flowequation.isFS, 148 148 if md.mesh.dimension==3 and md.flowequation.isFS: 149 pos=numpy.nonzero(numpy.logical_and(md.mask. vertexongroundedice,md.mesh.vertexonbed))149 pos=numpy.nonzero(numpy.logical_and(md.mask.groundedice_levelset,md.mesh.vertexonbed)) 150 150 if numpy.any(numpy.logical_not(numpy.isnan(md.stressbalance.referential[pos,:]))): 151 151 md.checkmessage("no referential should be specified for basal vertices of grounded ice") -
issm/trunk-jpl/src/m/contrib/ecco/MeltingGroundingLines.m
r13008 r15987 7 7 8 8 %get nodes on ice sheet and on ice shelf 9 pos_shelf=find( ~md.mask.vertexongroundedice);9 pos_shelf=find(md.mask.groundedice_levelset<0.); 10 10 pos_GL=intersect(unique(md.mesh.elements(find(md.mask.elementongroundedice),:)),unique(md.mesh.elements(find(md.mask.elementonfloatingice),:))); 11 11 -
issm/trunk-jpl/src/m/geometry/FlagElements.m
r11236 r15987 12 12 % flag=FlagElements(md,'Domain.exp'); 13 13 % flag=FlagElements(md,'~Domain.exp'); 14 % flag=FlagElements(md,md.mask.elementongroundedice);15 14 16 15 if ischar(region), -
issm/trunk-jpl/src/m/geometry/FlagElements.py
r14211 r15987 20 20 flag=FlagElements(md,'Domain.exp'); 21 21 flag=FlagElements(md,'~Domain.exp'); 22 flag=FlagElements(md,md.mask.elementongroundedice);23 22 """ 24 23 -
issm/trunk-jpl/src/m/geometry/ThicknessCorrection.m
r13008 r15987 23 23 24 24 %get nodes on ice sheet and on ice shelf 25 pos_shelf=find( ~md.mask.vertexongroundedice);25 pos_shelf=find(md.mask.groundedice_levelset<0.); 26 26 pos_GL=intersect(unique(md.mesh.elements(find(md.mask.elementongroundedice),:)),unique(md.mesh.elements(find(md.mask.elementonfloatingice),:))); 27 27 debug=(length(pos_shelf)>50000); -
issm/trunk-jpl/src/m/parameterization/contourenvelope.m
r15106 r15987 7 7 % Example: 8 8 % segments=contourenvelope(md,'Stream.exp'); 9 % segments=contourenvelope(md,md.mask.elementonfloatingice)10 9 % segments=contourenvelope(md); 11 10 -
issm/trunk-jpl/src/m/parameterization/contourenvelope.py
r14231 r15987 15 15 Example: 16 16 segments=contourenvelope(md,'Stream.exp'); 17 segments=contourenvelope(md,md.mask.elementonfloatingice)18 17 segments=contourenvelope(md); 19 18 """ -
issm/trunk-jpl/src/m/parameterization/setflowequation.m
r15859 r15987 17 17 % 18 18 % Example: 19 % md=setflowequation(md,'HO','HO.exp','SSA',md.mask.elementonfloatingice,'fill','SIA');20 19 % md=setflowequation(md,'HO','HO.exp',fill','SIA','coupling','tiling'); 21 20 -
issm/trunk-jpl/src/m/parameterization/setflowequation.py
r15859 r15987 24 24 25 25 Example: 26 md=setflowequation(md,'HO','HO.exp','SSA',md.mask.elementonfloatingice,'fill','SIA');27 26 md=setflowequation(md,'HO','HO.exp',fill','SIA','coupling','tiling'); 28 27 """ -
issm/trunk-jpl/src/m/parameterization/setmask.m
r15944 r15987 41 41 %}}} 42 42 43 %Return:44 md.mask.elementonfloatingice=elementonfloatingice;45 md.mask.vertexonfloatingice=vertexonfloatingice;46 md.mask.elementongroundedice=elementongroundedice;47 md.mask.vertexongroundedice=vertexongroundedice;48 49 43 %level sets 50 44 md.mask.ice_levelset=ones(md.mesh.numberofvertices,1); -
issm/trunk-jpl/src/m/parameterization/setmask.py
r15944 r15987 41 41 #}}} 42 42 43 #Return:44 md.mask.elementonfloatingice = elementonfloatingice45 md.mask.vertexonfloatingice = vertexonfloatingice46 md.mask.elementongroundedice = elementongroundedice47 md.mask.vertexongroundedice = vertexongroundedice48 49 43 #level sets 50 44 md.mask.ice_levelset = numpy.ones(md.mesh.numberofvertices,bool) -
issm/trunk-jpl/src/m/parameterization/setmask2.m
r13006 r15987 139 139 140 140 %Return: 141 md.mask.vertexonfloatingice=vertexonfloatingice;142 md.mask.elementonfloatingice=elementonfloatingice;143 md.mask.vertexonwater=vertexonwater;144 md.mask.elementonwater=elementonwater;145 md.mask.vertexongroundedice=vertexongroundedice;146 md.mask.elementongroundedice=elementongroundedice;147 148 141 md.mesh.segmentmarkers(:)=1; -
issm/trunk-jpl/src/m/regional/BasinConstrainShelf.m
r15771 r15987 66 66 67 67 %iceshelves: any vertex on floating ice is spc'd 68 pos=find(md.mask. vertexongroundedice);68 pos=find(md.mask.groundedice_levelset<0.); 69 69 md.stressbalance.spcvx(pos)=md.inversion.vx_obs(pos); 70 70 md.stressbalance.spcvy(pos)=md.inversion.vy_obs(pos);
Note:
See TracChangeset
for help on using the changeset viewer.