Merge lp:~fluidity-core/fluidity/iceshelf into lp:fluidity

Proposed by Satoshi Kimura
Status: Work in progress
Proposed branch: lp:~fluidity-core/fluidity/iceshelf
Merge into: lp:fluidity
Diff against target: 1796 lines (+987/-706)
8 files modified
main/Fluids.F90 (+11/-16)
main/Makefile.dependencies (+1/-1)
parameterisation/Ice_Melt_Interface.F90 (+905/-0)
parameterisation/Makefile.dependencies (+11/-10)
parameterisation/Makefile.in (+1/-1)
parameterisation/iceshelf_meltrate_surf_normal.F90 (+0/-678)
schemas/fluidity_options.rnc (+27/-0)
schemas/fluidity_options.rng (+31/-0)
To merge this branch: bzr merge lp:~fluidity-core/fluidity/iceshelf
Reviewer Review Type Date Requested Status
Matthew Piggott Pending
Jon Hill Pending
Alexandros Avdis Pending
Adam Candy Pending
Stephan Kramer Pending
Review via email: mp+123186@code.launchpad.net

Description of the change

I would like to add the capability to simulate an ice shelf cavity in Fluidity-ICOM.
This code passed the buildbot (see http://buildbot-ocean.ese.ic.ac.uk:8080/builders/iceshelf/builds/16).
The previous merge request was rejected earlier because some codes were not necessary to model the ice shelf cavity.
Now, I have put together necessary pieces of codes to model the ice shelf cavity.
I am interested in hearing back from you all if this merge is acceptable or not.

Cheers,
Toshi

To post a comment you must log in.
lp:~fluidity-core/fluidity/iceshelf updated
4053. By Satoshi Kimura

Merged the trunk to be updated

4054. By Satoshi Kimura

Changed the min velocity for melting

4055. By Satoshi Kimura

Changed the min velocity for melting

4056. By Satoshi Kimura

Merge the recent trunk

4057. By Satoshi Kimura

Merge the trunk

4058. By Satoshi Kimura

Merge the trunk

Unmerged revisions

4058. By Satoshi Kimura

Merge the trunk

4057. By Satoshi Kimura

Merge the trunk

4056. By Satoshi Kimura

Merge the recent trunk

4055. By Satoshi Kimura

Changed the min velocity for melting

4054. By Satoshi Kimura

Changed the min velocity for melting

4053. By Satoshi Kimura

Merged the trunk to be updated

4052. By Satoshi Kimura

Fixing the test case, iceshelf

4051. By Satoshi Kimura

Fixed my test case to pass the medium test

4050. By Satoshi Kimura

Deleted some comments in Ice_Melt_Interface.F90

4049. By Satoshi Kimura

Added the test case

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'main/Fluids.F90'
2--- main/Fluids.F90 2013-10-07 16:23:35 +0000
3+++ main/Fluids.F90 2013-10-25 15:24:41 +0000
4@@ -83,7 +83,7 @@
5 use discrete_properties_module
6 use gls
7 use k_epsilon
8- use iceshelf_meltrate_surf_normal
9+ use ice_melt_interface
10 use halos
11 use memory_diagnostics
12 use free_surface_module
13@@ -401,15 +401,9 @@
14
15 call initialise_diagnostics(filename, state)
16
17- ! Initialise ice_meltrate, read constatns, allocate surface, and calculate melt rate
18+ ! Initialise melt interface paramerisation
19 if (have_option("/ocean_forcing/iceshelf_meltrate/Holland08")) then
20- call melt_surf_init(state(1))
21- call melt_allocate_surface(state(1))
22- call melt_surf_calc(state(1))
23- !BC for ice melt
24- if (have_option('/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries')) then
25- call melt_bc(state(1))
26- endif
27+ call melt_interface_initialisation(state(1))
28 end if
29
30 ! Checkpoint at start
31@@ -650,12 +644,13 @@
32 end if
33 end if
34
35- ! Calculate the meltrate
36- if(have_option("/ocean_forcing/iceshelf_meltrate/Holland08/") ) then
37- if( (trim(field_name_list(it))=="MeltRate")) then
38- call melt_surf_calc(state(1))
39+ ! Calculate the (ice) interface meltrate using the parameterisation described in Holland et al. 2008 doi:10.1175/2007JCLI1909.1
40+ if (have_option("/ocean_forcing/iceshelf_meltrate/Holland08")) then
41+ if ((trim(field_name_list(it)) == "MeltRate")) then
42+ call melt_interface_calculate(state(1))
43 endif
44- end if
45+ end if
46+
47
48 call get_option(trim(field_optionpath_list(it))//&
49 '/prognostic/equation[0]/name', &
50@@ -721,9 +716,9 @@
51 call gls_diffusivity(state(1))
52 end if
53
54- !BC for ice melt
55+ ! Boundary conditions for the (ice) melt interface parameterisation
56 if (have_option('/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries')) then
57- call melt_bc(state(1))
58+ call melt_interface_boundary_condition(state(1))
59 endif
60
61 if(option_count("/material_phase/scalar_field/prognostic/spatial_discretisation/coupled_cv")>0) then
62
63=== modified file 'main/Makefile.dependencies'
64--- main/Makefile.dependencies 2013-05-31 07:04:15 +0000
65+++ main/Makefile.dependencies 2013-10-25 15:24:41 +0000
66@@ -45,7 +45,7 @@
67 ../include/fldebug.mod ../include/foam_flow_module.mod \
68 ../include/free_surface_module.mod ../include/global_parameters.mod \
69 ../include/gls.mod ../include/goals.mod ../include/halos.mod \
70- ../include/iceshelf_meltrate_surf_normal.mod ../include/implicit_solids.mod \
71+ ../include/ice_melt_interface.mod ../include/implicit_solids.mod \
72 ../include/k_epsilon.mod ../include/memory_diagnostics.mod \
73 ../include/meshdiagnostics.mod ../include/meshmovement.mod \
74 ../include/momentum_diagnostic_fields.mod ../include/momentum_equation.mod \
75
76=== added file 'parameterisation/Ice_Melt_Interface.F90'
77--- parameterisation/Ice_Melt_Interface.F90 1970-01-01 00:00:00 +0000
78+++ parameterisation/Ice_Melt_Interface.F90 2013-10-25 15:24:41 +0000
79@@ -0,0 +1,905 @@
80+! Copyright (C) 2006 Imperial College London and others.
81+!
82+! Please see the AUTHORS file in the main source directory for a full list
83+! of copyright holders.
84+!
85+! Prof. C Pain
86+! Applied Modelling and Computation Group
87+! Department of Earth Science and Engineering
88+! Imperial College London
89+!
90+! amcgsoftware@imperial.ac.uk
91+!
92+! This library is free software; you can redistribute it and/or
93+! modify it under the terms of the GNU Lesser General Public
94+! License as published by the Free Software Foundation,
95+! version 2.1 of the License.
96+!
97+! This library is distributed in the hope that it will be useful,
98+! but WITHOUT ANY WARRANTY; without even the implied arranty of
99+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
100+! Lesser General Public License for more details.
101+!
102+! You should have received a copy of the GNU Lesser General Public
103+! License along with this library; if not, write to the Free Software
104+! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
105+! USA
106+
107+#include "fdebug.h"
108+
109+module ice_melt_interface
110+ use quadrature
111+ use elements
112+ use field_derivatives
113+ use fields
114+ use fields_base
115+ use field_options
116+ use fields_allocates
117+ use state_module
118+ use spud
119+ use global_parameters, only: FIELD_NAME_LEN, OPTION_PATH_LEN
120+ use state_fields_module
121+ use boundary_conditions
122+ use fields_manipulation
123+ use surface_integrals
124+ use fetools
125+ use vector_tools
126+ use FLDebug
127+ use integer_set_module
128+ use pickers_inquire
129+ use transform_elements
130+ use state_fields_module
131+ use global_parameters, only: PYTHON_FUNC_LEN
132+ use embed_python
133+implicit none
134+
135+ private
136+ integer, save :: nnodes, dimen
137+ type(vector_field), save :: surface_positions
138+ type(vector_field), save :: funky_positions
139+ ! Normals to the iceshelf interface surface
140+ type(vector_field), save :: unit_normal_vectors
141+ integer, dimension(:), pointer, save :: sf_nodes_point
142+
143+ ! Fields and variables for the interface surface
144+ type(scalar_field), save :: ice_surfaceT, ice_surfaceS! these are used to populate the bcs
145+
146+ public :: melt_interface_initialisation, populate_iceshelf_boundary_conditions, melt_interface_calculate, melt_interface_boundary_condition, melt_interface_cleanup, melt_interface_allocate_surface
147+
148+contains
149+
150+ ! Calculation of the (ice) interface meltrate using the parameterisation described in Holland et al. 2008 doi:10.1175/2007JCLI1909.1
151+
152+ !----------
153+ ! initialise parameters based on options
154+ !----------
155+
156+ subroutine melt_interface_initialisation(state)
157+
158+ type(state_type), intent(inout) :: state
159+ type(scalar_field), pointer :: T, S
160+ ! For the case when Dirichlet boundary conditions are used
161+ character(len=FIELD_NAME_LEN) :: bc_type
162+ type(integer_set) :: surface_ids
163+ integer, dimension(:),allocatable :: interface_surface_id
164+ integer, dimension(2) :: shape_option
165+ type(mesh_type), pointer :: mesh
166+ type(mesh_type) :: surface_mesh
167+ ! Allocated and returned by create_surface_mesh
168+ integer, dimension(:), pointer :: surface_nodes
169+ integer, dimension(:), allocatable :: surface_element_list
170+ integer :: i,the_node
171+ ! For input of the hydrostatic pressure
172+ character(len=PYTHON_FUNC_LEN) :: subshelf_hydrostatic_pressure_function
173+ real :: current_time
174+ type(vector_field), pointer :: positions
175+ type(scalar_field), pointer :: subshelf_hydrostatic_pressure
176+ real :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance
177+ real :: T_steady, S_steady
178+ logical :: calculate_boundaries_T, calculate_boundaries_S
179+ logical :: calculate_boundary_temperature, calculate_boundary_salinity
180+ character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08'
181+
182+ ewrite(1,*) 'Melt interface initialisation begins'
183+
184+ call melt_interface_read_coefficients(c0=c0, cI=cI, L=L, TI=TI, a=a, b=b, gammaT=gammaT, gammaS=gammaS, farfield_distance=farfield_distance, T_steady=T_steady, S_steady=S_steady)
185+
186+ calculate_boundary_temperature=have_option(trim(option_path)//'/calculate_boundaries/bc_value_temperature')
187+ calculate_boundary_salinity=have_option(trim(option_path)//'/calculate_boundaries/bc_value_salinity')
188+ if (calculate_boundary_temperature) write(3,*) "Melt interface, initialised T_steady", T_steady
189+ if (calculate_boundary_salinity) write(3,*) "Melt interface, initialised S_steady", S_steady
190+
191+ ! bc= Dirichlet initialize T and S at the ice-ocean interface
192+ ! This change with bc type
193+ if (have_option(trim(option_path)//'/calculate_boundaries')) then
194+ call get_option(trim(option_path)//'/calculate_boundaries', bc_type)
195+ select case(bc_type)
196+ case('neumann')
197+ ewrite(3,*) 'Calculating steady Neumann boundary condition - nothing to be done here.'
198+ case('dirichlet')
199+ ewrite(3,*) 'Calculating steady Dirichlet boundary condition - nothing to be done here.'
200+ ! Define values of temperature and salinity at ice-ocean interface
201+ ! Get the surface_id of the ice-ocean interface
202+ ! Note this code needs working through - Neumann is definitely the best choice here!
203+ shape_option = option_shape(trim(option_path)//"/melt_surfaceID")
204+ allocate(interface_surface_id(1:shape_option(1)))
205+ call get_option(trim(option_path)//'/melt_surfaceID', interface_surface_id)
206+ call allocate(surface_ids)
207+ call insert(surface_ids,interface_surface_id)
208+ mesh => extract_mesh(state,"VelocityMesh")
209+ ! Obtain surface_mesh, surface_element_list, from mesh and surface_id
210+ call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list)
211+
212+ T => extract_scalar_field(state,"Temperature")
213+ S => extract_scalar_field(state,"Salinity")
214+ do i=1, size(surface_nodes)
215+ the_node = surface_nodes(i)
216+ call set(T,the_node,T_steady)
217+ call set(S,the_node,S_steady)
218+ enddo
219+ case default
220+ FLAbort('Unknown boundary type for ice-ocean interface.')
221+ end select
222+ else
223+
224+ endif
225+
226+ ! Read the hydrostatic pressure
227+ if(have_option(trim(option_path)//'/subshelf_hydrostatic_pressure')) then
228+ call get_option(trim(option_path)//'/subshelf_hydrostatic_pressure/python', subshelf_hydrostatic_pressure_function)
229+ ! Get current time
230+ call get_option("/timestepping/current_time", current_time)
231+ ! Set initial condition from python function
232+
233+ subshelf_hydrostatic_pressure => extract_scalar_field(state,"subshelf_hydrostatic_pressure")
234+ positions => extract_vector_field(state,"Coordinate")
235+ call set_from_python_function(subshelf_hydrostatic_pressure, trim(subshelf_hydrostatic_pressure_function), positions, current_time)
236+ ewrite(1,*) "Melt interface initialisation, found hydrostatic pressure field"
237+ endif
238+
239+ ! Additional initialisation routines
240+ call melt_interface_allocate_surface(state)
241+ call melt_interface_calculate(state)
242+ ! Boundary conditions for the (ice) melt interface parameterisation
243+ if (have_option(trim(option_path)//'/calculate_boundaries')) then
244+ call melt_interface_boundary_condition(state)
245+ endif
246+
247+ ewrite(1,*) "Melt interface initialisation end"
248+
249+ end subroutine melt_interface_initialisation
250+
251+ subroutine populate_iceshelf_boundary_conditions(state)
252+ type(state_type), intent(in) :: state
253+ type(scalar_field), pointer :: T,S
254+ character(len=FIELD_NAME_LEN) :: bc_type
255+ integer, dimension(:), allocatable :: surf_id
256+ integer, dimension(2) :: shape_option
257+ type(integer_set) :: surface_ids
258+ !!
259+ type(mesh_type), pointer :: surface_mesh
260+ type(scalar_field) :: scalar_surface_field
261+
262+ ewrite(1,*) "-----*** Begin iceshelf BC-----"
263+ ! Get vector of surface ids
264+ shape_option=option_shape("/ocean_forcing/iceshelf_meltrate/Holland08/melt_surfaceID")
265+ allocate(surf_id(1:shape_option(1)))
266+ call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/melt_surfaceID", surf_id)
267+ ewrite(1,*) "surf_id", surf_id
268+ call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries", bc_type)
269+ call allocate(surface_ids)
270+ call insert(surface_ids,surf_id)
271+
272+ ewrite(1,*) "bc_type: ", bc_type
273+ ! Add boundary condition
274+ T => extract_scalar_field(state,"Temperature")
275+ S => extract_scalar_field(state,"Salinity")
276+
277+ call add_boundary_condition(T, 'temperature_iceshelf_BC', bc_type, surf_id)
278+ call add_boundary_condition(S, 'salinity_iceshelf_BC', bc_type, surf_id)
279+ deallocate(surf_id)
280+
281+ ! mesh of only the part of the surface where this b.c. applies for temperature
282+ call get_boundary_condition(T, 'temperature_iceshelf_BC', surface_mesh=surface_mesh)
283+ call allocate(scalar_surface_field, surface_mesh, name="value")
284+ call insert_surface_field(T, 'temperature_iceshelf_BC', scalar_surface_field)
285+ call deallocate(scalar_surface_field)
286+
287+ ! mesh of only the part of the surface where this b.c. applies for salinity
288+ call get_boundary_condition(S, 'salinity_iceshelf_BC', surface_mesh=surface_mesh)
289+ call allocate(scalar_surface_field, surface_mesh, name="value")
290+ call insert_surface_field(S, 'salinity_iceshelf_BC', scalar_surface_field)
291+ call deallocate(scalar_surface_field)
292+
293+ ewrite(1,*) "-----*** End iceshelf BC-----"
294+ end subroutine populate_iceshelf_boundary_conditions
295+
296+ subroutine melt_interface_calculate(state)
297+ ! Calculate the melt rate
298+
299+ type(state_type), intent(inout) :: state
300+ type(scalar_field), pointer :: Tb, Sb,MeltRate,Heat_flux,Salt_flux
301+ type(scalar_field), pointer :: scalarfield
302+ type(vector_field), pointer :: velocity,positions
303+ ! Debugging purpose pointer
304+ type(scalar_field), pointer :: T_loc,S_loc,P_loc
305+ type(vector_field), pointer :: V_loc,Location,Location_org
306+ real, dimension(:), allocatable :: vel
307+ integer :: i
308+ ! Some internal variables
309+ real :: speed, T,S,P,Aa,Bb,Cc,topo
310+ real :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance
311+ real ::loc_Tb,loc_Sb,loc_meltrate,loc_heatflux,loc_saltflux
312+ ! Aa*Sb^2+Bv*Sb+Cc
313+ ! Sink mesh part
314+ integer :: ele,stat,the_node
315+ real, dimension(:), allocatable :: local_coord,coord
316+ integer, dimension(:), allocatable :: surface_node_list
317+ type(scalar_field) :: re_pressure,re_DistanceToTop
318+ type(scalar_field), pointer :: temperature, salinity
319+
320+ ewrite(1,*) "Melt interface calculation begins"
321+
322+ call melt_interface_read_coefficients(c0=c0, cI=cI, L=L, TI=TI, a=a, b=b, gammaT=gammaT, gammaS=gammaS, farfield_distance=farfield_distance)
323+
324+ !! All the variable under /ocean_forcing/iceshelf_meltrate/Holland08 should be in coordinate mesh
325+ !! coordinate mesh = continous mesh
326+ MeltRate => extract_scalar_field(state,"MeltRate")
327+ call set(MeltRate,0.0)
328+ Tb => extract_scalar_field(state,"Tb")
329+ Sb => extract_scalar_field(state,"Sb")
330+
331+ call set(Tb,0.0)
332+ call set(Sb,-1.0)
333+ Heat_flux => extract_scalar_field(state,"Heat_flux")
334+ Salt_flux => extract_scalar_field(state,"Salt_flux")
335+ call set(Heat_flux,0.0)
336+ call set(Salt_flux,0.0)
337+
338+ ! Local far field values
339+ T_loc => extract_scalar_field(state,"Tloc")
340+ S_loc => extract_scalar_field(state,"Sloc")
341+ P_loc => extract_scalar_field(state,"Ploc")
342+ V_loc => extract_vector_field(state,"Vloc")
343+ Location => extract_vector_field(state,"Location")
344+ Location_org => extract_vector_field(state,"Location_org")
345+ call set(T_loc,0.0)
346+ call set(S_loc,-1.0)
347+ call set(P_loc,-1.0)
348+ allocate(vel(V_loc%dim))
349+ vel = 0.0
350+ call set(V_loc,vel)
351+ call set(Location,vel)
352+ call set(Location_org,vel)
353+
354+ positions => extract_vector_field(state,"Coordinate")
355+
356+ ! Surface node list
357+ allocate(surface_node_list(size(sf_nodes_point)))
358+ ! sf_nodes is calculated in "melt_allocate_surface"
359+ surface_node_list=sf_nodes_point
360+
361+ ! Pressure read the hydrostatic pressure, specified at schema
362+ scalarfield => extract_scalar_field(state,"subshelf_hydrostatic_pressure")
363+ call allocate(re_pressure,positions%mesh, name="RePressure")
364+ call remap_field(scalarfield,re_pressure,stat)
365+
366+ if (have_option("/geometry/ocean_boundaries/scalar_field::DistanceToBottom")) then
367+ scalarfield => extract_scalar_field(state,"DistanceToBottom")
368+ call allocate(re_DistanceToTop,positions%mesh, name="ReDistanceToBottom")
369+ call remap_field(scalarfield,re_DistanceToTop,stat)
370+ endif
371+
372+ allocate(local_coord(positions%dim+1))
373+ allocate(coord(positions%dim))
374+
375+ temperature => extract_scalar_field(state,"Temperature")
376+ salinity => extract_scalar_field(state,"Salinity")
377+ velocity => extract_vector_field(state,"Velocity")
378+
379+ ! Loop over the surface nodes to calculate melt rate
380+ do i=1,size(surface_node_list)
381+ the_node = surface_node_list(i)
382+ ! Interpolating
383+ coord = node_val(funky_positions,the_node)
384+ call picker_inquire(positions, coord, ele, local_coord,global=.false.)
385+
386+ !! we know that this coord (funky position) does not exist in the domain.
387+ if (sum(local_coord) .gt. 2.0) then
388+ ewrite(0,*) "Melt interface, funky coordinate: ", node_val(funky_positions,the_node)
389+ !! node_val(surface_positions,the_node) = node_val(positions,the_node)
390+ ewrite(0,*) "Melt interface, original element: ",ele
391+ ewrite(0,*) "Melt interface, sum of local_coord: ", sum(local_coord)
392+ FLExit("Melt interface, your funky_positions is out of the domain. Change melt_LayerLength.")
393+ endif
394+
395+ !Number of nodes per element for temperature
396+ ! Find T at a particular element given the field,element,
397+ !INPUT: field, element number
398+ !Output: real value
399+
400+ call scalar_finder_ele(temperature,ele,positions%dim+1,local_coord,T)
401+ call scalar_finder_ele(salinity,ele,positions%dim+1,local_coord,S)
402+ call vector_finder_ele(velocity,ele,positions%dim+1,local_coord,vel)
403+
404+ ! Pressure from the schema
405+ P = node_val(re_pressure,the_node)
406+ speed = sqrt(sum(vel**2))
407+
408+ if (speed .lt. 0.0001) then
409+ speed = 0.0001
410+
411+ endif
412+ ! constant = -7.53e-8 [C Pa^(-1)] comes from Holland and Jenkins Table 1
413+ topo = -7.53e-8*P
414+
415+ ! Define Aa,Bb,Cc
416+ ! Aa*Sb**2 + Bb*Sb + Cc = 0.0
417+ Aa = -gammaS * speed * cI * a + a * c0 * gammaT * speed
418+
419+ Bb = -gammaS * speed * L + gammaS * speed * S * cI * a
420+ Bb = Bb - gammaS * speed * cI * (b + topo) + gammaS * speed * cI * TI
421+ Bb = Bb - c0 * gammaT * speed * T + c0 * gammaT * speed * (b + topo)
422+
423+ Cc = gammaS * speed * S * L + gammaS * speed * S * cI * (b + topo) + gammaS * speed * S * (-cI * TI)
424+
425+ ! This could be a linear equation if Aa=0
426+ if (Aa .eq. 0.0) then
427+ loc_Sb = -Cc/Bb
428+ else
429+ ! Calculate for the 2nd oewrite(1,*) "size(surface_element_list)"rder polynomial.
430+ ! We have two solutions.
431+ loc_Sb = (-Bb + sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa)
432+ ! loc_Sb has to be larger than 0; since the salinity in the ocean is positive definite.
433+ if (loc_Sb .lt. 0.0) then
434+ loc_Sb = (-Bb - sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa)
435+ endif
436+ if (loc_Sb .lt. 0.0) then
437+ ewrite(0,*) "Melt interface, loc_Sb: ", loc_Sb
438+ ewrite(0,*) "Melt interface, Aa: ", Aa
439+ ewrite(0,*) "Melt interface, Bb: ", Bb
440+ ewrite(0,*) "Melt interface, Cc: ", Cc
441+ ewrite(0,*) "Melt interface, T: ", T
442+ ewrite(0,*) "Melt interface, S: ", S
443+ ewrite(0,*) "Melt interface, P: ", P
444+ ewrite(0,*) "Melt interface, speed: ", speed
445+ FLExit("Melt interface, Sb is negative. The range of Salinity is not right.")
446+ endif
447+ endif
448+
449+ loc_Tb = a*loc_Sb + b + topo
450+ loc_meltrate = gammaS*speed*(S-loc_Sb)/loc_Sb
451+ !! Heat flux to the ocean
452+ loc_heatflux = (gammaT*speed+ loc_meltrate)*(loc_Tb - T)
453+ !! Salt flux to the ocean
454+ loc_saltflux = (gammaS*speed+loc_meltrate)*(loc_Sb - S)
455+
456+ !! These are needed to implement BCs.
457+ call set(MeltRate, the_node, loc_meltrate)
458+ call set(Tb, the_node, loc_Tb)
459+ call set(Sb, the_node, loc_Sb)
460+ call set(Heat_flux, the_node,loc_heatflux)
461+ call set(Salt_flux, the_node,loc_saltflux)
462+
463+ !!Far field values
464+ call set(T_loc,the_node,T)
465+ call set(S_loc,the_node,S)
466+ call set(P_loc,the_node,P)
467+ call set(V_loc,the_node,vel)
468+ call set(Location,the_node,node_val(funky_positions,the_node))
469+ call set(Location_org,the_node,node_val(positions,the_node))
470+
471+ enddo
472+
473+ deallocate(local_coord)
474+ deallocate(coord)
475+ call deallocate(re_pressure)
476+
477+ if (have_option("/geometry/ocean_boundaries/scalar_field::DistanceToBottom")) then
478+ call deallocate(re_DistanceToTop)
479+ endif
480+
481+ ! Remap meltrate_p heat_flux_p salt_flux_p onto MeltRate Heat_flux Salt_flux
482+ ! Mappting continous mesh to discontinous mesh
483+
484+ ewrite(1,*) "Melt interface calculation end"
485+
486+ end subroutine melt_interface_calculate
487+
488+ subroutine melt_interface_boundary_condition(state)
489+ ! See preprocessor/Boundary_Conditions_From_options.F90 populate_iceshelf_boundary_conditions(states(1)) as well
490+ type(state_type), intent(inout) :: state
491+ ! Boundary conditions
492+ type(scalar_field), pointer :: TT,SS
493+ type(scalar_field), pointer :: scalar_surface, scalar_surface2
494+ type(mesh_type), pointer :: ice_mesh
495+ character(len=FIELD_NAME_LEN) :: bc_type
496+ type(scalar_field) :: T_bc,S_bc
497+ type(scalar_field), pointer :: Tflux,Sflux
498+ type(scalar_field), pointer :: Tb,Sb
499+ integer :: i, the_node
500+ real :: Tz,Sz
501+ type(mesh_type), pointer :: mesh
502+ type(mesh_type) :: surface_mesh
503+ integer, dimension(:), pointer :: surface_nodes ! allocated and returned by create_surface_mesh
504+ integer, dimension(:), allocatable :: surface_element_list
505+ type(integer_set) :: surface_ids
506+ integer, dimension(:),allocatable :: surf_id
507+ integer, dimension(2) :: shape_option
508+ type(vector_field) :: unit_normal_vectors_vel
509+ type(scalar_field) :: heat_flux_vel,salt_flux_vel
510+ type(vector_field), pointer :: velocity
511+ integer :: stat
512+ real, dimension(:), allocatable :: vel
513+ real :: T_steady, S_steady
514+ logical :: calculate_boundary_temperature, calculate_boundary_salinity
515+ character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08'
516+ character(len=*), parameter :: option_path_bc = '/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries'
517+
518+ ewrite(1,*) "Melt interface boundary condition begins"
519+ call melt_interface_read_coefficients(T_steady=T_steady, S_steady=S_steady)
520+ calculate_boundary_temperature=have_option(trim(option_path)//'/calculate_boundaries/bc_value_temperature')
521+ calculate_boundary_salinity=have_option(trim(option_path)//'/calculate_boundaries/bc_value_salinity')
522+
523+!! See ./preprocessor/Boundary_Conditions_From_options.F90 populate_iceshelf_boundary_conditions(states(1)) as well
524+ ! Get the surface_id of the ice-ocean interface
525+ shape_option=option_shape(trim(option_path)//"/melt_surfaceID")
526+ allocate(surf_id(1:shape_option(1)))
527+ call get_option(trim(option_path)//'/melt_surfaceID',surf_id)
528+ call allocate(surface_ids)
529+ call insert(surface_ids,surf_id)
530+
531+ TT=> extract_scalar_field(state,"Temperature")
532+ SS=> extract_scalar_field(state,"Salinity")
533+ velocity => extract_vector_field(state,"Velocity")
534+
535+ if (node_count(TT) .eq. node_count(velocity)) then
536+ mesh => extract_mesh(state,"VelocityMesh")
537+ else
538+ mesh => extract_mesh(state,"CoordinateMesh")
539+ endif
540+ call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list)
541+
542+!! Remapt the contious mesh to discon, unit_normal vecotr
543+
544+ call allocate(unit_normal_vectors_vel,velocity%dim,TT%mesh,"MyVelocitySurfaceMesh")
545+
546+ allocate(vel(velocity%dim))
547+ vel = 0.0
548+ call set(unit_normal_vectors_vel,vel)
549+ deallocate(vel)
550+
551+ call remap_field(unit_normal_vectors,unit_normal_vectors_vel,stat)
552+
553+ call allocate(T_bc,TT%mesh, name="T_boundary")
554+ call allocate(S_bc,SS%mesh, name="S_boundary")
555+
556+ ! Surface node list
557+ ! This change with bc type
558+ call get_option(trim(option_path_bc), bc_type)
559+
560+ select case(bc_type)
561+ case("neumann")
562+ Tflux => extract_scalar_field(state,"Heat_flux")
563+ Sflux => extract_scalar_field(state,"Salt_flux")
564+
565+ !! Remap the heat flux
566+ call allocate(heat_flux_vel,TT%mesh,"MyHeatFluxSurfaceMesh")
567+ call set(heat_flux_vel,0.0)
568+ call remap_field(Tflux,heat_flux_vel,stat)
569+
570+ !! Remap the salt flux
571+ call allocate(salt_flux_vel,SS%mesh,"MySaltFluxSurfaceMesh")
572+ call set(salt_flux_vel,0.0)
573+ call remap_field(Sflux,salt_flux_vel,stat)
574+
575+ ! create a surface mesh to place values onto. This is for the top surface
576+ call get_boundary_condition(TT, 'temperature_iceshelf_BC', surface_mesh=ice_mesh)
577+ call allocate(ice_surfaceT, ice_mesh, name="ice_surfaceT")
578+ !! Temperature
579+ scalar_surface => extract_surface_field(TT, 'temperature_iceshelf_BC', "value")
580+
581+ do i=1,node_count(ice_surfaceT)
582+ the_node = surface_nodes(i)
583+ Tz = node_val(heat_flux_vel,the_node)
584+ call set(scalar_surface,i,Tz)
585+ enddo
586+
587+ ! Salinity
588+ call get_boundary_condition(SS, 'salinity_iceshelf_BC', surface_mesh=ice_mesh)
589+ call allocate(ice_surfaceS, ice_mesh, name="ice_surfaceS")
590+ !! Salinity
591+ scalar_surface2 => extract_surface_field(SS, 'salinity_iceshelf_BC', "value")
592+ do i=1,node_count(ice_surfaceS)
593+ the_node = surface_nodes(i)
594+ Sz = node_val(salt_flux_vel,the_node)
595+ call set(scalar_surface2,i,Sz)
596+ enddo
597+ ! Deallocate the heat_flux and salt_flux on velocity mesh
598+ call deallocate(heat_flux_vel)
599+ call deallocate(salt_flux_vel)
600+
601+ ! If the fluxes were constant
602+ if (calculate_boundary_temperature) then
603+ call set(T_bc,T_steady)
604+ ! create a surface mesh to place values onto. This is for the top surface
605+ call get_boundary_condition(TT, 'temperature_iceshelf_BC', surface_mesh=ice_mesh)
606+ call allocate(ice_surfaceT, ice_mesh, name="ice_surfaceT")
607+ do i=1,node_count(ice_surfaceT)
608+ the_node = surface_nodes(i)
609+ call set(ice_surfaceT,i,node_val(T_bc,the_node))
610+ enddo
611+ ! Temperature
612+ scalar_surface => extract_surface_field(TT, 'temperature_iceshelf_BC', "value")
613+ call remap_field(ice_surfaceT, scalar_surface)
614+ endif
615+
616+ if (have_option(trim(option_path_bc)//'/bc_value_salinity')) then
617+ call set(S_bc,S_steady)
618+ ! Salinity
619+ call get_boundary_condition(SS, 'salinity_iceshelf_BC', surface_mesh=ice_mesh)
620+ call allocate(ice_surfaceS, ice_mesh, name="ice_surfaceS")
621+ do i=1,node_count(ice_surfaceS)
622+ the_node = surface_nodes(i)
623+ call set(ice_surfaceS,i,node_val(S_bc,the_node))
624+ enddo
625+ !! Salinity
626+ scalar_surface => extract_surface_field(SS, 'salinity_iceshelf_BC', "value")
627+ call remap_field(ice_surfaceS, scalar_surface)
628+ endif
629+
630+ case("dirichlet")
631+ Tb => extract_scalar_field(state,"Tb")
632+ Sb => extract_scalar_field(state,"Sb")
633+ do i=1,node_count(T_bc)
634+ call set(T_bc,i,node_val(Tb,i))
635+ call set(S_bc,i,node_val(Sb,i))
636+ enddo
637+ ! When testing BC implementation
638+ if (calculate_boundary_temperature) then
639+ call set(T_bc,T_steady)
640+ ewrite(3,*) "Melt interface, initialised T_steady", T_steady
641+ endif
642+ if (calculate_boundary_salinity) then
643+ call set(S_bc,S_steady)
644+ ewrite(3,*) "Melt interface, initialised S_steady", S_steady
645+ endif
646+
647+ case default
648+ FLAbort('Unknown boundary condition for ice-ocean interface')
649+ end select
650+
651+ call deallocate(T_bc)
652+ call deallocate(S_bc)
653+ call deallocate(ice_surfaceT)
654+ call deallocate(ice_surfaceS)
655+ call deallocate(unit_normal_vectors_vel)
656+ call deallocate(surface_mesh)
657+
658+ ewrite(1,*) "Melt interface boundary condition end"
659+
660+ end subroutine melt_interface_boundary_condition
661+
662+
663+ subroutine melt_interface_cleanup()
664+ ewrite(1,*) "Melt interface, cleaning up melt variables"
665+ call deallocate(surface_positions)
666+ call deallocate(funky_positions)
667+ call deallocate(unit_normal_vectors)
668+
669+ deallocate(sf_nodes_point)
670+ end subroutine melt_interface_cleanup
671+
672+
673+ !------------------------------------------------------------------!
674+ ! Private subroutines !
675+ !------------------------------------------------------------------!
676+
677+ subroutine melt_interface_allocate_surface(state)
678+ type(state_type), intent(inout) :: state
679+ type(vector_field), pointer :: positions
680+ type(mesh_type), pointer :: mesh
681+ type(mesh_type) :: surface_mesh
682+ ! Allocated and returned by create_surface_mesh
683+ integer, dimension(:), pointer :: surface_nodes
684+ integer, dimension(:), allocatable :: surface_element_list
685+ integer :: face,i,j,k
686+ real, dimension(:), allocatable :: coord
687+ ! For transform_facet_to_physical
688+ real, dimension(:,:), allocatable :: normal
689+ real, dimension(:), allocatable :: av_normal !Average of normal
690+ type(element_type), pointer :: x_shape_f
691+ real, dimension(:), allocatable :: xyz !New location of surface_mesh, farfield_distance away from the boundary
692+ type(integer_set) :: surface_ids
693+ integer, dimension(:),allocatable :: interface_surface_id
694+
695+ ! For the vector averaging schem, taking the area of the surface element etc
696+ real, dimension(:,:), allocatable :: table
697+ integer, dimension(:,:), allocatable :: node_occupants
698+ integer :: st,en,node,dim_vec
699+ real :: area_sum
700+ integer, dimension(2) :: shape_option
701+ real, dimension(:), allocatable :: local_coord
702+ integer :: ele, counter,Nit
703+ real, dimension(:), allocatable :: vel
704+ real :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance
705+ character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08/melt_surfaceID'
706+
707+ ewrite(1,*) "Melt interface allocation of surface parameters"
708+
709+ call melt_interface_read_coefficients(c0=c0, cI=cI, L=L, TI=TI, a=a, b=b, gammaT=gammaT, gammaS=gammaS, farfield_distance=farfield_distance)
710+
711+ ! Get the surface_id of the ice-ocean interface
712+ shape_option=option_shape(trim(option_path))
713+ allocate(interface_surface_id(1:shape_option(1)))
714+ call get_option(trim(option_path), interface_surface_id)
715+ call allocate(surface_ids)
716+ call insert(surface_ids,interface_surface_id)
717+
718+ mesh => extract_mesh(state,"CoordinateMesh")
719+ ! Input, mesh, surface_id
720+ ! Output surface_mesh, surface_element_list
721+ call melt_surf_mesh(mesh, surface_ids, surface_mesh, surface_nodes, surface_element_list)
722+
723+ allocate(sf_nodes_point(size(surface_nodes)))
724+ sf_nodes_point = surface_nodes
725+ positions => extract_vector_field(state,"Coordinate")
726+ ! Sink the surface_mesh to the 'far field'
727+ call allocate(surface_positions,positions%dim,mesh,"MySurfacePosition")
728+ call allocate(funky_positions,surface_positions%dim, surface_positions%mesh,"MyFunkyPosition")
729+ call allocate(unit_normal_vectors,surface_positions%dim, surface_positions%mesh,"MyFunkyUnitVec")
730+ allocate(vel(positions%dim))
731+ vel = 0.0
732+ call set(unit_normal_vectors,vel)
733+ deallocate(vel)
734+ ! Check above
735+
736+ ! Remap the positions vector to the surface mesh, surface_positions
737+ call remap_field_to_surface(positions, surface_positions, surface_element_list)
738+
739+ ! Loop over # of surface elements
740+ !nf = size(surface_element_list)
741+ !2 comes because there are 2 nodes per a surface_element (assumption!)
742+ ! this number could be three for 3D problem, room for change
743+ ! dim_vec is the dimension of the positions, either 2 or 3.
744+ ! node_occupants(1,1:dim_vec*nf) = nodes that occupies the surface elements
745+ ! node_occupants(2,:) = surface elements
746+ ! table(1,:) = area of the face
747+ ! table(2,:) = normal_x
748+ ! table(3,:) = normal_y
749+ ! table(4,:) = normal_z
750+ dim_vec = positions%dim
751+ allocate(coord(dim_vec))
752+ allocate(node_occupants(2,dim_vec*size(surface_element_list)))
753+ allocate(table(dim_vec+1,dim_vec*size(surface_element_list)))
754+ allocate(av_normal(dim_vec))
755+ allocate(xyz(dim_vec))
756+ allocate(local_coord(positions%dim+1))
757+
758+ do i=1,size(surface_element_list)
759+ st = 1+dim_vec*(i-1)
760+ en = dim_vec+dim_vec*(i-1)
761+ face = surface_element_list(i)
762+ node_occupants(2,st:en) = face
763+ node_occupants(1,st:en) = face_global_nodes(positions, face)
764+ ! Calculate the area of the surface element
765+ ! For 2D, the area is the length
766+ if (dim_vec .eq. 2) then
767+ table(1,st:en) = calc_area2(positions,node_occupants(1,st:en))
768+ endif
769+
770+ ! For 3D, the area become the area of the triangle (assumption here).
771+ ! Subroutine calc_area3 uses Heron's formula.
772+ if (dim_vec .eq. 3) then
773+ table(1,st:en) = calc_area3(positions,node_occupants(1,st:en))
774+ endif
775+ ! Compute the normal vector at the surface element.
776+ x_shape_f=>face_shape(positions,face)
777+ allocate(normal(dim_vec,x_shape_f%ngi)) !(dim x x_shape_f%ngi)
778+ call transform_facet_to_physical(positions, face, normal=normal)
779+ av_normal = sum(normal,2)
780+ !"normal" should be the same; since the normal vector on the quadrature point does not change.
781+ av_normal = av_normal/(sum(av_normal*av_normal))**(0.5) ! normalize the vector
782+ deallocate(normal)
783+ ! Since av_normal is outward to the boundary, we will put -sign. We want the vector into the boundary
784+ av_normal = -av_normal
785+ ! Store av_normal, the normal vector averaged over quadrature points, in table
786+ do j=1,dim_vec
787+ table(j+1,st:en)=av_normal(j)
788+ enddo
789+ enddo
790+
791+
792+ do i=1,size(node_occupants(1,:))
793+ node = node_occupants(1,i)
794+ av_normal(:) = 0.0
795+ area_sum = 0.0
796+ ! This loop average the normal vector based on the areas of surface elements
797+ ! which share the "node". Using hash table may speed up this process
798+ do j=1,size(node_occupants(1,:))
799+ !Pick the surface elements that sheare the "node"
800+ if (node_occupants(1,j) .eq. node) then
801+ do k=1,dim_vec
802+
803+ av_normal(k) = av_normal(k) + table(k+1,j)*table(1,j)
804+ enddo
805+ !The total areas of the surface elements that occupies the "node"
806+ area_sum = area_sum + table(1,j)
807+ endif
808+ enddo
809+
810+ av_normal = av_normal / area_sum
811+ ! normalize
812+ av_normal = av_normal/(sum(av_normal*av_normal))**(0.5)
813+
814+ farfield_distance = abs(farfield_distance)
815+ ! Shift the location of the surface nodes.
816+ !The coordinate of the surface node.
817+
818+ coord = node_val(positions,node)
819+ ! farfield_distance = ||xyz - coord|| xyz and coord are vectors
820+ xyz = av_normal*farfield_distance + coord
821+
822+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
823+ ! have options /ocean_forcing/iceshelf_meltrate/Holland08/melt_LayerRelax
824+ if (have_option("/ocean_forcing/iceshelf_meltrate/Holland08/melt_LayerRelax")) then
825+ call get_option('/ocean_forcing/iceshelf_meltrate/Holland08/melt_LayerRelax/N',Nit)
826+ !!Check if xyz is within the domain
827+ call picker_inquire(positions, xyz, ele, local_coord,global=.false.)
828+ !! If sum(local_coord) is not equal to 1,
829+ !! we know that this coord (funky position) does not exist in the domain.
830+
831+ counter = 1
832+ do while (sum(local_coord) .gt. 2.0 .and. counter .lt. Nit)
833+ xyz = av_normal*(farfield_distance-counter*(farfield_distance/Nit)) + coord
834+ call picker_inquire(positions, xyz, ele, local_coord,global=.false.)
835+ counter = counter+1
836+ enddo
837+
838+ if (sum(local_coord) .gt. 2.0) then
839+ ewrite(1,*) "icehslef location, coord: ", coord
840+ ewrite(1,*) "funky position, xyz: ", xyz
841+ call picker_inquire(positions, coord, ele, local_coord,global=.false.)
842+ ewrite(1,*) "Original ele: ",ele
843+ ewrite(1,*) "sum of local_coord: ", sum(local_coord)
844+ FLExit("In setting funky_position, your funky_positions is out of the domain. Change melt_LayerLength.")
845+ endif
846+ endif
847+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
848+
849+ call set(funky_positions,node,xyz) ! Set the coordinate of sinked nodes, funky positions.
850+ call set(surface_positions,node,coord) !Original coordinate of the surface
851+ call set(unit_normal_vectors,node,av_normal) !save the unit normal vector for Kt and Ks calculation
852+
853+ node = 0
854+ enddo
855+
856+ ! Now deallocate junk
857+ deallocate(coord)
858+ deallocate(table)
859+ deallocate(node_occupants)
860+ deallocate(av_normal)
861+ deallocate(xyz)
862+ deallocate(local_coord)
863+ call deallocate(surface_ids)
864+ call deallocate(surface_mesh)
865+ ewrite(1,*) "Melt interface allocation of surface parameters end"
866+
867+ end subroutine melt_interface_allocate_surface
868+
869+ subroutine melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list)
870+
871+ type(mesh_type), intent(in) :: mesh
872+ type(integer_set), intent(in) :: surface_ids
873+ type(mesh_type), intent(out) :: surface_mesh
874+ integer, dimension(:), pointer, intent(out) :: surface_nodes ! allocated and returned by create_surface_mesh
875+ integer, dimension(:), allocatable, intent(out) :: surface_element_list
876+ ! integer, dimension(:), allocatable :: surface_nodes_out
877+ type(integer_set) :: surface_elements
878+ integer :: i
879+ ! create a set of surface elements that have surface id in 'surface_ids'
880+
881+ call allocate(surface_elements)
882+ do i=1, surface_element_count(mesh)
883+ if (has_value(surface_ids, surface_element_id(mesh, i))) then
884+ call insert(surface_elements, i)
885+ end if
886+ end do
887+
888+ allocate(surface_element_list(key_count(surface_elements)))
889+ surface_element_list=set2vector(surface_elements)
890+ call create_surface_mesh(surface_mesh, surface_nodes, mesh, surface_element_list, name=trim(mesh%name)//"ToshisMesh")
891+ end subroutine melt_surf_mesh
892+
893+ subroutine melt_interface_read_coefficients(c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance, T_steady, S_steady)
894+ real, intent(out), optional :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance, T_steady, S_steady
895+ real :: Cd
896+ character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08'
897+
898+ ! Get the 6 model constants
899+ if (present(c0)) call get_option(trim(option_path)//'c0', c0, default = 3974.0)
900+ if (present(cI)) call get_option(trim(option_path)//'cI', cI, default = 2009.0)
901+ if (present(L)) call get_option(trim(option_path)//'/L', L, default = 3.35e5)
902+ if (present(TI)) call get_option(trim(option_path)//'/TI', TI, default = -25.0)
903+ if (present(a)) call get_option(trim(option_path)//'/a', a, default = -0.0573)
904+ if (present(b)) call get_option(trim(option_path)//'/b', b, default = 0.0832)
905+ if (present(farfield_distance)) call get_option(trim(option_path)//'/melt_LayerLength', farfield_distance)
906+
907+ if (present(gammaT).or.present(gammaS)) call get_option(trim(option_path)//'/Cd', Cd, default = 1.5e-3)
908+ if (present(gammaT)) gammaT = sqrt(Cd)/(12.5*(7.0**(2.0/3.0))-9.0)
909+ if (present(gammaS)) gammaS = sqrt(Cd)/(12.5*(700.0**(2.0/3.0))-9.0)
910+
911+ ! When steady boundary options are enabled
912+ if (present(T_steady)) call get_option(trim(option_path)//'/calculate_boundaries/bc_value_temperature',T_steady, default = 0.0)
913+ if (present(S_steady)) call get_option(trim(option_path)//'/calculate_boundaries/bc_value_salinity',S_steady, default = 34.0)
914+
915+ end subroutine melt_interface_read_coefficients
916+
917+ subroutine scalar_finder_ele(scalar,ele,element_dim,local_coord,scalar_out)
918+ type(scalar_field), pointer, intent(in) :: scalar
919+ integer, intent(in) :: ele
920+ integer, intent(in) :: element_dim
921+ real, dimension(element_dim), intent(in) :: local_coord
922+ real, intent(out) :: scalar_out
923+ integer :: j,node
924+ integer, dimension(:), allocatable :: node_lists
925+
926+ allocate(node_lists(size(ele_nodes(scalar,ele))))
927+ node_lists = ele_nodes(scalar,ele) !Lists of nodes that occupies the element.
928+ scalar_out = 0.0
929+ do j=1,size(node_lists)
930+ node = node_lists(j)
931+ scalar_out = scalar_out + node_val(scalar,node)*local_coord(j)
932+ enddo
933+ end subroutine scalar_finder_ele
934+
935+ subroutine vector_finder_ele(vector,ele,element_dim,local_coord,vector_out)
936+ type(vector_field), pointer, intent(in) :: vector
937+ integer, intent(in) :: ele
938+ integer, intent(in) :: element_dim
939+ real, dimension(element_dim), intent(in) :: local_coord
940+ real, dimension(element_dim-1), intent(out) :: vector_out
941+ integer :: j,node
942+ integer, dimension(:), allocatable :: node_lists
943+
944+ allocate(node_lists(size(ele_nodes(vector,ele))))
945+
946+ node_lists = ele_nodes(vector,ele) !Lists of nodes that occupies the element.
947+ vector_out(:) = 0.0
948+ do j=1,size(node_lists)
949+ node = node_lists(j)
950+ vector_out = vector_out + node_val(vector,node)*local_coord(j)
951+ enddo
952+ end subroutine vector_finder_ele
953+
954+ real function setnan(arg)
955+ real :: arg
956+ setnan = sqrt(arg)
957+ end function
958+
959+ real function calc_area2(positions,nodes)
960+ type(vector_field), pointer :: positions
961+ integer, dimension(2) :: nodes
962+ real, dimension(2) :: coord1,coord2
963+ coord1 = node_val(positions,nodes(1))
964+ coord2 = node_val(positions,nodes(2))
965+ calc_area2 = (sum((coord2 - coord1)**2))**0.5
966+ end function
967+
968+ real function calc_area3(positions,nodes)
969+ type(vector_field), pointer :: positions
970+ integer, dimension(3) :: nodes
971+ real, dimension(3) :: coord1,coord2,coord3
972+ real :: a,b,c,s
973+ coord1 = node_val(positions,nodes(1))
974+ coord2 = node_val(positions,nodes(2))
975+ coord3 = node_val(positions,nodes(3))
976+ ! Use Heron's formula to calculate the area of triangle
977+ a = (sum((coord2 - coord1)**2))**0.5
978+ b = (sum((coord3 - coord1)**2))**0.5
979+ c = (sum((coord2 - coord3)**2))**0.5
980+ s = 0.5*(a+b+c)
981+ calc_area3 = (s*(s-a)*(s-b)*(s-c))**0.5
982+ end function
983+
984+end module ice_melt_interface
985
986=== modified file 'parameterisation/Makefile.dependencies'
987--- parameterisation/Makefile.dependencies 2013-02-25 18:41:05 +0000
988+++ parameterisation/Makefile.dependencies 2013-10-25 15:24:41 +0000
989@@ -21,20 +21,21 @@
990 ../include/state_fields_module.mod ../include/state_module.mod \
991 ../include/vertical_extrapolation_module.mod
992
993-../include/iceshelf_meltrate_surf_normal.mod: iceshelf_meltrate_surf_normal.o
994+../include/ice_melt_interface.mod: Ice_Melt_Interface.o
995 @true
996
997-iceshelf_meltrate_surf_normal.o ../include/iceshelf_meltrate_surf_normal.mod: \
998- iceshelf_meltrate_surf_normal.F90 ../include/boundary_conditions.mod \
999- ../include/elements.mod ../include/fdebug.h ../include/fetools.mod \
1000+Ice_Melt_Interface.o ../include/ice_melt_interface.mod: Ice_Melt_Interface.F90 \
1001+ ../include/boundary_conditions.mod ../include/elements.mod \
1002+ ../include/embed_python.mod ../include/fdebug.h ../include/fetools.mod \
1003 ../include/field_derivatives.mod ../include/field_options.mod \
1004 ../include/fields.mod ../include/fields_allocates.mod \
1005- ../include/fields_manipulation.mod ../include/fldebug.mod \
1006- ../include/global_parameters.mod ../include/integer_set_module.mod \
1007- ../include/pickers_inquire.mod ../include/quadrature.mod \
1008- ../include/spud.mod ../include/state_fields_module.mod \
1009- ../include/state_module.mod ../include/surface_integrals.mod \
1010- ../include/transform_elements.mod ../include/vector_tools.mod
1011+ ../include/fields_base.mod ../include/fields_manipulation.mod \
1012+ ../include/fldebug.mod ../include/global_parameters.mod \
1013+ ../include/integer_set_module.mod ../include/pickers_inquire.mod \
1014+ ../include/quadrature.mod ../include/spud.mod \
1015+ ../include/state_fields_module.mod ../include/state_module.mod \
1016+ ../include/surface_integrals.mod ../include/transform_elements.mod \
1017+ ../include/vector_tools.mod
1018
1019 ../include/k_epsilon.mod: k_epsilon.o
1020 @true
1021
1022=== modified file 'parameterisation/Makefile.in'
1023--- parameterisation/Makefile.in 2013-02-25 18:41:05 +0000
1024+++ parameterisation/Makefile.in 2013-10-25 15:24:41 +0000
1025@@ -47,7 +47,7 @@
1026 OBJS = Equation_of_State.o \
1027 Gls_vertical_turbulence_model.o \
1028 k_epsilon.o \
1029-iceshelf_meltrate_surf_normal.o
1030+Ice_Melt_Interface.o
1031
1032 .SUFFIXES: .F90 .c .o .a
1033
1034
1035=== removed file 'parameterisation/iceshelf_meltrate_surf_normal.F90'
1036--- parameterisation/iceshelf_meltrate_surf_normal.F90 2011-04-07 12:42:58 +0000
1037+++ parameterisation/iceshelf_meltrate_surf_normal.F90 1970-01-01 00:00:00 +0000
1038@@ -1,678 +0,0 @@
1039-! Copyright (C) 2006 Imperial College London and others.
1040-!
1041-! Please see the AUTHORS file in the main source directory for a full list
1042-! of copyright holders.
1043-!
1044-! Prof. C Pain
1045-! Applied Modelling and Computation Group
1046-! Department of Earth Science and Engineering
1047-! Imperial College London
1048-!
1049-! amcgsoftware@imperial.ac.uk
1050-!
1051-! This library is free software; you can redistribute it and/or
1052-! modify it under the terms of the GNU Lesser General Public
1053-! License as published by the Free Software Foundation,
1054-! version 2.1 of the License.
1055-!
1056-! This library is distributed in the hope that it will be useful,
1057-! but WITHOUT ANY WARRANTY; without even the implied arranty of
1058-! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1059-! Lesser General Public License for more details.
1060-!
1061-! You should have received a copy of the GNU Lesser General Public
1062-! License along with this library; if not, write to the Free Software
1063-! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
1064-! USA
1065-
1066-#include "fdebug.h"
1067-
1068-module iceshelf_meltrate_surf_normal
1069- use quadrature
1070- use elements
1071- use field_derivatives
1072- use fields
1073- use field_options
1074- use fields_allocates
1075- use state_module
1076- use spud
1077- use global_parameters, only: FIELD_NAME_LEN, OPTION_PATH_LEN
1078- use state_fields_module
1079- use boundary_conditions
1080- use fields_manipulation
1081- use surface_integrals
1082- use fetools
1083- use vector_tools
1084- use FLDebug
1085- use integer_set_module
1086- use pickers_inquire
1087- use transform_elements
1088- use state_fields_module
1089-implicit none
1090-
1091- private
1092- real, save :: c0, cI, L, TI, &
1093- a, b, gammaT, gammaS,Cd, dist_meltrate
1094- integer, save :: nnodes,dimen
1095-
1096- type(vector_field), save :: surface_positions
1097- type(vector_field), save :: funky_positions
1098- type(integer_set), save :: sf_nodes !Nodes at the surface
1099- !BC
1100- integer, dimension(:), pointer, save :: ice_element_list
1101- ! these are the fields and variables for the surface values
1102- type(scalar_field), save :: ice_surfaceT,ice_surfaceS! these are used to populate the bcs
1103- public :: melt_surf_init, melt_allocate_surface, melt_surf_calc, melt_bc
1104-
1105-
1106-
1107-contains
1108-
1109-!----------
1110-! initialise parameters based on options
1111-!----------
1112-
1113- subroutine melt_surf_init(state)
1114-
1115- type(state_type), intent(inout) :: state
1116- character(len=OPTION_PATH_LEN) :: melt_path
1117- ! hack
1118- type(scalar_field), pointer :: T,S
1119- ! When bc=Dirichlet
1120- character(len=FIELD_NAME_LEN) :: bc_type
1121- type(integer_set) :: surface_ids
1122- integer, dimension(:),allocatable :: surf_id
1123- integer, dimension(:), allocatable :: sf_nodes_ar
1124- integer, dimension(2) :: shape_option
1125- type(mesh_type), pointer :: mesh
1126- type(mesh_type) :: surface_mesh
1127- integer, dimension(:), pointer :: surface_nodes ! allocated and returned by create_surface_mesh
1128- integer, dimension(:), allocatable :: surface_element_list
1129- integer :: i,the_node
1130-
1131- melt_path = "/ocean_forcing/iceshelf_meltrate/Holland08"
1132-
1133-
1134- ewrite(1,*) "--------Begin melt_init-------------"
1135-
1136- ! Get the 6 model constants
1137- call get_option(trim(melt_path)//'/c0', c0, default = 3974.0)
1138- call get_option(trim(melt_path)//'/cI', cI, default = 2009.0)
1139- call get_option(trim(melt_path)//'/L', L, default = 3.35e5)
1140- call get_option(trim(melt_path)//'/TI', TI, default = -25.0)
1141- call get_option(trim(melt_path)//'/a', a, default = -0.0573)
1142- call get_option(trim(melt_path)//'/b', b, default = 0.0832)
1143- call get_option(trim(melt_path)//'/Cd', Cd, default = 1.5e-3)
1144- call get_option(trim(melt_path)//'/melt_LayerLength', dist_meltrate)
1145-
1146- gammaT = sqrt(Cd)/(12.5*(7.0**(2.0/3.0))-9.0)
1147- gammaS = sqrt(Cd)/(12.5*(700.0**(2.0/3.0))-9.0)
1148-
1149- !! bc= Dirichlet initialize T and S at the ice-ocean interface
1150- !hack
1151- !This change with bc type
1152- call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries", bc_type)
1153-
1154- select case(bc_type)
1155- case("neumann")
1156-
1157-
1158- case("dirichlet")
1159- !! Define the values at ice-ocean interface
1160- ! Get the surface_id of the ice-ocean interface
1161- shape_option=option_shape(trim(melt_path)//"/melt_surfaceID")
1162- allocate(surf_id(1:shape_option(1)))
1163- call get_option(trim(melt_path)//'/melt_surfaceID',surf_id)
1164- call allocate(surface_ids)
1165- call insert(surface_ids,surf_id)
1166- mesh => extract_mesh(state,"VelocityMesh")
1167- ! Input, mesh, surface_id
1168- ! Output surface_mesh,surface_element_list
1169- call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list)
1170-
1171- T => extract_scalar_field(state,"Temperature")
1172- S => extract_scalar_field(state,"Salinity")
1173- do i=1,size(surface_nodes)
1174- the_node = surface_nodes(i)
1175-
1176- call set(T,the_node,0.0)
1177- call set(S,the_node,34.0)
1178-
1179- enddo
1180-! T_bc => extract_scalar_field(state,"Tb")
1181-! S_bc => extract_scalar_field(state,"Sb")
1182- case default
1183- FLAbort('Unknown BC for TKE')
1184- end select
1185-
1186-
1187- ewrite(1,*) "---------End melt_surf_init---------------------------------"
1188-
1189- end subroutine melt_surf_init
1190-
1191-subroutine melt_allocate_surface(state)
1192-
1193- type(state_type), intent(inout) :: state
1194- type(vector_field), pointer :: positions
1195- type(mesh_type), pointer :: mesh
1196- type(mesh_type) :: surface_mesh
1197- type(integer_set) :: surface_elements
1198- integer, dimension(:), pointer :: surface_nodes ! allocated and returned by create_surface_mesh
1199- integer, dimension(:), allocatable :: surface_element_list
1200- integer :: ele, face,i,j,k
1201-!! The local coordinates of the coordinate in the owning element
1202-!! real, dimension(:), allocatable :: local_coord, local_coord_surf
1203- real, dimension(:), allocatable :: coord
1204-! for transform_facet_to_physical
1205- real, dimension(:,:), allocatable :: normal
1206- real, dimension(:), allocatable :: av_normal !Average of normal
1207-!! integer, dimension(:), pointer :: ele_faces,face_neighs
1208- type(element_type), pointer :: x_shape_f
1209- real :: al,be,ga
1210- real, dimension(:), allocatable :: xyz !New location of surface_mesh, dist_meltrate away from the boundary
1211-!integer, save :: melt_surfaceID
1212- character(len=OPTION_PATH_LEN) :: path
1213- type(integer_set) :: surface_ids
1214- integer, dimension(:),allocatable :: surf_id
1215-
1216-! For the vector averaging schem, taking the area of the surface element etc
1217- real, dimension(:,:), allocatable :: table
1218- integer, dimension(:,:), allocatable :: node_occupants
1219- integer :: st,en,node,dim_vec
1220- real :: area_sum
1221- integer, dimension(:), allocatable :: sf_nodes_ar
1222- integer, dimension(2) :: shape_option
1223-
1224- ewrite(1,*) "-------Begin melt_allocate_surface---------"
1225- path = "/ocean_forcing/iceshelf_meltrate/Holland08"
1226- ! Get the surface_id of the ice-ocean interface
1227- shape_option=option_shape(trim(path)//"/melt_surfaceID")
1228- allocate(surf_id(1:shape_option(1)))
1229- call get_option(trim(path)//'/melt_surfaceID',surf_id)
1230- call allocate(surface_ids)
1231- call insert(surface_ids,surf_id)
1232-! deallocate(surf_id)
1233-! ewrite(1,*) "aft_surface_ids: ", set2vector(surface_ids)
1234-
1235- mesh => extract_mesh(state,"VelocityMesh")
1236-! Input, mesh, surface_id
1237-! Output surface_mesh,surface_element_list
1238- call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list)
1239-
1240- positions => extract_vector_field(state,"Coordinate")
1241-!SINK THE surface_mesh!!
1242-! call get_option("/geometry/dimension/", dimension)
1243- call allocate(surface_positions,positions%dim,mesh,"MySurfacePosition")
1244- call allocate(funky_positions,surface_positions%dim, surface_positions%mesh,"MyFunkyPosition")
1245-
1246-
1247-! Remap the positions vector to the surface mesh, surface_positions
1248- call remap_field_to_surface(positions, surface_positions, surface_element_list)
1249-
1250-! Loop over # of surface elements
1251-!nf = size(surface_element_list)
1252-!2 comes because there are 2 nodes per a surface_element (assumption!)
1253-! this number could be three for 3D problem, room for change
1254-! dim_vec is the dimension of the positions, either 2 or 3.
1255-! node_occupants(1,1:dim_vec*nf) = nodes that occupies the surface elements
1256-! node_occupants(2,:) = surface elements
1257-! table(1,:) = area of the face
1258-! table(2,:) = normal_x
1259-! table(3,:) = normal_y
1260-! table(4,:) = normal_z
1261- dim_vec = positions%dim
1262- allocate(coord(dim_vec))
1263- allocate(node_occupants(2,dim_vec*size(surface_element_list)))
1264- allocate(table(dim_vec+1,dim_vec*size(surface_element_list)))
1265- allocate(av_normal(dim_vec))
1266- allocate(xyz(dim_vec))
1267-
1268- do i=1,size(surface_element_list)
1269- st = 1+dim_vec*(i-1)
1270- en = dim_vec+dim_vec*(i-1)
1271- face = surface_element_list(i)
1272- node_occupants(2,st:en) = face
1273- node_occupants(1,st:en) = face_global_nodes(positions, face)
1274- ! Calculate the area of the surface element
1275- ! For 2D, the area is the length
1276- if (dim_vec .eq. 2) then
1277- table(1,st:en) = calc_area2(positions,node_occupants(1,st:en))
1278- endif
1279-
1280- ! For 3D, the area become the area of the triangle (assumption here).
1281- ! Subroutine calc_area3 uses Heron's formula.
1282- if (dim_vec .eq. 3) then
1283- table(1,st:en) = calc_area3(positions,node_occupants(1,st:en))
1284- endif
1285- ! Compute the normal vector at the surface element.
1286- x_shape_f=>face_shape(positions,face)
1287- allocate(normal(dim_vec,x_shape_f%ngi)) !(dim x x_shape_f%ngi)
1288- call transform_facet_to_physical(positions, face, normal=normal)
1289- av_normal = sum(normal,2)
1290- !"normal" should be the same; since the normal vector on the quadrature point does not change.
1291- av_normal = av_normal/(sum(av_normal*av_normal))**(0.5) ! normalize the vector
1292- deallocate(normal)
1293- !Since av_normal is outward to the boundary, we will put -sign. We want the vector into the boundary
1294- av_normal = -av_normal
1295- ! Store av_normal, the normal vector averaged over quadrature points, in table
1296- do j=1,dim_vec
1297- table(j+1,st:en)=av_normal(j)
1298- enddo
1299- enddo
1300-!! Now loop over surface_nodes
1301-! ewrite(1,*) "table(1,1:3): ", table(1,1:3)
1302-! ewrite(1,*) "table(2,1:3),normal_x: ", table(2,1:3)
1303-! ewrite(1,*) "table(3,1:3),normal_y: ", table(3,1:3)
1304-! ewrite(1,*) "table(4,1:3),normal_z: ", table(4,1:3)
1305-!!In this loop, we will average adjacent normal vectors, using the area of the surface elements.
1306-
1307- !allocate(sf_nodes_ar(size(node_occupants(1,:))))
1308- call allocate(sf_nodes)
1309-! call insert(sf_nodes,sf_nodes_ar)
1310- do i=1,size(node_occupants(1,:))
1311- node = node_occupants(1,i)
1312- av_normal(:) = 0.0
1313- area_sum = 0.0
1314- ! This loop average the normal vector based on the areas of surface elements
1315- !, which share the "node". Using hash table may speed up this process
1316- do j=1,size(node_occupants(1,:))
1317- !Pick the surface elements that sheare the "node"
1318- if (node_occupants(1,j) .eq. node) then
1319- do k=1,dim_vec
1320- !table(1,j) = area of the surface element
1321- av_normal(k) = av_normal(k) + table(k+1,j)*table(1,j)
1322- enddo
1323- !The total areas of the surface elements that occupies the "node"
1324- area_sum = area_sum + table(1,j)
1325- endif
1326- enddo
1327-
1328- av_normal = av_normal / area_sum
1329- ! normalize
1330- av_normal = av_normal/(sum(av_normal*av_normal))**(0.5)
1331-
1332- dist_meltrate = abs(dist_meltrate)
1333- ! Shift the location of the surface nodes.
1334- !The coordinate of the surface node.
1335-
1336- coord = node_val(positions,node)
1337-
1338- ! dist_meltrate = ||xyz - coord|| xyz and coord are vectors
1339- xyz = av_normal*dist_meltrate + coord
1340-
1341- call set(funky_positions,node,xyz) ! Set the coordinate of sinked nodes, funky positions.
1342-
1343- call set(surface_positions,node,coord) !Original coordinate of the surface
1344-!! ewrite(1,*) "--------------------------------"
1345-!! ewrite(1,*) "node: ", node
1346-!! ewrite(1,*) "av_normal: ", av_normal
1347-!! ewrite(1,*) "funky: ", xyz
1348-!! ewrite(1,*) "coord: ", coord
1349-!! ! Save the corresponding node number.
1350-!! !sf_nodes_ar(i) = node
1351- call insert(sf_nodes,node)
1352-
1353- node = 0
1354- enddo
1355-
1356-
1357- deallocate(coord)
1358- deallocate(table)
1359- deallocate(node_occupants)
1360- deallocate(av_normal)
1361- deallocate(xyz)
1362- call deallocate(surface_ids)
1363- ewrite(1,*) "-------End melt_allocate_surface---------"
1364-end subroutine melt_allocate_surface
1365-
1366-
1367-
1368-! Calculate the melt rate
1369- subroutine melt_surf_calc(state)
1370-
1371- type(state_type), intent(inout) :: state
1372- type(scalar_field), pointer :: Tb, Sb,MeltRate,Heat_flux,Salt_flux
1373- type(scalar_field), pointer :: scalarfield
1374- type(vector_field), pointer :: velocity,positions
1375- !Debugging purpose pointer
1376- type(scalar_field), pointer :: T_loc,S_loc,P_loc
1377- type(vector_field), pointer :: V_loc,Location,Location_org
1378- real, dimension(:), allocatable :: vel
1379- integer :: i,j,k
1380- ! Some internal variables
1381- real :: speed, T,S,P,Aa,Bb,Cc,topo
1382- real ::loc_Tb,loc_Sb,loc_meltrate,loc_heatflux,loc_saltflux
1383- ! Aa*Sb^2+Bv*Sb+Cc
1384- real :: arg = -1.0
1385- !Sink mesh part
1386- integer :: ele,face,node,stat,the_node
1387- real, dimension(:), allocatable :: local_coord,coord
1388- type(element_type), pointer :: x_shape_f
1389- integer, dimension(:), allocatable :: surface_node_list,node_lists
1390- type(scalar_field) :: re_temperature,re_salinity,re_pressure
1391- type(vector_field) :: re_velocity
1392-
1393-
1394- ewrite(1,*) "-------Begin melt_surf_calc------------"
1395-
1396- MeltRate => extract_scalar_field(state,"MeltRate")
1397- Tb => extract_scalar_field(state,"Tb")
1398- Sb => extract_scalar_field(state,"Sb")
1399- call set(MeltRate,setnan(arg))
1400- call set(Tb,setnan(arg))
1401- call set(Sb,setnan(arg))
1402- Heat_flux => extract_scalar_field(state,"Heat_flux")
1403- Salt_flux => extract_scalar_field(state,"Salt_flux")
1404- call set(Heat_flux,setnan(arg))
1405- call set(Salt_flux,setnan(arg))
1406-
1407-! Debugging
1408- T_loc => extract_scalar_field(state,"Tloc")
1409- S_loc => extract_scalar_field(state,"Sloc")
1410- P_loc => extract_scalar_field(state,"Ploc")
1411- V_loc => extract_vector_field(state,"Vloc")
1412- Location => extract_vector_field(state,"Location")
1413- Location_org => extract_vector_field(state,"Location_org")
1414- call set(T_loc,setnan(arg))
1415- call set(S_loc,setnan(arg))
1416- call set(P_loc,setnan(arg))
1417- allocate(vel(V_loc%dim))
1418- vel = setnan(arg)
1419- call set(V_loc,vel)
1420- call set(Location,vel)
1421- call set(Location_org,vel)
1422-
1423- positions => extract_vector_field(state,"Coordinate")
1424- !my positions
1425-
1426- ! Surface node list
1427- allocate(surface_node_list(key_count(sf_nodes)))
1428- ! Make it to vector from integer_set.
1429- ! sf_nodes is calculated in "melt_allocate_surface"
1430- surface_node_list=set2vector(sf_nodes)
1431-
1432- ! Remap temperature, salinity, pressure, and velocity onto positions mesh
1433- scalarfield => extract_scalar_field(state,"Temperature")
1434-
1435- call allocate(re_temperature,positions%mesh,name="ReTemperature")
1436-
1437- call remap_field(scalarfield,re_temperature,stat)
1438-
1439- ! Salinity
1440- scalarfield=> extract_scalar_field(state,"Salinity")
1441-
1442- call allocate(re_salinity,positions%mesh, name="ReSalinity")
1443- call remap_field(scalarfield,re_salinity,stat)
1444-
1445- ! Pressure
1446- scalarfield => extract_scalar_field(state,"Pressure")
1447- call allocate(re_pressure,positions%mesh, name="RePressure")
1448- call remap_field(scalarfield,re_pressure,stat)
1449-
1450- ! Velocity
1451- velocity => extract_vector_field(state,"Velocity")
1452- call allocate(re_velocity,velocity%dim,positions%mesh,name="ReVelocity")
1453- call remap_field(velocity, re_velocity, stat)
1454-
1455- allocate(local_coord(positions%dim+1))
1456- allocate(coord(positions%dim))
1457-
1458-
1459-
1460-
1461-!!!!!!!!!!!!!!!!!!!!!!!!!
1462- !surface_positions
1463-
1464- !! Loope over the surface nodes to calculate melt rate etc.
1465- do i=1,size(surface_node_list)
1466- the_node = surface_node_list(i)
1467- !!! Interpolating
1468- coord = node_val(funky_positions,the_node)
1469- call picker_inquire(positions, coord, ele, local_coord,global=.true.)
1470-
1471- !! If sum(local_coord) is not equal to 1,
1472- !! we know that this coord (funky position) does not exist in the domain.
1473-
1474- if (sum(local_coord) .gt. 2.0) then
1475- ewrite(1,*) "Funk coord: ", node_val(funky_positions,the_node)
1476- !! node_val(surface_positions,the_node) = node_val(positions,the_node)
1477- ewrite(1,*) "Original ele: ",ele
1478- ewrite(1,*) "sum of local_coord: ", sum(local_coord)
1479- FLExit("Your funky_positions is out of the domain. Change melt_LayerLength.")
1480- endif
1481- !Number of nodes per element
1482- allocate(node_lists(ele_and_faces_loc(positions, ele)))
1483- node_lists = ele_nodes(positions,ele) !Lists of nodes that occupies the element.
1484- ! This method of finding values at funky_positions works for P1, which are T,S, and velocity.
1485- coord = 0.0
1486- T = 0.0
1487- S = 0.0
1488- speed = 0.0
1489- vel = 0.0
1490-
1491- do j=1,size(node_lists)
1492- node = node_lists(j)
1493- coord = coord + node_val(positions,node)*local_coord(j)
1494- T = T + node_val(re_temperature,node)*local_coord(j)
1495- S = S + node_val(re_salinity,node)*local_coord(j)
1496- vel = vel + node_val(re_velocity,node)*local_coord(j)
1497- enddo
1498- deallocate(node_lists)
1499- ! Luckly P needs to be at the surface for the three equations
1500- P = node_val(re_pressure,the_node)
1501- speed = sqrt(sum(vel**2))
1502-
1503- if (speed .lt. 0.001) then
1504- speed = 0.001
1505- !ewrite(1,*) "----------iceshelf, speed less----", the_node,speed
1506- endif
1507- topo = -7.53e-8*P ! constant = -7.53e-8 [C Pa^(-1)] comes from Holland and Jenkins Table 1
1508-
1509- !! Define Aa,Bb,Cc
1510- !! Aa*Sb**2 + Bb*Sb + Cc = 0.0
1511- Aa = -gammaS*speed*cI*a + a*c0*gammaT*speed
1512-
1513- Bb = -gammaS*speed*L + gammaS*speed*S*cI*a
1514- Bb = Bb - gammaS*speed*cI*(b+topo) + gammaS*speed*cI*TI
1515- Bb = Bb - c0*gammaT*speed*T + c0*gammaT*speed*(b+topo)
1516-
1517- Cc = gammaS*speed*S*L +gammaS*speed*S*cI*(b+topo) + gammaS*speed*S*(-cI*TI)
1518-
1519-
1520- !! This could be a linear equation if Aa=0
1521- if (Aa .eq. 0.0) then
1522- loc_Sb = -Cc/Bb
1523- else
1524- !! Calculate for the 2nd oewrite(1,*) "size(surface_element_list)"rder polynomial.
1525- !! We have two solutions.
1526- loc_Sb = (-Bb + sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa)
1527- !! loc_Sb has to be larger than 0; since the salinity in the ocean is positive definite.
1528- if (loc_Sb .lt. 0.0) then
1529- loc_Sb = (-Bb - sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa)
1530- endif
1531- endif
1532- !ewrite(1,*) "----------iceshelf, loc_Sb----", loc_Sb
1533- loc_Tb = a*loc_Sb + b + topo
1534- loc_meltrate = gammaS*speed*(S-loc_Sb)/loc_Sb
1535- !! Heat flux to the ocean
1536- loc_heatflux = c0*(gammaT*speed+ loc_meltrate)*(T-loc_Tb) ! or loc_meltrate*L + loc_meltrate*cI*(loc_Tb-TI)
1537- loc_saltflux = (gammaS*speed+loc_meltrate)*(S-loc_Sb)
1538- !! Some debugging
1539- !!ewrite(1,*) "melt_rate: ",loc_meltrate
1540- !!ewrite(1,*) "tLHS: ", c0*gammaT*speed*(T-loc_Tb)
1541- !!ewrite(1,*) "tRHS: ", loc_meltrate*L + loc_meltrate*cI*(loc_Tb-TI)
1542- !!ewrite(1,*) "sLHS: ", gammaS*speed*(S-loc_Sb)
1543- !!ewrite(1,*) "sRHS: ", loc_meltrate*loc_Sb
1544- !!ewrite(1,*) "bLHS: ", loc_Tb
1545- !!ewrite(1,*) "bRHS: ", a*loc_Sb + b + topo
1546-
1547- !! These are needed to implement BCs.
1548- call set(MeltRate, the_node, loc_meltrate)
1549- call set(Tb, the_node, loc_Tb)
1550- call set(Sb, the_node, loc_Sb)
1551- call set(Heat_flux, the_node,loc_heatflux)
1552- call set(Salt_flux, the_node,loc_saltflux)
1553- !! More or less for debugging purposes.
1554- call set(T_loc,the_node,T)
1555- call set(S_loc,the_node,S)
1556- call set(P_loc,the_node,P)
1557- call set(V_loc,the_node,vel)
1558- call set(Location,the_node,node_val(funky_positions,the_node))
1559- call set(Location_org,the_node,node_val(positions,the_node))
1560- !! BC test
1561- !!call set(TT,the_node,11.1)
1562-! ewrite(1,*) "----------iceshelf, loc_saltflux----", the_node,loc_saltflux
1563-! ewrite(1,*) "----------melt_surf_calc, loc_Tb----", the_node,loc_Tb
1564-! ewrite(1,*) "----------iceshelf, surfaceS----",node_val(re_salinity,the_node)
1565-! ewrite(1,*) "----------line 477 iceshelf, loc_meltrate----",loc_meltrate
1566-! ewrite(1,*) "----------iceshelf, node_val(TT,the_node)----",node_val(TT,the_node)
1567- enddo
1568-
1569- deallocate(local_coord)
1570- deallocate(coord)
1571- ewrite(1,*) "-----END melt_surf_calc-------"
1572-end subroutine melt_surf_calc
1573-
1574-
1575-subroutine melt_bc(state)
1576- type(state_type), intent(inout) :: state
1577- !! BC
1578- type(scalar_field), pointer :: TT,SS
1579- type(scalar_field), pointer :: scalar_surface
1580- type(mesh_type), pointer :: ice_mesh
1581- character(len=FIELD_NAME_LEN) :: bc_type
1582- type(scalar_field), pointer :: T_bc,S_bc
1583- integer, dimension(:), allocatable :: surface_node_list
1584- integer :: i, the_node
1585-!! Insert BC for temperature and salinity. This could be a separate subroutine
1586-
1587-
1588- TT=> extract_scalar_field(state,"Temperature")
1589- SS => extract_scalar_field(state,"Salinity")
1590-
1591- !This change with bc type
1592- call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries", bc_type)
1593-
1594- select case(bc_type)
1595- case("neumann")
1596- T_bc => extract_scalar_field(state,"Heat_flux")
1597- S_bc => extract_scalar_field(state,"Salt_flux")
1598- do i=1,node_count(T_bc)
1599- call set(T_bc,node_val(T_bc,i)*10.0**3)
1600- call set(S_bc,node_val(S_bc,i)*10.0**3)
1601- enddo
1602-
1603- case("dirichlet")
1604- T_bc => extract_scalar_field(state,"Tb")
1605- S_bc => extract_scalar_field(state,"Sb")
1606- case default
1607- FLAbort('Unknown BC for TKE')
1608- end select
1609-
1610-
1611- ! Surface node list
1612- allocate(surface_node_list(key_count(sf_nodes)))
1613- ! Make it to vector from integer_set.
1614- ! sf_nodes is calculated in "melt_allocate_surface"
1615- surface_node_list=set2vector(sf_nodes)
1616-
1617- ! create a surface mesh to place values onto. This is for the top surface
1618- call get_boundary_condition(TT, 'temperature_iceshelf_BC', surface_mesh=ice_mesh)
1619- call allocate(ice_surfaceT, ice_mesh, name="ice_surfaceT")
1620- call get_boundary_condition(SS, 'salinity_iceshelf_BC', surface_mesh=ice_mesh)
1621- call allocate(ice_surfaceS, ice_mesh, name="ice_surfaceS")
1622- ! Define ice_surfaceT according to Heat_flux?
1623- ewrite(1,*) "node_count(ice_surfaceT)",node_count(ice_surfaceT)
1624- do i=1,node_count(ice_surfaceT)
1625- the_node = surface_node_list(i)
1626- call set(ice_surfaceT,i,node_val(T_bc,the_node))
1627- call set(ice_surfaceS,i,node_val(S_bc,the_node))
1628- enddo
1629- !! Temperature
1630- scalar_surface => extract_surface_field(TT, 'temperature_iceshelf_BC', "value")
1631- call remap_field(ice_surfaceT, scalar_surface)
1632- !! Salinity
1633- scalar_surface => extract_surface_field(SS, 'salinity_iceshelf_BC', "value")
1634- call remap_field(ice_surfaceS, scalar_surface)
1635-! ewrite(1,*) "iceBC, ice_element_list",ice_element_list
1636-! ewrite(1,*) "iceBC, node_count(scalar_surface)", node_count(scalar_surface)
1637-! ewrite(1,*) "node_val(scalar_surface,1): ", node_val(scalar_surface,1)
1638-
1639-!! Insert BC for salinity
1640-
1641-
1642-end subroutine melt_bc
1643-
1644-
1645-
1646-!!------------------------------------------------------------------!
1647-!! Private subroutines !
1648-!!------------------------------------------------------------------!
1649-
1650-subroutine melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list)
1651-
1652- type(mesh_type), intent(in) :: mesh
1653- type(integer_set), intent(in) :: surface_ids
1654- type(mesh_type), intent(out) :: surface_mesh
1655- integer, dimension(:), pointer, intent(out) :: surface_nodes ! allocated and returned by create_surface_mesh
1656- integer, dimension(:), allocatable, intent(out) :: surface_element_list
1657- ! integer, dimension(:), allocatable :: surface_nodes_out
1658- type(scalar_field) :: surface_field
1659- type(integer_set) :: surface_elements
1660- integer :: i
1661- ! create a set of surface elements that have surface id in 'surface_ids'
1662-
1663- call allocate(surface_elements)
1664- do i=1, surface_element_count(mesh)
1665-! ewrite(1,*) "surf_normal surface_element_id(mesh, i)", surface_element_id(mesh, i)
1666-! ewrite(1,*) "surf_normal surface_ids", set2vector(surface_ids)
1667- if (has_value(surface_ids, surface_element_id(mesh, i))) then
1668- call insert(surface_elements, i)
1669-
1670- end if
1671- end do
1672-
1673- allocate(surface_element_list(key_count(surface_elements)))
1674- surface_element_list=set2vector(surface_elements)
1675- call create_surface_mesh(surface_mesh, surface_nodes, mesh, surface_element_list, name=trim(mesh%name)//"ToshisMesh")
1676-
1677-
1678-end subroutine melt_surf_mesh
1679-
1680-
1681-real function setnan(arg)
1682- real :: arg
1683- setnan = sqrt(arg)
1684-end function
1685-
1686-real function calc_area2(positions,nodes)
1687- type(vector_field), pointer :: positions
1688- integer, dimension(2) :: nodes
1689- real, dimension(2) :: coord1,coord2
1690-! real :: area
1691- coord1 = node_val(positions,nodes(1))
1692- coord2 = node_val(positions,nodes(2))
1693-
1694- calc_area2 = (sum((coord2 - coord1)**2))**0.5
1695-
1696-end function
1697-
1698-real function calc_area3(positions,nodes)
1699- type(vector_field), pointer :: positions
1700- integer, dimension(3) :: nodes
1701- real, dimension(3) :: coord1,coord2,coord3
1702- real :: a,b,c,s
1703-! real :: area
1704- coord1 = node_val(positions,nodes(1))
1705- coord2 = node_val(positions,nodes(2))
1706- coord3 = node_val(positions,nodes(3))
1707-! Use Heron's formula to calculate the area of triangle
1708- a = (sum((coord2 - coord1)**2))**0.5
1709- b = (sum((coord3 - coord1)**2))**0.5
1710- c = (sum((coord2 - coord3)**2))**0.5
1711- s = 0.5*(a+b+c)
1712- calc_area3 = (s*(s-a)*(s-b)*(s-c))**0.5
1713-
1714-end function
1715-
1716-end module iceshelf_meltrate_surf_normal
1717
1718=== modified file 'schemas/fluidity_options.rnc'
1719--- schemas/fluidity_options.rnc 2013-10-11 10:48:07 +0000
1720+++ schemas/fluidity_options.rnc 2013-10-25 15:24:41 +0000
1721@@ -6528,6 +6528,33 @@
1722 }
1723 )
1724 }?,
1725+ ## Provide the hydrostatic pressure under the shelf
1726+ ## for the interface melt parameterisation
1727+ element scalar_field {
1728+ attribute rank { "0" },
1729+ attribute name { "subshelf_hydrostatic_pressure" },
1730+ (
1731+ element diagnostic {
1732+ internal_algorithm,
1733+ velocity_mesh_choice,
1734+ diagnostic_scalar_field
1735+ }
1736+ )
1737+ }?,
1738+ element subshelf_hydrostatic_pressure {
1739+ (
1740+ ## Python function prescribing real input. Functions should be of the form:
1741+ ##
1742+ ## def val(t):
1743+ ## # Function code
1744+ ## return # Return value
1745+ ##
1746+ ##
1747+ element python {
1748+ python_code
1749+ }
1750+ )
1751+ }?,
1752 ## Boundary stuff
1753 element calculate_boundaries {
1754 element string_value {
1755
1756=== modified file 'schemas/fluidity_options.rng'
1757--- schemas/fluidity_options.rng 2013-10-11 10:48:07 +0000
1758+++ schemas/fluidity_options.rng 2013-10-25 15:24:41 +0000
1759@@ -8228,6 +8228,37 @@
1760 </element>
1761 </optional>
1762 <optional>
1763+ <element name="scalar_field">
1764+ <a:documentation>Provide the hydrostatic pressure under the shelf
1765+for the interface melt parameterisation</a:documentation>
1766+ <attribute name="rank">
1767+ <value>0</value>
1768+ </attribute>
1769+ <attribute name="name">
1770+ <value>subshelf_hydrostatic_pressure</value>
1771+ </attribute>
1772+ <element name="diagnostic">
1773+ <ref name="internal_algorithm"/>
1774+ <ref name="velocity_mesh_choice"/>
1775+ <ref name="diagnostic_scalar_field"/>
1776+ </element>
1777+ </element>
1778+ </optional>
1779+ <optional>
1780+ <element name="subshelf_hydrostatic_pressure">
1781+ <element name="python">
1782+ <a:documentation>Python function prescribing real input. Functions should be of the form:
1783+
1784+ def val(t):
1785+ # Function code
1786+ return # Return value
1787+
1788+</a:documentation>
1789+ <ref name="python_code"/>
1790+ </element>
1791+ </element>
1792+ </optional>
1793+ <optional>
1794 <element name="calculate_boundaries">
1795 <a:documentation>Boundary stuff </a:documentation>
1796 <element name="string_value">