Merge lp:~fluidity-core/fluidity/iceshelf into lp:fluidity
- iceshelf
- Merge into dev-trunk
Status: | Rejected |
---|---|
Rejected by: | Adam Candy |
Proposed branch: | lp:~fluidity-core/fluidity/iceshelf |
Merge into: | lp:fluidity |
Diff against target: |
202417 lines (+4975/-195824) 115 files modified
aclocal.m4 (+7/-25) configure (+53/-85) examples/backward_facing_step_3d/Ercoftac-test31-BFS/readme (+28/-0) examples/backward_facing_step_3d/Makefile (+1/-1) examples/hokkaido-nansei-oki_tsunami/hokkaido-nansei-oki_tsunami.xml (+2/-2) examples/restratification_after_oodc/Makefile (+1/-1) examples/tephra_settling/tephra_settling.flml (+0/-5) examples/tephra_settling/tephra_settling.xml (+0/-11) examples/top_hat/top_hat.xml (+1/-1) femtools/Diagnostic_Fields.F90 (+1/-19) femtools/Halos_Communications.F90 (+10/-13) femtools/Makefile.dependencies (+0/-12) femtools/Makefile.in (+1/-1) femtools/Parallel_fields.F90 (+8/-20) femtools/Vertical_Extrapolation.F90 (+0/-1290) main/Fluids.F90 (+11/-16) main/Makefile.dependencies (+1/-1) manual/embedded_models.tex (+0/-7) manual/model_equations.tex (+6/-37) manual/numerical_discretisation.tex (+5/-26) manual/parameterisations.tex (+0/-12) manual/visualisation_and_diagnostics.tex (+0/-1) parameterisation/Gls_vertical_turbulence_model.F90 (+103/-355) parameterisation/Ice_Melt_Interface.F90 (+950/-0) parameterisation/Makefile.dependencies (+5/-6) parameterisation/Makefile.in (+1/-1) parameterisation/iceshelf_meltrate_surf_normal.F90 (+0/-678) schemas/multiphase_interaction.rnc (+0/-58) schemas/multiphase_interaction.rng (+0/-65) schemas/prognostic_field_options.rnc (+1/-2) schemas/prognostic_field_options.rng (+1/-2) schemas/spatial_discretisation.rnc (+1/-1) schemas/spatial_discretisation.rng (+1/-1) tests/diff_src_robin_1d/diff_src_robin_1d.xml (+1/-16) tests/diff_src_robin_1d/diff_src_robin_1d_cvelegrad_p1_A.flml (+0/-244) tests/flux_bc/Makefile (+0/-22) tests/flux_bc/flux_bc.xml (+0/-54) tests/flux_bc/flux_bc_2d.flml (+0/-396) tests/flux_bc/flux_bc_3d.flml (+0/-405) tests/flux_bc/src/flux_bc_2d.geo (+0/-19) tests/flux_bc/src/flux_bc_3d.geo (+0/-69) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-gen-CA.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-gen-CB.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-gen-GL.flml (+8/-8) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-gen-KC94.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_e-CA.flml (+2/-1) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_e-CB.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_e-GL.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_e-KC94.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_w-CA.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_w-CB.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_w-GL.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth-k_w-KC94.flml (+4/-4) tests/gls-Kato_Phillips-mixed_layer_depth/gls-Kato_Phillips-mixed_layer_depth.xml (+38/-39) tests/gls-Kato_Phillips-mixed_layer_depth/mixed_layer_depth.py (+1/-1) tests/gls-Kato_Phillips-mixed_layer_depth/mixed_layer_depth_all.py (+3/-3) tests/gls-Kato_Phillips-mixed_layer_depth/mld_calc.py (+1/-1) tests/gls-ocean-param/Makefile (+0/-8) tests/gls-ocean-param/gls-StationPapa-orig.flml (+0/-1024) tests/gls-ocean-param/gls-StationPapa-param.flml (+0/-1032) tests/gls-ocean-param/gls-StationPapa-setup.flml (+0/-1071) tests/gls-ocean-param/gls-StationPapa-setup_CoordinateMesh_1_checkpoint.ele (+0/-601) tests/gls-ocean-param/gls-StationPapa-setup_CoordinateMesh_1_checkpoint.face (+0/-805) tests/gls-ocean-param/gls-StationPapa-setup_CoordinateMesh_1_checkpoint.node (+0/-405) tests/gls-ocean-param/gls-StationPapa-setup_VelocityMesh_1_checkpoint.vtu (+0/-27) tests/gls-ocean-param/gls-ocean-param.xml (+0/-57) tests/gls-ocean-param/gls_ocean_param.py (+0/-285) tests/gls-ocean-param/salinity.csv (+0/-125) tests/gls-ocean-param/src/gls-StationPapa-3D.geo (+0/-25) tests/gls-ocean-param/temperature.csv (+0/-125) tests/mphase_divergence_free_velocity/mphase_divergence_free_velocity.xml (+0/-10) tests/mphase_dusty_gas_shock_tube/Makefile (+0/-18) tests/mphase_dusty_gas_shock_tube/mphase_dusty_gas_shock_tube.flml (+0/-733) tests/mphase_dusty_gas_shock_tube/mphase_dusty_gas_shock_tube.xml (+0/-160) tests/mphase_dusty_gas_shock_tube/plot.py (+0/-93) tests/mphase_dusty_gas_shock_tube/shocktube.py (+0/-157) tests/mphase_dusty_gas_shock_tube/single_phase_frozen_flow_test.flml (+0/-379) tests/mphase_dusty_gas_shock_tube/single_phase_frozen_flow_test.py (+0/-75) tests/mphase_identical_velocities/mphase_identical_velocities.xml (+0/-10) tests/mphase_identical_velocities_dg/mphase_identical_velocities_dg.xml (+0/-11) tests/mphase_inlet_velocity_bc_incompressible/Makefile (+0/-17) tests/mphase_inlet_velocity_bc_incompressible/mphase_inlet_velocity_bc_incompressible.flml (+0/-527) tests/mphase_inlet_velocity_bc_incompressible/mphase_inlet_velocity_bc_incompressible.xml (+0/-73) tests/mphase_mms_p1dgp2_test_cty_cv_no_interactions/mphase_mms_p1dgp2_test_cty_cv_no_interactions.xml (+0/-10) tests/mphase_mms_p1p1stabilised_no_interactions/mphase_mms_p1p1stabilised_no_interactions.xml (+0/-9) tests/mphase_rising_body/mphase_rising_body.xml (+0/-9) tests/mphase_rogue_shock_tube_dense_bed_glass/Makefile (+0/-18) tests/mphase_rogue_shock_tube_dense_bed_glass/mphase_rogue_shock_tube_dense_bed_glass.flml (+0/-824) tests/mphase_rogue_shock_tube_dense_bed_glass/mphase_rogue_shock_tube_dense_bed_glass.xml (+0/-118) tests/mphase_rogue_shock_tube_dense_bed_glass/plot.py (+0/-70) tests/mphase_rogue_shock_tube_dense_bed_glass/src/mphase_rogue_shock_tube_dense_bed_glass.geo (+0/-19) tests/mphase_rogue_shock_tube_dense_bed_nylon/Makefile (+0/-17) tests/mphase_rogue_shock_tube_dense_bed_nylon/mphase_rogue_shock_tube_dense_bed_nylon.flml (+0/-824) tests/mphase_rogue_shock_tube_dense_bed_nylon/mphase_rogue_shock_tube_dense_bed_nylon.xml (+0/-118) tests/mphase_rogue_shock_tube_dense_bed_nylon/plot.py (+0/-96) tests/mphase_rogue_shock_tube_dense_bed_nylon/src/mphase_rogue_shock_tube_dense_bed_nylon.geo (+0/-19) tests/mphase_sedimentation_1d/mphase_sedimentation_1d.xml (+0/-9) tests/mphase_sedimentation_2d/mphase_sedimentation_2d.xml (+0/-10) tests/mphase_stokes_law/mphase_stokes_law.flml (+0/-5) tests/mphase_stokes_law/mphase_stokes_law.xml (+0/-10) tests/mphase_tephra_settling/mphase_tephra_settling.flml (+0/-5) tests/mphase_tephra_settling/mphase_tephra_settling.xml (+0/-10) tests/mphase_three_layers/mphase_three_layers.xml (+0/-10) tests/mphase_wen_yu_drag_correlation/Makefile (+0/-17) tests/mphase_wen_yu_drag_correlation/c_against_re.py (+0/-26) tests/mphase_wen_yu_drag_correlation/mphase_wen_yu_drag_correlation.flml (+0/-793) tests/mphase_wen_yu_drag_correlation/mphase_wen_yu_drag_correlation.xml (+0/-86) tests/mphase_wen_yu_drag_correlation/src/mphase_wen_yu_drag_correlation.geo (+0/-19) tests/photosynthetic_radiation/Makefile (+0/-1) tests/photosynthetic_radiation/photosynthetic_radiation.flml (+1/-1) tests/photosynthetic_radiation/photosynthetic_radiation.xml (+2/-2) tests/photosynthetic_radiation/src/column.geo (+4/-4) tests/photosynthetic_radiation/src/column.msh (+1837/-177170) tests/photosynthetic_radiation_cg/photosynthetic_radiation.flml (+1/-1) tests/photosynthetic_radiation_cg/src/column.msh (+1837/-3568) |
To merge this branch: | bzr merge lp:~fluidity-core/fluidity/iceshelf |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Adam Candy | Needs Fixing | ||
Stephan Kramer | Disapprove | ||
Review via email: mp+117538@code.launchpad.net |
Commit message
Description of the change
Adding iceshelf parameterization to the trunk.
As of today, this branch has green light from Buildbot (http://
The merge will enable us to:
1) prescribe ice as a boundary condition on T and S;
2) allow inhomogeneous Neumann BC on scalar fields discretized in P1DG.
Alexandros Avdis (alexandros-avdis) wrote : | # |
- 4021. By Jon Hill
-
New GLS updates which include:
- Ocean parameterisation which parameterises internal wave breaking, adding some surface TKE into deeper water
- Updates to assembly routines which are now mostly element-wise
- Updates to tests
- Manual updates - 4022. By Jon Hill
-
Adding tests for PAR and updating manual
- 4023. By Rhodri Davies
-
Bug fix for CV, when a diffusion term is present. Again supplied by Cian.
- 4024. By Christian Jacobs
-
Merging compressible-
multiphase branch revisions r3955 to r4067 (inclusive) into trunk. Summary of changes:
===================- Added multiphase support for the compressible projection method (currently only for CG Pressure).
- Small changes to the logic in Momentum_
Equation. F90. Replaced the use_compressibl e_projection logical with compressible_eos which is .true. if option_ count(" /material_ phase/equation_ of_state/ compressible" ) > 0, and .false. otherwise. - Added multiphase support for the InternalEnergy equation. Note that the whole state array is now passed to solve_field_
equation_ cg. - Implemented the heat transfer term by Gunn (1978).
- Added three P2-P1 multiphase MMS tests for model verification: one without InternalEnergy fields, one with InternalEnergy fields, and one with InternalEnergy fields and heat transfer. The tests will become longtests after merging into the trunk.
- The manual now has documentation on the compressible multiphase model, including the multiphase version of the InternalEnergy equation.
- Added a diagnostic field called CompressibleCon
tinuityResidual which computes the residual of the compressible multiphase continuity equation. This is similar to the SumVelocityDive rgence field for incompressible multiphase flow which computes \sum{div(vfrac*u)}. - Added two gas-solid shock tube tests to help to validate the model: mphase_
rogue_shock_ tube_dense_ bed_glass and mphase_ rogue_shock_ tube_dense_ bed_nylon. - Added another gas-solid shock tube test (mphase_
dusty_gas_ shock_tube) which uses the setup by Miura & Glass (1982). - Implemented two new correlations for fluid-particle drag. The one by Wen & Yu (1966) can support higher Reynolds numbers (compared to the existing Stokes' law correlation). The one by Ergun (1952) can support dense flows where the volume fraction of the particle phase is greater than 0.2, like in the dense bed shock tube tests (and in the pyroclastic flow tests which will hopefully come later).
- Changed the structure of the schema. Users now explicitly select which interaction terms they wish to include, as well as the drag correlation, under "/multiphase_
interaction" in Diamond. These options are stored in the new files multiphase_ interaction. rnc and multiphase_ interaction. rng. - Added a test for the Wen & Yu (1966) drag correlation. This is similar to mphase_stokes_law.
- Added a test to check if inlet velocity boundary conditions work with the incompressible multiphase flow model.
- Added a test for the flux boundary condition.
- 4025. By Christian Jacobs
-
Moved the compressible multiphase MMS tests to the longtests directory.
- 4026. By Christian Jacobs
-
- Updated the tephra_settling example's .flml file to use the new multiphase_
interaction schema structure.
- Corrected a small typo in the manual. - 4027. By Lawrence Mitchell
-
Fix DG momentum assembly corner case
Since r3984 we would assemble elements in DG momentum if
element_neighbour_ owned returned true. However, for some corner cases
element_neighbour_ owned need not return true if the element is owned
(consider the case of a process with one owned element). In this
situation we would not correctly assemble all elements. To fix this,
change the test for element assembly to directly check for element
ownership.At the same time, update the documentation for element_
neighbour_ owned
to note this issue. - 4028. By Rhodri Davies
-
Merge relax_halo_verifies branch into trunk. Thanks to dham for review.
- 4029. By j-bull08 <email address hidden>
-
Removing duplicate file in 3D BFS example.
- 4030. By Lawrence Mitchell
-
Fix CG momentum assembly on intel fortran
This only affects the have_les and .not. dynamic_les code path.
- 4031. By Rhodri Davies
-
Merge zoltan configure check for .mod files into trunk. Thanks to steph for help and jon for review.
- 4032. By Christian Jacobs
-
Added solvers_converged pass_tests to all multiphase tests.
- 4033. By Christian Jacobs
-
Added a solvers_converged pass_test to the tephra_settling example.
- 4034. By Samuel Parkinson
-
Updated Momentum_CG.F90 so that upwind stabilisation can be used with partial or full stress form. The issue is that when using partial or full stress form we tend to set all components of viscosity to the same value. This makes the tensor determinant zero and we cannot invert it. This fix simply sets all non-diagonal terms to zero for the purpose of handling stabilisation when using partial or full stress forms. This isn't ideal as it ignores the fact that we may have non-isotropic viscosities, but these aren't handled properly for these stress forms anyway - so this is a bigger issue that may need fixing later.
The same issue arises when we try to calculate the GridReynoldsNumber diagnostic field and the same fix has been applied here.
- 4035. By Samuel Parkinson
-
bug fix of SUPG stabilisation in Momentum_CG.F90
Tim Greaves (tim-greaves) wrote : | # |
Toshi is keen to get reviews of this and make any corrections needed prior to merging; if anyone with knowledge of this code is able to look through this request and give feedback that would be much appreciated!
Jon Hill (jon-hill) wrote : | # |
Also note that Toshi has made a change to the VTK interface which from the code looks like it allows the user to stop the DG-ifiying of output fields. Are the DG fields projected to continuous somewhere?
Are the fluidity.log and .err files meant to be there?
Looks OK to me, but I would prefer someone else cast an eye over it too.
Stephan Kramer (s-kramer) wrote : | # |
The DG Neumann bc is being further developed on this branch https:/
This merge seems to have all sorts of other unrelated stuff: FLHere(), /io/adhere_
Please have a look at the diff with the trunk yourself before you put anything up for merge proposal. Reviewing is a lot of work, so we expect things to be cleaned up properly before requesting a merge (no commented out code, etc.)
Adam Candy (asc) wrote : | # |
The latest commit deleting the ice shelf test cases to get the build machine passing was a retrograde step! These need to be fixed and returned to the merge.
Adam Candy (asc) wrote : | # |
This branch also contains features currently being worked on in other branches, which themselves are under merge review. These features are not required by the ice shelf thermodynamics, which is what this merge concerns and should be removed from the branch.
These include:
lp:~asc/fluidity/extrudeup
lp:~asc/fluidity/regularisespatialaspect
lp:~asc/fluidity/here
lp:~asc/fluidity/dgifychoice
Satoshi Kimura (skimura04) wrote : | # |
Thanks everyone for good thoughts.
I will start from merging in the thermodynamics part first and work the way up.
Toshi
> This branch also contains features currently being worked on in other
> branches, which themselves are under merge review. These features are not
> required by the ice shelf thermodynamics, which is what this merge concerns
> and should be removed from the branch.
>
> These include:
> lp:~asc/fluidity/extrudeup
> lp:~asc/fluidity/regularisespatialaspect
> lp:~asc/fluidity/here
> lp:~asc/fluidity/dgifychoice
- 4036. By Tim Greaves
-
One-line fix, setting the correct flml filename in the test xml.
- 4037. By Adam Candy
-
Removal of a runtime-generated test file.
jhill - please check! - 4038. By Samuel Parkinson
-
Added options for how the bed shear stress is calculated. Yuo can now either:
- use drag formulation as before
- calculate the shear stress based upon the gradient of the velocity field at the bed
- use the shear stress estimate generated by the wall boundary layer boundary condition algorithm - 4039. By Samuel Parkinson
-
change to lock_exchange example so that, when run as a test, it runs to 30 seconds so that the tests are checked properly
- 4040. By Christian Jacobs
-
Merging compressible-
multiphase branch revisions r4068 to r4077 (inclusive) into trunk. Summary of changes:
===================- Added multiphase support for stress_form, partial_stress_form and isotropic diagonal_viscosity in Momentum_CG.F90. The stress_form will be important in compressible multiphase flow simulations.
- Added an MMS test (mphase_
mms_p2p1_ stress_ form) for the stress_form changes. - 4041. By Christian Jacobs
-
Small edit to the manual to generalise the form of the multiphase stress term.
- 4042. By Xiaohu Guo
-
1. thread matrix assembly part for Advection_
Diffusion_ DG.F90
2. MASSLUMPED_RT0 diffusion scheme is not supported, simply set threads back to 1 if MASSLUMPED_RT0 diffusion scheme is being used, and there will be a warning message.
3. thread matrix assembly part for Advection_Diffusion_ FV.F90 - 4043. By Christian Jacobs
-
Merging k_epsilon_
extend_ and_fix branch into trunk. Changes to k-epsilon model:
============== ======= ======
- The code no longer lumps the mass matrix when calculating source terms for the k and epsilon fields, allowing element pairs other than P1-P1 to be used.
- k-epsilon field calculation moved to the beginning of the time-step and calculated with all other diagnostic fields.
- Added source term to momentum equation (-2/3 grad(rho*k)).
- Updated the manual documentation for the k-epsilon model.
- Users must now use partial-stress or full-stress form for the stress term in the momentum equation. This is the correct formulation when using spatially
varying viscosities. The ScalarEddyViscosity from the model is added to all components of the stress tensor to reflect this.
- Fixed calculation of c_eps_3.
- Added lots of debugging options.
- Improved the options_check subroutine.
- Changed how prescribed source terms are implemented for the k and epsilon fields so that multiple non-linear iterations can be carried out
with prescribed source terms.
- Altered calculation of Reynolds Stresses.
- Added a new equation_type (KEpsilon) for the k-epsilon equation. This includes the density in the advection-diffusion equation for the k and epsilon fields. Also made many other changes to the code to take account of density variations. Supports CG and CV discretisations.
- Made a few preliminary steps for adding multiphase support to the k-epsilon model.
- k and epsilon fields are now clipped at Gauss points rather than nodes.
- Moved element assembly to its own subroutine to avoid dynamic memory assignment.
- Changed k and epsilon diffusivity tensor to (nu + nu_t/sigma_*) instead of (nu_t/sigma_*)
- The turbulent buoyancy term is now calculated from the VelocityBuoyancyDensity rather than a summation of scalar fields that have been identified as
being buoyant. This means that any buoyant field will automatically result in a buoyancy term in the k-epsilon model (unless the entire term
is disabled in debugging_options)
- Removed several unused variables.
- Added the buoyancy term to the k-epsilon model.
- Added damping functions for the low_Re k-epsilon model.
- Changed epsilon low_Re boundary condition to d(eps)/dx = 0 as it's simpler than what we had before and still valid (Wilcox 1998).
- Fixes to high-Re boundary conditions.
- Removed length scale limiting.Changes to tests and examples:
============== ======= ======= ==
- The existing k-epsilon MMS test (k-epsilon_mms_cg_ p1p1) has been removed and replaced with one that uses a P2-P1 discretisation and runs to steady state.
- Three additional tests have been added for the low_Re boundary condition, and the LinearMomentum Velocity equation_type with CG and CV discretisations.
- Tests include the turbulent buoyancy term and scalar field turbulent diffusion.
- A unit test has been added for the tensor_inner_product function.
- Fixed the backward facing step 2D example based on the changes to the k-epsilon model. - 4044. By Christian Jacobs
-
Moved tests/mms_
rans_p2p1_ keps_linearmome ntum and tests/mms_ rans_p2p1_ keps_linearmome ntum_cv to the longtests directory. - 4045. By Christian Jacobs
-
Buildbot's makefiles-x86_64 queue has been failing since r4042. These updates from make makefiles will hopefully fix this.
- 4046. By Adam Candy
-
Wetting and Drying bug fix - the material phase had an assumed name of 'water'.
(It is now just assumed to be the first material phase) - 4047. By Satoshi Kimura
-
Added the meltrate code
- 4048. By Satoshi Kimura
-
Fixed the makefile.
dependencies
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
1 | === modified file 'aclocal.m4' |
2 | --- aclocal.m4 2012-08-16 17:13:12 +0000 |
3 | +++ aclocal.m4 2012-09-04 15:00:37 +0000 |
4 | @@ -412,6 +412,8 @@ |
5 | AC_MSG_ERROR( [You need to set PETSC_DIR to point at your PETSc installation... exiting] ) |
6 | fi |
7 | |
8 | + |
9 | + |
10 | PETSC_LINK_LIBS=`make -s -f petsc_makefile getlinklibs` |
11 | LIBS="$PETSC_LINK_LIBS $LIBS" |
12 | |
13 | @@ -465,7 +467,7 @@ |
14 | # petsc tutorial - using the headers in the same way as we do in the code |
15 | AC_LINK_IFELSE( |
16 | [AC_LANG_SOURCE([ |
17 | -program test_petsc |
18 | +program test |
19 | #include "petscversion.h" |
20 | #ifdef HAVE_PETSC_MODULES |
21 | use petsc |
22 | @@ -572,13 +574,13 @@ |
23 | call MatDestroy(A,ierr) |
24 | |
25 | call PetscFinalize(ierr) |
26 | -end program test_petsc |
27 | +end program test |
28 | ])], |
29 | [ |
30 | AC_MSG_NOTICE([PETSc program succesfully compiled and linked.]) |
31 | ], |
32 | [ |
33 | -cp conftest.F90 test_petsc.F90 |
34 | +cp conftest.F90 test.F90 |
35 | AC_MSG_FAILURE([Failed to compile and link PETSc program.])]) |
36 | |
37 | AC_LANG_RESTORE |
38 | @@ -1004,6 +1006,7 @@ |
39 | echo "note: using $zoltan_INCLUDES_PATH/zoltan.mod" |
40 | fi |
41 | |
42 | + |
43 | AC_LANG_SAVE |
44 | AC_LANG_C |
45 | AC_CHECK_LIB( |
46 | @@ -1011,28 +1014,7 @@ |
47 | [Zoltan_Initialize], |
48 | [AC_DEFINE(HAVE_ZOLTAN,1,[Define if you have zoltan library.])], |
49 | [AC_MSG_ERROR( [Could not link in the zoltan library... exiting] )] ) |
50 | - |
51 | -# Small test for zoltan .mod files: |
52 | -AC_LANG(Fortran) |
53 | -ac_ext=F90 |
54 | -# In fluidity's makefile we explicitly add CPPFLAGS, temporarily add it to |
55 | -# FCFLAGS here for this zoltan test: |
56 | -tmpFCFLAGS="$FCFLAGS" |
57 | -FCFLAGS="$FCFLAGS $CPPFLAGS" |
58 | -AC_LINK_IFELSE( |
59 | -[AC_LANG_SOURCE([ |
60 | -program test_zoltan |
61 | - use zoltan |
62 | -end program test_zoltan |
63 | -])], |
64 | -[ |
65 | -AC_MSG_NOTICE([Great success! Zoltan .mod files exist and are usable]) |
66 | -], |
67 | -[ |
68 | -cp conftest.F90 test_zoltan.F90 |
69 | -AC_MSG_FAILURE([Failed to find zoltan.mod files])]) |
70 | -# And now revert FCFLAGS |
71 | -FCFLAGS="$tmpFCFLAGS" |
72 | +# Save variables... |
73 | AC_LANG_RESTORE |
74 | |
75 | ZOLTAN="yes" |
76 | |
77 | === modified file 'configure' |
78 | --- configure 2012-08-16 17:13:12 +0000 |
79 | +++ configure 2012-09-04 15:00:37 +0000 |
80 | @@ -2137,52 +2137,6 @@ |
81 | |
82 | } # ac_fn_f77_try_link |
83 | |
84 | -# ac_fn_fc_try_link LINENO |
85 | -# ------------------------ |
86 | -# Try to link conftest.$ac_ext, and return whether this succeeded. |
87 | -ac_fn_fc_try_link () |
88 | -{ |
89 | - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
90 | - rm -f conftest.$ac_objext conftest$ac_exeext |
91 | - if { { ac_try="$ac_link" |
92 | -case "(($ac_try" in |
93 | - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; |
94 | - *) ac_try_echo=$ac_try;; |
95 | -esac |
96 | -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" |
97 | -$as_echo "$ac_try_echo"; } >&5 |
98 | - (eval "$ac_link") 2>conftest.err |
99 | - ac_status=$? |
100 | - if test -s conftest.err; then |
101 | - grep -v '^ *+' conftest.err >conftest.er1 |
102 | - cat conftest.er1 >&5 |
103 | - mv -f conftest.er1 conftest.err |
104 | - fi |
105 | - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
106 | - test $ac_status = 0; } && { |
107 | - test -z "$ac_fc_werror_flag" || |
108 | - test ! -s conftest.err |
109 | - } && test -s conftest$ac_exeext && { |
110 | - test "$cross_compiling" = yes || |
111 | - $as_test_x conftest$ac_exeext |
112 | - }; then : |
113 | - ac_retval=0 |
114 | -else |
115 | - $as_echo "$as_me: failed program was:" >&5 |
116 | -sed 's/^/| /' conftest.$ac_ext >&5 |
117 | - |
118 | - ac_retval=1 |
119 | -fi |
120 | - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information |
121 | - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would |
122 | - # interfere with the next link command; also delete a directory that is |
123 | - # left behind by Apple's compiler. We do this before executing the actions. |
124 | - rm -rf conftest.dSYM conftest_ipa8_conftest.oo |
125 | - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
126 | - as_fn_set_status $ac_retval |
127 | - |
128 | -} # ac_fn_fc_try_link |
129 | - |
130 | # ac_fn_c_check_func LINENO FUNC VAR |
131 | # ---------------------------------- |
132 | # Tests whether FUNC exists, setting the cache variable VAR accordingly |
133 | @@ -2266,6 +2220,52 @@ |
134 | |
135 | } # ac_fn_c_check_func |
136 | |
137 | +# ac_fn_fc_try_link LINENO |
138 | +# ------------------------ |
139 | +# Try to link conftest.$ac_ext, and return whether this succeeded. |
140 | +ac_fn_fc_try_link () |
141 | +{ |
142 | + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
143 | + rm -f conftest.$ac_objext conftest$ac_exeext |
144 | + if { { ac_try="$ac_link" |
145 | +case "(($ac_try" in |
146 | + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; |
147 | + *) ac_try_echo=$ac_try;; |
148 | +esac |
149 | +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" |
150 | +$as_echo "$ac_try_echo"; } >&5 |
151 | + (eval "$ac_link") 2>conftest.err |
152 | + ac_status=$? |
153 | + if test -s conftest.err; then |
154 | + grep -v '^ *+' conftest.err >conftest.er1 |
155 | + cat conftest.er1 >&5 |
156 | + mv -f conftest.er1 conftest.err |
157 | + fi |
158 | + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
159 | + test $ac_status = 0; } && { |
160 | + test -z "$ac_fc_werror_flag" || |
161 | + test ! -s conftest.err |
162 | + } && test -s conftest$ac_exeext && { |
163 | + test "$cross_compiling" = yes || |
164 | + $as_test_x conftest$ac_exeext |
165 | + }; then : |
166 | + ac_retval=0 |
167 | +else |
168 | + $as_echo "$as_me: failed program was:" >&5 |
169 | +sed 's/^/| /' conftest.$ac_ext >&5 |
170 | + |
171 | + ac_retval=1 |
172 | +fi |
173 | + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information |
174 | + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would |
175 | + # interfere with the next link command; also delete a directory that is |
176 | + # left behind by Apple's compiler. We do this before executing the actions. |
177 | + rm -rf conftest.dSYM conftest_ipa8_conftest.oo |
178 | + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
179 | + as_fn_set_status $ac_retval |
180 | + |
181 | +} # ac_fn_fc_try_link |
182 | + |
183 | # ac_fn_fc_try_run LINENO |
184 | # ----------------------- |
185 | # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes |
186 | @@ -11791,6 +11791,7 @@ |
187 | fi |
188 | |
189 | |
190 | + |
191 | ac_ext=c |
192 | ac_cpp='$CPP $CPPFLAGS' |
193 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' |
194 | @@ -11857,42 +11858,7 @@ |
195 | as_fn_error $? "Could not link in the zoltan library... exiting " "$LINENO" 5 |
196 | fi |
197 | |
198 | - |
199 | -# Small test for zoltan .mod files: |
200 | -ac_ext=${ac_fc_srcext-f} |
201 | -ac_compile='$FC -c $FCFLAGS $ac_fcflags_srcext conftest.$ac_ext >&5' |
202 | -ac_link='$FC -o conftest$ac_exeext $FCFLAGS $LDFLAGS $ac_fcflags_srcext conftest.$ac_ext $LIBS >&5' |
203 | -ac_compiler_gnu=$ac_cv_fc_compiler_gnu |
204 | - |
205 | -ac_ext=F90 |
206 | -# In fluidity's makefile we explicitly add CPPFLAGS, temporarily add it to |
207 | -# FCFLAGS here for this zoltan test: |
208 | -tmpFCFLAGS="$FCFLAGS" |
209 | -FCFLAGS="$FCFLAGS $CPPFLAGS" |
210 | -cat > conftest.$ac_ext <<_ACEOF |
211 | - |
212 | -program test_zoltan |
213 | - use zoltan |
214 | -end program test_zoltan |
215 | - |
216 | -_ACEOF |
217 | -if ac_fn_fc_try_link "$LINENO"; then : |
218 | - |
219 | -{ $as_echo "$as_me:${as_lineno-$LINENO}: Great success! Zoltan .mod files exist and are usable" >&5 |
220 | -$as_echo "$as_me: Great success! Zoltan .mod files exist and are usable" >&6;} |
221 | - |
222 | -else |
223 | - |
224 | -cp conftest.F90 test_zoltan.F90 |
225 | -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 |
226 | -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
227 | -as_fn_error $? "Failed to find zoltan.mod files |
228 | -See \`config.log' for more details" "$LINENO" 5; } |
229 | -fi |
230 | -rm -f core conftest.err conftest.$ac_objext \ |
231 | - conftest$ac_exeext conftest.$ac_ext |
232 | -# And now revert FCFLAGS |
233 | -FCFLAGS="$tmpFCFLAGS" |
234 | +# Save variables... |
235 | ac_ext=c |
236 | ac_cpp='$CPP $CPPFLAGS' |
237 | ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' |
238 | @@ -12935,6 +12901,8 @@ |
239 | as_fn_error $? "You need to set PETSC_DIR to point at your PETSc installation... exiting " "$LINENO" 5 |
240 | fi |
241 | |
242 | + |
243 | + |
244 | PETSC_LINK_LIBS=`make -s -f petsc_makefile getlinklibs` |
245 | LIBS="$PETSC_LINK_LIBS $LIBS" |
246 | |
247 | @@ -13004,7 +12972,7 @@ |
248 | # petsc tutorial - using the headers in the same way as we do in the code |
249 | cat > conftest.$ac_ext <<_ACEOF |
250 | |
251 | -program test_petsc |
252 | +program test |
253 | #include "petscversion.h" |
254 | #ifdef HAVE_PETSC_MODULES |
255 | use petsc |
256 | @@ -13111,7 +13079,7 @@ |
257 | call MatDestroy(A,ierr) |
258 | |
259 | call PetscFinalize(ierr) |
260 | -end program test_petsc |
261 | +end program test |
262 | |
263 | _ACEOF |
264 | if ac_fn_fc_try_link "$LINENO"; then : |
265 | @@ -13121,7 +13089,7 @@ |
266 | |
267 | else |
268 | |
269 | -cp conftest.F90 test_petsc.F90 |
270 | +cp conftest.F90 test.F90 |
271 | { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 |
272 | $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
273 | as_fn_error $? "Failed to compile and link PETSc program. |
274 | |
275 | === added file 'examples/backward_facing_step_3d/Ercoftac-test31-BFS/readme' |
276 | --- examples/backward_facing_step_3d/Ercoftac-test31-BFS/readme 1970-01-01 00:00:00 +0000 |
277 | +++ examples/backward_facing_step_3d/Ercoftac-test31-BFS/readme 2012-09-04 15:00:37 +0000 |
278 | @@ -0,0 +1,28 @@ |
279 | +1) File name convention: filename.nnn |
280 | + nnn = streamwise nodal (cell center) location |
281 | + |
282 | + nnn = 181 ---> x/h = -3.0 |
283 | + nnn = 360 ---> x/h = 4.0 |
284 | + nnn = 411 ---> x/h = 6.0 |
285 | + nnn = 513 ---> x/h = 10.0 |
286 | + nnn = 641 ---> x/h = 15.0 |
287 | + nnn = 744 ---> x/h = 19.0 |
288 | + |
289 | +2) Files "x.nnn" contain U, V, u'(rms), v'(rms), w'(rms), u'v'. |
290 | + File header explains the data columns. |
291 | + |
292 | + All quantities are nomalized to U0, where U0 is the mean inlet |
293 | + free stream velocity. |
294 | + |
295 | +3) Files "r**.nnn" contain Reynolds stress budgets. |
296 | + |
297 | + r11.nnn ---> Streamwise component (u'u') |
298 | + r22.nnn ---> Vertical component (v'v') |
299 | + r33.nnn ---> Spanwise component (w'w') |
300 | + r12.nnn ---> Reynolds shear stress component (u'v') |
301 | + rkk.nnn ---> Turbulent kinetic energy |
302 | + |
303 | + All quantities are nomalized to U0^3/h. |
304 | + |
305 | +4) File "stat.info" contains additional information at each streamwise |
306 | + location (u_tau, Cf, etc...). |
307 | |
308 | === modified file 'examples/backward_facing_step_3d/Makefile' |
309 | --- examples/backward_facing_step_3d/Makefile 2012-07-27 08:10:27 +0000 |
310 | +++ examples/backward_facing_step_3d/Makefile 2012-09-04 15:00:37 +0000 |
311 | @@ -39,7 +39,7 @@ |
312 | ./postprocessor_3d.py |
313 | |
314 | input: clean |
315 | - $(MAKE) preprocess NPROCS=8 |
316 | + $(MAKE) preprocess |
317 | |
318 | clean: |
319 | @echo **********Cleaning the output from previous fluidity runs: |
320 | |
321 | === modified file 'examples/hokkaido-nansei-oki_tsunami/hokkaido-nansei-oki_tsunami.xml' |
322 | --- examples/hokkaido-nansei-oki_tsunami/hokkaido-nansei-oki_tsunami.xml 2012-08-22 21:21:08 +0000 |
323 | +++ examples/hokkaido-nansei-oki_tsunami/hokkaido-nansei-oki_tsunami.xml 2012-09-04 15:00:37 +0000 |
324 | @@ -2,8 +2,8 @@ |
325 | <testproblem> |
326 | <name>Monai Valley</name> |
327 | <owner userid="sf1409"/> |
328 | - <problem_definition length="long" nprocs="4"> |
329 | - <command_line>fluidity MonaiValley_C_p1p1_nu0.01_kmkstab_drag0.002_butcircularoundisland0.2.flml</command_line> |
330 | + <problem_definition length="special" nprocs="4"> |
331 | + <command_line>fluidity MonaiValley_C.flml</command_line> |
332 | </problem_definition> |
333 | <variables> |
334 | <variable name="gage_integral_error" language="python">import tools |
335 | |
336 | === modified file 'examples/restratification_after_oodc/Makefile' |
337 | --- examples/restratification_after_oodc/Makefile 2012-07-25 15:27:53 +0000 |
338 | +++ examples/restratification_after_oodc/Makefile 2012-09-04 15:00:37 +0000 |
339 | @@ -40,7 +40,7 @@ |
340 | @echo **********No postprocessing needed |
341 | |
342 | input: clean |
343 | - $(MAKE) preprocess NPROCS=32 |
344 | + $(MAKE) preprocess NPROCS=8 |
345 | |
346 | clean: |
347 | @echo **********Cleaning the output from previous fluidity runs: |
348 | |
349 | === modified file 'examples/tephra_settling/tephra_settling.flml' |
350 | --- examples/tephra_settling/tephra_settling.flml 2012-08-09 22:08:12 +0000 |
351 | +++ examples/tephra_settling/tephra_settling.flml 2012-09-04 15:00:37 +0000 |
352 | @@ -586,9 +586,4 @@ |
353 | </particle_diameter> |
354 | </multiphase_properties> |
355 | </material_phase> |
356 | - <multiphase_interaction> |
357 | - <fluid_particle_drag> |
358 | - <drag_correlation name="stokes"/> |
359 | - </fluid_particle_drag> |
360 | - </multiphase_interaction> |
361 | </fluidity_options> |
362 | |
363 | === modified file 'examples/tephra_settling/tephra_settling.xml' |
364 | --- examples/tephra_settling/tephra_settling.xml 2012-08-19 00:21:26 +0000 |
365 | +++ examples/tephra_settling/tephra_settling.xml 2012-09-04 15:00:37 +0000 |
366 | @@ -20,18 +20,11 @@ |
367 | s = stat_parser("tephra_settling.stat") |
368 | tephra_u_max=s["Tephra"]["Velocity%magnitude"]["max"] |
369 | </variable> |
370 | - |
371 | <variable name="time" language="python"> |
372 | from fluidity_tools import stat_parser |
373 | s = stat_parser("tephra_settling.stat") |
374 | time=s["ElapsedTime"]["value"] |
375 | </variable> |
376 | - |
377 | - <variable name="solvers_converged" language="python"> |
378 | -import os |
379 | -files = os.listdir("./") |
380 | -solvers_converged = not "matrixdump" in files and not "matrixdump.info" in files |
381 | - </variable> |
382 | </variables> |
383 | |
384 | <pass_tests> |
385 | @@ -49,10 +42,6 @@ |
386 | assert max(tephra_u_max[t:]) < 0.05 |
387 | break |
388 | </test> |
389 | - |
390 | - <test name="Solvers converged" language="python"> |
391 | -assert(solvers_converged) |
392 | - </test> |
393 | </pass_tests> |
394 | |
395 | <warn_tests> |
396 | |
397 | === modified file 'examples/top_hat/top_hat.xml' |
398 | --- examples/top_hat/top_hat.xml 2012-07-25 12:38:28 +0000 |
399 | +++ examples/top_hat/top_hat.xml 2012-09-04 15:00:37 +0000 |
400 | @@ -2,7 +2,7 @@ |
401 | <testproblem> |
402 | <name>tophat</name> |
403 | <owner userid="skramer"/> |
404 | - <problem_definition length="long" nprocs="1"> |
405 | + <problem_definition length="medium" nprocs="1"> |
406 | <command_line>fluidity -v2 -l top_hat_cg.flml && |
407 | fluidity -v2 -l top_hat_dg.flml && |
408 | fluidity -v2 -l top_hat_cv.flml</command_line> |
409 | |
410 | === modified file 'femtools/Diagnostic_Fields.F90' |
411 | --- femtools/Diagnostic_Fields.F90 2012-08-29 18:09:06 +0000 |
412 | +++ femtools/Diagnostic_Fields.F90 2012-09-04 15:00:37 +0000 |
413 | @@ -477,7 +477,7 @@ |
414 | type(scalar_field), intent(inout) :: grn |
415 | |
416 | type(vector_field), pointer :: U, X |
417 | - integer :: ele, gi, stat, a, b |
418 | + integer :: ele, gi, stat |
419 | ! Transformed quadrature weights. |
420 | real, dimension(ele_ngi(GRN, 1)) :: detwei |
421 | ! Inverse of the local coordinate change matrix. |
422 | @@ -525,24 +525,6 @@ |
423 | ! The matmul is as given by dham |
424 | GRN_q=ele_val_at_quad(U, ele) |
425 | vis_q=ele_val_at_quad(viscosity, ele) |
426 | - |
427 | - ! for full and partial stress form we need to set the off diagonal terms of the viscosity tensor to zero |
428 | - ! to be able to invert it |
429 | - if (have_option(trim(U%option_path)//& |
430 | - &"/prognostic/spatial_discretisation/continuous_galerkin"//& |
431 | - &"/stress_terms/stress_form") .or. & |
432 | - have_option(trim(U%option_path)//& |
433 | - &"/prognostic/spatial_discretisation/continuous_galerkin"//& |
434 | - &"/stress_terms/partial_stress_form")) then |
435 | - |
436 | - do a=1,size(vis_q,1) |
437 | - do b=1,size(vis_q,2) |
438 | - if(a.eq.b) cycle |
439 | - vis_q(a,b,:) = 0.0 |
440 | - end do |
441 | - end do |
442 | - end if |
443 | - |
444 | do gi=1, size(detwei) |
445 | GRN_q(:,gi)=matmul(GRN_q(:,gi), J(:,:,gi)) |
446 | GRN_q(:,gi)=matmul(inverse(vis_q(:,:,gi)), GRN_q(:,gi)) |
447 | |
448 | === modified file 'femtools/Halos_Communications.F90' |
449 | --- femtools/Halos_Communications.F90 2012-08-10 16:03:41 +0000 |
450 | +++ femtools/Halos_Communications.F90 2012-09-04 15:00:37 +0000 |
451 | @@ -765,8 +765,6 @@ |
452 | |
453 | type(halo_type), intent(in) :: halo |
454 | real, dimension(:), intent(in) :: real_array |
455 | - |
456 | - real :: epsl |
457 | |
458 | logical :: verifies |
459 | |
460 | @@ -780,16 +778,14 @@ |
461 | |
462 | call halo_update(halo, lreal_array) |
463 | |
464 | - epsl = spacing( maxval( abs( lreal_array ))) * 10000. |
465 | - call allmax(epsl) |
466 | - |
467 | - verifies = all(abs(real_array - lreal_array) < epsl ) |
468 | + verifies = all(abs(real_array - lreal_array) < 10000.0 * max(spacing(lreal_array), epsilon(lreal_array))) |
469 | #ifdef DDEBUG |
470 | if(.not. verifies) then |
471 | do i = 1, halo_proc_count(halo) |
472 | do j = 1, halo_receive_count(halo, i) |
473 | receive = halo_receive(halo, i, j) |
474 | - if(abs(real_array(receive) - lreal_array(receive)) >= epsl) then |
475 | + if(abs(real_array(receive) - lreal_array(receive)) >= 10000.0& |
476 | + &*max(spacing(real_array(receive)), epsilon(real_array(receive)))) then |
477 | ewrite(0, *) "Warning: Halo receive ", receive, " for halo " // halo_name(halo) // " failed verification" |
478 | ewrite(0, *) "Reference = ", real_array(receive) |
479 | ewrite(0, *) "Value in verification array = ", lreal_array(receive) |
480 | @@ -798,12 +794,13 @@ |
481 | end do |
482 | |
483 | do i = 1, size(real_array) |
484 | - if(abs(real_array(i) - lreal_array(i)) >= epsl ) then |
485 | - ewrite(0, *) "Warning: Reference index ", i, " for halo " // halo_name(halo) // " failed verification" |
486 | - ewrite(0, *) "Reference = ", real_array(i) |
487 | - ewrite(0, *) "Value in verification array = ", lreal_array(i) |
488 | - end if |
489 | - end do |
490 | + if(abs(real_array(i) - lreal_array(i)) >= 10000.0& |
491 | + &*max(spacing(real_array(i)), epsilon(real_array(i)))) then |
492 | + ewrite(0, *) "Warning: Reference index ", i, " for halo " // halo_name(halo) // " failed verification" |
493 | + ewrite(0, *) "Reference = ", real_array(i) |
494 | + ewrite(0, *) "Value in verification array = ", lreal_array(i) |
495 | + end if |
496 | + end do |
497 | end if |
498 | #endif |
499 | |
500 | |
501 | === modified file 'femtools/Makefile.dependencies' |
502 | --- femtools/Makefile.dependencies 2012-05-29 13:43:29 +0000 |
503 | +++ femtools/Makefile.dependencies 2012-09-04 15:00:37 +0000 |
504 | @@ -1192,18 +1192,6 @@ |
505 | |
506 | Vector_set.o ../include/vector_set.mod: Vector_set.F90 |
507 | |
508 | -../include/vertical_extrapolation_module.mod: Vertical_Extrapolation.o |
509 | - @true |
510 | - |
511 | -Vertical_Extrapolation.o ../include/vertical_extrapolation_module.mod: \ |
512 | - Vertical_Extrapolation.F90 ../include/boundary_conditions.mod \ |
513 | - ../include/dynamic_bin_sort_module.mod ../include/elements.mod \ |
514 | - ../include/fdebug.h ../include/fields.mod ../include/fldebug.mod \ |
515 | - ../include/global_parameters.mod ../include/integer_set_module.mod \ |
516 | - ../include/parallel_tools.mod ../include/pickers.mod \ |
517 | - ../include/sparse_tools.mod ../include/spud.mod ../include/state_module.mod \ |
518 | - ../include/transform_elements.mod ../include/vtk_interfaces.mod |
519 | - |
520 | ../include/wandzura_quadrature.mod: Wandzura_Quadrature.o |
521 | @true |
522 | |
523 | |
524 | === modified file 'femtools/Makefile.in' |
525 | --- femtools/Makefile.in 2012-06-08 20:28:35 +0000 |
526 | +++ femtools/Makefile.in 2012-09-04 15:00:37 +0000 |
527 | @@ -104,7 +104,7 @@ |
528 | CGAL_Tools_C.o CGAL_Tools.o \ |
529 | Rotated_Boundary_Conditions.o MPI_Interfaces.o Parallel_Tools.o \ |
530 | Fields_Halos.o Profiler.o Profiler_Fortran.o Streamfunction.o \ |
531 | - GMSH_Common.o Read_GMSH.o Write_GMSH.o Mesh_Files.o Vertical_Extrapolation.o |
532 | + GMSH_Common.o Read_GMSH.o Write_GMSH.o Mesh_Files.o |
533 | |
534 | |
535 | # objects to be included in libfemtools: |
536 | |
537 | === modified file 'femtools/Parallel_fields.F90' |
538 | --- femtools/Parallel_fields.F90 2012-08-13 12:39:57 +0000 |
539 | +++ femtools/Parallel_fields.F90 2012-09-04 15:00:37 +0000 |
540 | @@ -284,11 +284,8 @@ |
541 | !!< Return .true. if ELEMENT_NUMBER has a neighbour in MESH that |
542 | !!< is owned by this process otherwise .false. |
543 | |
544 | - !! Note, you cannot use this function to compute if |
545 | - !! ELEMENT_NUMBER is owned. Imagine if this is the only owned |
546 | - !! element on a process, then none of the neighbours will be owned. |
547 | - !! You can use this function to compute whether ELEMENT_NUMBER is |
548 | - !! in the L1 element halo. |
549 | + !! Effectively, this computes whether ELEMENT_NUMBER is in the L1 |
550 | + !! halo. |
551 | type(mesh_type), intent(in) :: mesh |
552 | integer, intent(in) :: element_number |
553 | logical :: owned |
554 | @@ -314,11 +311,8 @@ |
555 | !!< Return .true. if ELEMENT_NUMBER has a neighbour in FIELD that |
556 | !!< is owned by this process otherwise .false. |
557 | |
558 | - !! Note, you cannot use this function to compute if |
559 | - !! ELEMENT_NUMBER is owned. Imagine if this is the only owned |
560 | - !! element on a process, then none of the neighbours will be owned. |
561 | - !! You can use this function to compute whether ELEMENT_NUMBER is |
562 | - !! in the L1 element halo. |
563 | + !! Effectively, this computes whether ELEMENT_NUMBER is in the L1 |
564 | + !! halo. |
565 | type(scalar_field), intent(in) :: field |
566 | integer, intent(in) :: element_number |
567 | logical :: owned |
568 | @@ -330,11 +324,8 @@ |
569 | !!< Return .true. if ELEMENT_NUMBER has a neighbour in FIELD that |
570 | !!< is owned by this process otherwise .false. |
571 | |
572 | - !! Note, you cannot use this function to compute if |
573 | - !! ELEMENT_NUMBER is owned. Imagine if this is the only owned |
574 | - !! element on a process, then none of the neighbours will be owned. |
575 | - !! You can use this function to compute whether ELEMENT_NUMBER is |
576 | - !! in the L1 element halo. |
577 | + !! Effectively, this computes whether ELEMENT_NUMBER is in the L1 |
578 | + !! halo. |
579 | type(vector_field), intent(in) :: field |
580 | integer, intent(in) :: element_number |
581 | logical :: owned |
582 | @@ -346,11 +337,8 @@ |
583 | !!< Return .true. if ELEMENT_NUMBER has a neighbour in FIELD that |
584 | !!< is owned by this process otherwise .false. |
585 | |
586 | - !! Note, you cannot use this function to compute if |
587 | - !! ELEMENT_NUMBER is owned. Imagine if this is the only owned |
588 | - !! element on a process, then none of the neighbours will be owned. |
589 | - !! You can use this function to compute whether ELEMENT_NUMBER is |
590 | - !! in the L1 element halo. |
591 | + !! Effectively, this computes whether ELEMENT_NUMBER is in the L1 |
592 | + !! halo. |
593 | type(tensor_field), intent(in) :: field |
594 | integer, intent(in) :: element_number |
595 | logical :: owned |
596 | |
597 | === removed file 'femtools/Vertical_Extrapolation.F90' |
598 | --- femtools/Vertical_Extrapolation.F90 2012-05-29 13:43:29 +0000 |
599 | +++ femtools/Vertical_Extrapolation.F90 1970-01-01 00:00:00 +0000 |
600 | @@ -1,1290 +0,0 @@ |
601 | -! Copyright (C) 2007 Imperial College London and others. |
602 | -! |
603 | -! Please see the AUTHORS file in the main source directory for a full list |
604 | -! of copyright holders. |
605 | -! |
606 | -! Prof. C Pain |
607 | -! Applied Modelling and Computation Group |
608 | -! Department of Earth Science and Engineering |
609 | -! Imperial College London |
610 | -! |
611 | -! amcgsoftware@imperial.ac.uk |
612 | -! |
613 | -! This library is free software; you can redistribute it and/or |
614 | -! modify it under the terms of the GNU Lesser General Public |
615 | -! License as published by the Free Software Foundation, |
616 | -! version 2.1 of the License. |
617 | -! |
618 | -! This library is distributed in the hope that it will be useful, |
619 | -! but WITHOUT ANY WARRANTY; without even the implied warranty of |
620 | -! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
621 | -! Lesser General Public License for more details. |
622 | -! |
623 | -! You should have received a copy of the GNU Lesser General Public |
624 | -! License along with this library; if not, write to the Free Software |
625 | -! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
626 | -! USA |
627 | - |
628 | - |
629 | -#include "confdefs.h" |
630 | -#include "fdebug.h" |
631 | - |
632 | -module vertical_extrapolation_module |
633 | -!!< Module containing routines for vertical extrapolation on |
634 | -!!< fully unstructured 3D meshes. Also contains routines for updating |
635 | -!!< distance to top and bottom fields. |
636 | -use fldebug |
637 | -use elements |
638 | -use sparse_tools |
639 | -use fields |
640 | -use state_module |
641 | -use transform_elements |
642 | -use boundary_conditions |
643 | -use parallel_tools |
644 | -use global_parameters, only: real_4, real_8 |
645 | -use spud |
646 | -use dynamic_bin_sort_module |
647 | -use pickers |
648 | -use integer_set_module |
649 | -use vtk_interfaces |
650 | -implicit none |
651 | - |
652 | -interface VerticalExtrapolation |
653 | - module procedure VerticalExtrapolationScalar, & |
654 | - VerticalExtrapolationMultiple, VerticalExtrapolationVector |
655 | -end interface VerticalExtrapolation |
656 | - |
657 | -interface vertical_integration |
658 | - module procedure vertical_integration_scalar, & |
659 | - vertical_integration_multiple, vertical_integration_vector |
660 | -end interface vertical_integration |
661 | - |
662 | -!! element i is considered to be above j iff the inner product of the face |
663 | -!! normal point from i to j and the gravity normal is bigger than this |
664 | -real, parameter:: VERTICAL_INTEGRATION_EPS=1.0e-8 |
665 | - |
666 | -! the two hemispheres are both projected to the unit circle, but the projected southern |
667 | -! hemisphere will have its origin shifted. The projected hemispheres are slightly bigger |
668 | -! than the unit circle, as a bit of overlap with the opposite hemisphere is included around |
669 | -! the equator. So this shift needs to be big enough to not make both projected hemispheres |
670 | -! overlap |
671 | -real, parameter:: HEMISPHERE_SHIFT=10.0 |
672 | - |
673 | -private |
674 | - |
675 | -public CalculateTopBottomDistance |
676 | -public VerticalExtrapolation, vertical_integration |
677 | -public vertical_element_ordering |
678 | -public VerticalProlongationOperator |
679 | -public vertical_extrapolation_module_check_options |
680 | -public compute_face_normal_gravity |
681 | - |
682 | -contains |
683 | - |
684 | -subroutine UpdateDistanceField(state, name, vertical_coordinate) |
685 | - ! This sub calculates the vertical distance to the free surface |
686 | - ! and bottom of the ocean to all nodes. The results are stored |
687 | - ! in the 'DistanceToBottom/FreeSurface' fields from state. |
688 | - type(state_type), intent(inout):: state |
689 | - character(len=*), intent(in):: name |
690 | - type(scalar_field), intent(in):: vertical_coordinate |
691 | - |
692 | - ! Local variables |
693 | - type(vector_field), pointer:: positions, vertical_normal |
694 | - type(scalar_field), pointer:: distance |
695 | - |
696 | - integer, pointer, dimension(:):: surface_element_list |
697 | - |
698 | - ! the distance field to compute: |
699 | - distance => extract_scalar_field(state, name) |
700 | - ! its first boundary condition is on the related top or bottom mesh |
701 | - call get_boundary_condition(distance, 1, & |
702 | - surface_element_list=surface_element_list) |
703 | - positions => extract_vector_field(state, "Coordinate") |
704 | - vertical_normal => extract_vector_field(state, "GravityDirection") |
705 | - |
706 | - ! in each node of the mesh, set "distance" to the vertical coordinate |
707 | - ! of this node projected to the above/below surface mesh |
708 | - call VerticalExtrapolation(vertical_coordinate, distance, positions, & |
709 | - vertical_normal, surface_element_list, surface_name=name) |
710 | - |
711 | - ! the distance is then calculated by subtracting its own vertical coordinate |
712 | - call addto(distance, vertical_coordinate, scale=-1.0) |
713 | - |
714 | - if (name=="DistanceToBottom") then |
715 | - ! make distance to bottom positive |
716 | - call scale(distance, -1.0) |
717 | - end if |
718 | - |
719 | -end subroutine UpdateDistanceField |
720 | - |
721 | -subroutine CalculateTopBottomDistance(state) |
722 | - !! This sub calculates the vertical distance to the free surface |
723 | - !! and bottom of the ocean to all nodes. The results are stored |
724 | - !! in the 'DistanceToBottom/Top' fields from state. |
725 | - type(state_type), intent(inout):: state |
726 | - |
727 | - type(mesh_type), pointer:: xmesh |
728 | - type(scalar_field):: vertical_coordinate |
729 | - |
730 | - xmesh => extract_mesh(state, "CoordinateMesh") |
731 | - call allocate(vertical_coordinate, xmesh, "VerticalCoordinate") |
732 | - call calculate_vertical_coordinate(state, vertical_coordinate) |
733 | - call UpdateDistanceField(state, "DistanceToTop", vertical_coordinate) |
734 | - call UpdateDistanceField(state, "DistanceToBottom", vertical_coordinate) |
735 | - call deallocate(vertical_coordinate) |
736 | - |
737 | -end subroutine CalculateTopBottomDistance |
738 | - |
739 | -subroutine calculate_vertical_coordinate(state, vertical_coordinate) |
740 | - !! Computes a vertical coordinate, i.e. a scalar field such that |
741 | - !! for each 2 nodes above each other, the difference of the field |
742 | - !! in these nodes gives the distance between them. |
743 | - type(state_type), intent(inout):: state |
744 | - type(scalar_field), intent(inout):: vertical_coordinate |
745 | - |
746 | - type(vector_field), pointer:: positions, gravity_normal |
747 | - type(scalar_field):: positions_magnitude |
748 | - |
749 | - positions => extract_vector_field(state, "Coordinate") |
750 | - if(have_option('/geometry/spherical_earth')) then |
751 | - ! use the radius as vertical coordinate |
752 | - ! that is, the l2-norm of the coordinate field |
753 | - positions_magnitude=magnitude(positions) |
754 | - call set(vertical_coordinate, positions_magnitude) |
755 | - call deallocate(positions_magnitude) |
756 | - else |
757 | - gravity_normal => extract_vector_field(state, "GravityDirection") |
758 | - assert(gravity_normal%field_type==FIELD_TYPE_CONSTANT) |
759 | - call inner_product(vertical_coordinate, gravity_normal, positions) |
760 | - ! gravity points down, we want a vertical coordinate that increases upward |
761 | - call scale(vertical_coordinate, -1.0) |
762 | - end if |
763 | - |
764 | -end subroutine calculate_vertical_coordinate |
765 | - |
766 | -subroutine VerticalExtrapolationScalar(from_field, to_field, & |
767 | - positions, vertical_normal, surface_element_list, surface_name) |
768 | - !!< This sub extrapolates the values on a horizontal 2D surface |
769 | - !!< in the vertical direction to 3D fields |
770 | - !! The from_fields should be 3D fields of which only the values on the |
771 | - !! 2D horizontal surface are used. |
772 | - type(scalar_field), intent(in):: from_field |
773 | - !! Resulting extrapolated field. May be the same field or a field on |
774 | - !! a different mesh (different degree). |
775 | - type(scalar_field), intent(inout):: to_field |
776 | - !! positions, and upward normal vector on the whole domain |
777 | - type(vector_field), target, intent(inout):: positions |
778 | - type(vector_field), target, intent(in):: vertical_normal |
779 | - !! the surface elements (faces numbers) that make up the surface |
780 | - integer, dimension(:), intent(in):: surface_element_list |
781 | - !! If provided the projected surface mesh onto horizontal coordinates |
782 | - !! and its associated rtree/pickers are cached under this name and |
783 | - !! attached to the 'positions'. In this case when called again with |
784 | - !! the same 'positions' and the same surface_name, |
785 | - !! the same surface_element_list should again be provided. |
786 | - character(len=*), optional, intent(in):: surface_name |
787 | - |
788 | - type(scalar_field), dimension(1):: to_fields |
789 | - |
790 | - to_fields=(/ to_field /) |
791 | - call VerticalExtrapolationMultiple( (/ from_field /) , to_fields, & |
792 | - positions, vertical_normal, surface_element_list, & |
793 | - surface_name=surface_name) |
794 | - |
795 | -end subroutine VerticalExtrapolationScalar |
796 | - |
797 | -subroutine VerticalExtrapolationVector(from_field, to_field, & |
798 | - positions, vertical_normal, surface_element_list, surface_name) |
799 | - !!< This sub extrapolates the values on a horizontal 2D surface |
800 | - !!< in the vertical direction to 3D fields |
801 | - !! The from_fields should be 3D fields of which only the values on the |
802 | - !! 2D horizontal surface are used. |
803 | - type(vector_field), intent(in):: from_field |
804 | - !! Resulting extrapolated field. May be the same field or a field on |
805 | - !! a different mesh (different degree). |
806 | - type(vector_field), intent(inout):: to_field |
807 | - !! positions, and upward normal vector on the whole domain |
808 | - type(vector_field), target, intent(inout):: positions |
809 | - type(vector_field), target, intent(in):: vertical_normal |
810 | - !! the surface elements (faces numbers) that make up the surface |
811 | - integer, dimension(:), intent(in):: surface_element_list |
812 | - !! If provided the projected surface mesh onto horizontal coordinates |
813 | - !! and its associated rtree/pickers are cached under this name and |
814 | - !! attached to the 'positions'. In this case when called again with |
815 | - !! the same 'positions' and the same surface_name, |
816 | - !! the same surface_element_list should again be provided. |
817 | - character(len=*), optional, intent(in):: surface_name |
818 | - |
819 | - type(scalar_field), dimension(from_field%dim):: from_field_components, to_field_components |
820 | - integer i |
821 | - |
822 | - assert(from_field%dim==to_field%dim) |
823 | - |
824 | - do i=1, from_field%dim |
825 | - from_field_components(i)=extract_scalar_field(from_field, i) |
826 | - to_field_components(i)=extract_scalar_field(to_field, i) |
827 | - end do |
828 | - |
829 | - call VerticalExtrapolationMultiple( from_field_components, to_field_components, & |
830 | - positions, vertical_normal, surface_element_list, & |
831 | - surface_name=surface_name) |
832 | - |
833 | -end subroutine VerticalExtrapolationVector |
834 | - |
835 | -subroutine VerticalExtrapolationMultiple(from_fields, to_fields, & |
836 | - positions, vertical_normal, surface_element_list, surface_name) |
837 | - !!< This sub extrapolates the values on a horizontal 2D surface |
838 | - !!< in the vertical direction to 3D fields |
839 | - !! The from_fields should be 3D fields of which only the values on the |
840 | - !! 2D horizontal surface are used. |
841 | - !! This version takes multiple from_fields at the same time and extrapolates |
842 | - !! to to_fields, such that the surface search only has to be done once. This |
843 | - !! will only work if all the from_fields are on the same mesh, and on all the |
844 | - !! to_field are on the same (possibly a different) mesh. |
845 | - type(scalar_field), dimension(:), intent(in):: from_fields |
846 | - !! Resulting extrapolated field. May be the same field or a field on |
847 | - !! a different mesh (different degree). |
848 | - type(scalar_field), dimension(:), intent(inout):: to_fields |
849 | - !! positions, and upward normal vector on the whole domain |
850 | - type(vector_field), target, intent(inout):: positions |
851 | - type(vector_field), target, intent(in):: vertical_normal |
852 | - |
853 | - !! the surface elements (faces numbers) that make up the surface |
854 | - integer, dimension(:), intent(in):: surface_element_list |
855 | - !! If provided the projected surface mesh onto horizontal coordinates |
856 | - !! and its associated rtree/pickers are cached under this name and |
857 | - !! attached to the 'positions'. In this case when called again with |
858 | - !! the same 'positions' and the same surface_name, |
859 | - !! the same surface_element_list should again be provided. |
860 | - character(len=*), optional, intent(in):: surface_name |
861 | - |
862 | - character(len=FIELD_NAME_LEN):: lsurface_name |
863 | - real, dimension(:,:), allocatable:: loc_coords |
864 | - integer, dimension(:), allocatable:: seles |
865 | - integer i, j, to_nodes, face |
866 | - |
867 | - assert(size(from_fields)==size(to_fields)) |
868 | - assert(element_count(from_fields(1))==element_count(to_fields(1))) |
869 | - do i=2, size(to_fields) |
870 | - assert(to_fields(1)%mesh==to_fields(i)%mesh) |
871 | - assert(from_fields(1)%mesh==from_fields(i)%mesh) |
872 | - end do |
873 | - |
874 | - to_nodes=nowned_nodes(to_fields(1)) |
875 | - ! local coordinates is one more than horizontal coordinate dim |
876 | - allocate( seles(to_nodes), loc_coords(1:positions%dim, 1:to_nodes) ) |
877 | - |
878 | - if (present(surface_name)) then |
879 | - lsurface_name=surface_name |
880 | - else |
881 | - lsurface_name="TempSurfaceName" |
882 | - end if |
883 | - |
884 | - ! project the positions of to_fields(1)%mesh into the horizontal plane |
885 | - ! and returns 'seles' (indices in surface_element_list) and loc_coords |
886 | - ! to tell where these projected nodes are found in the surface mesh |
887 | - call horizontal_picker(to_fields(1)%mesh, positions, vertical_normal, & |
888 | - surface_element_list, lsurface_name, & |
889 | - seles, loc_coords) |
890 | - |
891 | - ! interpolate using the returned faces and loc_coords |
892 | - do i=1, size(to_fields) |
893 | - do j=1, to_nodes |
894 | - face=surface_element_list(seles(j)) |
895 | - call set(to_fields(i), j, & |
896 | - dot_product( eval_shape( face_shape(from_fields(i), face), loc_coords(:,j) ), & |
897 | - face_val( from_fields(i), face ) )) |
898 | - end do |
899 | - end do |
900 | - |
901 | - if (IsParallel()) then |
902 | - do i=1, size(to_fields) |
903 | - call halo_update(to_fields(i)) |
904 | - end do |
905 | - end if |
906 | - |
907 | - if (.not. present(surface_name)) then |
908 | - call remove_boundary_condition(positions, "TempSurfaceName") |
909 | - end if |
910 | - |
911 | -end subroutine VerticalExtrapolationMultiple |
912 | - |
913 | -subroutine horizontal_picker(mesh, positions, vertical_normal, & |
914 | - surface_element_list, surface_name, & |
915 | - seles, loc_coords) |
916 | - !! Searches the nodes of 'mesh' in the surface mesh above. |
917 | - !! Returns the surface elements 'seles' that each node lies under |
918 | - !! and the loc_coords in this element of this node projected |
919 | - !! upward (radially on the sphere) onto the surface mesh |
920 | - |
921 | - !! mesh |
922 | - type(mesh_type), intent(in):: mesh |
923 | - !! a valid positions field for the whole domain, not necessarily on 'mesh' |
924 | - !! for instance in a periodic domain, mesh is periodic and positions should not be |
925 | - type(vector_field), target, intent(inout):: positions |
926 | - !! upward normal vector on the whole domain |
927 | - type(vector_field), target, intent(in):: vertical_normal |
928 | - !! the surface elements (faces numbers) that make up the surface |
929 | - integer, dimension(:), intent(in):: surface_element_list |
930 | - !! The projected surface mesh onto horizontal coordinates |
931 | - !! and its associated rtree/pickers are cached under this name and |
932 | - !! attached to the 'positions'. When called again with |
933 | - !! the same 'positions' and the same surface_name, |
934 | - !! the same surface_element_list should again be provided. |
935 | - character(len=*), intent(in):: surface_name |
936 | - |
937 | - !! returned surface elements (face numbers in 'mesh') |
938 | - !! and loc coords each node has been found in |
939 | - !! size(seles)==size(loc_coords,2)==nowned_nodes(mesh) |
940 | - integer, dimension(:), intent(out):: seles |
941 | - real, dimension(:,:), intent(out):: loc_coords |
942 | - |
943 | - type(vector_field):: mesh_positions |
944 | - type(vector_field), pointer:: horizontal_positions |
945 | - integer, dimension(:), pointer:: horizontal_mesh_list |
946 | - real, dimension(:,:), allocatable:: horizontal_coordinate |
947 | - real, dimension(vertical_normal%dim):: normal_vector |
948 | - real, dimension(positions%dim):: xyz |
949 | - integer:: i, stat, nodes |
950 | - |
951 | - assert(.not. mesh_periodic(positions)) |
952 | - |
953 | - ! search only the first owned nodes |
954 | - nodes=nowned_nodes(mesh) |
955 | - |
956 | - assert( size(seles)==nodes ) |
957 | - assert(size(loc_coords,1)==positions%dim) |
958 | - assert( size(loc_coords,2)==nodes ) |
959 | - |
960 | - if (mesh==positions%mesh) then |
961 | - mesh_positions=positions |
962 | - ! make mesh_positions indep. ref. of the field, so we can deallocate it |
963 | - ! safely without destroying positions |
964 | - call incref(mesh_positions) |
965 | - else |
966 | - call allocate(mesh_positions, positions%dim, mesh, & |
967 | - name='ToPositions_VerticalExtrapolation') |
968 | - call remap_field(positions, mesh_positions, stat) |
969 | - if (stat/=0 .and. stat/=REMAP_ERR_HIGHER_LOWER_CONTINUOUS .and. & |
970 | - stat/=REMAP_ERR_UNPERIODIC_PERIODIC) then |
971 | - ! Mapping from higher order to lower order is allowed for coordinates |
972 | - ! (well depends on how the higher order is derived from the lower order) |
973 | - ! |
974 | - ! Mapping to periodic coordinates is ok in this case as we only need |
975 | - ! locations for the nodes individually (i.e. we don't care about elements |
976 | - ! in 'mesh') - the created horizontal_positions will be non-periodic |
977 | - ! So that we should be able to find nodes on the periodic boundary on |
978 | - ! either side. Using this to interpolate is consistent as long as |
979 | - ! the interpolated from field is indeed periodic. |
980 | - FLAbort("Unknown error in remmaping positions in horizontal_picker.") |
981 | - end if |
982 | - end if |
983 | - |
984 | - |
985 | - ! create an array of the horizontally projected coordinates of the 'mesh' nodes |
986 | - allocate( horizontal_coordinate(1:positions%dim-1, 1:nodes) ) |
987 | - if (have_option('/geometry/spherical_earth')) then |
988 | - assert(mesh_positions%dim==3) |
989 | - do i=1, nodes |
990 | - xyz=node_val(mesh_positions, i) |
991 | - if (xyz(3)>0.0) then |
992 | - horizontal_coordinate(:,i) = & |
993 | - map2horizontal_sphere( node_val(mesh_positions, i), +1.0) |
994 | - else |
995 | - horizontal_coordinate(:,i) = & |
996 | - map2horizontal_sphere( node_val(mesh_positions, i), -1.0) |
997 | - horizontal_coordinate(1,i)=horizontal_coordinate(1,i)+HEMISPHERE_SHIFT |
998 | - end if |
999 | - end do |
1000 | - else |
1001 | - assert( vertical_normal%field_type==FIELD_TYPE_CONSTANT ) |
1002 | - normal_vector=node_val(vertical_normal,1) |
1003 | - |
1004 | - do i=1, nodes |
1005 | - horizontal_coordinate(:,i) = & |
1006 | - map2horizontal( node_val(mesh_positions, i), normal_vector ) |
1007 | - end do |
1008 | - end if |
1009 | - |
1010 | - call get_horizontal_positions(positions, surface_element_list, & |
1011 | - vertical_normal, surface_name, & |
1012 | - horizontal_positions, horizontal_mesh_list) |
1013 | - |
1014 | - call picker_inquire( horizontal_positions, horizontal_coordinate, & |
1015 | - seles, loc_coords, global=.false. ) |
1016 | - |
1017 | - ! in the spherical case some of the surface elements may be duplicated |
1018 | - ! within horizontal positions, the returned seles should refer to entries |
1019 | - ! in surface_element_list however - also check for nodes not found |
1020 | - do i=1, size(seles) |
1021 | - if (seles(i)>0) then |
1022 | - seles(i)=horizontal_mesh_list(seles(i)) |
1023 | - else |
1024 | - ewrite(-1,*) "For node with coordinate", node_val(mesh_positions, i) |
1025 | - ewrite(-1,*) "no top surface node was found." |
1026 | - FLAbort("Something wrong with the geometry.") |
1027 | - end if |
1028 | - end do |
1029 | - |
1030 | - call deallocate(mesh_positions) |
1031 | - deallocate(horizontal_mesh_list) |
1032 | - |
1033 | -end subroutine horizontal_picker |
1034 | - |
1035 | -subroutine get_horizontal_positions(positions, surface_element_list, vertical_normal, surface_name, & |
1036 | - horizontal_positions, horizontal_mesh_list) |
1037 | -! returns a horizontal positions field over the surface mesh indicated by |
1038 | -! 'surface_element_list'. This field will be created and cached on 'positions' |
1039 | -! as a surface field attached to a dummy boundary condition under the name surface_name |
1040 | - type(vector_field), intent(inout):: positions |
1041 | - type(vector_field), intent(in):: vertical_normal |
1042 | - integer, dimension(:), intent(in):: surface_element_list |
1043 | - character(len=*), intent(in):: surface_name |
1044 | - |
1045 | - ! Returns the horizontal positions on a horizontal mesh, this mesh |
1046 | - ! may have some of the faces in surface_element_list duplicated - |
1047 | - ! this is only in the spherical case where the horizontal mesh |
1048 | - ! consists of two disjoint regions representing the two hemispheres |
1049 | - ! and surface elements near the equator may be represented in both. |
1050 | - ! Therefore we also return a map between elements in the horizontal positions mesh |
1051 | - ! and entries in surface_element_list. If ele is an element in the horizontal |
1052 | - ! position mesh, then surface_element_list(horizontal_mesh(ele)) |
1053 | - ! is the face number in the full mesh |
1054 | - ! horizontal_positions is a borrowed reference, don't allocate |
1055 | - ! horizontal_mesh_list does need to be deallocated |
1056 | - type(vector_field), pointer:: horizontal_positions |
1057 | - integer, dimension(:), pointer:: horizontal_mesh_list |
1058 | - |
1059 | - integer, dimension(:), pointer:: horizontal_sele_list |
1060 | - integer:: i, j, k, sele |
1061 | - |
1062 | - if (.not. has_boundary_condition_name(positions, surface_name)) then |
1063 | - if (have_option('/geometry/spherical_earth')) then |
1064 | - call create_horizontal_positions_sphere(positions, & |
1065 | - surface_element_list, surface_name) |
1066 | - else |
1067 | - call create_horizontal_positions_flat(positions, & |
1068 | - surface_element_list, vertical_normal, surface_name) |
1069 | - end if |
1070 | - end if |
1071 | - |
1072 | - horizontal_positions => extract_surface_field(positions, surface_name, & |
1073 | - trim(surface_name)//"HorizontalCoordinate") |
1074 | - |
1075 | -! call vtk_write_fields('horizontal_mesh', 0, horizontal_positions, & |
1076 | -! horizontal_positions%mesh) |
1077 | - |
1078 | - |
1079 | - allocate( horizontal_mesh_list(1:element_count(horizontal_positions)) ) |
1080 | - if (have_option('/geometry/spherical_earth')) then |
1081 | - call get_boundary_condition(positions, surface_name, & |
1082 | - surface_element_list=horizontal_sele_list) |
1083 | - ! by construction the map can be obtained by running |
1084 | - ! through surface_element_list twice (for each hemisphere) |
1085 | - i=1 ! position in horizontal_sele_list |
1086 | - sele=horizontal_sele_list(i) ! face we're looking for |
1087 | -outer_loop: & |
1088 | - do j=1, 2 |
1089 | - do k=1, size(surface_element_list) |
1090 | - if (surface_element_list(k)==sele) then |
1091 | - ! found matching position in surface_element_list |
1092 | - horizontal_mesh_list(i)=k |
1093 | - ! next one to search |
1094 | - i=i+1 |
1095 | - if (i>size(horizontal_sele_list)) exit outer_loop |
1096 | - sele=horizontal_sele_list(i) |
1097 | - end if |
1098 | - end do |
1099 | - end do outer_loop |
1100 | - |
1101 | - if (i<=size(horizontal_sele_list)) then |
1102 | - ! not all were found in 2 loops through surface_element_list |
1103 | - ! something's wrong |
1104 | - FLAbort("Internal error in horizontal mesh administration") |
1105 | - end if |
1106 | - |
1107 | - else |
1108 | - ! no duplication: horizontal_mesh_list is simply the identity map |
1109 | - do i=1, size(horizontal_mesh_list) |
1110 | - horizontal_mesh_list(i)=i |
1111 | - end do |
1112 | - end if |
1113 | - |
1114 | -end subroutine get_horizontal_positions |
1115 | - |
1116 | -subroutine create_horizontal_positions_flat(positions, surface_element_list, vertical_normal, surface_name) |
1117 | -! adds a "boundary condition" to 'positions' with an associated vector surface field containing a dim-1 |
1118 | -! horizontal coordinate field that can be used to map from the surface mesh specified |
1119 | -! by 'surface_element_list'. This "boundary condition" will be stored under the name 'surface_name' |
1120 | -! The horizontal coordinates are created by projecting out the component |
1121 | -! in the direction of 'vertical_normal' and then throwing out the x, y or z |
1122 | -! coordinate that is most aligned with 'vertical_normal' |
1123 | - type(vector_field), intent(inout):: positions |
1124 | - type(vector_field), intent(in):: vertical_normal |
1125 | - integer, dimension(:), intent(in):: surface_element_list |
1126 | - character(len=*), intent(in):: surface_name |
1127 | - |
1128 | - type(mesh_type), pointer:: surface_mesh |
1129 | - type(vector_field):: horizontal_positions |
1130 | - integer, dimension(:), pointer:: surface_node_list |
1131 | - real, dimension(vertical_normal%dim):: normal_vector |
1132 | - integer:: i, node |
1133 | - |
1134 | - assert(vertical_normal%field_type==FIELD_TYPE_CONSTANT) |
1135 | - normal_vector=node_val(vertical_normal, 1) |
1136 | - |
1137 | - call add_boundary_condition_surface_elements(positions, & |
1138 | - name=surface_name, type="verticalextrapolation", & |
1139 | - surface_element_list=surface_element_list) |
1140 | - ! now get back the created surface mesh |
1141 | - ! and surface_node_list a mapping between node nos in the projected mesh and node nos in the original 'positions' mesh |
1142 | - call get_boundary_condition(positions, name=surface_name, & |
1143 | - surface_mesh=surface_mesh, surface_node_list=surface_node_list) |
1144 | - call allocate( horizontal_positions, dim=positions%dim-1, mesh=surface_mesh, & |
1145 | - name=trim(surface_name)//"HorizontalCoordinate" ) |
1146 | - |
1147 | - call insert_surface_field(positions, name=surface_name, & |
1148 | - surface_field=horizontal_positions) |
1149 | - |
1150 | - do i=1, size(surface_node_list) |
1151 | - node=surface_node_list(i) |
1152 | - call set(horizontal_positions, i, & |
1153 | - map2horizontal(node_val(positions, node), normal_vector)) |
1154 | - end do |
1155 | - |
1156 | - call deallocate( horizontal_positions ) |
1157 | - |
1158 | -end subroutine create_horizontal_positions_flat |
1159 | - |
1160 | -subroutine create_horizontal_positions_sphere(positions, surface_element_list, surface_name) |
1161 | -! adds a "boundary condition" to 'positions' with an associated vector surface field containing a dim-1 |
1162 | -! horizontal coordinate field that can be used to map from the surface mesh specified |
1163 | -! by 'surface_element_list'. This "boundary condition" will be stored under the name 'surface_name' |
1164 | -! The horizontal coordinates are created by a stereographic projection from the unit sphere to the |
1165 | -! xy-plane. The northern hemisphere is projected to the unit-circle (including some extra surface |
1166 | -! elements on the southern hemisphere around the equator). The southern hemisphere (including some |
1167 | -! northern surface elements near the equator) is also projected to a unit circle but translated |
1168 | -! away from the origin to not overlap with the projected northern hemisphere. Thus the created |
1169 | -! projected horizontal positions field consists of two disjoint areas in the plane corresponding |
1170 | -! to both hemispheres, and elements in the original surface mesh (near the equator) may appear |
1171 | -! twice in the projected field. |
1172 | - type(vector_field), intent(inout):: positions |
1173 | - integer, dimension(:), intent(in):: surface_element_list |
1174 | - character(len=*), intent(in):: surface_name |
1175 | - |
1176 | - type(vector_field), pointer:: horizontal_positions_north, horizontal_positions_south |
1177 | - type(vector_field):: horizontal_positions |
1178 | - type(mesh_type), pointer:: surface_mesh_north, surface_mesh_south |
1179 | - type(mesh_type):: surface_mesh |
1180 | - integer, dimension(:), pointer:: surface_element_list_north, surface_element_list_south |
1181 | - integer, dimension(:), allocatable:: surface_element_list_combined |
1182 | - integer:: nodes_north, elements_south, elements_north |
1183 | - integer:: i |
1184 | - |
1185 | - ! first create 2 separate horizontal coordinate fields |
1186 | - ! for each hemisphere |
1187 | - |
1188 | - call create_horizontal_positions_hemisphere(positions, & |
1189 | - surface_element_list, trim(surface_name)//'North', +1.0) |
1190 | - |
1191 | - call create_horizontal_positions_hemisphere(positions, & |
1192 | - surface_element_list, trim(surface_name)//'South', -1.0) |
1193 | - |
1194 | - ! these are stored as bcs under the positions |
1195 | - ! retrieve this information back: |
1196 | - |
1197 | - call get_boundary_condition(positions, name=trim(surface_name)//'North', & |
1198 | - surface_mesh=surface_mesh_north, & |
1199 | - surface_element_list=surface_element_list_north) |
1200 | - call get_boundary_condition(positions, name=trim(surface_name)//'South', & |
1201 | - surface_mesh=surface_mesh_south, & |
1202 | - surface_element_list=surface_element_list_south) |
1203 | - |
1204 | - horizontal_positions_north => extract_surface_field(positions, & |
1205 | - trim(surface_name)//'North', trim(surface_name)//"NorthHorizontalCoordinate") |
1206 | - horizontal_positions_south => extract_surface_field(positions, & |
1207 | - trim(surface_name)//'South', trim(surface_name)//"SouthHorizontalCoordinate") |
1208 | - |
1209 | - ! merge these 2 meshes |
1210 | - surface_mesh=merge_meshes( (/ surface_mesh_north, surface_mesh_south /) ) |
1211 | - |
1212 | - ! and merge the positions field |
1213 | - call allocate( horizontal_positions, positions%dim-1, surface_mesh, & |
1214 | - trim(surface_name)//"HorizontalCoordinate" ) |
1215 | - |
1216 | - nodes_north=node_count(surface_mesh_north) |
1217 | - do i=1, nodes_north |
1218 | - call set( horizontal_positions, i, & |
1219 | - node_val(horizontal_positions_north, i)) |
1220 | - end do |
1221 | - ! but translate the projected southern hemisphere to the left |
1222 | - ! to not overlap it with the northern hemisphere |
1223 | - do i=1, node_count(surface_mesh_south) |
1224 | - call set( horizontal_positions, nodes_north+i, & |
1225 | - node_val(horizontal_positions_south, i)+(/ HEMISPHERE_SHIFT, 0.0 /) ) |
1226 | - end do |
1227 | - |
1228 | - ! merge the surface element lists |
1229 | - ! (note that this is different than the incoming surface_element_list |
1230 | - ! as it will have some duplicate equatorial elements) |
1231 | - elements_north=size(surface_element_list_north) |
1232 | - elements_south=size(surface_element_list_south) |
1233 | - allocate(surface_element_list_combined(1:elements_north+elements_south)) |
1234 | - surface_element_list_combined(1:elements_north)=surface_element_list_north |
1235 | - surface_element_list_combined(elements_north+1:)=surface_element_list_south |
1236 | - |
1237 | - ! finally the bc for the combined surface mesh: |
1238 | - ! (note that this creates a new surface mesh different than |
1239 | - ! the merged mesh, that we won't be using) |
1240 | - call add_boundary_condition_surface_elements( & |
1241 | - positions, name=surface_name, type="verticalextrapolation", & |
1242 | - surface_element_list=surface_element_list_combined) |
1243 | - |
1244 | - ! insert the horizontal positions under this bc |
1245 | - call insert_surface_field( positions, name=surface_name, & |
1246 | - surface_field=horizontal_positions) |
1247 | - |
1248 | - ! everything is safely stored, so we can deallocate our references |
1249 | - call deallocate(horizontal_positions) |
1250 | - call deallocate(surface_mesh) |
1251 | - deallocate(surface_element_list_combined) |
1252 | - |
1253 | - ! also we won't need the 2 hemisphere bcs anymore |
1254 | - call remove_boundary_condition( positions, trim(surface_name)//'North') |
1255 | - call remove_boundary_condition( positions, trim(surface_name)//'South') |
1256 | - |
1257 | -end subroutine create_horizontal_positions_sphere |
1258 | - |
1259 | -subroutine create_horizontal_positions_hemisphere(positions, & |
1260 | - surface_element_list, surface_name, hemi_sign) |
1261 | - type(vector_field), intent(inout):: positions |
1262 | - integer, dimension(:), intent(in):: surface_element_list |
1263 | - character(len=*), intent(in):: surface_name |
1264 | - real, intent(in):: hemi_sign |
1265 | - |
1266 | - type(vector_field):: horizontal_positions |
1267 | - type(mesh_type), pointer:: surface_mesh |
1268 | - real, dimension(2):: xy |
1269 | - integer, dimension(:), pointer:: nodes, surface_node_list |
1270 | - integer:: i, j, sele, node |
1271 | - |
1272 | - type(integer_set):: surface_element_set |
1273 | - |
1274 | - call allocate(surface_element_set) |
1275 | - |
1276 | - do i=1, size(surface_element_list) |
1277 | - sele=surface_element_list(i) |
1278 | - if (sele_is_on_hemisphere(sele)) then |
1279 | - call insert(surface_element_set, sele) |
1280 | - end if |
1281 | - end do |
1282 | - |
1283 | - call add_boundary_condition_surface_elements(positions, & |
1284 | - name=surface_name, type="verticalextrapolation", & |
1285 | - surface_element_list=set2vector(surface_element_set)) |
1286 | - call deallocate(surface_element_set) |
1287 | - |
1288 | - call get_boundary_condition(positions, name=surface_name, & |
1289 | - surface_mesh=surface_mesh, surface_node_list=surface_node_list) |
1290 | - |
1291 | - call allocate( horizontal_positions, dim=2, mesh=surface_mesh, & |
1292 | - name=trim(surface_name)//"HorizontalCoordinate" ) |
1293 | - |
1294 | - call insert_surface_field(positions, name=surface_name, & |
1295 | - surface_field=horizontal_positions) |
1296 | - |
1297 | - do i=1, element_count(horizontal_positions) |
1298 | - nodes => ele_nodes(horizontal_positions, i) |
1299 | - do j=1, size(nodes) |
1300 | - node=surface_node_list( nodes(j) ) |
1301 | - xy=map2horizontal_sphere(node_val(positions, node), hemi_sign) |
1302 | - assert(abs(xy(1))<HEMISPHERE_SHIFT/2.0) |
1303 | - call set( horizontal_positions, nodes(j), xy) |
1304 | - end do |
1305 | - end do |
1306 | - |
1307 | - call deallocate(horizontal_positions) |
1308 | - |
1309 | - contains |
1310 | - |
1311 | - logical function sele_is_on_hemisphere(sele) |
1312 | - integer, intent(in):: sele |
1313 | - |
1314 | - real, dimension(face_loc(positions, sele)):: znodes |
1315 | - |
1316 | - znodes=face_val(positions, 3, sele) |
1317 | - ! if any of the nodes is on the hemisphere or *very* close to the equator |
1318 | - ! (relative to the other nodes) |
1319 | - sele_is_on_hemisphere = any(hemi_sign * znodes > -sum(abs(znodes))*1e-6) |
1320 | - |
1321 | - end function sele_is_on_hemisphere |
1322 | - |
1323 | -end subroutine create_horizontal_positions_hemisphere |
1324 | - |
1325 | -function map2horizontal(xyz, normal_vector) |
1326 | -real, dimension(:), intent(in):: xyz, normal_vector |
1327 | -real, dimension(size(xyz)-1):: map2horizontal |
1328 | - |
1329 | - real, dimension(size(xyz)):: hxyz |
1330 | - integer:: i, c, takeout |
1331 | - |
1332 | - ! first subtract of the vertical component |
1333 | - hxyz=xyz-dot_product(xyz, normal_vector)*normal_vector |
1334 | - |
1335 | - ! then leave out the "most vertical" coordinate |
1336 | - takeout=maxloc(abs(normal_vector), dim=1) |
1337 | - |
1338 | - c=1 |
1339 | - do i=1, size(xyz) |
1340 | - if (i==takeout) cycle |
1341 | - map2horizontal(c)=hxyz(i) |
1342 | - c=c+1 |
1343 | - end do |
1344 | - |
1345 | -end function map2horizontal |
1346 | - |
1347 | -function map2horizontal_sphere(xyz, hemi_sign) |
1348 | -real, dimension(3), intent(in):: xyz |
1349 | -real, intent(in):: hemi_sign |
1350 | -real, dimension(2):: map2horizontal_sphere |
1351 | - |
1352 | - real:: r |
1353 | - |
1354 | - r=sqrt(sum(xyz**2)) |
1355 | - map2horizontal_sphere=xyz(1:2)/(r+hemi_sign*xyz(3)) |
1356 | - |
1357 | -end function map2horizontal_sphere |
1358 | - |
1359 | -function VerticalProlongationOperator(mesh, positions, vertical_normal, & |
1360 | - surface_element_list, surface_mesh) |
1361 | - !! creates a prolongation operator that prolongates values on |
1362 | - !! a surface mesh to a full mesh below using the same interpolation |
1363 | - !! as the vertical extrapolation code above. The transpose of this prolongation |
1364 | - !! operator can be used as a restriction/clustering operator |
1365 | - !! from the full mesh to the surface. |
1366 | - type(csr_matrix) :: VerticalProlongationOperator |
1367 | - !! the mesh to which to prolongate, its nodes are only considered as |
1368 | - !! a set of loose points |
1369 | - type(mesh_type), target, intent(in):: mesh |
1370 | - !! positions on the whole domain (doesn't have to be the same mesh) |
1371 | - type(vector_field), intent(inout):: positions |
1372 | - !! upward normal vector on the whole domain |
1373 | - type(vector_field), target, intent(in):: vertical_normal |
1374 | - !! the face numbers of the surface mesh |
1375 | - integer, dimension(:), intent(in):: surface_element_list |
1376 | - !! Optionally a surface mesh may be provided that represents the nodes |
1377 | - !! /from/ which to interpolate (may be of different signature than 'mesh') |
1378 | - !! Each column in the prolongator will correspond to a node in this surface_mesh. |
1379 | - !! If not provided, the "from mesh" is considered to consist of faces |
1380 | - !! given by surface_element_list (and same cont. and order as 'mesh'). |
1381 | - !! In this case however empty columns, i.e. surface nodes from which no |
1382 | - !! value in the full mesh is interpolated, are removed and there is no |
1383 | - !! necessary relation between column numbering and surface node numbering. |
1384 | - type(mesh_type), intent(in), target, optional:: surface_mesh |
1385 | - |
1386 | - type(csr_sparsity):: sparsity |
1387 | - type(mesh_type), pointer:: lsurface_mesh |
1388 | - real, dimension(:,:), allocatable:: loc_coords |
1389 | - real, dimension(:), allocatable:: mat |
1390 | - real:: coef |
1391 | - integer, dimension(:), pointer:: snodes |
1392 | - integer, dimension(:), allocatable:: seles, colm, findrm, snod2used_snod |
1393 | - integer i, j, k, rows, entries, count, snod, sele |
1394 | - ! coefficient have to be at least this otherwise they're negligable in an interpolation |
1395 | - real, parameter :: COEF_EPS=1d-10 |
1396 | - |
1397 | - ! only assemble the rows associted with nodes we own |
1398 | - rows=nowned_nodes(mesh) |
1399 | - |
1400 | - ! local coordinates is one more than horizontal coordinate dim |
1401 | - allocate( seles(rows), loc_coords(1:positions%dim, 1:rows) ) |
1402 | - |
1403 | - ! project the positions of to_fields(1)%mesh into the horizontal plane |
1404 | - ! and returns 'seles' (indices in surface_element_list) and loc_coords |
1405 | - ! to tell where these projected nodes are found in the surface mesh |
1406 | - call horizontal_picker(mesh, positions, vertical_normal, & |
1407 | - surface_element_list, "TempSurfaceName", & |
1408 | - seles, loc_coords) |
1409 | - |
1410 | - ! count upper estimate for n/o entries for sparsity |
1411 | - entries=0 |
1412 | - do i=1, rows |
1413 | - entries=entries+face_loc(mesh, seles(i)) |
1414 | - end do |
1415 | - ! preliminary matrix: |
1416 | - allocate( mat(1:entries), findrm(1:rows+1), & |
1417 | - colm(1:entries) ) |
1418 | - |
1419 | - if (.not. present(surface_mesh)) then |
1420 | - ! We use the entire surface mesh of 'mesh' |
1421 | - lsurface_mesh => mesh%faces%surface_mesh |
1422 | - ! Not all surface nodes may be used (i.e. interpolated from) - even |
1423 | - ! within surface elements that /are/ in surface_element-list. |
1424 | - ! We need a map between global surface node numbering and |
1425 | - ! a consecutive numbering of used surface nodes. |
1426 | - ! (this will be the column numbering) |
1427 | - allocate(snod2used_snod(1:node_count(lsurface_mesh))) |
1428 | - snod2used_snod=0 |
1429 | - count=0 ! counts number of used surface nodes |
1430 | - else |
1431 | - lsurface_mesh => surface_mesh |
1432 | - end if |
1433 | - |
1434 | - entries=0 ! this time only count nonzero entries |
1435 | - do i=1, rows |
1436 | - |
1437 | - ! beginning of each row in mat |
1438 | - findrm(i)=entries+1 |
1439 | - |
1440 | - if (present(surface_mesh)) then |
1441 | - ! element number within surface_mesh |
1442 | - sele=seles(i) |
1443 | - else |
1444 | - ! face number in 'mesh', i.e. element number within entire surface_mesh |
1445 | - sele=surface_element_list(seles(i)) |
1446 | - end if |
1447 | - |
1448 | - snodes => ele_nodes(lsurface_mesh, sele) |
1449 | - |
1450 | - do j=1, size(snodes) |
1451 | - coef=eval_shape(ele_shape(lsurface_mesh, sele), j, loc_coords(:,i)) |
1452 | - snod=snodes(j) |
1453 | - if (abs(coef)>COEF_EPS) then |
1454 | - if (.not. present(surface_mesh)) then |
1455 | - if (snod2used_snod(snod)==0) then |
1456 | - ! as of yet unused surface node |
1457 | - count=count+1 |
1458 | - snod2used_snod(snod)=count |
1459 | - end if |
1460 | - ! this is the column index we're gonna use instead |
1461 | - snod=snod2used_snod(snod) |
1462 | - end if |
1463 | - entries=entries+1 |
1464 | - colm(entries)=snod |
1465 | - mat(entries)=coef |
1466 | - end if |
1467 | - end do |
1468 | - |
1469 | - end do |
1470 | - findrm(i)=entries+1 |
1471 | - |
1472 | - if (present(surface_mesh)) then |
1473 | - ! we haven't counted used surface nodes, instead we're using all |
1474 | - ! nodes of surface mesh as columns |
1475 | - count=node_count(surface_mesh) |
1476 | - end if |
1477 | - |
1478 | - call allocate(sparsity, rows, count, & |
1479 | - entries, diag=.false., name="VerticalProlongationSparsity") |
1480 | - sparsity%findrm=findrm |
1481 | - sparsity%colm=colm(1:entries) |
1482 | - ! for lots of applications it's good to have sorted rows |
1483 | - call sparsity_sort(sparsity) |
1484 | - |
1485 | - call allocate(VerticalProlongationOperator, sparsity, & |
1486 | - name="VerticalProlongationOperator") |
1487 | - call deallocate(sparsity) |
1488 | - |
1489 | - ! as the sparsity has been sorted the ordering of mat(:) no longer |
1490 | - ! matches that of sparsity%colm, however it still matches the original |
1491 | - ! unsorted colm(:) |
1492 | - do i=1, rows |
1493 | - do k=findrm(i), findrm(i+1)-1 |
1494 | - j=colm(k) |
1495 | - call set(VerticalProlongationOperator, i, j, mat(k)) |
1496 | - end do |
1497 | - end do |
1498 | - |
1499 | - if (.not. present(surface_mesh)) then |
1500 | - deallocate( snod2used_snod ) |
1501 | - end if |
1502 | - deallocate( findrm, colm, mat ) |
1503 | - deallocate( seles, loc_coords ) |
1504 | - |
1505 | - call remove_boundary_condition(positions, "TempSurfaceName") |
1506 | - |
1507 | -end function VerticalProlongationOperator |
1508 | - |
1509 | -subroutine vertical_element_ordering(ordered_elements, face_normal_gravity, optimal_ordering) |
1510 | -!!< Calculates an element ordering such that each element is |
1511 | -!!< is preceded by all elements above it. |
1512 | -integer, dimension(:), intent(out):: ordered_elements |
1513 | -!! need to supply face_normal_gravity matrix, |
1514 | -!! created by compute_face_normal_gravity() subroutine below |
1515 | -type(csr_matrix), intent(in):: face_normal_gravity |
1516 | -!! returns .true. if an optimal ordering is found, i.e there are no |
1517 | -!! cycles, i.o.w. elements that are (indirectly) above and below each other |
1518 | -!! at the same time (deck of cards problem). |
1519 | -logical, optional, intent(out):: optimal_ordering |
1520 | - |
1521 | - type(dynamic_bin_type) dbin |
1522 | - real, dimension(:), pointer:: inn |
1523 | - integer, dimension(:), pointer:: neigh |
1524 | - integer, dimension(:), allocatable:: bin_list |
1525 | - integer i, j, elm, bin_no |
1526 | - logical warning |
1527 | - |
1528 | - assert( size(ordered_elements)==size(face_normal_gravity,1) ) |
1529 | - |
1530 | - ! create binlist, i.e. assign each element to a bin, according to |
1531 | - ! the number of elements above it |
1532 | - allocate(bin_list(1:size(ordered_elements))) |
1533 | - do i=1, size(ordered_elements) |
1534 | - neigh => row_m_ptr(face_normal_gravity, i) |
1535 | - inn => row_val_ptr(face_normal_gravity, i) |
1536 | - ! elements with no element above it go in bin 1 |
1537 | - ! elements with n elements above it go in bin n+1 |
1538 | - ! neigh>0 so we don't count exterior boundary faces |
1539 | - bin_list(i)=count( inn<-VERTICAL_INTEGRATION_EPS .and. neigh>0 )+1 |
1540 | - end do |
1541 | - |
1542 | - call allocate(dbin, bin_list) |
1543 | - |
1544 | - warning=.false. |
1545 | - do i=1, size(ordered_elements) |
1546 | - ! pull an element from the first non-empty bin |
1547 | - ! (hopefully an element with no unprocessed elements above) |
1548 | - call pull_element(dbin, elm, bin_no) |
1549 | - ordered_elements(i)=elm |
1550 | - ! if this is bin one then it is indeed an element with no unprocessed |
1551 | - ! elements above, otherwise issue a warning |
1552 | - if (bin_no>1) warning=.true. |
1553 | - |
1554 | - ! update elements below: |
1555 | - |
1556 | - ! adjacent elements: |
1557 | - neigh => row_m_ptr(face_normal_gravity, elm) |
1558 | - inn => row_val_ptr(face_normal_gravity, elm) |
1559 | - do j=1, size(neigh) |
1560 | - if (inn(j)>VERTICAL_INTEGRATION_EPS .and. neigh(j)>0) then |
1561 | - ! element neigh(j) is below element i, therefore now has one |
1562 | - ! less unprocessed element above it, so can be moved to |
1563 | - ! lower bin. |
1564 | - if (.not. element_pulled(dbin, neigh(j))) then |
1565 | - ! but only if neigh(j) itself hasn't been selected yet |
1566 | - ! (which might happen for imperfect vertical orderings) |
1567 | - call move_element(dbin, neigh(j), bin_list(neigh(j))-1) |
1568 | - end if |
1569 | - end if |
1570 | - end do |
1571 | - end do |
1572 | - |
1573 | - if (warning) then |
1574 | - ! this warning may be reduced (in verbosity level) if it occurs frequently: |
1575 | - ewrite(-1,*) "Warning: vertical_element_ordering has detected a cycle." |
1576 | - ewrite(-1,*) "(deck of cards problem). This may reduce the efficiency" |
1577 | - ewrite(-1,*) "of your vertically sweeping solve." |
1578 | - end if |
1579 | - |
1580 | - if (present(optimal_ordering)) then |
1581 | - optimal_ordering=.not. warning |
1582 | - end if |
1583 | - |
1584 | - call deallocate(dbin) |
1585 | - |
1586 | -end subroutine vertical_element_ordering |
1587 | - |
1588 | -subroutine compute_face_normal_gravity(face_normal_gravity, & |
1589 | - positions, vertical_normal) |
1590 | -!!< Returns a matrix where A_ij is the inner product of the face normal |
1591 | -!!< and the gravity normal vector of the face between element i and j. |
1592 | -type(csr_matrix), intent(out):: face_normal_gravity |
1593 | -type(vector_field), target, intent(in):: positions, vertical_normal |
1594 | - |
1595 | - type(mesh_type), pointer:: mesh |
1596 | - real, dimension(:), pointer:: face_normal_gravity_val |
1597 | - real, dimension(:), allocatable:: detwei_f |
1598 | - real, dimension(:,:), allocatable:: face_normal, gravity_normal |
1599 | - integer, dimension(:), pointer:: neigh, faces |
1600 | - real inn, area |
1601 | - integer sngi, nloc, i, k |
1602 | - |
1603 | - mesh => positions%mesh |
1604 | - call allocate(face_normal_gravity, mesh%faces%face_list%sparsity) |
1605 | - call zero(face_normal_gravity) |
1606 | - |
1607 | - sngi=face_ngi(mesh, 1) |
1608 | - nloc=ele_loc(mesh,1) |
1609 | - allocate( detwei_f(1:sngi), & |
1610 | - face_normal(1:positions%dim, 1:sngi), & |
1611 | - gravity_normal(1:positions%dim, 1:sngi)) |
1612 | - |
1613 | - do i=1, element_count(mesh) |
1614 | - ! elements adjacent to element i |
1615 | - ! this is a row (column indices) in the mesh%faces%face_list matrix |
1616 | - neigh => ele_neigh(mesh, i) |
1617 | - ! the surrounding faces |
1618 | - ! this is a row (integer values) in the mesh%faces%face_list matrix |
1619 | - faces => ele_faces(mesh, i) |
1620 | - do k=1, size(neigh) |
1621 | - if (neigh(k)>i .or. neigh(k)<=0) then |
1622 | - ! only handling neigh(k)>i to ensure anti-symmetry of the matrix |
1623 | - ! (and more efficient of course) |
1624 | - call transform_facet_to_physical(positions, faces(k), & |
1625 | - detwei_f=detwei_f, & |
1626 | - normal=face_normal) |
1627 | - gravity_normal=face_val_at_quad(vertical_normal, faces(k)) |
1628 | - area=sum(detwei_f) |
1629 | - ! inner product of face normal and vertical normal |
1630 | - ! integrated over face |
1631 | - inn=sum(matmul(face_normal*gravity_normal, detwei_f))/area |
1632 | - if (neigh(k)>0) then |
1633 | - call set(face_normal_gravity, i, neigh(k), inn) |
1634 | - call set(face_normal_gravity, neigh(k), i, -inn) |
1635 | - else |
1636 | - ! exterior surface: matrix entry does not have valid |
1637 | - ! column index, still want to store its value, so we |
1638 | - ! use a pointer |
1639 | - face_normal_gravity_val => row_val_ptr(face_normal_gravity, i) |
1640 | - face_normal_gravity_val(k)=inn |
1641 | - end if |
1642 | - end if |
1643 | - end do |
1644 | - |
1645 | - end do |
1646 | - |
1647 | -end subroutine compute_face_normal_gravity |
1648 | - |
1649 | -subroutine vertical_integration_scalar(from_field, to_field, & |
1650 | - positions, vertical_normal, surface_element_list, rhs) |
1651 | -!!< See description vertical_integration_multiple |
1652 | -type(scalar_field), intent(in):: from_field |
1653 | -type(scalar_field), intent(in):: to_field |
1654 | -type(vector_field), intent(in):: positions, vertical_normal |
1655 | -integer, dimension(:), intent(in):: surface_element_list |
1656 | -type(scalar_field), optional, intent(in):: rhs |
1657 | - |
1658 | - type(scalar_field) to_fields(1) |
1659 | - |
1660 | - to_fields=(/ to_field /) |
1661 | - if (present(rhs)) then |
1662 | - call vertical_integration_multiple( (/ from_field /), to_fields, & |
1663 | - positions, vertical_normal, surface_element_list, rhs=(/ rhs /) ) |
1664 | - else |
1665 | - call vertical_integration_multiple( (/ from_field /), to_fields, & |
1666 | - positions, vertical_normal, surface_element_list) |
1667 | - end if |
1668 | - |
1669 | -end subroutine vertical_integration_scalar |
1670 | - |
1671 | -subroutine vertical_integration_vector(from_field, to_field, & |
1672 | - positions, vertical_normal, surface_element_list, rhs) |
1673 | -!!< See description vertical_integration_multiple |
1674 | -type(vector_field), intent(in):: from_field |
1675 | -type(vector_field), intent(in):: to_field |
1676 | -type(vector_field), intent(in):: positions, vertical_normal |
1677 | -integer, dimension(:), intent(in):: surface_element_list |
1678 | -type(vector_field), optional, intent(in):: rhs |
1679 | - |
1680 | - type(scalar_field), dimension(from_field%dim):: from_field_components, & |
1681 | - to_field_components, rhs_components |
1682 | - integer i |
1683 | - |
1684 | - assert(from_field%dim==to_field%dim) |
1685 | - |
1686 | - do i=1, from_field%dim |
1687 | - from_field_components(i)=extract_scalar_field(from_field, i) |
1688 | - to_field_components(i)=extract_scalar_field(to_field, i) |
1689 | - if (present(rhs)) then |
1690 | - rhs_components(i)=extract_scalar_field(rhs, i) |
1691 | - end if |
1692 | - end do |
1693 | - |
1694 | - if (present(rhs)) then |
1695 | - call vertical_integration_multiple( from_field_components, & |
1696 | - to_field_components, positions, vertical_normal, & |
1697 | - surface_element_list, rhs=rhs_components) |
1698 | - else |
1699 | - call vertical_integration_multiple( from_field_components, & |
1700 | - to_field_components, positions, vertical_normal, & |
1701 | - surface_element_list) |
1702 | - end if |
1703 | - |
1704 | -end subroutine vertical_integration_vector |
1705 | - |
1706 | -subroutine vertical_integration_multiple(from_fields, to_fields, & |
1707 | - positions, vertical_normal, surface_element_list, rhs) |
1708 | -!!< This subroutine solves: dP/dz=rhs using DG |
1709 | -!!< It can be used for vertical integration downwards (dP/dz=0) as a drop |
1710 | -!!< in replacement of VerticalExtrapolation hence its similar interface. |
1711 | -!!< The field P is the to_field. A boundary condition is given by the |
1712 | -!!< from_field. Again completely similar to VerticalExtrapolation, it may |
1713 | -!!< be defined as a surface field on surface elements given by |
1714 | -!!< surface_element_list or it may be a field on the complete mesh |
1715 | -!!< in which case only its values on these surface elements are used. |
1716 | -!!< vertical_normal specifies the direction in which to integrate (usually downwards) |
1717 | -!!< If not specified rhs is assumed zero. |
1718 | -!!< |
1719 | -!!< This version accepts multiple from_fields, to_fields and rhs |
1720 | -type(scalar_field), dimension(:), intent(in):: from_fields |
1721 | -type(scalar_field), dimension(:), intent(inout):: to_fields |
1722 | -type(vector_field), intent(in):: positions, vertical_normal |
1723 | -integer, dimension(:), intent(in):: surface_element_list |
1724 | -type(scalar_field), dimension(:), optional, intent(in):: rhs |
1725 | - |
1726 | - type(csr_matrix) face_normal_gravity |
1727 | - type(element_type), pointer:: ele_shp, face_shp, x_face_shp |
1728 | - real, dimension(:), pointer:: inn |
1729 | - real, dimension(:,:,:), allocatable:: surface_rhs, dele_shp |
1730 | - real, dimension(:,:), allocatable:: ele_mat, face_mat, ele_rhs |
1731 | - real, dimension(:), allocatable:: detwei, detwei_f |
1732 | - integer, dimension(:), pointer:: neigh, ele_nds, faces, face_lnds |
1733 | - integer, dimension(:), allocatable:: ordered_elements, face_nds, face_nds2 |
1734 | - integer nloc, snloc, ngi, sngi |
1735 | - integer i, j, k, f, f2, elm, it, noit |
1736 | - logical optimal_ordering, from_surface_fields |
1737 | - |
1738 | - assert( size(from_fields)==size(to_fields) ) |
1739 | - |
1740 | - ! computes inner product of face normal and gravity (see above) |
1741 | - call compute_face_normal_gravity(face_normal_gravity, & |
1742 | - positions, vertical_normal) |
1743 | - |
1744 | - ! determine an ordering for the elements based on this |
1745 | - allocate( ordered_elements(1:element_count(positions)) ) |
1746 | - call vertical_element_ordering(ordered_elements, face_normal_gravity, & |
1747 | - optimal_ordering) |
1748 | - |
1749 | - ! General initalisation |
1750 | - !----------------------- |
1751 | - ! various grid numbers |
1752 | - nloc=ele_loc(to_fields(1), 1) |
1753 | - snloc=face_loc(to_fields(1), 1) |
1754 | - ngi=ele_ngi(positions, 1) |
1755 | - sngi=face_ngi(positions, 1) |
1756 | - ! shape functions |
1757 | - ele_shp => ele_shape(to_fields(1), 1) |
1758 | - face_shp => face_shape(to_fields(1), 1) |
1759 | - x_face_shp => face_shape(positions, 1) |
1760 | - ! various allocations: |
1761 | - allocate( & |
1762 | - surface_rhs(1:snloc, 1:size(to_fields), 1:surface_element_count(positions)), & |
1763 | - ele_mat(1:nloc, 1:nloc), ele_rhs(1:nloc,1:size(to_fields)), & |
1764 | - dele_shp(1:nloc, 1:ngi, 1:positions%dim), & |
1765 | - face_mat(1:snloc, 1:snloc), face_nds(1:snloc), face_nds2(1:snloc), & |
1766 | - detwei(1:ngi), detwei_f(1:sngi)) |
1767 | - |
1768 | - if (element_count(from_fields(1))==size(surface_element_list)) then |
1769 | - ! from_fields are fields over the surface mesh only |
1770 | - ! so we're using all of its values: |
1771 | - from_surface_fields=.true. |
1772 | - ! check the other fields as well: |
1773 | - do k=2, size(from_fields) |
1774 | - assert( element_count(from_fields(k))==size(surface_element_list) ) |
1775 | - end do |
1776 | - else |
1777 | - ! from_fields are on the full mesh and we only extract its values |
1778 | - ! at the specified surface_elements |
1779 | - |
1780 | - from_surface_fields=.false. |
1781 | - end if |
1782 | - |
1783 | - surface_rhs=0 |
1784 | - ! Compute contribution of exterior surface integral (boundary condition) to rhs |
1785 | - !----------------------- |
1786 | - do i=1, size(surface_element_list) |
1787 | - f=surface_element_list(i) |
1788 | - call transform_facet_to_physical(positions, f, detwei_f) |
1789 | - face_mat=-shape_shape(face_shp, face_shp, detwei_f) |
1790 | - do k=1, size(from_fields) |
1791 | - if (from_surface_fields) then |
1792 | - ! we need to use ele_val, where i is the element number in the surface_mesh |
1793 | - surface_rhs(:,k,f)=surface_rhs(:,k,f)+ & |
1794 | - matmul(face_mat, ele_val(from_fields(k), i)) |
1795 | - else |
1796 | - ! we can simply use face_val with face number f |
1797 | - surface_rhs(:,k,f)=surface_rhs(:,k,f)+ & |
1798 | - matmul(face_mat, face_val(from_fields(k), f)) |
1799 | - end if |
1800 | - end do |
1801 | - end do |
1802 | - |
1803 | - ! Solution loop |
1804 | - !----------------------- |
1805 | - if (optimal_ordering) then |
1806 | - noit=1 |
1807 | - else |
1808 | - noit=10 |
1809 | - end if |
1810 | - |
1811 | - do it=1, noit |
1812 | - do i=1, element_count(positions) |
1813 | - |
1814 | - elm=ordered_elements(i) |
1815 | - |
1816 | - ! construct diagonal matrix block for this element |
1817 | - call transform_to_physical(positions, elm, & |
1818 | - shape=ele_shp, dshape=dele_shp, detwei=detwei) |
1819 | - ele_mat=shape_vector_dot_dshape(ele_shp, & |
1820 | - ele_val_at_quad(vertical_normal,elm), & |
1821 | - dele_shp, detwei) |
1822 | - |
1823 | - ! initialise rhs |
1824 | - if (present(rhs)) then |
1825 | - do k=1, size(to_fields) |
1826 | - ele_rhs(:,k)=shape_rhs(ele_shp, detwei*ele_val_at_quad(rhs(k), elm)) |
1827 | - end do |
1828 | - else |
1829 | - ele_rhs=0.0 |
1830 | - end if |
1831 | - |
1832 | - |
1833 | - ! then add contribution of surface integrals of incoming |
1834 | - ! faces to the rhs and matrix |
1835 | - neigh => row_m_ptr(face_normal_gravity, elm) |
1836 | - inn => row_val_ptr(face_normal_gravity, elm) |
1837 | - faces => ele_faces(positions, elm) |
1838 | - do j=1, size(neigh) |
1839 | - if (inn(j)<-VERTICAL_INTEGRATION_EPS) then |
1840 | - call transform_facet_to_physical(positions, faces(j), & |
1841 | - detwei_f) |
1842 | - face_mat=-shape_shape(face_shp, face_shp, detwei_f)*inn(j) |
1843 | - |
1844 | - face_nds=face_global_nodes(to_fields(1), faces(j)) |
1845 | - face_lnds => face_local_nodes(to_fields(1)%mesh, faces(j)) |
1846 | - ele_mat(face_lnds,face_lnds)=ele_mat(face_lnds,face_lnds)+face_mat |
1847 | - |
1848 | - if (neigh(j)>0) then |
1849 | - ! face of element neigh(j), facing elm: |
1850 | - f2=ele_face(positions, neigh(j), elm) |
1851 | - face_nds2=face_global_nodes(to_fields(1), f2) |
1852 | - |
1853 | - do k=1, size(to_fields) |
1854 | - ele_rhs(face_lnds,k)=ele_rhs(face_lnds,k)+ & |
1855 | - matmul(face_mat, node_val(to_fields(k), face_nds2)) |
1856 | - end do |
1857 | - else |
1858 | - ! note that we've already multiplied with face_mat above, but not with inn(j) |
1859 | - ele_rhs(face_lnds,:)=ele_rhs(face_lnds,:)+surface_rhs(:,:,faces(j))*inn(j) |
1860 | - end if |
1861 | - end if |
1862 | - end do |
1863 | - |
1864 | - call invert(ele_mat) |
1865 | - |
1866 | - ! compute values for the to_fields: |
1867 | - ele_nds => ele_nodes(to_fields(1), elm) |
1868 | - do k=1, size(to_fields) |
1869 | - call set( to_fields(k), ele_nds, matmul(ele_mat, ele_rhs(:,k)) ) |
1870 | - end do |
1871 | - end do |
1872 | - end do |
1873 | - |
1874 | - call deallocate(face_normal_gravity) |
1875 | - |
1876 | -end subroutine vertical_integration_multiple |
1877 | - |
1878 | -subroutine vertical_extrapolation_module_check_options |
1879 | - |
1880 | - if (have_option("/geometry/ocean_boundaries")) then |
1881 | - if (.not. have_option("/physical_parameters/gravity")) then |
1882 | - ewrite(-1,*) "If you select /geometry/ocean_boundaries, you also need to "//& |
1883 | - &"set /physical_parameters/gravity" |
1884 | - FLExit("Missing gravity!") |
1885 | - end if |
1886 | - end if |
1887 | - |
1888 | -end subroutine vertical_extrapolation_module_check_options |
1889 | - |
1890 | -end module vertical_extrapolation_module |
1891 | |
1892 | === modified file 'main/Fluids.F90' |
1893 | --- main/Fluids.F90 2012-09-03 14:31:15 +0000 |
1894 | +++ main/Fluids.F90 2012-09-04 15:00:37 +0000 |
1895 | @@ -84,7 +84,7 @@ |
1896 | use discrete_properties_module |
1897 | use gls |
1898 | use k_epsilon |
1899 | - use iceshelf_meltrate_surf_normal |
1900 | + use ice_melt_interface |
1901 | use halos |
1902 | use memory_diagnostics |
1903 | use free_surface_module |
1904 | @@ -406,15 +406,9 @@ |
1905 | |
1906 | call initialise_diagnostics(filename, state) |
1907 | |
1908 | - ! Initialise ice_meltrate, read constatns, allocate surface, and calculate melt rate |
1909 | + ! Initialise melt interface paramerisation |
1910 | if (have_option("/ocean_forcing/iceshelf_meltrate/Holland08")) then |
1911 | - call melt_surf_init(state(1)) |
1912 | - call melt_allocate_surface(state(1)) |
1913 | - call melt_surf_calc(state(1)) |
1914 | - !BC for ice melt |
1915 | - if (have_option('/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries')) then |
1916 | - call melt_bc(state(1)) |
1917 | - endif |
1918 | + call melt_interface_initialisation(state(1)) |
1919 | end if |
1920 | |
1921 | ! Checkpoint at start |
1922 | @@ -636,12 +630,13 @@ |
1923 | end if |
1924 | end if |
1925 | |
1926 | - ! Calculate the meltrate |
1927 | - if(have_option("/ocean_forcing/iceshelf_meltrate/Holland08/") ) then |
1928 | - if( (trim(field_name_list(it))=="MeltRate")) then |
1929 | - call melt_surf_calc(state(1)) |
1930 | + ! Calculate the (ice) interface meltrate using the parameterisation described in Holland et al. 2008 doi:10.1175/2007JCLI1909.1 |
1931 | + if (have_option("/ocean_forcing/iceshelf_meltrate/Holland08")) then |
1932 | + if ((trim(field_name_list(it)) == "MeltRate")) then |
1933 | + call melt_interface_calculate(state(1)) |
1934 | endif |
1935 | - end if |
1936 | + end if |
1937 | + |
1938 | |
1939 | call get_option(trim(field_optionpath_list(it))//& |
1940 | '/prognostic/equation[0]/name', & |
1941 | @@ -713,9 +708,9 @@ |
1942 | call keps_eddyvisc(state(i)) |
1943 | end do |
1944 | |
1945 | - !BC for ice melt |
1946 | + ! Boundary conditions for the (ice) melt interface parameterisation |
1947 | if (have_option('/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries')) then |
1948 | - call melt_bc(state(1)) |
1949 | + call melt_interface_boundary_condition(state(1)) |
1950 | endif |
1951 | |
1952 | if(option_count("/material_phase/scalar_field/prognostic/spatial_discretisation/coupled_cv")>0) then |
1953 | |
1954 | === modified file 'main/Makefile.dependencies' |
1955 | --- main/Makefile.dependencies 2012-03-02 00:25:33 +0000 |
1956 | +++ main/Makefile.dependencies 2012-09-04 15:00:37 +0000 |
1957 | @@ -45,7 +45,7 @@ |
1958 | ../include/fldebug.mod ../include/foam_flow_module.mod \ |
1959 | ../include/free_surface_module.mod ../include/global_parameters.mod \ |
1960 | ../include/gls.mod ../include/goals.mod ../include/halos.mod \ |
1961 | - ../include/iceshelf_meltrate_surf_normal.mod ../include/implicit_solids.mod \ |
1962 | + ../include/ice_melt_interface.mod ../include/implicit_solids.mod \ |
1963 | ../include/k_epsilon.mod ../include/memory_diagnostics.mod \ |
1964 | ../include/meshdiagnostics.mod ../include/meshmovement.mod \ |
1965 | ../include/momentum_equation.mod ../include/multimaterial_module.mod \ |
1966 | |
1967 | === modified file 'manual/embedded_models.tex' |
1968 | --- manual/embedded_models.tex 2011-11-24 14:46:24 +0000 |
1969 | +++ manual/embedded_models.tex 2012-09-04 15:00:37 +0000 |
1970 | @@ -361,13 +361,6 @@ |
1971 | therefore requires a single boundary condition: the amount of light incident |
1972 | on the water surface. This is a Dirichlet condition on $I$. |
1973 | |
1974 | -As the PAR equation is relatively trivial to solve, the following options |
1975 | -are recommended: |
1976 | -\begin{itemize} |
1977 | -\item Discontinuous discretisation |
1978 | -\item Solver: gmres iterative method, with no preconditioner. |
1979 | -\end{itemize} |
1980 | - |
1981 | \subsection{Detritus falling velocity}\label{sec:detritus} |
1982 | |
1983 | Phytoplankton, zooplankton and nutrient are assumed to be neutrally buoyant |
1984 | |
1985 | === modified file 'manual/model_equations.tex' |
1986 | --- manual/model_equations.tex 2012-08-31 13:12:30 +0000 |
1987 | +++ manual/model_equations.tex 2012-09-04 15:00:37 +0000 |
1988 | @@ -10,7 +10,7 @@ |
1989 | problem & underlying equations & boundary conditions & other considerations\\ |
1990 | \hline |
1991 | scalar advection & \ref{sec:MP-AdvdifEqn-eqns}, \ref{sec:MP-AdvdifEqn-adv} & \ref{sec:bc_scalar_dirichlet}, \ref{sec:bc_scalar_neumann} & × \\ |
1992 | -scalar advection-diffusion & \ref{sec:MP-AdvdifEqn-eqns}, \ref{sec:MP-AdvdifEqn-diff} & \ref{sec:bc_scalar_dirichlet}, \ref{sec:bc_scalar_neumann}, \ref{sec:bc_scalar_robin} × & ×\\ |
1993 | +scalar advection-diffusion & \ref{sec:MP-AdvdifEqn-eqns}, \ref{sec:MP-AdvdifEqn-diff} & × & ×\\ |
1994 | momentum equation & \ref{sec:MP-MomEqn} & \ref{sec:bc_vector_dirichlet}, \ref{sec:bc_vector_stress}, \ref{sec:bc_vector_traction}, \ref{sec:FS} & \ref{sec:eqn_extensions} \\ |
1995 | \hline |
1996 | \end{tabular} |
1997 | @@ -119,21 +119,6 @@ |
1998 | and substituting in this surface integral to the discretised equation. Note that $q$ is often termed a flux. |
1999 | |
2000 | |
2001 | -\subsubsection{Robin condition for a scalar field}\label{sec:bc_scalar_robin} |
2002 | -\index{boundary conditions!Neumann} |
2003 | - |
2004 | -Taking the weak form (applying Green's theorem to the diffusion term) of the advection-diffusion equation \eqref{eq:general_scalar_eqn} leads to a surface integral of the form |
2005 | -\begin{equation*} |
2006 | -\int_{\partial\Omega} \phi (\kaptens\nabla c)\cdot\bmn \;d\Gamma, |
2007 | -\end{equation*} |
2008 | -where $\phi$ is a test function (see section \ref{chap:numerical_discretisation}). |
2009 | -The Robin condition is specified by relating the surface diffusive flux $(\kaptens\nabla c)\cdot\bmn$ to an ambient field value $c_{a}$, with an associated surface transfer coefficient $h$. This is given by the relationship |
2010 | -\begin{equation*} |
2011 | --(\kaptens\nabla c)\cdot\bmn = h (c - c_{a}),\quad \textrm{on}\quad \partial\Omega, |
2012 | -\end{equation*} |
2013 | -where in general $h$ and $c_{a}$ can vary spatially and temporally. This is substituted into the discretised equation to give a surface absorption term given by $hc$ and a surface source given by $-hc_{a}$. |
2014 | - |
2015 | - |
2016 | \section{Fluid equations}\label{sec:MP-MomEqn} |
2017 | |
2018 | \index{conservation!equation} |
2019 | @@ -727,7 +712,7 @@ |
2020 | |
2021 | \subsection{Multi-material simulations} |
2022 | \index{multi-material flow} |
2023 | -The ability to differentiate between regions with distinct material properties is of fundamental importance in the modelling of many physical systems. Two different approaches exist for achieving this: the multi-material approach and the multiphase approach. The multi-material approach is implemented within \fluidity, and the multiphase approach (discussed in the next subsection) is currently under development. |
2024 | +The ability to differentiate between regions with distinct material properties is of fundamental importance in the modelling of many physical systems. Two different approaches exist for achieving this: the multi-material approach and the multi-phase approach. The multi-material approach is implemented within \fluidity, and the multi-phase approach (discussed in the next subsection) is currently under development. |
2025 | In situations where the model can resolve physical mixing of immiscible materials, or where there is no mixing, only one velocity field (and hence one momentum equation) is required to describe the flow of all materials. The \emph{multi-material} approach, considers all materials to be immiscible materials separated by a sharp interface. |
2026 | |
2027 | In a multi-material approach, the various forms of the conservation equations can be solved for multiple material flows if the point-wise mass density $\rho$ in the equations is defined as the bulk density at each point. If the flow comprises $n$ materials and the volume fraction of the $i^{th}$ material is denoted $\phi_i$ then the bulk density is given by: |
2028 | @@ -749,17 +734,14 @@ |
2029 | \end{equation} |
2030 | where the volume fraction field at time zero must be specified. |
2031 | |
2032 | -\subsection{Multiphase simulations} |
2033 | +\subsection{Multi-phase simulations} |
2034 | \label{sec:multiphase_equations} |
2035 | -\index{multiphase flow} |
2036 | -Multiphase flows are defined by \cite{prosperettiEtAl2007} to be flows in which two or more phases of matter (solid, liquid, gas, etc) are simultaneously present and are allowed to inter-penetrate. Simple examples include the flow of a fizzy drink which is composed of a liquid and a finite number of gas bubbles, the transportation of solid sediment particles in a river, and the flow of blood cells around the human body. |
2037 | +\index{multi-phase flow} |
2038 | +Multi-phase flows are defined by \cite{prosperettiEtAl2007} to be flows in which two or more phases of matter (solid, liquid, gas, etc) are simultaneously present and are allowed to inter-penetrate. Simple examples include the flow of a fizzy drink which is composed of a liquid and a finite number of gas bubbles, the transportation of solid sediment particles in a river, and the flow of blood cells around the human body. |
2039 | |
2040 | Further to the above definition, each phase is classed as either \textit{continuous} or \textit{dispersed}, where a continuous phase is a connected liquid or gas substance in which dispersed phases (comprising a finite number of solid particles, liquid droplets and/or gas bubbles) may be immersed \citep{croweEtAl1998}. |
2041 | |
2042 | -To enable the mixing and inter-penetration of phases, a separate velocity field (and hence a separate momentum equation) is assigned to each one and solved for. Extra terms are then included to account for inter-phase interactions. Furthermore, the model currently assumes no mass transfer between phases, incompressible flow, and a common pressure field $p$ so that only one continuity equation is used. The form of the governing equations depends on whether we are dealing with incompressible or compressible flow. |
2043 | - |
2044 | -\subsubsection{Incompressible flow} |
2045 | -For an incompressible multiphase flow, the continuity equation and momentum equation for phase $i$ (based on the derivation in \cite{ishii1975}, written in non-conservative form) are: |
2046 | +To enable the mixing and inter-penetration of phases, a separate velocity field (and hence a separate momentum equation) is assigned to each one and solved for. Extra terms are then included to account for inter-phase interactions. Furthermore, the model currently assumes no mass transfer between phases, incompressible flow, and a common pressure field $p$ so that only one continuity equation is used. Thus, the continuity equation and momentum equation for phase $i$ (based on the derivation in \cite{ishii1975}, written in non-conservative form) are: |
2047 | \begin{equation} |
2048 | \sum_{i=1}^N\nabla\cdot\left(\alpha_i\mathbf{u}_i\right) = 0, |
2049 | \end{equation} |
2050 | @@ -772,19 +754,6 @@ |
2051 | \end{equation} |
2052 | where $\mathbf{u}_i$, $\rho_i$, $\tautens_i$ and $\alpha_i$ are the velocity, density, viscous stress tensor and volume fraction of phase $i$ respectively, and $\mathbf{F}_i$ represents the forces imposed on phase $i$ by the other $N-1$ phases. Details of momentum transfer terms are given in Chapter \ref{chap:configuration}. |
2053 | |
2054 | -\subsubsection{Compressible flow} |
2055 | -Fluidity currently only supports the case where the continuous phase is compressible. All other phases (the dispersed phases) are incompressible. The momentum equation is the same as the one given above, but the continuity equation becomes: |
2056 | -\begin{equation} |
2057 | -\alpha_1\frac{\partial\rho_1}{\partial t} + \nabla\cdot\left(\alpha_1\rho_1\mathbf{u}_1\right) + \rho_1\left(\sum_{i=2}^N\nabla\cdot\left(\alpha_i\mathbf{u}_i\right)\right) = 0, |
2058 | -\end{equation} |
2059 | -where the compressible phase has an index of $i=1$ here. |
2060 | - |
2061 | -An internal energy equation may also need to be solved depending on the equation of state used for the compressible phase. This is given by: |
2062 | -\begin{equation} |
2063 | -\alpha_i\rho_i\frac{\partial e_i}{\partial t} + \alpha_i\rho_i\mathbf{u}_i\cdot\nabla e_i = -p\nabla\cdot\left(\alpha_i\mathbf{u}_i\right) + Q_i |
2064 | -\end{equation} |
2065 | -where $e_i$ is the internal energy and $Q_i$ is an inter-phase energy transfer term described in Chapter \ref{chap:configuration}. |
2066 | - |
2067 | \subsection{Porous Media Darcy Flow} |
2068 | \label{sec:porous_media_darcy_flow_equations} |
2069 | \index{porous media darcy flow} |
2070 | |
2071 | === modified file 'manual/numerical_discretisation.tex' |
2072 | --- manual/numerical_discretisation.tex 2012-07-26 15:38:42 +0000 |
2073 | +++ manual/numerical_discretisation.tex 2012-09-04 15:00:37 +0000 |
2074 | @@ -9,12 +9,11 @@ |
2075 | $\Omega$ is defined as $\dOmega$ |
2076 | %(NB. $\Gamma$ is another common symbol for a boundary) |
2077 | and can be split into different sections, e.g. |
2078 | -$\partial\Omega = \dOmega^{N}\cup \dOmega^{R}\cup \dOmega^{D}$ |
2079 | +$\partial\Omega = \dOmega^{N}\cup \dOmega^{D}$ |
2080 | where $\dOmega^{N}$ is that part of the boundary over |
2081 | -which Neumann conditions are applied, $\dOmega^{R}$ is the part of the |
2082 | -boundary over which Robin conditions are applied and $\dOmega^{D}$ is that part of the boundary over |
2083 | +which Neumann conditions are applied and $\dOmega^{D}$ is that part of the boundary over |
2084 | which Dirichlet conditions are applied. For clarity a subscript showing the field in question will |
2085 | -be given on the $N$, $R$ and $D$ characters. |
2086 | +be given on the $N$ and $D$ characters. |
2087 | |
2088 | The unit vector \vec{n} is always assumed to be the |
2089 | outward facing normal vector to the domain. |
2090 | @@ -31,11 +30,10 @@ |
2091 | \end{equation} |
2092 | |
2093 | We now define a partition of the boundary such that |
2094 | -$\partial\Omega = \dOmega^{N}\cup \dOmega^{R}\cup \dOmega^{D}$, and impose boundary conditions on $c$: |
2095 | +$\partial\Omega = \dOmega^{N}\cup \dOmega^{D}$, and impose boundary conditions on $c$: |
2096 | \begin{gather} |
2097 | \label{eq:cboundary} |
2098 | \vec{n}\cdot\tensor{\kappa}\cdot\grad c=g_{N_c} \quad\textrm{on}\quad \dOmega^{N_c},\\ |
2099 | - -\vec{n}\cdot\tensor{\kappa}\cdot\grad c=h(c-c_{a})\quad\textrm{on}\quad \dOmega^{R_c},\\ |
2100 | c=g_{D_c} \quad\textrm{on}\quad \dOmega^{D_c}. |
2101 | \end{gather} |
2102 | |
2103 | @@ -371,7 +369,7 @@ |
2104 | |
2105 | The SUPG implementation in \fluidity\ does not modify the test function derivatives |
2106 | or the face test functions. Hence the SUPG implementation is only consistent |
2107 | -for degree one elements with no non-zero Neumann, Robin or weak Dirichlet boundary |
2108 | +for degree one elements with no non-zero Neumann or weak Dirichlet boundary |
2109 | conditions. |
2110 | |
2111 | SUPG is considered ready for production use for scalar advection-diffusion |
2112 | @@ -435,25 +433,6 @@ |
2113 | boundary term \eqref{eq:missing_boundary_term} with an integral of $\phi~g_N$ |
2114 | over the boundary. |
2115 | |
2116 | -The Robin boundary condition |
2117 | -\begin{equation*} |
2118 | - -\vec{n}\cdot\tensor{\kappa}\cdot\grad c=h(c-c_{a}), |
2119 | -\end{equation*} |
2120 | -where $h$ and $c_{a}$ can be any prescribed function on the boundary $\partial\Omega$, is also imposed |
2121 | -weakly. As for the Neumann boundary condition, weighting the Robin boundary condition with a test function |
2122 | -and integrating over the relevant domain boundary gives the weak form: |
2123 | -\begin{equation}\label{eq:weak_robin} |
2124 | - - \int_{\partial\Omega} \phi~\vec{n}\cdot\tensor{\kappa}\cdot\grad c= |
2125 | - \int_{\partial\Omega} \phi~h(c-c_{a}), \quad \text{for all }\phi. |
2126 | -\end{equation} |
2127 | -Thus \eqref{eq:weak_robin} can be used to replace the missing |
2128 | -boundary term \eqref{eq:missing_boundary_term} with an integral of $\phi~h(c-c_{a})$ |
2129 | -over the relevant part of the boundary. The two terms within the integral can be treated slightly differently. |
2130 | -The term $\phi~hc_{a}$ is always included in the right hand side of the linear system. |
2131 | -The term $\phi~hc$ is effectively a surface absorption term where any implicit contributions |
2132 | -are included in the left had side matrix, while any explicit contributions are included into the |
2133 | -right hand side of the linear system. |
2134 | - |
2135 | \index{boundary conditions!Dirichlet!weakly imposed} |
2136 | In a similar way, a weakly imposed Dirichlet boundary condition can be related to an |
2137 | integration by parts of the advection term. Let us consider a pure advection problem |
2138 | |
2139 | === modified file 'manual/parameterisations.tex' |
2140 | --- manual/parameterisations.tex 2012-08-30 14:23:11 +0000 |
2141 | +++ manual/parameterisations.tex 2012-09-04 15:00:37 +0000 |
2142 | @@ -83,18 +83,6 @@ |
2143 | \end{equation} |
2144 | where $c_\mu^0$ is a model constant used to make $\Psi$ identifiable with any of the transitional |
2145 | models, e.g. $kl$, $\epsilon$, and $\omega$, by adopting the values shown in Table \ref{tab:glsparams} \citep{umlauf2003}. |
2146 | - |
2147 | -There is also the option to add an extra term to account for various |
2148 | -oceanic parameters, such an internal waves breaking. This is based on the NEMO |
2149 | -ocean model and takes a user-defined percentage of the surface $k$ and adds it down-depth |
2150 | -using an exponential profile: |
2151 | -\begin{equation} |
2152 | - k_z = {k_z}_o + p*k_{\mathrm{sur}} * \exp{\left( -z / l_k \right)} |
2153 | -\end{equation} |
2154 | -where $k_z$ is the new turbulent kinetic energy value at depth, $z$, ${k_z}_o$ is the original TKE, $k_{\mathrm{sur}}$ |
2155 | -is the surface TKE, $p$ is a constant, and $l_k$ is a lengthscale. The options for this can be found in |
2156 | -\option{\ldots/subgridscale\_parameterisations/gls/ocean\_parameterisation}. |
2157 | - |
2158 | The second equation is: |
2159 | \begin{equation} |
2160 | \frac{\partial \Psi}{\partial t} + \bmu_i\frac{\partial \Psi}{\partial x_i} = |
2161 | |
2162 | === modified file 'manual/visualisation_and_diagnostics.tex' |
2163 | --- manual/visualisation_and_diagnostics.tex 2012-08-09 22:08:12 +0000 |
2164 | +++ manual/visualisation_and_diagnostics.tex 2012-09-04 15:00:37 +0000 |
2165 | @@ -66,7 +66,6 @@ |
2166 | Limitations: Requires the diagnostic \option{scalar\_field::IsopycnalCoordinate} and (therefore) is not parallelised. |
2167 | \item[BulkMaterialPressure:]Calculates the bulk material pressure based on the MaterialDensity and MaterialVolumeFraction (and MaterialInternalEnergy if appropriate) for the equation of state of all materials. |
2168 | \item[CFLNumber:]CFLNumber as defined on the co-ordinate mesh. It is calculated as $\triangle t \vec{u} \mat{J}^{-1}$ where $\triangle t$ is the timestep, $\vec{u}$ the velocity and $\mat{J}$ the Jacobian. |
2169 | -\item[CompressibleContinuityResidual:]Computes the residual of the compressible multiphase continuity equation. Used only in compressible multiphase flow simulations. |
2170 | \item[ControlVolumeCFLNumber:]CFL Number as defined on a control volume mesh. It is calculated as $\triangle t \frac{1}{V} \int _{cv_{face}} \vec{u}$ where $\triangle t$ is the timestep and $\vec{u}$ the velocity. The integral is taken over the faces of the control volume and $V$ is the volume of the control volume. |
2171 | \item[ControlVolumeDivergence:]Divergence of the velocity field where the divergence operator is defined using the control volume $\mathrm{C}^\mathrm{T}$ matrix. This assumes that the test space is discontinuous control volumes. |
2172 | \item[CVMaterialDensityCFLNumber:]Courant Number as defined on a control volume mesh and incorporating the MaterialDensity. Requires a MaterialDensity field! |
2173 | |
2174 | === modified file 'parameterisation/Gls_vertical_turbulence_model.F90' |
2175 | --- parameterisation/Gls_vertical_turbulence_model.F90 2012-06-08 20:26:43 +0000 |
2176 | +++ parameterisation/Gls_vertical_turbulence_model.F90 2012-09-04 15:00:37 +0000 |
2177 | @@ -42,7 +42,6 @@ |
2178 | use Coordinates |
2179 | use FLDebug |
2180 | use fefields |
2181 | - use vertical_extrapolation_module |
2182 | |
2183 | implicit none |
2184 | |
2185 | @@ -355,13 +354,10 @@ |
2186 | type(tensor_field), pointer :: tke_diff, background_diff |
2187 | type(scalar_field), pointer :: tke |
2188 | real :: prod, buoyan, diss |
2189 | - integer :: i, stat, ele |
2190 | + integer :: i, stat |
2191 | character(len=FIELD_NAME_LEN) :: bc_type |
2192 | type(scalar_field), pointer :: scalar_surface |
2193 | type(vector_field), pointer :: positions |
2194 | - type(scalar_field), pointer :: lumped_mass |
2195 | - type(scalar_field) :: inverse_lumped_mass |
2196 | - |
2197 | |
2198 | ! Temporary tensor to hold rotated values if on the sphere (note: must be a 3x3 mat) |
2199 | real, dimension(3,3) :: K_M_sphere_node |
2200 | @@ -371,10 +367,6 @@ |
2201 | ! Get N^2 and M^2 -> NN2 and MM2 |
2202 | call gls_buoyancy(state) |
2203 | |
2204 | - do i=1,NNodes_sur |
2205 | - call set(NN2,top_surface_nodes(i),0.0) |
2206 | - end do |
2207 | - |
2208 | ! calculate stability function |
2209 | call gls_stability_function(state) |
2210 | |
2211 | @@ -384,35 +376,26 @@ |
2212 | tke_diff => extract_tensor_field(state, "GLSTurbulentKineticEnergyDiffusivity") |
2213 | positions => extract_vector_field(state, "Coordinate") |
2214 | |
2215 | - ! Create a local_tke in which we can mess about with the surface values |
2216 | - ! for creating some of the diagnostic values later |
2217 | + ! swap state tke for our local one - the state tke has had the upper and |
2218 | + ! lower boundaries ammended with the Dirichlet condition as in Warner et al |
2219 | + ! 2005. The local TKE is the non-amended version. This ensures a |
2220 | + ! non-ill-posed problem. |
2221 | call set(tke,local_tke) |
2222 | - ! Assembly loop |
2223 | - call zero(P) |
2224 | - call zero(B) |
2225 | - call allocate(inverse_lumped_mass, P%mesh, "InverseLumpedMass") |
2226 | - lumped_mass => get_lumped_mass(state, P%mesh) |
2227 | - call invert(lumped_mass, inverse_lumped_mass) |
2228 | - ! create production terms, P, B |
2229 | - do ele=1, ele_count(P) |
2230 | - call assemble_tke_prodcution_terms(ele, P, B, mesh_dim(P)) |
2231 | - end do |
2232 | - call scale(P,inverse_lumped_mass) |
2233 | - call scale(B,inverse_lumped_mass) |
2234 | - call deallocate(inverse_lumped_mass) |
2235 | |
2236 | - call zero(source) |
2237 | - call zero(absorption) |
2238 | - do ele = 1, ele_count(tke) |
2239 | - call assemble_kk_src_abs(ele,tke, mesh_dim(tke)) |
2240 | - end do |
2241 | - call allocate(inverse_lumped_mass, tke%mesh, "InverseLumpedMass") |
2242 | - lumped_mass => get_lumped_mass(state, tke%mesh) |
2243 | - call invert(lumped_mass, inverse_lumped_mass) |
2244 | - ! source and absorption terms are set, apart from the / by lumped mass |
2245 | - call scale(source,inverse_lumped_mass) |
2246 | - call scale(absorption,inverse_lumped_mass) |
2247 | - call deallocate(inverse_lumped_mass) |
2248 | + do i=1,nNodes |
2249 | + prod = node_val(K_M,i)*node_val(MM2,i) |
2250 | + buoyan = -1.*node_val(K_H,i)*node_val(NN2,i) |
2251 | + diss = node_val(eps,i) |
2252 | + if (prod+buoyan.gt.0) then |
2253 | + call set(source,i, prod + buoyan) |
2254 | + call set(absorption,i, diss / node_val(tke,i)) |
2255 | + else |
2256 | + call set(source,i, prod) |
2257 | + call set(absorption,i, (diss-buoyan)/node_val(tke,i)) |
2258 | + end if |
2259 | + call set(P, i, prod) |
2260 | + call set(B, i, buoyan) |
2261 | + enddo |
2262 | |
2263 | ! set diffusivity for tke |
2264 | call zero(tke_diff) |
2265 | @@ -457,66 +440,6 @@ |
2266 | call set(scalarField,absorption) |
2267 | end if |
2268 | |
2269 | - contains |
2270 | - |
2271 | - subroutine assemble_tke_prodcution_terms(ele, P, B, dim) |
2272 | - |
2273 | - integer, intent(in) :: ele, dim |
2274 | - type(scalar_field), intent(inout) :: P, B |
2275 | - |
2276 | - real, dimension(ele_loc(P,ele),ele_ngi(P,ele),dim) :: dshape_P |
2277 | - real, dimension(ele_ngi(P,ele)) :: detwei |
2278 | - real, dimension(ele_loc(P,ele)) :: rhs_addto_vel, rhs_addto_buoy |
2279 | - type(element_type), pointer :: shape_p |
2280 | - integer, pointer, dimension(:) :: nodes_p |
2281 | - |
2282 | - nodes_p => ele_nodes(p, ele) |
2283 | - shape_p => ele_shape(p, ele) |
2284 | - call transform_to_physical( positions, ele, shape_p, dshape=dshape_p, detwei=detwei ) |
2285 | - |
2286 | - ! Shear production term: |
2287 | - rhs_addto_vel = shape_rhs(shape_p, detwei*ele_val_at_quad(K_M,ele)*ele_val_at_quad(MM2,ele)) |
2288 | - ! Buoyancy production term: |
2289 | - rhs_addto_buoy = shape_rhs(shape_p, -detwei*ele_val_at_quad(K_H,ele)*ele_val_at_quad(NN2,ele)) |
2290 | - |
2291 | - call addto(P, nodes_p, rhs_addto_vel) |
2292 | - call addto(B, nodes_p, rhs_addto_buoy) |
2293 | - |
2294 | - end subroutine assemble_tke_prodcution_terms |
2295 | - |
2296 | - subroutine assemble_kk_src_abs(ele, kk, dim) |
2297 | - |
2298 | - integer, intent(in) :: ele, dim |
2299 | - type(scalar_field), intent(in) :: kk |
2300 | - |
2301 | - real, dimension(ele_loc(kk,ele),ele_ngi(kk,ele),dim) :: dshape_kk |
2302 | - real, dimension(ele_ngi(kk,ele)) :: detwei |
2303 | - real, dimension(ele_loc(kk,ele)) :: rhs_addto_disip, rhs_addto_src |
2304 | - type(element_type), pointer :: shape_kk |
2305 | - integer, pointer, dimension(:) :: nodes_kk |
2306 | - |
2307 | - nodes_kk => ele_nodes(kk, ele) |
2308 | - shape_kk => ele_shape(kk, ele) |
2309 | - call transform_to_physical( positions, ele, shape_kk, dshape=dshape_kk, detwei=detwei ) |
2310 | - |
2311 | - ! ROMS and GOTM hide the absorption term in the source if the |
2312 | - ! total is > 0. Kinda hard to do that over an element (*what* should |
2313 | - ! be > 0?). So we don't pull this trick. Doesn't seem to make a |
2314 | - ! difference to anything. |
2315 | - rhs_addto_src = shape_rhs(shape_kk, detwei * (& |
2316 | - (ele_val_at_quad(P,ele))) & |
2317 | - ) |
2318 | - rhs_addto_disip = shape_rhs(shape_kk, detwei * ( & |
2319 | - (ele_val_at_quad(eps,ele) - & |
2320 | - ele_val_at_quad(B,ele)) / & |
2321 | - ele_val_at_quad(tke,ele)) & |
2322 | - ) |
2323 | - |
2324 | - call addto(source, nodes_kk, rhs_addto_src) |
2325 | - call addto(absorption, nodes_kk, rhs_addto_disip) |
2326 | - |
2327 | - |
2328 | - end subroutine assemble_kk_src_abs |
2329 | |
2330 | end subroutine gls_tke |
2331 | |
2332 | @@ -532,19 +455,9 @@ |
2333 | type(tensor_field), pointer :: psi_diff, background_diff |
2334 | real :: prod, buoyan,diss,PsiOverTke |
2335 | character(len=FIELD_NAME_LEN) :: bc_type |
2336 | - integer :: i, stat, ele |
2337 | + integer :: i, stat |
2338 | type(scalar_field), pointer :: scalar_surface |
2339 | type(vector_field), pointer :: positions |
2340 | - type(scalar_field), pointer :: lumped_mass |
2341 | - type(scalar_field) :: inverse_lumped_mass, vel_prod, buoy_prod |
2342 | - ! variables for the ocean parameterisation |
2343 | - type(csr_matrix) :: face_normal_gravity |
2344 | - integer, dimension(:), allocatable :: ordered_elements |
2345 | - logical, dimension(:), allocatable :: node_list |
2346 | - logical :: got_surface |
2347 | - real :: lengthscale, percentage, tke_surface |
2348 | - type(scalar_field), pointer :: distanceToTop, distanceToBottom |
2349 | - type(vector_field), pointer :: vertical_normal |
2350 | |
2351 | ! Temporary tensor to hold rotated values (note: must be a 3x3 mat) |
2352 | real, dimension(3,3) :: psi_sphere_node |
2353 | @@ -558,16 +471,26 @@ |
2354 | psi => extract_scalar_field(state, "GLSGenericSecondQuantity") |
2355 | psi_diff => extract_tensor_field(state, "GLSGenericSecondQuantityDiffusivity") |
2356 | positions => extract_vector_field(state, "Coordinate") |
2357 | - vertical_normal => extract_vector_field(state, "GravityDirection") |
2358 | - call allocate(vel_prod, psi%mesh, "_vel_prod_psi") |
2359 | - call allocate(buoy_prod, psi%mesh, "_buoy_prod_psi") |
2360 | + |
2361 | ewrite(2,*) "In gls_psi: setting up" |
2362 | |
2363 | ! store the tke in an internal field and then |
2364 | ! add the dirichlet conditions to the upper and lower surfaces. This |
2365 | ! helps stabilise the diffusivity (e.g. rapid heating cooling of the surface |
2366 | - ! can destabilise the run) |
2367 | + ! can destabilise the run) but also is then done for output so we match |
2368 | + ! other models which also play this trick, c.f. Warner et al 2005. |
2369 | call set(local_tke,tke) |
2370 | + ! Call the bc code, but specify we want dirichlet |
2371 | + call gls_tke_bc(state, 'dirichlet') |
2372 | + ! copy the values onto the mesh using the global node id |
2373 | + do i=1,NNodes_sur |
2374 | + call set(tke,top_surface_nodes(i),node_val(top_surface_values,i)) |
2375 | + call set(tke_old,top_surface_nodes(i),node_val(top_surface_values,i)) |
2376 | + end do |
2377 | + do i=1,NNodes_bot |
2378 | + call set(tke,bottom_surface_nodes(i),node_val(bottom_surface_values,i)) |
2379 | + call set(tke_old,bottom_surface_nodes(i),node_val(bottom_surface_values,i)) |
2380 | + end do |
2381 | |
2382 | ! clip at k_min |
2383 | do i=1,nNodes |
2384 | @@ -576,76 +499,41 @@ |
2385 | call set(local_tke,i, max(node_val(local_tke,i),k_min)) |
2386 | end do |
2387 | |
2388 | - ! This is the extra term meant to add in internal wave breaking and the |
2389 | - ! like. Based on a similar term in NEMO |
2390 | - if (have_option("/material_phase[0]/subgridscale_parameterisations/GLS/ocean_parameterisation")) then |
2391 | - |
2392 | - distanceToTop => extract_scalar_field(state, "DistanceToTop") |
2393 | - distanceToBottom => extract_scalar_field(state, "DistanceToBottom") |
2394 | - |
2395 | - call get_option("/material_phase[0]/subgridscale_parameterisations/GLS/ocean_parameterisation/lengthscale",lengthscale) |
2396 | - call get_option("/material_phase[0]/subgridscale_parameterisations/GLS/ocean_parameterisation/percentage",percentage) |
2397 | - ewrite(2,*) "Computing extra ocean parameterisation" |
2398 | - allocate(node_list(NNodes)) |
2399 | - node_list = .false. |
2400 | - ! create gravity face normal |
2401 | - call compute_face_normal_gravity(face_normal_gravity, positions, vertical_normal) |
2402 | - allocate(ordered_elements(size(face_normal_gravity,1))) |
2403 | - |
2404 | - ! create an element ordering from the mesh that moves vertically downwards |
2405 | - call vertical_element_ordering(ordered_elements, face_normal_gravity) |
2406 | - ! I assume the above fails gracefully if the mesh isn't suitable, hence |
2407 | - ! no options checks are carried out |
2408 | - |
2409 | - got_surface = .false. |
2410 | - do i=1, size(ordered_elements) |
2411 | - if (.not. got_surface) then |
2412 | - ! First time around grab, the surface TKE |
2413 | - ! for this column |
2414 | - tke_surface = maxval(ele_val(tke,i)) |
2415 | - got_surface = .true. |
2416 | - end if |
2417 | - if (got_surface) then |
2418 | - call ocean_tke(i,tke,distanceToTop,lengthscale,percentage,tke_surface, node_list) |
2419 | - end if |
2420 | - if (minval(ele_val(distanceToBottom,i)) < 1e-6) then |
2421 | - got_surface = .false. |
2422 | - end if |
2423 | - end do |
2424 | - |
2425 | - deallocate(ordered_elements) |
2426 | - call deallocate(face_normal_gravity) |
2427 | - deallocate(node_list) |
2428 | - |
2429 | - end if |
2430 | - |
2431 | - call allocate(inverse_lumped_mass, psi%mesh, "InverseLumpedMass") |
2432 | - lumped_mass => get_lumped_mass(state, psi%mesh) |
2433 | - call invert(lumped_mass, inverse_lumped_mass) |
2434 | - ! Set Psi from previous timestep |
2435 | + ! re-construct psi at "old" timestep |
2436 | do i=1,nNodes |
2437 | call set(psi,i, cm0**gls_p * node_val(tke_old,i)**gls_m * node_val(ll,i)**gls_n) |
2438 | call set(psi,i,max(node_val(psi,i),psi_min)) |
2439 | end do |
2440 | |
2441 | ewrite(2,*) "In gls_psi: computing RHS" |
2442 | - call zero(vel_prod) |
2443 | - call zero(buoy_prod) |
2444 | - call zero(source) |
2445 | - call zero(absorption) |
2446 | - do ele = 1, ele_count(psi) |
2447 | - call assemble_production_terms_psi(ele, vel_prod, buoy_prod, psi, mesh_dim(psi)) |
2448 | - end do |
2449 | - call scale(vel_prod,inverse_lumped_mass) |
2450 | - call scale(buoy_prod,inverse_lumped_mass) |
2451 | - |
2452 | - do ele = 1, ele_count(psi) |
2453 | - call assemble_psi_src_abs(ele, psi, tke_old, mesh_dim(psi)) |
2454 | - end do |
2455 | - call scale(source,inverse_lumped_mass) |
2456 | - call scale(absorption,inverse_lumped_mass) |
2457 | - call deallocate(inverse_lumped_mass) |
2458 | - |
2459 | + ! compute RHS |
2460 | + do i=1,nNodes |
2461 | + |
2462 | + ! compute production terms in psi-equation |
2463 | + if (node_val(B,i).gt.0) then ! note that we have already set B when setting up the RHS for TKE |
2464 | + cPsi3=cPsi3_plus ! unstable strat |
2465 | + else |
2466 | + cPsi3=cPsi3_minus ! stable strat |
2467 | + end if |
2468 | + |
2469 | + ! compute production terms in psi-equation |
2470 | + PsiOverTke = node_val(psi,i)/node_val(tke_old,i) |
2471 | + prod = cPsi1*PsiOverTke*node_val(P,i) |
2472 | + buoyan = cPsi3*PsiOverTke*node_val(B,i) |
2473 | + diss = cPsi2*PsiOverTke*node_val(eps,i)*node_val(Fwall,i) |
2474 | + if (prod+buoyan.gt.0) then |
2475 | + src = prod+buoyan |
2476 | + absn = diss/node_val(psi,i) |
2477 | + call set(source,i, src) |
2478 | + call set(absorption,i, absn) |
2479 | + else |
2480 | + src = prod |
2481 | + absn = (diss-buoyan)/node_val(psi,i) |
2482 | + call set(source,i, src) |
2483 | + call set(absorption,i, absn) |
2484 | + end if |
2485 | + end do |
2486 | + |
2487 | ewrite(2,*) "In gls_psi: setting diffusivity" |
2488 | ! Set diffusivity for Psi |
2489 | call zero(psi_diff) |
2490 | @@ -689,150 +577,6 @@ |
2491 | call set(scalarField,absorption) |
2492 | end if |
2493 | |
2494 | - call deallocate(vel_prod) |
2495 | - call deallocate(buoy_prod) |
2496 | - |
2497 | - |
2498 | - contains |
2499 | - |
2500 | - subroutine ocean_tke(ele, tke, distanceToTop, lengthscale, percentage, tke_surface, nodes_done) |
2501 | - type(scalar_field),pointer, intent(in) :: distanceToTop |
2502 | - type(scalar_field),pointer, intent(out) :: tke |
2503 | - real, intent(in) :: lengthscale, percentage, tke_surface |
2504 | - integer, intent(in) :: ele |
2505 | - logical, dimension(:), intent(inout) :: nodes_done |
2506 | - |
2507 | - integer, dimension(:), pointer :: element_nodes |
2508 | - integer :: i, node |
2509 | - real :: current_TKE, depth |
2510 | - |
2511 | - element_nodes => ele_nodes(tke, ele) |
2512 | - |
2513 | - |
2514 | - ! smooth out TKE according to length scale |
2515 | - do i = 1, size(element_nodes) |
2516 | - node = element_nodes(i) |
2517 | - depth = node_val(distanceToTop,node) |
2518 | - current_TKE = node_val(tke,node) |
2519 | - if (nodes_done(node)) then |
2520 | - cycle |
2521 | - end if |
2522 | - current_TKE = current_TKE + & |
2523 | - & percentage*TKE_surface * EXP( -depth / lengthscale ) |
2524 | - call set(tke,node,current_TKE) |
2525 | - |
2526 | - nodes_done(node) = .true. |
2527 | - end do |
2528 | - |
2529 | - end subroutine ocean_tke |
2530 | - |
2531 | - subroutine reconstruct_psi(ele, psi, dim) |
2532 | - |
2533 | - integer, intent(in) :: ele, dim |
2534 | - type(scalar_field), intent(inout) :: psi |
2535 | - |
2536 | - real, dimension(ele_loc(psi,ele),ele_ngi(psi,ele),dim) :: dshape_psi |
2537 | - real, dimension(ele_ngi(psi,ele)) :: detwei |
2538 | - real, dimension(ele_loc(psi,ele)) :: rhs_addto |
2539 | - type(element_type), pointer :: shape_psi |
2540 | - integer, pointer, dimension(:) :: nodes_psi |
2541 | - |
2542 | - nodes_psi => ele_nodes(psi, ele) |
2543 | - shape_psi => ele_shape(psi, ele) |
2544 | - call transform_to_physical( positions, ele, shape_psi, dshape=dshape_psi, detwei=detwei ) |
2545 | - |
2546 | - rhs_addto = shape_rhs(shape_psi, detwei* & |
2547 | - (cm0**gls_p) * & |
2548 | - ele_val_at_quad(tke_old,ele)**gls_m * & |
2549 | - ele_val_at_quad(ll,ele)**gls_n) |
2550 | - |
2551 | - call addto(psi, nodes_psi, rhs_addto) |
2552 | - |
2553 | - end subroutine reconstruct_psi |
2554 | - |
2555 | - subroutine assemble_production_terms_psi(ele, vel_prod, buoy_prod, psi, dim) |
2556 | - |
2557 | - |
2558 | - integer, intent(in) :: ele, dim |
2559 | - type(scalar_field), intent(inout) :: psi, vel_prod, buoy_prod |
2560 | - |
2561 | - real, dimension(ele_loc(psi,ele),ele_ngi(psi,ele),dim) :: dshape_psi |
2562 | - real, dimension(ele_ngi(psi,ele)) :: detwei |
2563 | - real, dimension(ele_loc(psi,ele)) :: rhs_addto_vel, rhs_addto_buoy |
2564 | - real, dimension(ele_ngi(psi,ele)) :: cPsi3 |
2565 | - type(element_type), pointer :: shape_psi |
2566 | - integer, pointer, dimension(:) :: nodes_psi |
2567 | - |
2568 | - nodes_psi => ele_nodes(psi, ele) |
2569 | - shape_psi => ele_shape(psi, ele) |
2570 | - call transform_to_physical( positions, ele, shape_psi, dshape=dshape_psi, detwei=detwei ) |
2571 | - |
2572 | - ! Buoyancy production term: |
2573 | - ! First we need to work out if cPsi3 is for stable or unstable |
2574 | - ! stratification |
2575 | - where(ele_val_at_quad(B,ele) .gt. 0.0) |
2576 | - cPsi3 = cPsi3_plus ! unstable strat |
2577 | - elsewhere |
2578 | - cPsi3 = cPsi3_minus ! stable strat |
2579 | - end where |
2580 | - rhs_addto_buoy = shape_rhs(shape_psi, detwei*(cPsi3*ele_val_at_quad(B,ele)*& |
2581 | - (ele_val_at_quad(psi, ele)/ele_val_at_quad(local_tke,ele)))) |
2582 | - |
2583 | - ! shear production term: |
2584 | - rhs_addto_vel = shape_rhs(shape_psi, detwei*(cPsi1*ele_val_at_quad(P,ele)*& |
2585 | - (ele_val_at_quad(psi, ele)/ele_val_at_quad(local_tke,ele)))) |
2586 | - |
2587 | - call addto(vel_prod, nodes_psi, rhs_addto_vel) |
2588 | - call addto(buoy_prod, nodes_psi, rhs_addto_buoy) |
2589 | - |
2590 | - |
2591 | - end subroutine assemble_production_terms_psi |
2592 | - |
2593 | - subroutine assemble_psi_src_abs(ele, psi, tke, dim) |
2594 | - |
2595 | - integer, intent(in) :: ele, dim |
2596 | - type(scalar_field), intent(in) :: psi, tke |
2597 | - |
2598 | - real, dimension(ele_loc(psi,ele),ele_ngi(psi,ele),dim) :: dshape_psi |
2599 | - real, dimension(ele_ngi(psi,ele)) :: detwei |
2600 | - real, dimension(ele_loc(psi,ele)) :: rhs_addto_src, rhs_addto_disip |
2601 | - type(element_type), pointer :: shape_psi |
2602 | - integer, pointer, dimension(:) :: nodes_psi |
2603 | - |
2604 | - nodes_psi => ele_nodes(psi, ele) |
2605 | - shape_psi => ele_shape(psi, ele) |
2606 | - call transform_to_physical( positions, ele, shape_psi, dshape=dshape_psi, detwei=detwei ) |
2607 | - |
2608 | - where (ele_val_at_quad(vel_prod,ele) + ele_val_at_quad(buoy_prod,ele) .gt. 0) |
2609 | - rhs_addto_src = shape_rhs(shape_psi, detwei* ( & |
2610 | - (ele_val_at_quad(vel_prod,ele)) + & |
2611 | - (ele_val_at_quad(buoy_prod,ele)) & |
2612 | - ) & !detwei |
2613 | - ) ! shape_rhs |
2614 | - rhs_addto_disip = shape_rhs(shape_psi, detwei* (& |
2615 | - (cPsi2*ele_val_at_quad(eps,ele) * & |
2616 | - (ele_val_at_quad(Fwall,ele)*ele_val_at_quad(psi, ele)/ele_val_at_quad(tke,ele))) / & |
2617 | - ele_val_at_quad(psi,ele) & |
2618 | - ) & ! detwei |
2619 | - ) !shape_rhs |
2620 | - elsewhere |
2621 | - rhs_addto_src = shape_rhs(shape_psi, detwei * ( & |
2622 | - (ele_val_at_quad(vel_prod,ele)) & |
2623 | - ) & !detwei |
2624 | - ) !shape_rhs |
2625 | - rhs_addto_disip = shape_rhs(shape_psi, detwei * (& |
2626 | - ((cPsi2*ele_val_at_quad(eps,ele) * & |
2627 | - (ele_val_at_quad(Fwall,ele)*ele_val_at_quad(psi, ele)/ele_val_at_quad(tke,ele))) - &! disipation term |
2628 | - (ele_val_at_quad(buoy_prod,ele)))/ & ! buoyancy term |
2629 | - ele_val_at_quad(psi,ele)& |
2630 | - ) & !detwei |
2631 | - ) !shape_rhs |
2632 | - end where |
2633 | - call addto(source, nodes_psi, rhs_addto_src) |
2634 | - call addto(absorption, nodes_psi, rhs_addto_disip) |
2635 | - |
2636 | - end subroutine assemble_psi_src_abs |
2637 | - |
2638 | end subroutine gls_psi |
2639 | |
2640 | |
2641 | @@ -872,15 +616,27 @@ |
2642 | velocity => extract_vector_field(state, "Velocity") |
2643 | |
2644 | call allocate(tke, tke_state%mesh, name="MyLocalTKE") |
2645 | - !if (gls_n > 0) then |
2646 | + if (gls_n > 0) then |
2647 | ! set the TKE to use below to the unaltered TKE |
2648 | - ! with no changes to the upper/lower surfaces |
2649 | + ! with no chnages tothe upper/lower surfaces |
2650 | ! Applies to k-kl model only |
2651 | - ! call set (tke, local_tke) |
2652 | - !else |
2653 | + call set (tke, local_tke) |
2654 | + else |
2655 | ! Use the altered TKE to get the surface diffusivity correct |
2656 | call set (tke, tke_state) |
2657 | - !end if |
2658 | + end if |
2659 | + |
2660 | + ! call the bc code, but specify we want dirichlet |
2661 | + if (gls_n < 0) then |
2662 | + call gls_psi_bc(state, 'dirichlet') |
2663 | + ! copy the values onto the mesh using the global node id |
2664 | + do i=1,NNodes_sur |
2665 | + call set(psi,top_surface_nodes(i),node_val(top_surface_values,i)) |
2666 | + end do |
2667 | + do i=1,NNodes_bot |
2668 | + call set(psi,bottom_surface_nodes(i),node_val(bottom_surface_values,i)) |
2669 | + end do |
2670 | + end if |
2671 | |
2672 | exp1 = 3.0 + gls_p/gls_n |
2673 | exp2 = 1.5 + gls_m/gls_n |
2674 | @@ -913,12 +669,12 @@ |
2675 | |
2676 | ! compute dissipative scale |
2677 | call set(ll,i,cde*sqrt(tke_cur**3.)/node_val(eps,i)) |
2678 | - !if (gls_n > 0) then |
2679 | - ! if (node_val(NN2,i) > 0) then |
2680 | - ! limit = sqrt(0.56 * tke_cur / node_val(NN2,i)) |
2681 | - ! call set(ll,i,min(limit,node_val(ll,i))) |
2682 | - ! end if |
2683 | - !end if |
2684 | + if (gls_n > 0) then |
2685 | + if (node_val(NN2,i) > 0) then |
2686 | + limit = sqrt(0.56 * tke_cur / node_val(NN2,i)) |
2687 | + call set(ll,i,min(limit,node_val(ll,i))) |
2688 | + end if |
2689 | + end if |
2690 | |
2691 | end do |
2692 | |
2693 | @@ -1684,24 +1440,20 @@ |
2694 | case("neumann") |
2695 | do i=1,NNodes_sur |
2696 | ! GOTM Boundary |
2697 | - value = -(gls_n*(cm0**(gls_p+1.))*(kappa**(gls_n+1.)))/sigma_psi & |
2698 | - *node_val(top_surface_tke_values,i)**(gls_m+0.5)*(z0s(i))**gls_n |
2699 | - ! Warner 2005 - left here for posterity and debugging |
2700 | - !value = -gls_n*(cm0**(gls_p))*(node_val(top_surface_tke_values,i)**gls_m)* & |
2701 | - ! (kappa**gls_n)*(z0s(i)**(gls_n-1))*((node_val(top_surface_km_values,i)/sigma_psi)) |
2702 | + !value = -(gls_n*(cm0**(gls_p+1.))*(kappa**(gls_n+1.)))/sigma_psi & |
2703 | + ! *node_val(top_surface_values,i)**(gls_m+0.5)*(z0s(i))**gls_n |
2704 | + ! Warner 2005 |
2705 | + value = -gls_n*(cm0**(gls_p))*(node_val(top_surface_tke_values,i)**gls_m)* & |
2706 | + (kappa**gls_n)*(z0s(i)**(gls_n-1))*((node_val(top_surface_km_values,i)/sigma_psi)) |
2707 | call set(top_surface_values,i,value) |
2708 | end do |
2709 | do i=1,NNodes_bot |
2710 | - if (u_taub_squared(i) < 1e-16) then |
2711 | - value = 0.0 |
2712 | - else |
2713 | - ! GOTM Boundary |
2714 | - value = - gls_n*cm0**(gls_p+1.)*(kappa**(gls_n+1.)/sigma_psi) & |
2715 | - *node_val(bottom_surface_tke_values,i)**(gls_m+0.5)*(z0b(i))**gls_n |
2716 | - ! Warner 2005 - as above |
2717 | - !value = gls_n*cm0**(gls_p)*node_val(bottom_surface_tke_values,i)**(gls_m)* & |
2718 | - ! kappa**gls_n*(z0b(i)**(gls_n-1))*(node_val(bottom_surface_km_values,i)/sigma_psi) |
2719 | - end if |
2720 | + ! GOTM Boundary |
2721 | + !value = - gls_n*cm0**(gls_p+1.)*(kappa**(gls_n+1.)/sigma_psi) & |
2722 | + ! *node_val(bottom_surface_tke_values,i)**(gls_m+0.5)*(z0b(i))**gls_n |
2723 | + ! Warner 2005 |
2724 | + value = gls_n*cm0**(gls_p)*node_val(bottom_surface_tke_values,i)**(gls_m)* & |
2725 | + kappa**gls_n*(z0b(i)**(gls_n-1))*(node_val(bottom_surface_km_values,i)/sigma_psi) |
2726 | call set(bottom_surface_values,i,value) |
2727 | end do |
2728 | case("dirichlet") |
2729 | @@ -1741,7 +1493,7 @@ |
2730 | integer :: nobcs |
2731 | integer :: i,ii, MaxIter |
2732 | real :: rr |
2733 | - real :: charnock_val=18500. |
2734 | + real :: charnock_val=1400. |
2735 | character(len=OPTION_PATH_LEN) :: bctype |
2736 | type(vector_field), pointer :: wind_surface_field, positions, velocity |
2737 | type(scalar_field), pointer :: tke |
2738 | @@ -1835,15 +1587,12 @@ |
2739 | |
2740 | do i=1,NNodes_bot |
2741 | temp_vector_3D = node_val(bottom_velocity,i) |
2742 | - u_taub = sqrt(temp_vector_3D(1)**2+temp_vector_3D(2)**2+temp_vector_3D(3)**2) |
2743 | - if (u_taub <= 1e-12) then |
2744 | - z0b(i) = z0s_min |
2745 | - else |
2746 | + u_taub = max(1e-12,sqrt(temp_vector_3D(1)**2+temp_vector_3D(2)**2+temp_vector_3D(3)**2)) |
2747 | |
2748 | |
2749 | ! iterate bottom roughness length MaxIter times |
2750 | do ii=1,MaxIter |
2751 | - z0b(i)=(1e-7/max(1e-6,u_taub)+0.03*0.1) |
2752 | + z0b(i)=1e-7/max(1e-6,u_taub)+0.03*0.1 |
2753 | |
2754 | ! compute the factor r |
2755 | rr=kappa/log(z0b(i)) |
2756 | @@ -1852,7 +1601,6 @@ |
2757 | u_taub = rr*sqrt(temp_vector_3D(1)**2+temp_vector_3D(2)**2+temp_vector_3D(3)**2) |
2758 | |
2759 | end do |
2760 | - end if |
2761 | |
2762 | u_taub_squared(i) = u_taub**2 |
2763 | end do |
2764 | @@ -1861,7 +1609,7 @@ |
2765 | if (surface_allocated) then |
2766 | do i=1,NNodes_sur |
2767 | temp_vector_1D = node_val(surface_forcing,i) |
2768 | - u_taus_squared(i) = max(1e-12,abs(temp_vector_1D(1))) |
2769 | + u_taus_squared(i) = max(1e-12,temp_vector_1D(1)) |
2770 | ! use the Charnock formula to compute the surface roughness |
2771 | z0s(i)=charnock_val*u_taus_squared(i)/gravity_magnitude |
2772 | if (z0s(i).lt.z0s_min) z0s(i)=z0s_min |
2773 | @@ -1874,11 +1622,11 @@ |
2774 | |
2775 | do i=1,NNodes_bot |
2776 | temp_vector_2D = node_val(bottom_velocity,i) |
2777 | - u_taub = sqrt(temp_vector_2D(1)**2+temp_vector_2D(2)**2) |
2778 | + u_taub = max(1e-12,sqrt(temp_vector_2D(1)**2+temp_vector_2D(2)**2)) |
2779 | |
2780 | ! iterate bottom roughness length MaxIter times |
2781 | do ii=1,MaxIter |
2782 | - z0b(i)=(1e-7/(max(1e-6,u_taub)+0.03*0.1)) |
2783 | + z0b(i)=1e-7/(max(1e-6,u_taub)+0.03*0.1) |
2784 | rr=kappa/log(z0b(i)) |
2785 | |
2786 | ! compute the friction velocity at the bottom |
2787 | |
2788 | === added file 'parameterisation/Ice_Melt_Interface.F90' |
2789 | --- parameterisation/Ice_Melt_Interface.F90 1970-01-01 00:00:00 +0000 |
2790 | +++ parameterisation/Ice_Melt_Interface.F90 2012-09-04 15:00:37 +0000 |
2791 | @@ -0,0 +1,950 @@ |
2792 | +! Copyright (C) 2006 Imperial College London and others. |
2793 | +! |
2794 | +! Please see the AUTHORS file in the main source directory for a full list |
2795 | +! of copyright holders. |
2796 | +! |
2797 | +! Prof. C Pain |
2798 | +! Applied Modelling and Computation Group |
2799 | +! Department of Earth Science and Engineering |
2800 | +! Imperial College London |
2801 | +! |
2802 | +! amcgsoftware@imperial.ac.uk |
2803 | +! |
2804 | +! This library is free software; you can redistribute it and/or |
2805 | +! modify it under the terms of the GNU Lesser General Public |
2806 | +! License as published by the Free Software Foundation, |
2807 | +! version 2.1 of the License. |
2808 | +! |
2809 | +! This library is distributed in the hope that it will be useful, |
2810 | +! but WITHOUT ANY WARRANTY; without even the implied arranty of |
2811 | +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2812 | +! Lesser General Public License for more details. |
2813 | +! |
2814 | +! You should have received a copy of the GNU Lesser General Public |
2815 | +! License along with this library; if not, write to the Free Software |
2816 | +! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
2817 | +! USA |
2818 | + |
2819 | +#include "fdebug.h" |
2820 | + |
2821 | +module ice_melt_interface |
2822 | + use quadrature |
2823 | + use elements |
2824 | + use field_derivatives |
2825 | + use fields |
2826 | + use fields_base |
2827 | + use field_options |
2828 | + use fields_allocates |
2829 | + use state_module |
2830 | + use spud |
2831 | + use global_parameters, only: FIELD_NAME_LEN, OPTION_PATH_LEN |
2832 | + use state_fields_module |
2833 | + use boundary_conditions |
2834 | + use fields_manipulation |
2835 | + use surface_integrals |
2836 | + use fetools |
2837 | + use vector_tools |
2838 | + use FLDebug |
2839 | + use integer_set_module |
2840 | + use pickers_inquire |
2841 | + use transform_elements |
2842 | + use state_fields_module |
2843 | + use global_parameters, only: PYTHON_FUNC_LEN |
2844 | + use embed_python |
2845 | +implicit none |
2846 | + |
2847 | + private |
2848 | + integer, save :: nnodes, dimen |
2849 | + type(vector_field), save :: surface_positions |
2850 | + type(vector_field), save :: funky_positions |
2851 | + ! Normals to the iceshelf interface surface |
2852 | + type(vector_field), save :: unit_normal_vectors |
2853 | + integer, dimension(:), pointer, save :: sf_nodes_point |
2854 | + |
2855 | + ! Fields and variables for the interface surface |
2856 | + type(scalar_field), save :: ice_surfaceT, ice_surfaceS! these are used to populate the bcs |
2857 | + |
2858 | + public :: melt_interface_initialisation, populate_iceshelf_boundary_conditions, melt_interface_calculate, melt_interface_boundary_condition, melt_interface_cleanup, melt_interface_allocate_surface |
2859 | + |
2860 | +contains |
2861 | + |
2862 | + ! Calculation of the (ice) interface meltrate using the parameterisation described in Holland et al. 2008 doi:10.1175/2007JCLI1909.1 |
2863 | + |
2864 | + !---------- |
2865 | + ! initialise parameters based on options |
2866 | + !---------- |
2867 | + |
2868 | + subroutine melt_interface_initialisation(state) |
2869 | + |
2870 | + type(state_type), intent(inout) :: state |
2871 | + type(scalar_field), pointer :: T, S |
2872 | + ! For the case when Dirichlet boundary conditions are used |
2873 | + character(len=FIELD_NAME_LEN) :: bc_type |
2874 | + type(integer_set) :: surface_ids |
2875 | + integer, dimension(:),allocatable :: interface_surface_id |
2876 | + integer, dimension(2) :: shape_option |
2877 | + type(mesh_type), pointer :: mesh |
2878 | + type(mesh_type) :: surface_mesh |
2879 | + ! Allocated and returned by create_surface_mesh |
2880 | + integer, dimension(:), pointer :: surface_nodes |
2881 | + integer, dimension(:), allocatable :: surface_element_list |
2882 | + integer :: i,the_node |
2883 | + ! For input of the hydrostatic pressure |
2884 | + character(len=PYTHON_FUNC_LEN) :: subshelf_hydrostatic_pressure_function |
2885 | + real :: current_time |
2886 | + type(vector_field), pointer :: positions |
2887 | + type(scalar_field), pointer :: subshelf_hydrostatic_pressure |
2888 | + real :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance |
2889 | + real :: T_steady, S_steady |
2890 | + logical :: calculate_boundaries_T, calculate_boundaries_S |
2891 | + logical :: calculate_boundary_temperature, calculate_boundary_salinity |
2892 | + character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08' |
2893 | + |
2894 | + ewrite(1,*) 'Melt interface initialisation begins' |
2895 | + |
2896 | + 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) |
2897 | + |
2898 | + calculate_boundary_temperature=have_option(trim(option_path)//'/calculate_boundaries/bc_value_temperature') |
2899 | + calculate_boundary_salinity=have_option(trim(option_path)//'/calculate_boundaries/bc_value_salinity') |
2900 | + if (calculate_boundary_temperature) write(3,*) "Melt interface, initialised T_steady", T_steady |
2901 | + if (calculate_boundary_salinity) write(3,*) "Melt interface, initialised S_steady", S_steady |
2902 | + |
2903 | + ! bc= Dirichlet initialize T and S at the ice-ocean interface |
2904 | + ! This change with bc type |
2905 | + if (have_option(trim(option_path)//'/calculate_boundaries')) then |
2906 | + call get_option(trim(option_path)//'/calculate_boundaries', bc_type) |
2907 | + select case(bc_type) |
2908 | + case('neumann') |
2909 | + ewrite(3,*) 'Calculating steady Neumann boundary condition - nothing to be done here.' |
2910 | + case('dirichlet') |
2911 | + ewrite(3,*) 'Calculating steady Dirichlet boundary condition - nothing to be done here.' |
2912 | + ! Define values of temperature and salinity at ice-ocean interface |
2913 | + ! Get the surface_id of the ice-ocean interface |
2914 | + ! Note this code needs working through - Neumann is definitely the best choice here! |
2915 | + shape_option = option_shape(trim(option_path)//"/melt_surfaceID") |
2916 | + allocate(interface_surface_id(1:shape_option(1))) |
2917 | + call get_option(trim(option_path)//'/melt_surfaceID', interface_surface_id) |
2918 | + call allocate(surface_ids) |
2919 | + call insert(surface_ids,interface_surface_id) |
2920 | + mesh => extract_mesh(state,"VelocityMesh") |
2921 | + ! Obtain surface_mesh, surface_element_list, from mesh and surface_id |
2922 | + call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list) |
2923 | + |
2924 | + T => extract_scalar_field(state,"Temperature") |
2925 | + S => extract_scalar_field(state,"Salinity") |
2926 | + do i=1, size(surface_nodes) |
2927 | + the_node = surface_nodes(i) |
2928 | + call set(T,the_node,T_steady) |
2929 | + call set(S,the_node,S_steady) |
2930 | + enddo |
2931 | + case default |
2932 | + FLAbort('Unknown boundary type for ice-ocean interface.') |
2933 | + end select |
2934 | + else |
2935 | + |
2936 | + endif |
2937 | + |
2938 | + ! Read the hydrostatic pressure |
2939 | + if(have_option(trim(option_path)//'/subshelf_hydrostatic_pressure')) then |
2940 | + call get_option(trim(option_path)//'/subshelf_hydrostatic_pressure/python', subshelf_hydrostatic_pressure_function) |
2941 | + ! Get current time |
2942 | + call get_option("/timestepping/current_time", current_time) |
2943 | + ! Set initial condition from python function |
2944 | + ! TODO: This field should be generated automatically and is not needed in the schema |
2945 | + subshelf_hydrostatic_pressure => extract_scalar_field(state,"subshelf_hydrostatic_pressure") |
2946 | + positions => extract_vector_field(state,"Coordinate") |
2947 | + call set_from_python_function(subshelf_hydrostatic_pressure, trim(subshelf_hydrostatic_pressure_function), positions, current_time) |
2948 | + ewrite(1,*) "Melt interface initialisation, found hydrostatic pressure field" |
2949 | + endif |
2950 | + |
2951 | + ! Additional initialisation routines |
2952 | + call melt_interface_allocate_surface(state) |
2953 | + call melt_interface_calculate(state) |
2954 | + ! Boundary conditions for the (ice) melt interface parameterisation |
2955 | + if (have_option(trim(option_path)//'/calculate_boundaries')) then |
2956 | + call melt_interface_boundary_condition(state) |
2957 | + endif |
2958 | + |
2959 | + ewrite(1,*) "Melt interface initialisation end" |
2960 | + |
2961 | + end subroutine melt_interface_initialisation |
2962 | + |
2963 | + subroutine populate_iceshelf_boundary_conditions(state) |
2964 | + type(state_type), intent(in) :: state |
2965 | + type(scalar_field), pointer :: T,S |
2966 | + character(len=FIELD_NAME_LEN) :: bc_type |
2967 | + integer, dimension(:), allocatable :: surf_id |
2968 | + integer, dimension(2) :: shape_option |
2969 | + type(integer_set) :: surface_ids |
2970 | + !! |
2971 | + type(mesh_type), pointer :: surface_mesh |
2972 | + type(scalar_field) :: scalar_surface_field |
2973 | + |
2974 | + ewrite(1,*) "-----*** Begin iceshelf BC-----" |
2975 | + ! Get vector of surface ids |
2976 | + shape_option=option_shape("/ocean_forcing/iceshelf_meltrate/Holland08/melt_surfaceID") |
2977 | + allocate(surf_id(1:shape_option(1))) |
2978 | + call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/melt_surfaceID", surf_id) |
2979 | + ewrite(1,*) "surf_id", surf_id |
2980 | + call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries", bc_type) |
2981 | + call allocate(surface_ids) |
2982 | + call insert(surface_ids,surf_id) |
2983 | + ewrite(1,*) "set2vector(surface_ids)", set2vector(surface_ids) |
2984 | + |
2985 | + ewrite(1,*) "bc_type: ", bc_type |
2986 | + ! Add boundary condition |
2987 | + T => extract_scalar_field(state,"Temperature") |
2988 | + S => extract_scalar_field(state,"Salinity") |
2989 | +! do i=1,node_count(T) |
2990 | +! ewrite(1,*) "line2100,i,node_val(T,i): ",i, node_val(T,i) |
2991 | +! enddo |
2992 | + call add_boundary_condition(T, 'temperature_iceshelf_BC', bc_type, surf_id) |
2993 | + call add_boundary_condition(S, 'salinity_iceshelf_BC', bc_type, surf_id) |
2994 | + deallocate(surf_id) |
2995 | + |
2996 | + ! mesh of only the part of the surface where this b.c. applies for temperature |
2997 | + call get_boundary_condition(T, 'temperature_iceshelf_BC', surface_mesh=surface_mesh) |
2998 | + call allocate(scalar_surface_field, surface_mesh, name="value") |
2999 | + call insert_surface_field(T, 'temperature_iceshelf_BC', scalar_surface_field) |
3000 | + call deallocate(scalar_surface_field) |
3001 | + |
3002 | + ! mesh of only the part of the surface where this b.c. applies for salinity |
3003 | + call get_boundary_condition(S, 'salinity_iceshelf_BC', surface_mesh=surface_mesh) |
3004 | + call allocate(scalar_surface_field, surface_mesh, name="value") |
3005 | + call insert_surface_field(S, 'salinity_iceshelf_BC', scalar_surface_field) |
3006 | + call deallocate(scalar_surface_field) |
3007 | + |
3008 | + ewrite(1,*) "-----*** End iceshelf BC-----" |
3009 | + end subroutine populate_iceshelf_boundary_conditions |
3010 | + |
3011 | + subroutine melt_interface_calculate(state) |
3012 | + ! Calculate the melt rate |
3013 | + |
3014 | + type(state_type), intent(inout) :: state |
3015 | + type(scalar_field), pointer :: Tb, Sb,MeltRate,Heat_flux,Salt_flux |
3016 | + type(scalar_field), pointer :: scalarfield |
3017 | + type(vector_field), pointer :: velocity,positions |
3018 | + ! Debugging purpose pointer |
3019 | + type(scalar_field), pointer :: T_loc,S_loc,P_loc |
3020 | + type(vector_field), pointer :: V_loc,Location,Location_org |
3021 | + real, dimension(:), allocatable :: vel |
3022 | + integer :: i |
3023 | + ! Some internal variables |
3024 | + real :: speed, T,S,P,Aa,Bb,Cc,topo |
3025 | + real :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance |
3026 | + real ::loc_Tb,loc_Sb,loc_meltrate,loc_heatflux,loc_saltflux |
3027 | + ! Aa*Sb^2+Bv*Sb+Cc |
3028 | + ! Sink mesh part |
3029 | + integer :: ele,stat,the_node |
3030 | + real, dimension(:), allocatable :: local_coord,coord |
3031 | + integer, dimension(:), allocatable :: surface_node_list |
3032 | + type(scalar_field) :: re_pressure,re_DistanceToTop |
3033 | + type(scalar_field), pointer :: temperature, salinity |
3034 | + |
3035 | + ewrite(1,*) "Melt interface calculation begins" |
3036 | + |
3037 | + 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) |
3038 | + |
3039 | + !! All the variable under /ocean_forcing/iceshelf_meltrate/Holland08 should be in coordinate mesh |
3040 | + !! coordinate mesh = continous mesh |
3041 | + MeltRate => extract_scalar_field(state,"MeltRate") |
3042 | + call set(MeltRate,0.0) |
3043 | + Tb => extract_scalar_field(state,"Tb") |
3044 | + Sb => extract_scalar_field(state,"Sb") |
3045 | + ! call set(MeltRate,setnan(arg)) |
3046 | + call set(Tb,0.0) |
3047 | + call set(Sb,-1.0) |
3048 | + Heat_flux => extract_scalar_field(state,"Heat_flux") |
3049 | + Salt_flux => extract_scalar_field(state,"Salt_flux") |
3050 | + call set(Heat_flux,0.0) |
3051 | + call set(Salt_flux,0.0) |
3052 | + |
3053 | + ! Local far field values |
3054 | + T_loc => extract_scalar_field(state,"Tloc") |
3055 | + S_loc => extract_scalar_field(state,"Sloc") |
3056 | + P_loc => extract_scalar_field(state,"Ploc") |
3057 | + V_loc => extract_vector_field(state,"Vloc") |
3058 | + Location => extract_vector_field(state,"Location") |
3059 | + Location_org => extract_vector_field(state,"Location_org") |
3060 | + call set(T_loc,0.0) |
3061 | + call set(S_loc,-1.0) |
3062 | + call set(P_loc,-1.0) |
3063 | + allocate(vel(V_loc%dim)) |
3064 | + vel = 0.0 |
3065 | + call set(V_loc,vel) |
3066 | + call set(Location,vel) |
3067 | + call set(Location_org,vel) |
3068 | + |
3069 | + positions => extract_vector_field(state,"Coordinate") |
3070 | + |
3071 | + ! Surface node list |
3072 | + allocate(surface_node_list(size(sf_nodes_point))) |
3073 | + ! sf_nodes is calculated in "melt_allocate_surface" |
3074 | + surface_node_list=sf_nodes_point |
3075 | + |
3076 | + ! Pressure read the hydrostatic pressure, specified at schema |
3077 | + scalarfield => extract_scalar_field(state,"subshelf_hydrostatic_pressure") |
3078 | + call allocate(re_pressure,positions%mesh, name="RePressure") |
3079 | + call remap_field(scalarfield,re_pressure,stat) |
3080 | + |
3081 | + if (have_option("/geometry/ocean_boundaries/scalar_field::DistanceToBottom")) then |
3082 | + scalarfield => extract_scalar_field(state,"DistanceToBottom") |
3083 | + call allocate(re_DistanceToTop,positions%mesh, name="ReDistanceToBottom") |
3084 | + call remap_field(scalarfield,re_DistanceToTop,stat) |
3085 | + endif |
3086 | + |
3087 | + allocate(local_coord(positions%dim+1)) |
3088 | + allocate(coord(positions%dim)) |
3089 | + |
3090 | + temperature => extract_scalar_field(state,"Temperature") |
3091 | + salinity => extract_scalar_field(state,"Salinity") |
3092 | + velocity => extract_vector_field(state,"Velocity") |
3093 | + |
3094 | + ! Loop over the surface nodes to calculate melt rate |
3095 | + do i=1,size(surface_node_list) |
3096 | + the_node = surface_node_list(i) |
3097 | + ! Interpolating |
3098 | + coord = node_val(funky_positions,the_node) |
3099 | + call picker_inquire(positions, coord, ele, local_coord,global=.false.) |
3100 | + |
3101 | + !! If sum(local_coord) is not equal to 1, |
3102 | + !! we know that this coord (funky position) does not exist in the domain. |
3103 | + if (sum(local_coord) .gt. 2.0) then |
3104 | + ewrite(0,*) "Melt interface, funky coordinate: ", node_val(funky_positions,the_node) |
3105 | + !! node_val(surface_positions,the_node) = node_val(positions,the_node) |
3106 | + ewrite(0,*) "Melt interface, original element: ",ele |
3107 | + ewrite(0,*) "Melt interface, sum of local_coord: ", sum(local_coord) |
3108 | + FLExit("Melt interface, your funky_positions is out of the domain. Change melt_LayerLength.") |
3109 | + endif |
3110 | + |
3111 | + !Number of nodes per element for temperature |
3112 | + ! Find T at a particular element given the field,element, |
3113 | + !INPUT: field, element number |
3114 | + !Output: real value |
3115 | + |
3116 | + call scalar_finder_ele(temperature,ele,positions%dim+1,local_coord,T) |
3117 | + call scalar_finder_ele(salinity,ele,positions%dim+1,local_coord,S) |
3118 | + call vector_finder_ele(velocity,ele,positions%dim+1,local_coord,vel) |
3119 | + |
3120 | + ! Pressure from the schema |
3121 | + P = node_val(re_pressure,the_node) |
3122 | + speed = sqrt(sum(vel**2)) |
3123 | + |
3124 | + if (speed .lt. 0.001) then |
3125 | + speed = 0.001 |
3126 | + !TODO: Use a maxval here instead |
3127 | + endif |
3128 | + ! constant = -7.53e-8 [C Pa^(-1)] comes from Holland and Jenkins Table 1 |
3129 | + ! TODO: Define as a constant explicitly, i.e. real, parameter :: topo = -7.53e-8 |
3130 | + topo = -7.53e-8*P |
3131 | + |
3132 | + ! Define Aa,Bb,Cc |
3133 | + ! Aa*Sb**2 + Bb*Sb + Cc = 0.0 |
3134 | + Aa = -gammaS * speed * cI * a + a * c0 * gammaT * speed |
3135 | + |
3136 | + Bb = -gammaS * speed * L + gammaS * speed * S * cI * a |
3137 | + Bb = Bb - gammaS * speed * cI * (b + topo) + gammaS * speed * cI * TI |
3138 | + Bb = Bb - c0 * gammaT * speed * T + c0 * gammaT * speed * (b + topo) |
3139 | + |
3140 | + Cc = gammaS * speed * S * L + gammaS * speed * S * cI * (b + topo) + gammaS * speed * S * (-cI * TI) |
3141 | + |
3142 | + ! This could be a linear equation if Aa=0 |
3143 | + if (Aa .eq. 0.0) then |
3144 | + loc_Sb = -Cc/Bb |
3145 | + else |
3146 | + ! Calculate for the 2nd oewrite(1,*) "size(surface_element_list)"rder polynomial. |
3147 | + ! We have two solutions. |
3148 | + loc_Sb = (-Bb + sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa) |
3149 | + ! loc_Sb has to be larger than 0; since the salinity in the ocean is positive definite. |
3150 | + if (loc_Sb .lt. 0.0) then |
3151 | + loc_Sb = (-Bb - sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa) |
3152 | + endif |
3153 | + if (loc_Sb .lt. 0.0) then |
3154 | + ewrite(0,*) "Melt interface, loc_Sb: ", loc_Sb |
3155 | + ewrite(0,*) "Melt interface, Aa: ", Aa |
3156 | + ewrite(0,*) "Melt interface, Bb: ", Bb |
3157 | + ewrite(0,*) "Melt interface, Cc: ", Cc |
3158 | + ewrite(0,*) "Melt interface, T: ", T |
3159 | + ewrite(0,*) "Melt interface, S: ", S |
3160 | + ewrite(0,*) "Melt interface, P: ", P |
3161 | + ewrite(0,*) "Melt interface, speed: ", speed |
3162 | + FLExit("Melt interface, Sb is negative. The range of Salinity is not right.") |
3163 | + endif |
3164 | + endif |
3165 | + |
3166 | + loc_Tb = a*loc_Sb + b + topo |
3167 | + loc_meltrate = gammaS*speed*(S-loc_Sb)/loc_Sb |
3168 | + !! Heat flux to the ocean |
3169 | + loc_heatflux = (gammaT*speed+ loc_meltrate)*(loc_Tb - T) ! or loc_meltrate*L + loc_meltrate*cI*(loc_Tb-TI) |
3170 | + !! Salt flux to the ocean |
3171 | + loc_saltflux = (gammaS*speed+loc_meltrate)*(loc_Sb - S) |
3172 | + |
3173 | + !! These are needed to implement BCs. |
3174 | + call set(MeltRate, the_node, loc_meltrate) |
3175 | + call set(Tb, the_node, loc_Tb) |
3176 | + call set(Sb, the_node, loc_Sb) |
3177 | + call set(Heat_flux, the_node,loc_heatflux) |
3178 | + call set(Salt_flux, the_node,loc_saltflux) |
3179 | + |
3180 | + !!Far field values |
3181 | + call set(T_loc,the_node,T) |
3182 | + call set(S_loc,the_node,S) |
3183 | + call set(P_loc,the_node,P) |
3184 | + call set(V_loc,the_node,vel) |
3185 | + call set(Location,the_node,node_val(funky_positions,the_node)) |
3186 | + call set(Location_org,the_node,node_val(positions,the_node)) |
3187 | + |
3188 | + enddo |
3189 | + |
3190 | + deallocate(local_coord) |
3191 | + deallocate(coord) |
3192 | + call deallocate(re_pressure) |
3193 | + ! TODO: check this below |
3194 | + if (have_option("/geometry/ocean_boundaries/scalar_field::DistanceToBottom")) then |
3195 | + call deallocate(re_DistanceToTop) |
3196 | + endif |
3197 | + |
3198 | + ! Remap meltrate_p heat_flux_p salt_flux_p onto MeltRate Heat_flux Salt_flux |
3199 | + ! Mappting continous mesh to discontinous mesh |
3200 | + |
3201 | + ewrite(1,*) "Melt interface calculation end" |
3202 | + |
3203 | + end subroutine melt_interface_calculate |
3204 | + |
3205 | + subroutine melt_interface_boundary_condition(state) |
3206 | + ! See preprocessor/Boundary_Conditions_From_options.F90 populate_iceshelf_boundary_conditions(states(1)) as well |
3207 | + type(state_type), intent(inout) :: state |
3208 | + ! Boundary conditions |
3209 | + type(scalar_field), pointer :: TT,SS |
3210 | + type(scalar_field), pointer :: scalar_surface, scalar_surface2 |
3211 | + type(mesh_type), pointer :: ice_mesh |
3212 | + character(len=FIELD_NAME_LEN) :: bc_type |
3213 | + type(scalar_field) :: T_bc,S_bc |
3214 | + type(scalar_field), pointer :: Tflux,Sflux |
3215 | + type(scalar_field), pointer :: Tb,Sb |
3216 | + integer :: i, the_node |
3217 | + real :: Tz,Sz |
3218 | + type(mesh_type), pointer :: mesh |
3219 | + type(mesh_type) :: surface_mesh |
3220 | + integer, dimension(:), pointer :: surface_nodes ! allocated and returned by create_surface_mesh |
3221 | + integer, dimension(:), allocatable :: surface_element_list |
3222 | + type(integer_set) :: surface_ids |
3223 | + integer, dimension(:),allocatable :: surf_id |
3224 | + integer, dimension(2) :: shape_option |
3225 | + type(vector_field) :: unit_normal_vectors_vel |
3226 | + type(scalar_field) :: heat_flux_vel,salt_flux_vel |
3227 | + type(vector_field), pointer :: velocity |
3228 | + integer :: stat |
3229 | + real, dimension(:), allocatable :: vel |
3230 | + real :: T_steady, S_steady |
3231 | + logical :: calculate_boundary_temperature, calculate_boundary_salinity |
3232 | + character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08' |
3233 | + character(len=*), parameter :: option_path_bc = '/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries' |
3234 | + |
3235 | + ewrite(1,*) "Melt interface boundary condition begins" |
3236 | + call melt_interface_read_coefficients(T_steady=T_steady, S_steady=S_steady) |
3237 | + calculate_boundary_temperature=have_option(trim(option_path)//'/calculate_boundaries/bc_value_temperature') |
3238 | + calculate_boundary_salinity=have_option(trim(option_path)//'/calculate_boundaries/bc_value_salinity') |
3239 | + |
3240 | +!! See ./preprocessor/Boundary_Conditions_From_options.F90 populate_iceshelf_boundary_conditions(states(1)) as well |
3241 | + ! Get the surface_id of the ice-ocean interface |
3242 | + shape_option=option_shape(trim(option_path)//"/melt_surfaceID") |
3243 | + allocate(surf_id(1:shape_option(1))) |
3244 | + call get_option(trim(option_path)//'/melt_surfaceID',surf_id) |
3245 | + call allocate(surface_ids) |
3246 | + call insert(surface_ids,surf_id) |
3247 | + |
3248 | + TT=> extract_scalar_field(state,"Temperature") |
3249 | + SS=> extract_scalar_field(state,"Salinity") |
3250 | + velocity => extract_vector_field(state,"Velocity") |
3251 | + |
3252 | + if (node_count(TT) .eq. node_count(velocity)) then |
3253 | + mesh => extract_mesh(state,"VelocityMesh") |
3254 | + else |
3255 | + mesh => extract_mesh(state,"CoordinateMesh") |
3256 | + endif |
3257 | + call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list) |
3258 | + |
3259 | +!! Remapt the contious mesh to discon, unit_normal vecotr |
3260 | + |
3261 | + call allocate(unit_normal_vectors_vel,velocity%dim,TT%mesh,"MyVelocitySurfaceMesh") |
3262 | + |
3263 | + allocate(vel(velocity%dim)) |
3264 | + vel = 0.0 |
3265 | + call set(unit_normal_vectors_vel,vel) |
3266 | + deallocate(vel) |
3267 | + |
3268 | + call remap_field(unit_normal_vectors,unit_normal_vectors_vel,stat) |
3269 | + |
3270 | + call allocate(T_bc,TT%mesh, name="T_boundary") |
3271 | + call allocate(S_bc,SS%mesh, name="S_boundary") |
3272 | + |
3273 | + ! Surface node list |
3274 | + ! This change with bc type |
3275 | + call get_option(trim(option_path_bc), bc_type) |
3276 | + |
3277 | + select case(bc_type) |
3278 | + case("neumann") |
3279 | + Tflux => extract_scalar_field(state,"Heat_flux") |
3280 | + Sflux => extract_scalar_field(state,"Salt_flux") |
3281 | + |
3282 | + !! Remap the heat flux |
3283 | + call allocate(heat_flux_vel,TT%mesh,"MyHeatFluxSurfaceMesh") |
3284 | + call set(heat_flux_vel,0.0) |
3285 | + call remap_field(Tflux,heat_flux_vel,stat) |
3286 | + |
3287 | + !! Remap the salt flux |
3288 | + call allocate(salt_flux_vel,SS%mesh,"MySaltFluxSurfaceMesh") |
3289 | + call set(salt_flux_vel,0.0) |
3290 | + call remap_field(Sflux,salt_flux_vel,stat) |
3291 | + |
3292 | + ! create a surface mesh to place values onto. This is for the top surface |
3293 | + call get_boundary_condition(TT, 'temperature_iceshelf_BC', surface_mesh=ice_mesh) |
3294 | + call allocate(ice_surfaceT, ice_mesh, name="ice_surfaceT") |
3295 | + !! Temperature |
3296 | + scalar_surface => extract_surface_field(TT, 'temperature_iceshelf_BC', "value") |
3297 | + |
3298 | + do i=1,node_count(ice_surfaceT) |
3299 | + the_node = surface_nodes(i) |
3300 | + ! Kt = (sum(node_val(unit_normal_vectors_vel,the_node)*Kt_ar)) |
3301 | + ! Tz = node_val(heat_flux_vel,the_node)/(-Kt*c0) |
3302 | + Tz = node_val(heat_flux_vel,the_node) |
3303 | + call set(scalar_surface,i,Tz) |
3304 | + enddo |
3305 | + |
3306 | + ! Salinity |
3307 | + call get_boundary_condition(SS, 'salinity_iceshelf_BC', surface_mesh=ice_mesh) |
3308 | + call allocate(ice_surfaceS, ice_mesh, name="ice_surfaceS") |
3309 | + !! Salinity |
3310 | + scalar_surface2 => extract_surface_field(SS, 'salinity_iceshelf_BC', "value") |
3311 | + do i=1,node_count(ice_surfaceS) |
3312 | + the_node = surface_nodes(i) |
3313 | + ! Ks = abs(sum(node_val(unit_normal_vectors_vel,the_node)*Ks_ar)) |
3314 | + ! Sz = node_val(salt_flux_vel,the_node)/(-Ks) |
3315 | + Sz = node_val(salt_flux_vel,the_node) |
3316 | + !call set(ice_surfaceS,i,Sz) |
3317 | + call set(scalar_surface2,i,Sz) |
3318 | + enddo |
3319 | + ! Deallocate the heat_flux and salt_flux on velocity mesh |
3320 | + call deallocate(heat_flux_vel) |
3321 | + call deallocate(salt_flux_vel) |
3322 | + |
3323 | + ! If the fluxes were constant |
3324 | + if (calculate_boundary_temperature) then |
3325 | + call set(T_bc,T_steady) |
3326 | + ! create a surface mesh to place values onto. This is for the top surface |
3327 | + call get_boundary_condition(TT, 'temperature_iceshelf_BC', surface_mesh=ice_mesh) |
3328 | + call allocate(ice_surfaceT, ice_mesh, name="ice_surfaceT") |
3329 | + do i=1,node_count(ice_surfaceT) |
3330 | + the_node = surface_nodes(i) |
3331 | + call set(ice_surfaceT,i,node_val(T_bc,the_node)) |
3332 | + enddo |
3333 | + ! Temperature |
3334 | + scalar_surface => extract_surface_field(TT, 'temperature_iceshelf_BC', "value") |
3335 | + call remap_field(ice_surfaceT, scalar_surface) |
3336 | + endif |
3337 | + |
3338 | + if (have_option(trim(option_path_bc)//'/bc_value_salinity')) then |
3339 | + call set(S_bc,S_steady) |
3340 | + ! Salinity |
3341 | + call get_boundary_condition(SS, 'salinity_iceshelf_BC', surface_mesh=ice_mesh) |
3342 | + call allocate(ice_surfaceS, ice_mesh, name="ice_surfaceS") |
3343 | + do i=1,node_count(ice_surfaceS) |
3344 | + the_node = surface_nodes(i) |
3345 | + call set(ice_surfaceS,i,node_val(S_bc,the_node)) |
3346 | + enddo |
3347 | + !! Salinity |
3348 | + scalar_surface => extract_surface_field(SS, 'salinity_iceshelf_BC', "value") |
3349 | + call remap_field(ice_surfaceS, scalar_surface) |
3350 | + endif |
3351 | + |
3352 | + case("dirichlet") |
3353 | + Tb => extract_scalar_field(state,"Tb") |
3354 | + Sb => extract_scalar_field(state,"Sb") |
3355 | + do i=1,node_count(T_bc) |
3356 | + call set(T_bc,i,node_val(Tb,i)) |
3357 | + call set(S_bc,i,node_val(Sb,i)) |
3358 | + enddo |
3359 | + ! When testing BC implementation |
3360 | + if (calculate_boundary_temperature) then |
3361 | + call set(T_bc,T_steady) |
3362 | + ewrite(3,*) "Melt interface, initialised T_steady", T_steady |
3363 | + endif |
3364 | + if (calculate_boundary_salinity) then |
3365 | + call set(S_bc,S_steady) |
3366 | + ewrite(3,*) "Melt interface, initialised S_steady", S_steady |
3367 | + endif |
3368 | + |
3369 | + case default |
3370 | + FLAbort('Unknown boundary condition for ice-ocean interface') |
3371 | + end select |
3372 | + |
3373 | + ! create a surface mesh to place values onto. This is for the top surface |
3374 | + !call get_boundary_condition(TT, 'temperature_iceshelf_BC', surface_mesh=ice_mesh) |
3375 | + !call allocate(ice_surfaceT, ice_mesh, name="ice_surfaceT") |
3376 | + ! Define ice_surfaceT according to Heat_flux? |
3377 | + |
3378 | + !do i=1,node_count(ice_surfaceT) |
3379 | + ! the_node = surface_node_list(i) |
3380 | + ! call set(ice_surfaceT,i,node_val(T_bc,the_node)) |
3381 | + !enddo |
3382 | + |
3383 | + ! Salinity |
3384 | + !call get_boundary_condition(SS, 'salinity_iceshelf_BC', surface_mesh=ice_mesh) |
3385 | + !call allocate(ice_surfaceS, ice_mesh, name="ice_surfaceS") |
3386 | + !do i=1,node_count(ice_surfaceS) |
3387 | + ! the_node = surface_node_list(i) |
3388 | + ! call set(ice_surfaceS,i,node_val(S_bc,the_node)) |
3389 | + !enddo |
3390 | + |
3391 | + !!! Temperature |
3392 | + !scalar_surface => extract_surface_field(TT, 'temperature_iceshelf_BC', "value") |
3393 | + !call remap_field(ice_surfaceT, scalar_surface) |
3394 | + !!! Salinity |
3395 | + !scalar_surface => extract_surface_field(SS, 'salinity_iceshelf_BC', "value") |
3396 | + !call remap_field(ice_surfaceS, scalar_surface) |
3397 | + |
3398 | + call deallocate(T_bc) |
3399 | + call deallocate(S_bc) |
3400 | + call deallocate(ice_surfaceT) |
3401 | + call deallocate(ice_surfaceS) |
3402 | + call deallocate(unit_normal_vectors_vel) |
3403 | + call deallocate(surface_mesh) |
3404 | + |
3405 | + ewrite(1,*) "Melt interface boundary condition end" |
3406 | + |
3407 | + end subroutine melt_interface_boundary_condition |
3408 | + |
3409 | + |
3410 | + subroutine melt_interface_cleanup() |
3411 | + ewrite(1,*) "Melt interface, cleaning up melt variables" |
3412 | + call deallocate(surface_positions) |
3413 | + call deallocate(funky_positions) |
3414 | + call deallocate(unit_normal_vectors) |
3415 | + |
3416 | + deallocate(sf_nodes_point) |
3417 | + end subroutine melt_interface_cleanup |
3418 | + |
3419 | + |
3420 | + !------------------------------------------------------------------! |
3421 | + ! Private subroutines ! |
3422 | + !------------------------------------------------------------------! |
3423 | + |
3424 | + subroutine melt_interface_allocate_surface(state) |
3425 | + type(state_type), intent(inout) :: state |
3426 | + type(vector_field), pointer :: positions |
3427 | + type(mesh_type), pointer :: mesh |
3428 | + type(mesh_type) :: surface_mesh |
3429 | + ! Allocated and returned by create_surface_mesh |
3430 | + integer, dimension(:), pointer :: surface_nodes |
3431 | + integer, dimension(:), allocatable :: surface_element_list |
3432 | + integer :: face,i,j,k |
3433 | + real, dimension(:), allocatable :: coord |
3434 | + ! For transform_facet_to_physical |
3435 | + real, dimension(:,:), allocatable :: normal |
3436 | + real, dimension(:), allocatable :: av_normal !Average of normal |
3437 | + type(element_type), pointer :: x_shape_f |
3438 | + real, dimension(:), allocatable :: xyz !New location of surface_mesh, farfield_distance away from the boundary |
3439 | + type(integer_set) :: surface_ids |
3440 | + integer, dimension(:),allocatable :: interface_surface_id |
3441 | + |
3442 | + ! For the vector averaging schem, taking the area of the surface element etc |
3443 | + real, dimension(:,:), allocatable :: table |
3444 | + integer, dimension(:,:), allocatable :: node_occupants |
3445 | + integer :: st,en,node,dim_vec |
3446 | + real :: area_sum |
3447 | + integer, dimension(2) :: shape_option |
3448 | + real, dimension(:), allocatable :: local_coord |
3449 | + integer :: ele, counter,Nit |
3450 | + real, dimension(:), allocatable :: vel |
3451 | + real :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance |
3452 | + character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08/melt_surfaceID' |
3453 | + |
3454 | + ewrite(1,*) "Melt interface allocation of surface parameters" |
3455 | + |
3456 | + 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) |
3457 | + |
3458 | + ! Get the surface_id of the ice-ocean interface |
3459 | + shape_option=option_shape(trim(option_path)) |
3460 | + allocate(interface_surface_id(1:shape_option(1))) |
3461 | + call get_option(trim(option_path), interface_surface_id) |
3462 | + call allocate(surface_ids) |
3463 | + call insert(surface_ids,interface_surface_id) |
3464 | + |
3465 | + mesh => extract_mesh(state,"CoordinateMesh") |
3466 | + ! Input, mesh, surface_id |
3467 | + ! Output surface_mesh, surface_element_list |
3468 | + call melt_surf_mesh(mesh, surface_ids, surface_mesh, surface_nodes, surface_element_list) |
3469 | + |
3470 | + allocate(sf_nodes_point(size(surface_nodes))) |
3471 | + sf_nodes_point = surface_nodes |
3472 | + positions => extract_vector_field(state,"Coordinate") |
3473 | + ! Sink the surface_mesh to the 'far field' |
3474 | + call allocate(surface_positions,positions%dim,mesh,"MySurfacePosition") |
3475 | + call allocate(funky_positions,surface_positions%dim, surface_positions%mesh,"MyFunkyPosition") |
3476 | + call allocate(unit_normal_vectors,surface_positions%dim, surface_positions%mesh,"MyFunkyUnitVec") |
3477 | + allocate(vel(positions%dim)) |
3478 | + vel = 0.0 |
3479 | + call set(unit_normal_vectors,vel) |
3480 | + deallocate(vel) |
3481 | + ! Check above |
3482 | + |
3483 | + ! Remap the positions vector to the surface mesh, surface_positions |
3484 | + call remap_field_to_surface(positions, surface_positions, surface_element_list) |
3485 | + |
3486 | + ! Loop over # of surface elements |
3487 | + !nf = size(surface_element_list) |
3488 | + !2 comes because there are 2 nodes per a surface_element (assumption!) |
3489 | + ! this number could be three for 3D problem, room for change |
3490 | + ! dim_vec is the dimension of the positions, either 2 or 3. |
3491 | + ! node_occupants(1,1:dim_vec*nf) = nodes that occupies the surface elements |
3492 | + ! node_occupants(2,:) = surface elements |
3493 | + ! table(1,:) = area of the face |
3494 | + ! table(2,:) = normal_x |
3495 | + ! table(3,:) = normal_y |
3496 | + ! table(4,:) = normal_z |
3497 | + dim_vec = positions%dim |
3498 | + allocate(coord(dim_vec)) |
3499 | + allocate(node_occupants(2,dim_vec*size(surface_element_list))) |
3500 | + allocate(table(dim_vec+1,dim_vec*size(surface_element_list))) |
3501 | + allocate(av_normal(dim_vec)) |
3502 | + allocate(xyz(dim_vec)) |
3503 | + allocate(local_coord(positions%dim+1)) |
3504 | + |
3505 | + do i=1,size(surface_element_list) |
3506 | + st = 1+dim_vec*(i-1) |
3507 | + en = dim_vec+dim_vec*(i-1) |
3508 | + face = surface_element_list(i) |
3509 | + node_occupants(2,st:en) = face |
3510 | + node_occupants(1,st:en) = face_global_nodes(positions, face) |
3511 | + ! Calculate the area of the surface element |
3512 | + ! For 2D, the area is the length |
3513 | + if (dim_vec .eq. 2) then |
3514 | + table(1,st:en) = calc_area2(positions,node_occupants(1,st:en)) |
3515 | + endif |
3516 | + |
3517 | + ! For 3D, the area become the area of the triangle (assumption here). |
3518 | + ! Subroutine calc_area3 uses Heron's formula. |
3519 | + if (dim_vec .eq. 3) then |
3520 | + table(1,st:en) = calc_area3(positions,node_occupants(1,st:en)) |
3521 | + endif |
3522 | + ! Compute the normal vector at the surface element. |
3523 | + x_shape_f=>face_shape(positions,face) |
3524 | + allocate(normal(dim_vec,x_shape_f%ngi)) !(dim x x_shape_f%ngi) |
3525 | + call transform_facet_to_physical(positions, face, normal=normal) |
3526 | + av_normal = sum(normal,2) |
3527 | + !"normal" should be the same; since the normal vector on the quadrature point does not change. |
3528 | + av_normal = av_normal/(sum(av_normal*av_normal))**(0.5) ! normalize the vector |
3529 | + deallocate(normal) |
3530 | + ! Since av_normal is outward to the boundary, we will put -sign. We want the vector into the boundary |
3531 | + av_normal = -av_normal |
3532 | + ! Store av_normal, the normal vector averaged over quadrature points, in table |
3533 | + do j=1,dim_vec |
3534 | + table(j+1,st:en)=av_normal(j) |
3535 | + enddo |
3536 | + enddo |
3537 | + ! Now loop over surface_nodes |
3538 | + ! ewrite(1,*) "table(1,1:3): ", table(1,1:3) |
3539 | + ! ewrite(1,*) "table(2,1:3),normal_x: ", table(2,1:3) |
3540 | + ! ewrite(1,*) "table(3,1:3),normal_y: ", table(3,1:3) |
3541 | + ! ewrite(1,*) "table(4,1:3),normal_z: ", table(4,1:3) |
3542 | + ! In this loop, we will average adjacent normal vectors, using the area of the surface elements. |
3543 | + |
3544 | + |
3545 | + do i=1,size(node_occupants(1,:)) |
3546 | + node = node_occupants(1,i) |
3547 | + av_normal(:) = 0.0 |
3548 | + area_sum = 0.0 |
3549 | + ! This loop average the normal vector based on the areas of surface elements |
3550 | + ! which share the "node". Using hash table may speed up this process |
3551 | + do j=1,size(node_occupants(1,:)) |
3552 | + !Pick the surface elements that sheare the "node" |
3553 | + if (node_occupants(1,j) .eq. node) then |
3554 | + do k=1,dim_vec |
3555 | + !table(1,j) = area of the surface element |
3556 | + av_normal(k) = av_normal(k) + table(k+1,j)*table(1,j) |
3557 | + enddo |
3558 | + !The total areas of the surface elements that occupies the "node" |
3559 | + area_sum = area_sum + table(1,j) |
3560 | + endif |
3561 | + enddo |
3562 | + |
3563 | + av_normal = av_normal / area_sum |
3564 | + ! normalize |
3565 | + av_normal = av_normal/(sum(av_normal*av_normal))**(0.5) |
3566 | + |
3567 | + farfield_distance = abs(farfield_distance) |
3568 | + ! Shift the location of the surface nodes. |
3569 | + !The coordinate of the surface node. |
3570 | + |
3571 | + coord = node_val(positions,node) |
3572 | + ! farfield_distance = ||xyz - coord|| xyz and coord are vectors |
3573 | + xyz = av_normal*farfield_distance + coord |
3574 | + |
3575 | +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
3576 | + ! have options /ocean_forcing/iceshelf_meltrate/Holland08/melt_LayerRelax |
3577 | + if (have_option("/ocean_forcing/iceshelf_meltrate/Holland08/melt_LayerRelax")) then |
3578 | + call get_option('/ocean_forcing/iceshelf_meltrate/Holland08/melt_LayerRelax/N',Nit) |
3579 | + !!Check if xyz is within the domain |
3580 | + call picker_inquire(positions, xyz, ele, local_coord,global=.false.) |
3581 | + !! If sum(local_coord) is not equal to 1, |
3582 | + !! we know that this coord (funky position) does not exist in the domain. |
3583 | + |
3584 | + counter = 1 |
3585 | + do while (sum(local_coord) .gt. 2.0 .and. counter .lt. Nit) |
3586 | + xyz = av_normal*(farfield_distance-counter*(farfield_distance/Nit)) + coord |
3587 | + call picker_inquire(positions, xyz, ele, local_coord,global=.false.) |
3588 | + counter = counter+1 |
3589 | + enddo |
3590 | + |
3591 | + if (sum(local_coord) .gt. 2.0) then |
3592 | + ewrite(1,*) "icehslef location, coord: ", coord |
3593 | + ewrite(1,*) "funky position, xyz: ", xyz |
3594 | + call picker_inquire(positions, coord, ele, local_coord,global=.false.) |
3595 | + !! node_val(surface_positions,the_node) = node_val(positions,the_node) |
3596 | + ewrite(1,*) "Original ele: ",ele |
3597 | + ewrite(1,*) "sum of local_coord: ", sum(local_coord) |
3598 | + FLExit("In setting funky_position, your funky_positions is out of the domain. Change melt_LayerLength.") |
3599 | + endif |
3600 | + endif |
3601 | +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
3602 | + |
3603 | + call set(funky_positions,node,xyz) ! Set the coordinate of sinked nodes, funky positions. |
3604 | + call set(surface_positions,node,coord) !Original coordinate of the surface |
3605 | + call set(unit_normal_vectors,node,av_normal) !save the unit normal vector for Kt and Ks calculation |
3606 | + |
3607 | + node = 0 |
3608 | + enddo |
3609 | + |
3610 | + ! Now deallocate junk |
3611 | + deallocate(coord) |
3612 | + deallocate(table) |
3613 | + deallocate(node_occupants) |
3614 | + deallocate(av_normal) |
3615 | + deallocate(xyz) |
3616 | + deallocate(local_coord) |
3617 | + call deallocate(surface_ids) |
3618 | + call deallocate(surface_mesh) |
3619 | + ewrite(1,*) "Melt interface allocation of surface parameters end" |
3620 | + |
3621 | + end subroutine melt_interface_allocate_surface |
3622 | + |
3623 | + subroutine melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list) |
3624 | + |
3625 | + type(mesh_type), intent(in) :: mesh |
3626 | + type(integer_set), intent(in) :: surface_ids |
3627 | + type(mesh_type), intent(out) :: surface_mesh |
3628 | + integer, dimension(:), pointer, intent(out) :: surface_nodes ! allocated and returned by create_surface_mesh |
3629 | + integer, dimension(:), allocatable, intent(out) :: surface_element_list |
3630 | + ! integer, dimension(:), allocatable :: surface_nodes_out |
3631 | + type(integer_set) :: surface_elements |
3632 | + integer :: i |
3633 | + ! create a set of surface elements that have surface id in 'surface_ids' |
3634 | + |
3635 | + call allocate(surface_elements) |
3636 | + do i=1, surface_element_count(mesh) |
3637 | + ! ewrite(1,*) "surf_normal surface_element_id(mesh, i)", surface_element_id(mesh, i) |
3638 | + ! ewrite(1,*) "surf_normal surface_ids", set2vector(surface_ids) |
3639 | + if (has_value(surface_ids, surface_element_id(mesh, i))) then |
3640 | + call insert(surface_elements, i) |
3641 | + end if |
3642 | + end do |
3643 | + |
3644 | + allocate(surface_element_list(key_count(surface_elements))) |
3645 | + surface_element_list=set2vector(surface_elements) |
3646 | + call create_surface_mesh(surface_mesh, surface_nodes, mesh, surface_element_list, name=trim(mesh%name)//"ToshisMesh") |
3647 | + end subroutine melt_surf_mesh |
3648 | + |
3649 | + subroutine melt_interface_read_coefficients(c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance, T_steady, S_steady) |
3650 | + real, intent(out), optional :: c0, cI, L, TI, a, b, gammaT, gammaS, farfield_distance, T_steady, S_steady |
3651 | + real :: Cd |
3652 | + character(len=*), parameter :: option_path = '/ocean_forcing/iceshelf_meltrate/Holland08' |
3653 | + |
3654 | + ! Get the 6 model constants |
3655 | + ! TODO: Check these exist first and error with a useful message if not - in preprocessor |
3656 | + if (present(c0)) call get_option(trim(option_path)//'c0', c0, default = 3974.0) |
3657 | + if (present(cI)) call get_option(trim(option_path)//'cI', cI, default = 2009.0) |
3658 | + if (present(L)) call get_option(trim(option_path)//'/L', L, default = 3.35e5) |
3659 | + if (present(TI)) call get_option(trim(option_path)//'/TI', TI, default = -25.0) |
3660 | + if (present(a)) call get_option(trim(option_path)//'/a', a, default = -0.0573) |
3661 | + if (present(b)) call get_option(trim(option_path)//'/b', b, default = 0.0832) |
3662 | + if (present(farfield_distance)) call get_option(trim(option_path)//'/melt_LayerLength', farfield_distance) |
3663 | + |
3664 | + if (present(gammaT).or.present(gammaS)) call get_option(trim(option_path)//'/Cd', Cd, default = 1.5e-3) |
3665 | + if (present(gammaT)) gammaT = sqrt(Cd)/(12.5*(7.0**(2.0/3.0))-9.0) |
3666 | + if (present(gammaS)) gammaS = sqrt(Cd)/(12.5*(700.0**(2.0/3.0))-9.0) |
3667 | + |
3668 | + ! When steady boundary options are enabled |
3669 | + if (present(T_steady)) call get_option(trim(option_path)//'/calculate_boundaries/bc_value_temperature',T_steady, default = 0.0) |
3670 | + if (present(S_steady)) call get_option(trim(option_path)//'/calculate_boundaries/bc_value_salinity',S_steady, default = 34.0) |
3671 | + |
3672 | + end subroutine melt_interface_read_coefficients |
3673 | + |
3674 | + subroutine scalar_finder_ele(scalar,ele,element_dim,local_coord,scalar_out) |
3675 | + type(scalar_field), pointer, intent(in) :: scalar |
3676 | + integer, intent(in) :: ele |
3677 | + integer, intent(in) :: element_dim |
3678 | + real, dimension(element_dim), intent(in) :: local_coord |
3679 | + real, intent(out) :: scalar_out |
3680 | + integer :: j,node |
3681 | + integer, dimension(:), allocatable :: node_lists |
3682 | + |
3683 | + allocate(node_lists(size(ele_nodes(scalar,ele)))) |
3684 | + node_lists = ele_nodes(scalar,ele) !Lists of nodes that occupies the element. |
3685 | + scalar_out = 0.0 |
3686 | + do j=1,size(node_lists) |
3687 | + node = node_lists(j) |
3688 | + scalar_out = scalar_out + node_val(scalar,node)*local_coord(j) |
3689 | + enddo |
3690 | + end subroutine scalar_finder_ele |
3691 | + |
3692 | + subroutine vector_finder_ele(vector,ele,element_dim,local_coord,vector_out) |
3693 | + type(vector_field), pointer, intent(in) :: vector |
3694 | + integer, intent(in) :: ele |
3695 | + integer, intent(in) :: element_dim |
3696 | + real, dimension(element_dim), intent(in) :: local_coord |
3697 | + real, dimension(element_dim-1), intent(out) :: vector_out |
3698 | + integer :: j,node |
3699 | + integer, dimension(:), allocatable :: node_lists |
3700 | + |
3701 | + allocate(node_lists(size(ele_nodes(vector,ele)))) |
3702 | + |
3703 | + node_lists = ele_nodes(vector,ele) !Lists of nodes that occupies the element. |
3704 | + vector_out(:) = 0.0 |
3705 | + do j=1,size(node_lists) |
3706 | + node = node_lists(j) |
3707 | + vector_out = vector_out + node_val(vector,node)*local_coord(j) |
3708 | + enddo |
3709 | + end subroutine vector_finder_ele |
3710 | + |
3711 | + real function setnan(arg) |
3712 | + real :: arg |
3713 | + setnan = sqrt(arg) |
3714 | + end function |
3715 | + |
3716 | + real function calc_area2(positions,nodes) |
3717 | + type(vector_field), pointer :: positions |
3718 | + integer, dimension(2) :: nodes |
3719 | + real, dimension(2) :: coord1,coord2 |
3720 | + coord1 = node_val(positions,nodes(1)) |
3721 | + coord2 = node_val(positions,nodes(2)) |
3722 | + calc_area2 = (sum((coord2 - coord1)**2))**0.5 |
3723 | + end function |
3724 | + |
3725 | + real function calc_area3(positions,nodes) |
3726 | + type(vector_field), pointer :: positions |
3727 | + integer, dimension(3) :: nodes |
3728 | + real, dimension(3) :: coord1,coord2,coord3 |
3729 | + real :: a,b,c,s |
3730 | + coord1 = node_val(positions,nodes(1)) |
3731 | + coord2 = node_val(positions,nodes(2)) |
3732 | + coord3 = node_val(positions,nodes(3)) |
3733 | + ! Use Heron's formula to calculate the area of triangle |
3734 | + a = (sum((coord2 - coord1)**2))**0.5 |
3735 | + b = (sum((coord3 - coord1)**2))**0.5 |
3736 | + c = (sum((coord2 - coord3)**2))**0.5 |
3737 | + s = 0.5*(a+b+c) |
3738 | + calc_area3 = (s*(s-a)*(s-b)*(s-c))**0.5 |
3739 | + end function |
3740 | + |
3741 | +end module ice_melt_interface |
3742 | |
3743 | === modified file 'parameterisation/Makefile.dependencies' |
3744 | --- parameterisation/Makefile.dependencies 2012-08-29 10:53:27 +0000 |
3745 | +++ parameterisation/Makefile.dependencies 2012-09-04 15:00:37 +0000 |
3746 | @@ -18,16 +18,15 @@ |
3747 | ../include/fields.mod ../include/fldebug.mod \ |
3748 | ../include/global_parameters.mod ../include/quadrature.mod \ |
3749 | ../include/sparse_matrices_fields.mod ../include/spud.mod \ |
3750 | - ../include/state_fields_module.mod ../include/state_module.mod \ |
3751 | - ../include/vertical_extrapolation_module.mod |
3752 | + ../include/state_fields_module.mod ../include/state_module.mod |
3753 | |
3754 | -../include/iceshelf_meltrate_surf_normal.mod: iceshelf_meltrate_surf_normal.o |
3755 | +../include/ice_melt_interface.mod: Ice_Melt_Interface.o |
3756 | @true |
3757 | |
3758 | -iceshelf_meltrate_surf_normal.o ../include/iceshelf_meltrate_surf_normal.mod: \ |
3759 | - iceshelf_meltrate_surf_normal.F90 ../include/boundary_conditions.mod \ |
3760 | +Ice_Melt_Interface.o ../include/ice_melt_interface.mod: \ |
3761 | + Ice_Melt_Interface.F90 ../include/boundary_conditions.mod \ |
3762 | ../include/elements.mod ../include/fdebug.h ../include/fetools.mod \ |
3763 | - ../include/field_derivatives.mod ../include/field_options.mod \ |
3764 | + ../include/field_derivatives.mod ../include/fields_base.mod ../include/field_options.mod \ |
3765 | ../include/fields.mod ../include/fields_allocates.mod \ |
3766 | ../include/fields_manipulation.mod ../include/fldebug.mod \ |
3767 | ../include/global_parameters.mod ../include/integer_set_module.mod \ |
3768 | |
3769 | === modified file 'parameterisation/Makefile.in' |
3770 | --- parameterisation/Makefile.in 2011-10-21 10:05:25 +0000 |
3771 | +++ parameterisation/Makefile.in 2012-09-04 15:00:37 +0000 |
3772 | @@ -47,7 +47,7 @@ |
3773 | OBJS = Equation_of_State.o \ |
3774 | Gls_vertical_turbulence_model.o \ |
3775 | k_epsilon.o \ |
3776 | -iceshelf_meltrate_surf_normal.o |
3777 | +Ice_Melt_Interface.o |
3778 | |
3779 | .SUFFIXES: .F90 .c .o .a |
3780 | |
3781 | |
3782 | === removed file 'parameterisation/iceshelf_meltrate_surf_normal.F90' |
3783 | --- parameterisation/iceshelf_meltrate_surf_normal.F90 2011-04-07 12:42:58 +0000 |
3784 | +++ parameterisation/iceshelf_meltrate_surf_normal.F90 1970-01-01 00:00:00 +0000 |
3785 | @@ -1,678 +0,0 @@ |
3786 | -! Copyright (C) 2006 Imperial College London and others. |
3787 | -! |
3788 | -! Please see the AUTHORS file in the main source directory for a full list |
3789 | -! of copyright holders. |
3790 | -! |
3791 | -! Prof. C Pain |
3792 | -! Applied Modelling and Computation Group |
3793 | -! Department of Earth Science and Engineering |
3794 | -! Imperial College London |
3795 | -! |
3796 | -! amcgsoftware@imperial.ac.uk |
3797 | -! |
3798 | -! This library is free software; you can redistribute it and/or |
3799 | -! modify it under the terms of the GNU Lesser General Public |
3800 | -! License as published by the Free Software Foundation, |
3801 | -! version 2.1 of the License. |
3802 | -! |
3803 | -! This library is distributed in the hope that it will be useful, |
3804 | -! but WITHOUT ANY WARRANTY; without even the implied arranty of |
3805 | -! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3806 | -! Lesser General Public License for more details. |
3807 | -! |
3808 | -! You should have received a copy of the GNU Lesser General Public |
3809 | -! License along with this library; if not, write to the Free Software |
3810 | -! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
3811 | -! USA |
3812 | - |
3813 | -#include "fdebug.h" |
3814 | - |
3815 | -module iceshelf_meltrate_surf_normal |
3816 | - use quadrature |
3817 | - use elements |
3818 | - use field_derivatives |
3819 | - use fields |
3820 | - use field_options |
3821 | - use fields_allocates |
3822 | - use state_module |
3823 | - use spud |
3824 | - use global_parameters, only: FIELD_NAME_LEN, OPTION_PATH_LEN |
3825 | - use state_fields_module |
3826 | - use boundary_conditions |
3827 | - use fields_manipulation |
3828 | - use surface_integrals |
3829 | - use fetools |
3830 | - use vector_tools |
3831 | - use FLDebug |
3832 | - use integer_set_module |
3833 | - use pickers_inquire |
3834 | - use transform_elements |
3835 | - use state_fields_module |
3836 | -implicit none |
3837 | - |
3838 | - private |
3839 | - real, save :: c0, cI, L, TI, & |
3840 | - a, b, gammaT, gammaS,Cd, dist_meltrate |
3841 | - integer, save :: nnodes,dimen |
3842 | - |
3843 | - type(vector_field), save :: surface_positions |
3844 | - type(vector_field), save :: funky_positions |
3845 | - type(integer_set), save :: sf_nodes !Nodes at the surface |
3846 | - !BC |
3847 | - integer, dimension(:), pointer, save :: ice_element_list |
3848 | - ! these are the fields and variables for the surface values |
3849 | - type(scalar_field), save :: ice_surfaceT,ice_surfaceS! these are used to populate the bcs |
3850 | - public :: melt_surf_init, melt_allocate_surface, melt_surf_calc, melt_bc |
3851 | - |
3852 | - |
3853 | - |
3854 | -contains |
3855 | - |
3856 | -!---------- |
3857 | -! initialise parameters based on options |
3858 | -!---------- |
3859 | - |
3860 | - subroutine melt_surf_init(state) |
3861 | - |
3862 | - type(state_type), intent(inout) :: state |
3863 | - character(len=OPTION_PATH_LEN) :: melt_path |
3864 | - ! hack |
3865 | - type(scalar_field), pointer :: T,S |
3866 | - ! When bc=Dirichlet |
3867 | - character(len=FIELD_NAME_LEN) :: bc_type |
3868 | - type(integer_set) :: surface_ids |
3869 | - integer, dimension(:),allocatable :: surf_id |
3870 | - integer, dimension(:), allocatable :: sf_nodes_ar |
3871 | - integer, dimension(2) :: shape_option |
3872 | - type(mesh_type), pointer :: mesh |
3873 | - type(mesh_type) :: surface_mesh |
3874 | - integer, dimension(:), pointer :: surface_nodes ! allocated and returned by create_surface_mesh |
3875 | - integer, dimension(:), allocatable :: surface_element_list |
3876 | - integer :: i,the_node |
3877 | - |
3878 | - melt_path = "/ocean_forcing/iceshelf_meltrate/Holland08" |
3879 | - |
3880 | - |
3881 | - ewrite(1,*) "--------Begin melt_init-------------" |
3882 | - |
3883 | - ! Get the 6 model constants |
3884 | - call get_option(trim(melt_path)//'/c0', c0, default = 3974.0) |
3885 | - call get_option(trim(melt_path)//'/cI', cI, default = 2009.0) |
3886 | - call get_option(trim(melt_path)//'/L', L, default = 3.35e5) |
3887 | - call get_option(trim(melt_path)//'/TI', TI, default = -25.0) |
3888 | - call get_option(trim(melt_path)//'/a', a, default = -0.0573) |
3889 | - call get_option(trim(melt_path)//'/b', b, default = 0.0832) |
3890 | - call get_option(trim(melt_path)//'/Cd', Cd, default = 1.5e-3) |
3891 | - call get_option(trim(melt_path)//'/melt_LayerLength', dist_meltrate) |
3892 | - |
3893 | - gammaT = sqrt(Cd)/(12.5*(7.0**(2.0/3.0))-9.0) |
3894 | - gammaS = sqrt(Cd)/(12.5*(700.0**(2.0/3.0))-9.0) |
3895 | - |
3896 | - !! bc= Dirichlet initialize T and S at the ice-ocean interface |
3897 | - !hack |
3898 | - !This change with bc type |
3899 | - call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries", bc_type) |
3900 | - |
3901 | - select case(bc_type) |
3902 | - case("neumann") |
3903 | - |
3904 | - |
3905 | - case("dirichlet") |
3906 | - !! Define the values at ice-ocean interface |
3907 | - ! Get the surface_id of the ice-ocean interface |
3908 | - shape_option=option_shape(trim(melt_path)//"/melt_surfaceID") |
3909 | - allocate(surf_id(1:shape_option(1))) |
3910 | - call get_option(trim(melt_path)//'/melt_surfaceID',surf_id) |
3911 | - call allocate(surface_ids) |
3912 | - call insert(surface_ids,surf_id) |
3913 | - mesh => extract_mesh(state,"VelocityMesh") |
3914 | - ! Input, mesh, surface_id |
3915 | - ! Output surface_mesh,surface_element_list |
3916 | - call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list) |
3917 | - |
3918 | - T => extract_scalar_field(state,"Temperature") |
3919 | - S => extract_scalar_field(state,"Salinity") |
3920 | - do i=1,size(surface_nodes) |
3921 | - the_node = surface_nodes(i) |
3922 | - |
3923 | - call set(T,the_node,0.0) |
3924 | - call set(S,the_node,34.0) |
3925 | - |
3926 | - enddo |
3927 | -! T_bc => extract_scalar_field(state,"Tb") |
3928 | -! S_bc => extract_scalar_field(state,"Sb") |
3929 | - case default |
3930 | - FLAbort('Unknown BC for TKE') |
3931 | - end select |
3932 | - |
3933 | - |
3934 | - ewrite(1,*) "---------End melt_surf_init---------------------------------" |
3935 | - |
3936 | - end subroutine melt_surf_init |
3937 | - |
3938 | -subroutine melt_allocate_surface(state) |
3939 | - |
3940 | - type(state_type), intent(inout) :: state |
3941 | - type(vector_field), pointer :: positions |
3942 | - type(mesh_type), pointer :: mesh |
3943 | - type(mesh_type) :: surface_mesh |
3944 | - type(integer_set) :: surface_elements |
3945 | - integer, dimension(:), pointer :: surface_nodes ! allocated and returned by create_surface_mesh |
3946 | - integer, dimension(:), allocatable :: surface_element_list |
3947 | - integer :: ele, face,i,j,k |
3948 | -!! The local coordinates of the coordinate in the owning element |
3949 | -!! real, dimension(:), allocatable :: local_coord, local_coord_surf |
3950 | - real, dimension(:), allocatable :: coord |
3951 | -! for transform_facet_to_physical |
3952 | - real, dimension(:,:), allocatable :: normal |
3953 | - real, dimension(:), allocatable :: av_normal !Average of normal |
3954 | -!! integer, dimension(:), pointer :: ele_faces,face_neighs |
3955 | - type(element_type), pointer :: x_shape_f |
3956 | - real :: al,be,ga |
3957 | - real, dimension(:), allocatable :: xyz !New location of surface_mesh, dist_meltrate away from the boundary |
3958 | -!integer, save :: melt_surfaceID |
3959 | - character(len=OPTION_PATH_LEN) :: path |
3960 | - type(integer_set) :: surface_ids |
3961 | - integer, dimension(:),allocatable :: surf_id |
3962 | - |
3963 | -! For the vector averaging schem, taking the area of the surface element etc |
3964 | - real, dimension(:,:), allocatable :: table |
3965 | - integer, dimension(:,:), allocatable :: node_occupants |
3966 | - integer :: st,en,node,dim_vec |
3967 | - real :: area_sum |
3968 | - integer, dimension(:), allocatable :: sf_nodes_ar |
3969 | - integer, dimension(2) :: shape_option |
3970 | - |
3971 | - ewrite(1,*) "-------Begin melt_allocate_surface---------" |
3972 | - path = "/ocean_forcing/iceshelf_meltrate/Holland08" |
3973 | - ! Get the surface_id of the ice-ocean interface |
3974 | - shape_option=option_shape(trim(path)//"/melt_surfaceID") |
3975 | - allocate(surf_id(1:shape_option(1))) |
3976 | - call get_option(trim(path)//'/melt_surfaceID',surf_id) |
3977 | - call allocate(surface_ids) |
3978 | - call insert(surface_ids,surf_id) |
3979 | -! deallocate(surf_id) |
3980 | -! ewrite(1,*) "aft_surface_ids: ", set2vector(surface_ids) |
3981 | - |
3982 | - mesh => extract_mesh(state,"VelocityMesh") |
3983 | -! Input, mesh, surface_id |
3984 | -! Output surface_mesh,surface_element_list |
3985 | - call melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list) |
3986 | - |
3987 | - positions => extract_vector_field(state,"Coordinate") |
3988 | -!SINK THE surface_mesh!! |
3989 | -! call get_option("/geometry/dimension/", dimension) |
3990 | - call allocate(surface_positions,positions%dim,mesh,"MySurfacePosition") |
3991 | - call allocate(funky_positions,surface_positions%dim, surface_positions%mesh,"MyFunkyPosition") |
3992 | - |
3993 | - |
3994 | -! Remap the positions vector to the surface mesh, surface_positions |
3995 | - call remap_field_to_surface(positions, surface_positions, surface_element_list) |
3996 | - |
3997 | -! Loop over # of surface elements |
3998 | -!nf = size(surface_element_list) |
3999 | -!2 comes because there are 2 nodes per a surface_element (assumption!) |
4000 | -! this number could be three for 3D problem, room for change |
4001 | -! dim_vec is the dimension of the positions, either 2 or 3. |
4002 | -! node_occupants(1,1:dim_vec*nf) = nodes that occupies the surface elements |
4003 | -! node_occupants(2,:) = surface elements |
4004 | -! table(1,:) = area of the face |
4005 | -! table(2,:) = normal_x |
4006 | -! table(3,:) = normal_y |
4007 | -! table(4,:) = normal_z |
4008 | - dim_vec = positions%dim |
4009 | - allocate(coord(dim_vec)) |
4010 | - allocate(node_occupants(2,dim_vec*size(surface_element_list))) |
4011 | - allocate(table(dim_vec+1,dim_vec*size(surface_element_list))) |
4012 | - allocate(av_normal(dim_vec)) |
4013 | - allocate(xyz(dim_vec)) |
4014 | - |
4015 | - do i=1,size(surface_element_list) |
4016 | - st = 1+dim_vec*(i-1) |
4017 | - en = dim_vec+dim_vec*(i-1) |
4018 | - face = surface_element_list(i) |
4019 | - node_occupants(2,st:en) = face |
4020 | - node_occupants(1,st:en) = face_global_nodes(positions, face) |
4021 | - ! Calculate the area of the surface element |
4022 | - ! For 2D, the area is the length |
4023 | - if (dim_vec .eq. 2) then |
4024 | - table(1,st:en) = calc_area2(positions,node_occupants(1,st:en)) |
4025 | - endif |
4026 | - |
4027 | - ! For 3D, the area become the area of the triangle (assumption here). |
4028 | - ! Subroutine calc_area3 uses Heron's formula. |
4029 | - if (dim_vec .eq. 3) then |
4030 | - table(1,st:en) = calc_area3(positions,node_occupants(1,st:en)) |
4031 | - endif |
4032 | - ! Compute the normal vector at the surface element. |
4033 | - x_shape_f=>face_shape(positions,face) |
4034 | - allocate(normal(dim_vec,x_shape_f%ngi)) !(dim x x_shape_f%ngi) |
4035 | - call transform_facet_to_physical(positions, face, normal=normal) |
4036 | - av_normal = sum(normal,2) |
4037 | - !"normal" should be the same; since the normal vector on the quadrature point does not change. |
4038 | - av_normal = av_normal/(sum(av_normal*av_normal))**(0.5) ! normalize the vector |
4039 | - deallocate(normal) |
4040 | - !Since av_normal is outward to the boundary, we will put -sign. We want the vector into the boundary |
4041 | - av_normal = -av_normal |
4042 | - ! Store av_normal, the normal vector averaged over quadrature points, in table |
4043 | - do j=1,dim_vec |
4044 | - table(j+1,st:en)=av_normal(j) |
4045 | - enddo |
4046 | - enddo |
4047 | -!! Now loop over surface_nodes |
4048 | -! ewrite(1,*) "table(1,1:3): ", table(1,1:3) |
4049 | -! ewrite(1,*) "table(2,1:3),normal_x: ", table(2,1:3) |
4050 | -! ewrite(1,*) "table(3,1:3),normal_y: ", table(3,1:3) |
4051 | -! ewrite(1,*) "table(4,1:3),normal_z: ", table(4,1:3) |
4052 | -!!In this loop, we will average adjacent normal vectors, using the area of the surface elements. |
4053 | - |
4054 | - !allocate(sf_nodes_ar(size(node_occupants(1,:)))) |
4055 | - call allocate(sf_nodes) |
4056 | -! call insert(sf_nodes,sf_nodes_ar) |
4057 | - do i=1,size(node_occupants(1,:)) |
4058 | - node = node_occupants(1,i) |
4059 | - av_normal(:) = 0.0 |
4060 | - area_sum = 0.0 |
4061 | - ! This loop average the normal vector based on the areas of surface elements |
4062 | - !, which share the "node". Using hash table may speed up this process |
4063 | - do j=1,size(node_occupants(1,:)) |
4064 | - !Pick the surface elements that sheare the "node" |
4065 | - if (node_occupants(1,j) .eq. node) then |
4066 | - do k=1,dim_vec |
4067 | - !table(1,j) = area of the surface element |
4068 | - av_normal(k) = av_normal(k) + table(k+1,j)*table(1,j) |
4069 | - enddo |
4070 | - !The total areas of the surface elements that occupies the "node" |
4071 | - area_sum = area_sum + table(1,j) |
4072 | - endif |
4073 | - enddo |
4074 | - |
4075 | - av_normal = av_normal / area_sum |
4076 | - ! normalize |
4077 | - av_normal = av_normal/(sum(av_normal*av_normal))**(0.5) |
4078 | - |
4079 | - dist_meltrate = abs(dist_meltrate) |
4080 | - ! Shift the location of the surface nodes. |
4081 | - !The coordinate of the surface node. |
4082 | - |
4083 | - coord = node_val(positions,node) |
4084 | - |
4085 | - ! dist_meltrate = ||xyz - coord|| xyz and coord are vectors |
4086 | - xyz = av_normal*dist_meltrate + coord |
4087 | - |
4088 | - call set(funky_positions,node,xyz) ! Set the coordinate of sinked nodes, funky positions. |
4089 | - |
4090 | - call set(surface_positions,node,coord) !Original coordinate of the surface |
4091 | -!! ewrite(1,*) "--------------------------------" |
4092 | -!! ewrite(1,*) "node: ", node |
4093 | -!! ewrite(1,*) "av_normal: ", av_normal |
4094 | -!! ewrite(1,*) "funky: ", xyz |
4095 | -!! ewrite(1,*) "coord: ", coord |
4096 | -!! ! Save the corresponding node number. |
4097 | -!! !sf_nodes_ar(i) = node |
4098 | - call insert(sf_nodes,node) |
4099 | - |
4100 | - node = 0 |
4101 | - enddo |
4102 | - |
4103 | - |
4104 | - deallocate(coord) |
4105 | - deallocate(table) |
4106 | - deallocate(node_occupants) |
4107 | - deallocate(av_normal) |
4108 | - deallocate(xyz) |
4109 | - call deallocate(surface_ids) |
4110 | - ewrite(1,*) "-------End melt_allocate_surface---------" |
4111 | -end subroutine melt_allocate_surface |
4112 | - |
4113 | - |
4114 | - |
4115 | -! Calculate the melt rate |
4116 | - subroutine melt_surf_calc(state) |
4117 | - |
4118 | - type(state_type), intent(inout) :: state |
4119 | - type(scalar_field), pointer :: Tb, Sb,MeltRate,Heat_flux,Salt_flux |
4120 | - type(scalar_field), pointer :: scalarfield |
4121 | - type(vector_field), pointer :: velocity,positions |
4122 | - !Debugging purpose pointer |
4123 | - type(scalar_field), pointer :: T_loc,S_loc,P_loc |
4124 | - type(vector_field), pointer :: V_loc,Location,Location_org |
4125 | - real, dimension(:), allocatable :: vel |
4126 | - integer :: i,j,k |
4127 | - ! Some internal variables |
4128 | - real :: speed, T,S,P,Aa,Bb,Cc,topo |
4129 | - real ::loc_Tb,loc_Sb,loc_meltrate,loc_heatflux,loc_saltflux |
4130 | - ! Aa*Sb^2+Bv*Sb+Cc |
4131 | - real :: arg = -1.0 |
4132 | - !Sink mesh part |
4133 | - integer :: ele,face,node,stat,the_node |
4134 | - real, dimension(:), allocatable :: local_coord,coord |
4135 | - type(element_type), pointer :: x_shape_f |
4136 | - integer, dimension(:), allocatable :: surface_node_list,node_lists |
4137 | - type(scalar_field) :: re_temperature,re_salinity,re_pressure |
4138 | - type(vector_field) :: re_velocity |
4139 | - |
4140 | - |
4141 | - ewrite(1,*) "-------Begin melt_surf_calc------------" |
4142 | - |
4143 | - MeltRate => extract_scalar_field(state,"MeltRate") |
4144 | - Tb => extract_scalar_field(state,"Tb") |
4145 | - Sb => extract_scalar_field(state,"Sb") |
4146 | - call set(MeltRate,setnan(arg)) |
4147 | - call set(Tb,setnan(arg)) |
4148 | - call set(Sb,setnan(arg)) |
4149 | - Heat_flux => extract_scalar_field(state,"Heat_flux") |
4150 | - Salt_flux => extract_scalar_field(state,"Salt_flux") |
4151 | - call set(Heat_flux,setnan(arg)) |
4152 | - call set(Salt_flux,setnan(arg)) |
4153 | - |
4154 | -! Debugging |
4155 | - T_loc => extract_scalar_field(state,"Tloc") |
4156 | - S_loc => extract_scalar_field(state,"Sloc") |
4157 | - P_loc => extract_scalar_field(state,"Ploc") |
4158 | - V_loc => extract_vector_field(state,"Vloc") |
4159 | - Location => extract_vector_field(state,"Location") |
4160 | - Location_org => extract_vector_field(state,"Location_org") |
4161 | - call set(T_loc,setnan(arg)) |
4162 | - call set(S_loc,setnan(arg)) |
4163 | - call set(P_loc,setnan(arg)) |
4164 | - allocate(vel(V_loc%dim)) |
4165 | - vel = setnan(arg) |
4166 | - call set(V_loc,vel) |
4167 | - call set(Location,vel) |
4168 | - call set(Location_org,vel) |
4169 | - |
4170 | - positions => extract_vector_field(state,"Coordinate") |
4171 | - !my positions |
4172 | - |
4173 | - ! Surface node list |
4174 | - allocate(surface_node_list(key_count(sf_nodes))) |
4175 | - ! Make it to vector from integer_set. |
4176 | - ! sf_nodes is calculated in "melt_allocate_surface" |
4177 | - surface_node_list=set2vector(sf_nodes) |
4178 | - |
4179 | - ! Remap temperature, salinity, pressure, and velocity onto positions mesh |
4180 | - scalarfield => extract_scalar_field(state,"Temperature") |
4181 | - |
4182 | - call allocate(re_temperature,positions%mesh,name="ReTemperature") |
4183 | - |
4184 | - call remap_field(scalarfield,re_temperature,stat) |
4185 | - |
4186 | - ! Salinity |
4187 | - scalarfield=> extract_scalar_field(state,"Salinity") |
4188 | - |
4189 | - call allocate(re_salinity,positions%mesh, name="ReSalinity") |
4190 | - call remap_field(scalarfield,re_salinity,stat) |
4191 | - |
4192 | - ! Pressure |
4193 | - scalarfield => extract_scalar_field(state,"Pressure") |
4194 | - call allocate(re_pressure,positions%mesh, name="RePressure") |
4195 | - call remap_field(scalarfield,re_pressure,stat) |
4196 | - |
4197 | - ! Velocity |
4198 | - velocity => extract_vector_field(state,"Velocity") |
4199 | - call allocate(re_velocity,velocity%dim,positions%mesh,name="ReVelocity") |
4200 | - call remap_field(velocity, re_velocity, stat) |
4201 | - |
4202 | - allocate(local_coord(positions%dim+1)) |
4203 | - allocate(coord(positions%dim)) |
4204 | - |
4205 | - |
4206 | - |
4207 | - |
4208 | -!!!!!!!!!!!!!!!!!!!!!!!!! |
4209 | - !surface_positions |
4210 | - |
4211 | - !! Loope over the surface nodes to calculate melt rate etc. |
4212 | - do i=1,size(surface_node_list) |
4213 | - the_node = surface_node_list(i) |
4214 | - !!! Interpolating |
4215 | - coord = node_val(funky_positions,the_node) |
4216 | - call picker_inquire(positions, coord, ele, local_coord,global=.true.) |
4217 | - |
4218 | - !! If sum(local_coord) is not equal to 1, |
4219 | - !! we know that this coord (funky position) does not exist in the domain. |
4220 | - |
4221 | - if (sum(local_coord) .gt. 2.0) then |
4222 | - ewrite(1,*) "Funk coord: ", node_val(funky_positions,the_node) |
4223 | - !! node_val(surface_positions,the_node) = node_val(positions,the_node) |
4224 | - ewrite(1,*) "Original ele: ",ele |
4225 | - ewrite(1,*) "sum of local_coord: ", sum(local_coord) |
4226 | - FLExit("Your funky_positions is out of the domain. Change melt_LayerLength.") |
4227 | - endif |
4228 | - !Number of nodes per element |
4229 | - allocate(node_lists(ele_and_faces_loc(positions, ele))) |
4230 | - node_lists = ele_nodes(positions,ele) !Lists of nodes that occupies the element. |
4231 | - ! This method of finding values at funky_positions works for P1, which are T,S, and velocity. |
4232 | - coord = 0.0 |
4233 | - T = 0.0 |
4234 | - S = 0.0 |
4235 | - speed = 0.0 |
4236 | - vel = 0.0 |
4237 | - |
4238 | - do j=1,size(node_lists) |
4239 | - node = node_lists(j) |
4240 | - coord = coord + node_val(positions,node)*local_coord(j) |
4241 | - T = T + node_val(re_temperature,node)*local_coord(j) |
4242 | - S = S + node_val(re_salinity,node)*local_coord(j) |
4243 | - vel = vel + node_val(re_velocity,node)*local_coord(j) |
4244 | - enddo |
4245 | - deallocate(node_lists) |
4246 | - ! Luckly P needs to be at the surface for the three equations |
4247 | - P = node_val(re_pressure,the_node) |
4248 | - speed = sqrt(sum(vel**2)) |
4249 | - |
4250 | - if (speed .lt. 0.001) then |
4251 | - speed = 0.001 |
4252 | - !ewrite(1,*) "----------iceshelf, speed less----", the_node,speed |
4253 | - endif |
4254 | - topo = -7.53e-8*P ! constant = -7.53e-8 [C Pa^(-1)] comes from Holland and Jenkins Table 1 |
4255 | - |
4256 | - !! Define Aa,Bb,Cc |
4257 | - !! Aa*Sb**2 + Bb*Sb + Cc = 0.0 |
4258 | - Aa = -gammaS*speed*cI*a + a*c0*gammaT*speed |
4259 | - |
4260 | - Bb = -gammaS*speed*L + gammaS*speed*S*cI*a |
4261 | - Bb = Bb - gammaS*speed*cI*(b+topo) + gammaS*speed*cI*TI |
4262 | - Bb = Bb - c0*gammaT*speed*T + c0*gammaT*speed*(b+topo) |
4263 | - |
4264 | - Cc = gammaS*speed*S*L +gammaS*speed*S*cI*(b+topo) + gammaS*speed*S*(-cI*TI) |
4265 | - |
4266 | - |
4267 | - !! This could be a linear equation if Aa=0 |
4268 | - if (Aa .eq. 0.0) then |
4269 | - loc_Sb = -Cc/Bb |
4270 | - else |
4271 | - !! Calculate for the 2nd oewrite(1,*) "size(surface_element_list)"rder polynomial. |
4272 | - !! We have two solutions. |
4273 | - loc_Sb = (-Bb + sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa) |
4274 | - !! loc_Sb has to be larger than 0; since the salinity in the ocean is positive definite. |
4275 | - if (loc_Sb .lt. 0.0) then |
4276 | - loc_Sb = (-Bb - sqrt(Bb**2 - 4.0*Aa*Cc))/(2.0*Aa) |
4277 | - endif |
4278 | - endif |
4279 | - !ewrite(1,*) "----------iceshelf, loc_Sb----", loc_Sb |
4280 | - loc_Tb = a*loc_Sb + b + topo |
4281 | - loc_meltrate = gammaS*speed*(S-loc_Sb)/loc_Sb |
4282 | - !! Heat flux to the ocean |
4283 | - loc_heatflux = c0*(gammaT*speed+ loc_meltrate)*(T-loc_Tb) ! or loc_meltrate*L + loc_meltrate*cI*(loc_Tb-TI) |
4284 | - loc_saltflux = (gammaS*speed+loc_meltrate)*(S-loc_Sb) |
4285 | - !! Some debugging |
4286 | - !!ewrite(1,*) "melt_rate: ",loc_meltrate |
4287 | - !!ewrite(1,*) "tLHS: ", c0*gammaT*speed*(T-loc_Tb) |
4288 | - !!ewrite(1,*) "tRHS: ", loc_meltrate*L + loc_meltrate*cI*(loc_Tb-TI) |
4289 | - !!ewrite(1,*) "sLHS: ", gammaS*speed*(S-loc_Sb) |
4290 | - !!ewrite(1,*) "sRHS: ", loc_meltrate*loc_Sb |
4291 | - !!ewrite(1,*) "bLHS: ", loc_Tb |
4292 | - !!ewrite(1,*) "bRHS: ", a*loc_Sb + b + topo |
4293 | - |
4294 | - !! These are needed to implement BCs. |
4295 | - call set(MeltRate, the_node, loc_meltrate) |
4296 | - call set(Tb, the_node, loc_Tb) |
4297 | - call set(Sb, the_node, loc_Sb) |
4298 | - call set(Heat_flux, the_node,loc_heatflux) |
4299 | - call set(Salt_flux, the_node,loc_saltflux) |
4300 | - !! More or less for debugging purposes. |
4301 | - call set(T_loc,the_node,T) |
4302 | - call set(S_loc,the_node,S) |
4303 | - call set(P_loc,the_node,P) |
4304 | - call set(V_loc,the_node,vel) |
4305 | - call set(Location,the_node,node_val(funky_positions,the_node)) |
4306 | - call set(Location_org,the_node,node_val(positions,the_node)) |
4307 | - !! BC test |
4308 | - !!call set(TT,the_node,11.1) |
4309 | -! ewrite(1,*) "----------iceshelf, loc_saltflux----", the_node,loc_saltflux |
4310 | -! ewrite(1,*) "----------melt_surf_calc, loc_Tb----", the_node,loc_Tb |
4311 | -! ewrite(1,*) "----------iceshelf, surfaceS----",node_val(re_salinity,the_node) |
4312 | -! ewrite(1,*) "----------line 477 iceshelf, loc_meltrate----",loc_meltrate |
4313 | -! ewrite(1,*) "----------iceshelf, node_val(TT,the_node)----",node_val(TT,the_node) |
4314 | - enddo |
4315 | - |
4316 | - deallocate(local_coord) |
4317 | - deallocate(coord) |
4318 | - ewrite(1,*) "-----END melt_surf_calc-------" |
4319 | -end subroutine melt_surf_calc |
4320 | - |
4321 | - |
4322 | -subroutine melt_bc(state) |
4323 | - type(state_type), intent(inout) :: state |
4324 | - !! BC |
4325 | - type(scalar_field), pointer :: TT,SS |
4326 | - type(scalar_field), pointer :: scalar_surface |
4327 | - type(mesh_type), pointer :: ice_mesh |
4328 | - character(len=FIELD_NAME_LEN) :: bc_type |
4329 | - type(scalar_field), pointer :: T_bc,S_bc |
4330 | - integer, dimension(:), allocatable :: surface_node_list |
4331 | - integer :: i, the_node |
4332 | -!! Insert BC for temperature and salinity. This could be a separate subroutine |
4333 | - |
4334 | - |
4335 | - TT=> extract_scalar_field(state,"Temperature") |
4336 | - SS => extract_scalar_field(state,"Salinity") |
4337 | - |
4338 | - !This change with bc type |
4339 | - call get_option("/ocean_forcing/iceshelf_meltrate/Holland08/calculate_boundaries", bc_type) |
4340 | - |
4341 | - select case(bc_type) |
4342 | - case("neumann") |
4343 | - T_bc => extract_scalar_field(state,"Heat_flux") |
4344 | - S_bc => extract_scalar_field(state,"Salt_flux") |
4345 | - do i=1,node_count(T_bc) |
4346 | - call set(T_bc,node_val(T_bc,i)*10.0**3) |
4347 | - call set(S_bc,node_val(S_bc,i)*10.0**3) |
4348 | - enddo |
4349 | - |
4350 | - case("dirichlet") |
4351 | - T_bc => extract_scalar_field(state,"Tb") |
4352 | - S_bc => extract_scalar_field(state,"Sb") |
4353 | - case default |
4354 | - FLAbort('Unknown BC for TKE') |
4355 | - end select |
4356 | - |
4357 | - |
4358 | - ! Surface node list |
4359 | - allocate(surface_node_list(key_count(sf_nodes))) |
4360 | - ! Make it to vector from integer_set. |
4361 | - ! sf_nodes is calculated in "melt_allocate_surface" |
4362 | - surface_node_list=set2vector(sf_nodes) |
4363 | - |
4364 | - ! create a surface mesh to place values onto. This is for the top surface |
4365 | - call get_boundary_condition(TT, 'temperature_iceshelf_BC', surface_mesh=ice_mesh) |
4366 | - call allocate(ice_surfaceT, ice_mesh, name="ice_surfaceT") |
4367 | - call get_boundary_condition(SS, 'salinity_iceshelf_BC', surface_mesh=ice_mesh) |
4368 | - call allocate(ice_surfaceS, ice_mesh, name="ice_surfaceS") |
4369 | - ! Define ice_surfaceT according to Heat_flux? |
4370 | - ewrite(1,*) "node_count(ice_surfaceT)",node_count(ice_surfaceT) |
4371 | - do i=1,node_count(ice_surfaceT) |
4372 | - the_node = surface_node_list(i) |
4373 | - call set(ice_surfaceT,i,node_val(T_bc,the_node)) |
4374 | - call set(ice_surfaceS,i,node_val(S_bc,the_node)) |
4375 | - enddo |
4376 | - !! Temperature |
4377 | - scalar_surface => extract_surface_field(TT, 'temperature_iceshelf_BC', "value") |
4378 | - call remap_field(ice_surfaceT, scalar_surface) |
4379 | - !! Salinity |
4380 | - scalar_surface => extract_surface_field(SS, 'salinity_iceshelf_BC', "value") |
4381 | - call remap_field(ice_surfaceS, scalar_surface) |
4382 | -! ewrite(1,*) "iceBC, ice_element_list",ice_element_list |
4383 | -! ewrite(1,*) "iceBC, node_count(scalar_surface)", node_count(scalar_surface) |
4384 | -! ewrite(1,*) "node_val(scalar_surface,1): ", node_val(scalar_surface,1) |
4385 | - |
4386 | -!! Insert BC for salinity |
4387 | - |
4388 | - |
4389 | -end subroutine melt_bc |
4390 | - |
4391 | - |
4392 | - |
4393 | -!!------------------------------------------------------------------! |
4394 | -!! Private subroutines ! |
4395 | -!!------------------------------------------------------------------! |
4396 | - |
4397 | -subroutine melt_surf_mesh(mesh,surface_ids,surface_mesh,surface_nodes,surface_element_list) |
4398 | - |
4399 | - type(mesh_type), intent(in) :: mesh |
4400 | - type(integer_set), intent(in) :: surface_ids |
4401 | - type(mesh_type), intent(out) :: surface_mesh |
4402 | - integer, dimension(:), pointer, intent(out) :: surface_nodes ! allocated and returned by create_surface_mesh |
4403 | - integer, dimension(:), allocatable, intent(out) :: surface_element_list |
4404 | - ! integer, dimension(:), allocatable :: surface_nodes_out |
4405 | - type(scalar_field) :: surface_field |
4406 | - type(integer_set) :: surface_elements |
4407 | - integer :: i |
4408 | - ! create a set of surface elements that have surface id in 'surface_ids' |
4409 | - |
4410 | - call allocate(surface_elements) |
4411 | - do i=1, surface_element_count(mesh) |
4412 | -! ewrite(1,*) "surf_normal surface_element_id(mesh, i)", surface_element_id(mesh, i) |
4413 | -! ewrite(1,*) "surf_normal surface_ids", set2vector(surface_ids) |
4414 | - if (has_value(surface_ids, surface_element_id(mesh, i))) then |
4415 | - call insert(surface_elements, i) |
4416 | - |
4417 | - end if |
4418 | - end do |
4419 | - |
4420 | - allocate(surface_element_list(key_count(surface_elements))) |
4421 | - surface_element_list=set2vector(surface_elements) |
4422 | - call create_surface_mesh(surface_mesh, surface_nodes, mesh, surface_element_list, name=trim(mesh%name)//"ToshisMesh") |
4423 | - |
4424 | - |
4425 | -end subroutine melt_surf_mesh |
4426 | - |
4427 | - |
4428 | -real function setnan(arg) |
4429 | - real :: arg |
4430 | - setnan = sqrt(arg) |
4431 | -end function |
4432 | - |
4433 | -real function calc_area2(positions,nodes) |
4434 | - type(vector_field), pointer :: positions |
4435 | - integer, dimension(2) :: nodes |
4436 | - real, dimension(2) :: coord1,coord2 |
4437 | -! real :: area |
4438 | - coord1 = node_val(positions,nodes(1)) |
4439 | - coord2 = node_val(positions,nodes(2)) |
4440 | - |
4441 | - calc_area2 = (sum((coord2 - coord1)**2))**0.5 |
4442 | - |
4443 | -end function |
4444 | - |
4445 | -real function calc_area3(positions,nodes) |
4446 | - type(vector_field), pointer :: positions |
4447 | - integer, dimension(3) :: nodes |
4448 | - real, dimension(3) :: coord1,coord2,coord3 |
4449 | - real :: a,b,c,s |
4450 | -! real :: area |
4451 | - coord1 = node_val(positions,nodes(1)) |
4452 | - coord2 = node_val(positions,nodes(2)) |
4453 | - coord3 = node_val(positions,nodes(3)) |
4454 | -! Use Heron's formula to calculate the area of triangle |
4455 | - a = (sum((coord2 - coord1)**2))**0.5 |
4456 | - b = (sum((coord3 - coord1)**2))**0.5 |
4457 | - c = (sum((coord2 - coord3)**2))**0.5 |
4458 | - s = 0.5*(a+b+c) |
4459 | - calc_area3 = (s*(s-a)*(s-b)*(s-c))**0.5 |
4460 | - |
4461 | -end function |
4462 | - |
4463 | -end module iceshelf_meltrate_surf_normal |
4464 | |
4465 | === removed file 'schemas/multiphase_interaction.rnc' |
4466 | --- schemas/multiphase_interaction.rnc 2012-06-15 19:32:03 +0000 |
4467 | +++ schemas/multiphase_interaction.rnc 1970-01-01 00:00:00 +0000 |
4468 | @@ -1,58 +0,0 @@ |
4469 | -# Phase interaction options for Fluidity's multiphase flow model. |
4470 | - |
4471 | -multiphase_interaction = |
4472 | - ( |
4473 | - ## Phase interaction options for Fluidity's multiphase flow model. |
4474 | - element multiphase_interaction { |
4475 | - comment, |
4476 | - fluid_particle_drag?, |
4477 | - heat_transfer? |
4478 | - } |
4479 | - ) |
4480 | - |
4481 | -fluid_particle_drag = |
4482 | - ( |
4483 | - ## Fluid-particle drag term. |
4484 | - element fluid_particle_drag { |
4485 | - drag_correlation |
4486 | - } |
4487 | - ) |
4488 | - |
4489 | -drag_correlation = |
4490 | - ( |
4491 | - ## Stokes drag correlation: 24/Re_p |
4492 | - ## where Re_p is the particle Reynolds number. |
4493 | - element drag_correlation { |
4494 | - attribute name { "stokes" }, |
4495 | - comment |
4496 | - }| |
4497 | - ## Fluid-particle drag term by Wen & Yu (1966). |
4498 | - element drag_correlation { |
4499 | - attribute name { "wen_yu" }, |
4500 | - comment |
4501 | - }| |
4502 | - ## Fluid-particle drag term by Ergun (1952). |
4503 | - element drag_correlation { |
4504 | - attribute name { "ergun" }, |
4505 | - comment |
4506 | - } |
4507 | - ) |
4508 | - |
4509 | -heat_transfer = |
4510 | - ( |
4511 | - ## Heat transfer term for the |
4512 | - ## multiphase internal energy equation. |
4513 | - ## Note: Only for fluid-particle phase pairs. |
4514 | - element heat_transfer { |
4515 | - heat_transfer_coefficient |
4516 | - } |
4517 | - ) |
4518 | - |
4519 | -heat_transfer_coefficient = |
4520 | - ( |
4521 | - ## Heat transfer coefficient by Gunn (1978). |
4522 | - element heat_transfer_coefficient { |
4523 | - attribute name { "gunn" }, |
4524 | - comment |
4525 | - } |
4526 | - ) |
4527 | \ No newline at end of file |
4528 | |
4529 | === removed file 'schemas/multiphase_interaction.rng' |
4530 | --- schemas/multiphase_interaction.rng 2012-06-15 19:32:03 +0000 |
4531 | +++ schemas/multiphase_interaction.rng 1970-01-01 00:00:00 +0000 |
4532 | @@ -1,65 +0,0 @@ |
4533 | -<?xml version="1.0" encoding="UTF-8"?> |
4534 | -<grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0"> |
4535 | - <!-- Phase interaction options for Fluidity's multiphase flow model. --> |
4536 | - <define name="multiphase_interaction"> |
4537 | - <element name="multiphase_interaction"> |
4538 | - <a:documentation>Phase interaction options for Fluidity's multiphase flow model.</a:documentation> |
4539 | - <ref name="comment"/> |
4540 | - <optional> |
4541 | - <ref name="fluid_particle_drag"/> |
4542 | - </optional> |
4543 | - <optional> |
4544 | - <ref name="heat_transfer"/> |
4545 | - </optional> |
4546 | - </element> |
4547 | - </define> |
4548 | - <define name="fluid_particle_drag"> |
4549 | - <element name="fluid_particle_drag"> |
4550 | - <a:documentation>Fluid-particle drag term.</a:documentation> |
4551 | - <ref name="drag_correlation"/> |
4552 | - </element> |
4553 | - </define> |
4554 | - <define name="drag_correlation"> |
4555 | - <choice> |
4556 | - <element name="drag_correlation"> |
4557 | - <a:documentation>Stokes drag correlation: 24/Re_p |
4558 | -where Re_p is the particle Reynolds number.</a:documentation> |
4559 | - <attribute name="name"> |
4560 | - <value>stokes</value> |
4561 | - </attribute> |
4562 | - <ref name="comment"/> |
4563 | - </element> |
4564 | - <element name="drag_correlation"> |
4565 | - <a:documentation>Fluid-particle drag term by Wen & Yu (1966).</a:documentation> |
4566 | - <attribute name="name"> |
4567 | - <value>wen_yu</value> |
4568 | - </attribute> |
4569 | - <ref name="comment"/> |
4570 | - </element> |
4571 | - <element name="drag_correlation"> |
4572 | - <a:documentation>Fluid-particle drag term by Ergun (1952).</a:documentation> |
4573 | - <attribute name="name"> |
4574 | - <value>ergun</value> |
4575 | - </attribute> |
4576 | - <ref name="comment"/> |
4577 | - </element> |
4578 | - </choice> |
4579 | - </define> |
4580 | - <define name="heat_transfer"> |
4581 | - <element name="heat_transfer"> |
4582 | - <a:documentation>Heat transfer term for the |
4583 | -multiphase internal energy equation. |
4584 | -Note: Only for fluid-particle phase pairs.</a:documentation> |
4585 | - <ref name="heat_transfer_coefficient"/> |
4586 | - </element> |
4587 | - </define> |
4588 | - <define name="heat_transfer_coefficient"> |
4589 | - <element name="heat_transfer_coefficient"> |
4590 | - <a:documentation>Heat transfer coefficient by Gunn (1978).</a:documentation> |
4591 | - <attribute name="name"> |
4592 | - <value>gunn</value> |
4593 | - </attribute> |
4594 | - <ref name="comment"/> |
4595 | - </element> |
4596 | - </define> |
4597 | -</grammar> |
4598 | |
4599 | === modified file 'schemas/prognostic_field_options.rnc' |
4600 | --- schemas/prognostic_field_options.rnc 2012-08-22 16:03:09 +0000 |
4601 | +++ schemas/prognostic_field_options.rnc 2012-09-04 15:00:37 +0000 |
4602 | @@ -91,8 +91,7 @@ |
4603 | ## T the scalar field value on the surface, |
4604 | ## C0 is the input order zero coefficient and |
4605 | ## C1 is the input order one coefficient. |
4606 | - ## THIS WILL ONLY WORK FOR CONTINUOUS GALERKIN OR CONTROL VOLUME |
4607 | - ## (USING AN ELEMENTGRADIENT DIFFUSION SCHEME) SPATIAL DISCRETISATIONS. |
4608 | + ## THIS WILL ONLY WORK FOR CONTINUOUS GALERKIN SPATIAL DISCRETISATION |
4609 | element type { |
4610 | attribute name { "robin" }, |
4611 | ## The order zero coefficient represented as C0 in |
4612 | |
4613 | === modified file 'schemas/prognostic_field_options.rng' |
4614 | --- schemas/prognostic_field_options.rng 2012-08-22 16:03:09 +0000 |
4615 | +++ schemas/prognostic_field_options.rng 2012-09-04 15:00:37 +0000 |
4616 | @@ -113,8 +113,7 @@ |
4617 | T the scalar field value on the surface, |
4618 | C0 is the input order zero coefficient and |
4619 | C1 is the input order one coefficient. |
4620 | - THIS WILL ONLY WORK FOR CONTINUOUS GALERKIN OR CONTROL VOLUME |
4621 | - (USING AN ELEMENTGRADIENT DIFFUSION SCHEME) SPATIAL DISCRETISATIONS.</a:documentation> |
4622 | + THIS WILL ONLY WORK FOR CONTINUOUS GALERKIN SPATIAL DISCRETISATION</a:documentation> |
4623 | <attribute name="name"> |
4624 | <value>robin</value> |
4625 | </attribute> |
4626 | |
4627 | === modified file 'schemas/spatial_discretisation.rnc' |
4628 | --- schemas/spatial_discretisation.rnc 2012-06-02 12:15:06 +0000 |
4629 | +++ schemas/spatial_discretisation.rnc 2012-09-04 15:00:37 +0000 |
4630 | @@ -494,7 +494,7 @@ |
4631 | ## basis functions of the parent finite element mesh to |
4632 | ## form the divergence. |
4633 | ## |
4634 | - ## DOES NOT CURRENTLY WORK WITH WEAK DIRICHLET BOUNDARY CONDITIONS! |
4635 | + ## DOES NOT CURRENTLY WORK WITH ROBIN OR WEAK DIRICHLET BOUNDARY CONDITIONS! |
4636 | ## |
4637 | ## Based on schemes in Handbook of Numerical Analysis, |
4638 | ## P.G. Ciarlet, J.L. Lions eds, vol 7, pp 713-1020 |
4639 | |
4640 | === modified file 'schemas/spatial_discretisation.rng' |
4641 | --- schemas/spatial_discretisation.rng 2012-06-02 12:15:06 +0000 |
4642 | +++ schemas/spatial_discretisation.rng 2012-09-04 15:00:37 +0000 |
4643 | @@ -546,7 +546,7 @@ |
4644 | basis functions of the parent finite element mesh to |
4645 | form the divergence. |
4646 | |
4647 | -DOES NOT CURRENTLY WORK WITH WEAK DIRICHLET BOUNDARY CONDITIONS! |
4648 | +DOES NOT CURRENTLY WORK WITH ROBIN OR WEAK DIRICHLET BOUNDARY CONDITIONS! |
4649 | |
4650 | Based on schemes in Handbook of Numerical Analysis, |
4651 | P.G. Ciarlet, J.L. Lions eds, vol 7, pp 713-1020</a:documentation> |
4652 | |
4653 | === modified file 'tests/diff_src_robin_1d/diff_src_robin_1d.xml' |
4654 | --- tests/diff_src_robin_1d/diff_src_robin_1d.xml 2012-06-02 12:15:06 +0000 |
4655 | +++ tests/diff_src_robin_1d/diff_src_robin_1d.xml 2012-09-04 15:00:37 +0000 |
4656 | @@ -6,8 +6,7 @@ |
4657 | <tags>flml</tags> |
4658 | <problem_definition length="short" nprocs="1"> |
4659 | <command_line> |
4660 | -../../bin/fluidity diff_src_robin_1d_cg_p1_A.flml |
4661 | -../../bin/fluidity diff_src_robin_1d_cvelegrad_p1_A.flml |
4662 | +../../bin/fluidity diff_src_robin_1d_cg_p1_A.flml |
4663 | </command_line> |
4664 | <!-- One dimensional problem for diffusion, source with right robin bc and left neumann zero compared to analytic--> |
4665 | </problem_definition> |
4666 | @@ -20,14 +19,6 @@ |
4667 | from fluidity_tools import stat_parser as stat |
4668 | cg_p1_A_error_linf = stat("diff_src_robin_1d_cg_p1_A.stat")["fluid"]["TError"]["max"][-1] |
4669 | </variable> |
4670 | - <variable name="cvelegrad_p1_A_error_l2" language="python"> |
4671 | -from fluidity_tools import stat_parser as stat |
4672 | -cvelegrad_p1_A_error_l2 = stat("diff_src_robin_1d_cvelegrad_p1_A.stat")["fluid"]["TError"]["cv_l2norm"][-1] |
4673 | - </variable> |
4674 | - <variable name="cvelegrad_p1_A_error_linf" language="python"> |
4675 | -from fluidity_tools import stat_parser as stat |
4676 | -cvelegrad_p1_A_error_linf = stat("diff_src_robin_1d_cvelegrad_p1_A.stat")["fluid"]["TError"]["max"][-1] |
4677 | - </variable> |
4678 | </variables> |
4679 | <pass_tests> |
4680 | <test name="Check cg_p1_A_error_l2 less than 1.0e-8" language="python"> |
4681 | @@ -36,12 +27,6 @@ |
4682 | <test name="Check cg_p1_A_error_linf less than 1.0e-8" language="python"> |
4683 | assert(abs(cg_p1_A_error_linf) < 1.0e-8) |
4684 | </test> |
4685 | - <test name="Check cvelegrad_p1_A_error_l2 less than 1.0e-8" language="python"> |
4686 | -assert(abs(cvelegrad_p1_A_error_l2) < 1.0e-8) |
4687 | - </test> |
4688 | - <test name="Check cvelegrad_p1_A_error_linf less than 1.0e-8" language="python"> |
4689 | -assert(abs(cvelegrad_p1_A_error_linf) < 1.0e-8) |
4690 | - </test> |
4691 | </pass_tests> |
4692 | <warn_tests> |
4693 | </warn_tests> |
4694 | |
4695 | === removed file 'tests/diff_src_robin_1d/diff_src_robin_1d_cvelegrad_p1_A.flml' |
4696 | --- tests/diff_src_robin_1d/diff_src_robin_1d_cvelegrad_p1_A.flml 2012-06-02 12:18:06 +0000 |
4697 | +++ tests/diff_src_robin_1d/diff_src_robin_1d_cvelegrad_p1_A.flml 1970-01-01 00:00:00 +0000 |
4698 | @@ -1,244 +0,0 @@ |
4699 | -<?xml version='1.0' encoding='utf-8'?> |
4700 | -<fluidity_options> |
4701 | - <simulation_name> |
4702 | - <string_value lines="1">diff_src_robin_1d_cvelegrad_p1_A</string_value> |
4703 | - </simulation_name> |
4704 | - <problem_type> |
4705 | - <string_value lines="1">fluids</string_value> |
4706 | - </problem_type> |
4707 | - <geometry> |
4708 | - <dimension> |
4709 | - <integer_value rank="0">1</integer_value> |
4710 | - </dimension> |
4711 | - <mesh name="CoordinateMesh"> |
4712 | - <from_file file_name="diff_src_robin_1d_A"> |
4713 | - <format name="triangle"/> |
4714 | - <stat> |
4715 | - <include_in_stat/> |
4716 | - </stat> |
4717 | - </from_file> |
4718 | - </mesh> |
4719 | - <quadrature> |
4720 | - <degree> |
4721 | - <integer_value rank="0">2</integer_value> |
4722 | - </degree> |
4723 | - </quadrature> |
4724 | - </geometry> |
4725 | - <io> |
4726 | - <dump_format> |
4727 | - <string_value>vtk</string_value> |
4728 | - </dump_format> |
4729 | - <dump_period_in_timesteps> |
4730 | - <constant> |
4731 | - <integer_value rank="0">0</integer_value> |
4732 | - </constant> |
4733 | - </dump_period_in_timesteps> |
4734 | - <output_mesh name="CoordinateMesh"/> |
4735 | - <stat/> |
4736 | - </io> |
4737 | - <timestepping> |
4738 | - <current_time> |
4739 | - <real_value rank="0">0.0</real_value> |
4740 | - </current_time> |
4741 | - <timestep> |
4742 | - <real_value rank="0">2.5</real_value> |
4743 | - <comment>Time stepping is not actually needed for this test case but this is just to check the acceleration field solver</comment> |
4744 | - </timestep> |
4745 | - <finish_time> |
4746 | - <real_value rank="0">10.0</real_value> |
4747 | - <comment>Time stepping is not actually needed for this test case but this is just to check the acceleration field solver</comment> |
4748 | - </finish_time> |
4749 | - </timestepping> |
4750 | - <physical_parameters/> |
4751 | - <material_phase name="fluid"> |
4752 | - <vector_field name="Velocity" rank="1"> |
4753 | - <prescribed> |
4754 | - <mesh name="CoordinateMesh"/> |
4755 | - <value name="WholeMesh"> |
4756 | - <constant> |
4757 | - <real_value shape="1" dim1="dim" rank="1">0.0</real_value> |
4758 | - </constant> |
4759 | - </value> |
4760 | - <output/> |
4761 | - <stat> |
4762 | - <include_in_stat/> |
4763 | - </stat> |
4764 | - <detectors> |
4765 | - <exclude_from_detectors/> |
4766 | - </detectors> |
4767 | - </prescribed> |
4768 | - </vector_field> |
4769 | - <scalar_field name="T" rank="0"> |
4770 | - <prognostic> |
4771 | - <mesh name="CoordinateMesh"/> |
4772 | - <equation name="AdvectionDiffusion"/> |
4773 | - <spatial_discretisation> |
4774 | - <control_volumes> |
4775 | - <mass_terms> |
4776 | - <exclude_mass_terms/> |
4777 | - </mass_terms> |
4778 | - <face_value name="FirstOrderUpwind"/> |
4779 | - <diffusion_scheme name="ElementGradient"/> |
4780 | - </control_volumes> |
4781 | - <conservative_advection> |
4782 | - <real_value rank="0">1.0</real_value> |
4783 | - </conservative_advection> |
4784 | - </spatial_discretisation> |
4785 | - <temporal_discretisation> |
4786 | - <theta> |
4787 | - <real_value rank="0">1.0</real_value> |
4788 | - </theta> |
4789 | - <control_volumes> |
4790 | - <pivot_theta> |
4791 | - <real_value rank="0">1.0</real_value> |
4792 | - </pivot_theta> |
4793 | - </control_volumes> |
4794 | - </temporal_discretisation> |
4795 | - <solver> |
4796 | - <iterative_method name="gmres"> |
4797 | - <restart> |
4798 | - <integer_value rank="0">30</integer_value> |
4799 | - </restart> |
4800 | - </iterative_method> |
4801 | - <preconditioner name="sor"/> |
4802 | - <relative_error> |
4803 | - <real_value rank="0">1.0e-10</real_value> |
4804 | - </relative_error> |
4805 | - <absolute_error> |
4806 | - <real_value rank="0">1.0e-10</real_value> |
4807 | - </absolute_error> |
4808 | - <max_iterations> |
4809 | - <integer_value rank="0">1000</integer_value> |
4810 | - </max_iterations> |
4811 | - <never_ignore_solver_failures/> |
4812 | - <diagnostics> |
4813 | - <monitors/> |
4814 | - </diagnostics> |
4815 | - </solver> |
4816 | - <initial_condition name="WholeMesh"> |
4817 | - <constant> |
4818 | - <real_value rank="0">9.87654321</real_value> |
4819 | - </constant> |
4820 | - </initial_condition> |
4821 | - <boundary_conditions name="right"> |
4822 | - <surface_ids> |
4823 | - <integer_value shape="1" rank="1">2</integer_value> |
4824 | - </surface_ids> |
4825 | - <type name="robin"> |
4826 | - <order_zero_coefficient> |
4827 | - <constant> |
4828 | - <real_value rank="0">3.14</real_value> |
4829 | - </constant> |
4830 | - </order_zero_coefficient> |
4831 | - <order_one_coefficient> |
4832 | - <constant> |
4833 | - <real_value rank="0">0.78</real_value> |
4834 | - </constant> |
4835 | - </order_one_coefficient> |
4836 | - </type> |
4837 | - </boundary_conditions> |
4838 | - <tensor_field name="Diffusivity" rank="2"> |
4839 | - <prescribed> |
4840 | - <value name="WholeMesh"> |
4841 | - <isotropic> |
4842 | - <constant> |
4843 | - <real_value rank="0">1.0</real_value> |
4844 | - </constant> |
4845 | - </isotropic> |
4846 | - </value> |
4847 | - <output/> |
4848 | - </prescribed> |
4849 | - </tensor_field> |
4850 | - <scalar_field name="Source" rank="0"> |
4851 | - <prescribed> |
4852 | - <value name="WholeMesh"> |
4853 | - <constant> |
4854 | - <real_value rank="0">1.234</real_value> |
4855 | - </constant> |
4856 | - </value> |
4857 | - <output/> |
4858 | - <stat/> |
4859 | - <detectors> |
4860 | - <exclude_from_detectors/> |
4861 | - </detectors> |
4862 | - </prescribed> |
4863 | - </scalar_field> |
4864 | - <output/> |
4865 | - <stat> |
4866 | - <include_cv_stats/> |
4867 | - </stat> |
4868 | - <convergence> |
4869 | - <include_in_convergence/> |
4870 | - </convergence> |
4871 | - <detectors> |
4872 | - <include_in_detectors/> |
4873 | - </detectors> |
4874 | - <steady_state> |
4875 | - <include_in_steady_state/> |
4876 | - </steady_state> |
4877 | - <consistent_interpolation/> |
4878 | - </prognostic> |
4879 | - </scalar_field> |
4880 | - <scalar_field name="TAnalytic" rank="0"> |
4881 | - <prescribed> |
4882 | - <mesh name="CoordinateMesh"/> |
4883 | - <value name="WholeMesh"> |
4884 | - <python> |
4885 | - <string_value lines="20" type="code" language="python">def val(X,t): |
4886 | - # get the 1d coord |
4887 | - x = X[0] |
4888 | - |
4889 | - # define the analytic input |
4890 | - x_left = 0.0 |
4891 | - x_right = 10.0 |
4892 | - src = 1.234 |
4893 | - bc_right_r0 = 3.14 |
4894 | - bc_right_r1 = 0.78 |
4895 | - |
4896 | - T_inf = bc_right_r0 / bc_right_r1 |
4897 | - gamma = bc_right_r1 |
4898 | - |
4899 | - # calc the analytic solution |
4900 | - T = (src/2.0)*(x_right**2 - x**2) \ |
4901 | - + (src*x_left)*(x - x_right) \ |
4902 | - + (src/gamma)*(x_right - x_left) \ |
4903 | - + T_inf |
4904 | - |
4905 | - return T</string_value> |
4906 | - </python> |
4907 | - </value> |
4908 | - <output/> |
4909 | - <stat> |
4910 | - <include_cv_stats/> |
4911 | - </stat> |
4912 | - <detectors> |
4913 | - <exclude_from_detectors/> |
4914 | - </detectors> |
4915 | - </prescribed> |
4916 | - </scalar_field> |
4917 | - <scalar_field name="TError" rank="0"> |
4918 | - <diagnostic> |
4919 | - <algorithm name="scalar_python_diagnostic" material_phase_support="single"> |
4920 | - <string_value lines="20" type="code" language="python">field1=state.scalar_fields["T"] |
4921 | -field2=state.scalar_fields["TAnalytic"] |
4922 | -for i in range(field.node_count): |
4923 | - field.set(i, abs(field1.node_val(i)-field2.node_val(i)))</string_value> |
4924 | - </algorithm> |
4925 | - <mesh name="CoordinateMesh"/> |
4926 | - <output/> |
4927 | - <stat> |
4928 | - <include_cv_stats/> |
4929 | - </stat> |
4930 | - <convergence> |
4931 | - <include_in_convergence/> |
4932 | - </convergence> |
4933 | - <detectors> |
4934 | - <include_in_detectors/> |
4935 | - </detectors> |
4936 | - <steady_state> |
4937 | - <include_in_steady_state/> |
4938 | - </steady_state> |
4939 | - </diagnostic> |
4940 | - </scalar_field> |
4941 | - </material_phase> |
4942 | -</fluidity_options> |
4943 | |
4944 | === removed directory 'tests/flux_bc' |
4945 | === removed file 'tests/flux_bc/Makefile' |
4946 | --- tests/flux_bc/Makefile 2012-07-09 23:48:46 +0000 |
4947 | +++ tests/flux_bc/Makefile 1970-01-01 00:00:00 +0000 |
4948 | @@ -1,22 +0,0 @@ |
4949 | -preprocess: |
4950 | - @echo **********Creating meshes |
4951 | - gmsh -2 -o flux_bc_2d.msh src/flux_bc_2d.geo |
4952 | - gmsh -3 -o flux_bc_3d.msh src/flux_bc_3d.geo |
4953 | - ../../bin/gmsh2triangle --2d flux_bc_2d.msh |
4954 | - ../../bin/gmsh2triangle flux_bc_3d.msh |
4955 | - |
4956 | -run: |
4957 | - @echo **********Running 2D simulation |
4958 | - ../../bin/fluidity flux_bc_2d.flml |
4959 | - @echo **********Running 3D simulation |
4960 | - ../../bin/fluidity flux_bc_3d.flml |
4961 | - |
4962 | -input: clean preprocess |
4963 | - |
4964 | -clean: |
4965 | - rm -f *.stat *.steady_state* |
4966 | - rm -f *.d.* *.vtu |
4967 | - rm -f *.msh |
4968 | - rm -f *.ele *.edge *.node *.poly *.face |
4969 | - rm -f matrixdump* *checkpoint* *.log* *.err* |
4970 | - |
4971 | |
4972 | === removed file 'tests/flux_bc/flux_bc.xml' |
4973 | --- tests/flux_bc/flux_bc.xml 2012-08-17 19:58:54 +0000 |
4974 | +++ tests/flux_bc/flux_bc.xml 1970-01-01 00:00:00 +0000 |
4975 | @@ -1,54 +0,0 @@ |
4976 | -<?xml version="1.0" encoding="UTF-8" ?> |
4977 | -<!DOCTYPE testproblem SYSTEM "regressiontest.dtd"> |
4978 | - |
4979 | -<testproblem> |
4980 | - |
4981 | - <name>flux_bc</name> |
4982 | - <owner userid="ctj10"/> |
4983 | - <tags>flml</tags> |
4984 | - |
4985 | - <problem_definition length="medium" nprocs="1"> |
4986 | - <command_line>make run</command_line> |
4987 | - <!-- This checks the integral of the PhaseVolumeFraction field at t = 1 second. --> |
4988 | - <!-- The volumetric flux (r) is set to 0.5 m^3/s/m^2, and the flux boundary condition --> |
4989 | - <!-- enforces d/dt \int_{volume} vfrac = \int_{surface} r --> |
4990 | - </problem_definition> |
4991 | - |
4992 | - <variables> |
4993 | - <variable name="vfrac_integral_2d" language="python"> |
4994 | -from fluidity_tools import stat_parser |
4995 | -s = stat_parser("flux_bc_2d.stat") |
4996 | -vfrac_integral_2d = s["Tephra"]["PhaseVolumeFraction"]["integral"] |
4997 | - </variable> |
4998 | - |
4999 | - <variable name="vfrac_integral_3d" language="python"> |
5000 | -from fluidity_tools import stat_parser |
The in-homogeneous Neumann BC is incomplete, will be making some additions (really made by Stefan) to lp:~fluidity-core/fluidity/DG_Neumann.