!> This module contains definitions of global parameters and variables and some !> generic functions/subroutines used in AMRVAC. !> module mod_global_parameters use mod_physicaldata use mod_connectivity use mpi use mod_constants use mod_variables use mod_basic_types implicit none public ! Parameters character(len=*), parameter :: undefined = 'undefined' !> The number of MPI tasks integer :: npe !> The rank of the current MPI task integer :: mype !> The MPI communicator integer :: icomm !> A global MPI error return code integer :: ierrmpi !> MPI file handle for logfile integer :: log_fh !> MPI type for block including ghost cells and its size integer :: type_block, size_block !> MPI type for block coarsened by 2, and for its children blocks integer :: type_coarse_block, type_sub_block(2,2,2) !> MPI type for staggered block coarsened by 2, and for its children blocks integer :: type_coarse_block_stg(3,2,2,2), type_sub_block_stg(3,2,2,2) !> MPI type for IO: block excluding ghost cells integer :: type_block_io, size_block_io !> MPI type for IO of staggered variables integer :: type_block_io_stg, size_block_io_stg !> MPI type for IO: cell corner (xc) or cell center (xcc) coordinates integer :: type_block_xc_io,type_block_xcc_io !> MPI type for IO: cell corner (wc) or cell center (wcc) variables integer :: type_block_wc_io,type_block_wcc_io ! geometry and domain setups !> the mesh range of a physical block without ghost cells integer :: ixMlo1,ixMlo2,ixMlo3,ixMhi1,ixMhi2,ixMhi3 !> minimum and maximum domain boundaries for each dimension double precision :: xprobmin1,xprobmin2,xprobmin3,xprobmax1,xprobmax2,& xprobmax3 !> Offset of the logarithmic radial map, r0 in s = ln(1 + r/r0). !> !> Only meaningful in a LOG_RADIUS build. Zero - the default - selects the !> plain map s = ln(r), which cannot reach r = 0. A positive value moves the !> singularity of the map to r = -r0, so the mesh is uniform (with width !> r0*ds) for r << r0 and logarithmic for r >> r0, and r = 0 becomes an !> ordinary face of the grid at s = 0. double precision :: log_r0 = 0.0d0 !> The same map written as r = log_ra*exp(s) + log_rb, which is what device !> code evaluates where s >= 0 is guaranteed. log_ra = 1, log_rb = 0 for !> log_r0 = 0, so a plain logarithmic build gets bit-for-bit exp(s). double precision :: log_ra = 1.0d0, log_rb = 0.0d0 !> Indices for cylindrical coordinates FOR TESTS, negative value when not used: integer :: r_ = -1 integer :: phi_ = -1 integer :: z_ = -1 !> Number of spatial dimensions for grid variables integer, parameter :: ndim=3 !> Number of spatial dimensions (components) for vector variables integer :: ndir=ndim !> starting dimension for electric field integer, parameter :: sdim=1 !> Cartesian geometry or not logical :: slab = .true. !> uniform Cartesian geometry or not (stretched Cartesian) logical :: slab_uniform=.true. !> each cell has its own timestep or not logical :: local_timestep = .false. !> number of grid blocks in domain per dimension, in array over levels integer, dimension(:), allocatable :: ng1,ng2,ng3 !> extent of grid blocks in domain per dimension, in array over levels double precision, dimension(:), allocatable :: dg1,dg2,dg3 !> number of cells for each dimension in level-one mesh integer :: domain_nx1,domain_nx2,domain_nx3 !> number of cells for each dimension in grid block excluding ghostcells integer :: block_nx1,block_nx2,block_nx3 !> Lower index of grid block arrays (always 1) integer, parameter :: ixGlo1 = 1, ixGlo2 = 1, ixGlo3 = 1 !> Upper index of grid block arrays integer :: ixGhi1,ixGhi2,ixGhi3 !> Lower index of stagger grid block arrays (always 0) integer, parameter :: ixGslo1 = 0, ixGslo2 = 0, ixGslo3 = 0 !> Upper index of stagger grid block arrays integer :: ixGshi1,ixGshi2,ixGshi3 !> Index range over which the cell metrics (dvolume, ds) are known. This is !> the ghosted block range ixG, plus one extra layer on either side when the !> number of ghost cells is odd (or the grid is staggered), because ghost !> cell prolongation then needs volumes and dx-intervals one cell beyond it. integer :: ixGextmin1,ixGextmin2,ixGextmin3,ixGextmax1,ixGextmax2,ixGextmax3 !> Number of ghost cells surrounding a grid integer :: nghostcells = 2 ! --- Vestigial general-grid-stretching state ------------------------------- ! Upstream MPI-AMRVAC's qstretch/dxfirst stretched-grid machinery has been ! removed: this fork builds every cell metric analytically on the device ! from the block corner and a constant spacing, which general stretch_dim ! stretching cannot express. The one supported non-uniform radius, ! geometry='logSpherical'/'logCylindrical', is still a uniform mesh in the ! logical coordinate xi = ln(r + log_r0) and needs none of this. ! ! The variables below are kept only because a handful of code paths this ! fork does not exercise (mod_slice's get_igslice, mod_particle_base's ! particle-index lookup, mod_thermal_emission's line-of-sight sub-grids) ! still branch on them. They are pinned to the unstretched state here and ! there is no longer any way to change them: stretch_dim and friends are no ! longer read from &meshlist. integer, parameter :: stretch_none = 0 !< No stretching integer, parameter :: stretch_uni = 1 !< Unidirectional stretching (unused) integer, parameter :: stretch_symm = 2 !< Symmetric stretching (unused) logical :: stretch_uncentered = .false. logical :: stretched_dim(ndim) = .false. integer :: stretch_type(ndim) = stretch_none double precision :: qstretch_baselevel(ndim) = 1.0d0 integer :: nstretchedblocks_baselevel(ndim) = 0 integer, allocatable :: nstretchedblocks(:,:) double precision :: xstretch1 = 0.0d0, xstretch2 = 0.0d0, xstretch3 = 0.0d0 double precision, allocatable :: qstretch(:,:), dxfirst(:,:), dxfirst_1mq(:,:),& dxmid(:,:) ! -------------------------------------------------------------------------- !> grid hierarchy info (level and grid indices) integer, parameter :: nodehi=3+1 integer, parameter :: plevel_=1 integer, parameter :: pig1_=plevel_+1,pig2_=plevel_+2,pig3_=plevel_+3 integer, allocatable :: node(:,:) integer, allocatable :: node_sub(:,:) !> grid location info (corner coordinates and grid spacing) integer, parameter :: rnodehi=3*3 integer, parameter :: rpxmin0_=0 integer, parameter :: rpxmin1_=rpxmin0_+1,rpxmin2_=rpxmin0_+2,& rpxmin3_=rpxmin0_+3 integer, parameter :: rpxmax0_=3 integer, parameter :: rpxmax1_=rpxmax0_+1,rpxmax2_=rpxmax0_+2,& rpxmax3_=rpxmax0_+3 integer, parameter :: rpdx1_=2*3+1,rpdx2_=2*3+2,rpdx3_=2*3+3 !> Corner coordinates double precision, allocatable :: rnode(:,:) double precision, allocatable :: rnode_sub(:,:) double precision, allocatable :: dx(:,:) double precision :: dxlevel(ndim) ! IO related quantities !> Maximum number of saves that can be defined by tsave or itsave integer, parameter :: nsavehi=100 !> Number of output methods integer, parameter :: nfile = 5 !> index number of the latest existing data file integer :: index_latest_data !> Names of the output methods character(len=40), parameter :: output_names(nfile) = ['log ',& 'normal ', 'slice ', 'collapsed', 'analysis '] !> User parameter file character(len=std_len) :: usr_filename !> If collapse(DIM) is true, generate output integrated over DIM logical :: collapse(ndim) !> Save output of type N on times tsave(:, N) double precision :: tsave(nsavehi,nfile) double precision :: tsavelast(nfile) !> Repeatedly save output of type N when dtsave(N) simulation time has passed double precision :: dtsave(nfile) !> Save output of type N on iterations itsave(:, N) integer :: itsave(nsavehi,nfile) integer :: itsavelast(nfile) !> Repeatedly save output of type N when ditsave(N) time steps have passed integer :: ditsave(nfile) integer :: isavet(nfile) integer :: isaveit(nfile) !> Start of read out (not counting specified read outs) double precision :: tsavestart(nfile) !> The level at which to produce line-integrated / collapsed output integer :: collapseLevel !> Number of saved files of each type integer :: n_saves(1:nfile) !> whether or not to save an output file logical :: save_file(nfile) !> to monitor timeintegration loop at given wall-clock time intervals double precision :: time_between_print !> accumulated wall-clock time spent on boundary conditions double precision :: time_bc !> IO: snapshot and collapsed views output numbers/labels integer :: snapshotnext, collapsenext !> IO: slice output numbers/labels integer :: slicenext !> Constant indicating log output integer, parameter :: filelog_ = 1 !> Constant indicating regular output integer, parameter :: fileout_ = 2 !> Constant indicating slice output integer, parameter :: fileslice_ = 3 !> Constant indicating collapsed output integer, parameter :: filecollapse_ = 4 !> Constant indicating analysis output (see @ref analysis.md) integer, parameter :: fileanalysis_ = 5 !> Unit for standard input integer, parameter :: unitstdin=5 !> Unit for standard output integer, parameter :: unitterm=6 !> Unit for error messages integer, parameter :: uniterr=6 !> file handle for IO integer, parameter :: unitpar=9 integer, parameter :: unitconvert=10 integer, parameter :: unitslice=11 integer, parameter :: unitsnapshot=12 integer, parameter :: unitcollapse=13 integer, parameter :: unitanalysis=14 !> Number of auxiliary variables that are only included in output integer :: nwauxio !> IO switches for conversion logical :: nocartesian logical, allocatable :: w_write(:) logical, allocatable :: writelevel(:) double precision :: writespshift(ndim,2) integer :: level_io, level_io_min, level_io_max, type_endian !> Which par files are used as input character(len=std_len), allocatable :: par_files(:) !> Base file name for simulation output, which will be followed by a number character(len=std_len) :: base_filename !> If not 'unavailable', resume from snapshot with this base file name character(len=std_len) :: restart_from_file !> Which type of log to write: 'normal', 'special', 'regression_test' character(len=std_len) :: typefilelog !> Resume from the snapshot with this index integer :: snapshotini !> If true, restart a previous run from the latest snapshot logical :: resume_previous_run !> If true and restart_from_file is given, convert snapshots to !> other file formats logical :: convert !> If true, already convert to output format during the run logical :: autoconvert !> If true, convert from conservative to primitive variables in output logical :: saveprim !> Which format to use when converting !> !> Options are: tecplot, tecplotCC, vtu, vtuCC, vtuB, vtuBCC, !> tecplotmpi, tecplotCCmpi, vtumpi, vtuCCmpi, vtuBmpi, vtuBCCmpi, pvtumpi, pvtuCCmpi, !> pvtuBmpi, pvtuBCCmpi, tecline, teclinempi, onegrid character(len=std_len) :: convert_type character(len=std_len) :: collapse_type !> Conversion factors the primitive variables double precision, allocatable :: w_convert_factor(:) double precision :: length_convert_factor !> Conversion factor for time unit double precision :: time_convert_factor !> Stores the memory and load imbalance, used in printlog double precision :: Xload, Xmemory !> Save a snapshot before crash a run met unphysical values logical :: crash=.false. !> type of physics to build character(len=std_len) :: phys !> coordinate system to build for: 'Cartesian', 'spherical', 'cylindrical', !> or the logarithmic-radius variants 'logSpherical'/'logCylindrical' (which !> emit GEOM='spherical'/'cylindrical' plus the LOG_RADIUS flag). !> Read from &meshlist and turned into the GEOM fypp define by the config !> system; must be consistent with the set_coordinate_system call in mod_usr. character(len=std_len) :: geometry='Cartesian' ! Physics factors !> Physical scaling factor for length double precision :: unit_length=1.d0 !> Physical scaling factor for time double precision :: unit_time=1.d0 !> Physical scaling factor for density double precision :: unit_density=1.d0 !> Physical scaling factor for velocity double precision :: unit_velocity=1.d0 !> Physical scaling factor for temperature double precision :: unit_temperature=1.d0 !> Physical scaling factor for pressure double precision :: unit_pressure=1.d0 !> Physical scaling factor for magnetic field double precision :: unit_magneticfield=1.d0 !> Physical scaling factor for number density double precision :: unit_numberdensity=1.d0 !> Physical scaling factor for charge double precision :: unit_charge=1.d0 !> Physical scaling factor for mass double precision :: unit_mass=1.d0 !> Normalised speed of light double precision :: c_norm=1.d0 !> Physical scaling factor for Opacity double precision :: unit_opacity=1.d0 !> Physical scaling factor for radiation flux double precision :: unit_radflux=1.d0 !> amplitude of background dipolar, quadrupolar, octupolar, user's field double precision :: Bdip=0.d0 double precision :: Bquad=0.d0 double precision :: Boct=0.d0 double precision :: Busr=0.d0 !> split magnetic field as background B0 field ! TODO these should be moved in a different file logical :: B0field=.false. logical :: B0fieldAllocCoarse=.false. ! number of equilibrium set variables, besides the mag field integer :: number_equi_vars = 0 !> Use SI units (.true.) or use cgs units (.false.) logical :: SI_unit=.false. !> Use TRAC (Johnston 2019 ApJL, 873, L22) for MHD or 1D HD logical :: phys_trac=.false. integer :: phys_trac_type=1 double precision :: phys_trac_mask !> Use particles module or not logical :: use_particles=.false. !> Use multigrid (only available in 2D and 3D) logical :: use_multigrid = .false. ! AMR switches !> The maximum number of grid blocks in a processor integer :: max_blocks=4000 !> The maximum number of levels in the grid refinement integer, parameter :: nlevelshi = 20 !> Maximal number of AMR levels integer :: refine_max_level !> Specify to use user-defined refinement criterion logical :: refine_usr = .false. !> Weights of variables used to calculate error for mesh refinement double precision, allocatable :: w_refine_weight(:) !> Fix the AMR grid after this time double precision :: tfixgrid !> Whether to apply flux conservation at refinement boundaries logical :: fix_conserve_global = .true. !> Fix the AMR grid after this many time steps integer :: itfixgrid !> Reconstruct the AMR grid once every ditregrid iteration(s) integer :: ditregrid !> refinement: lohner estimate wavefilter setting double precision, allocatable :: amr_wavefilter(:) integer :: refine_criterion logical :: prolongprimitive=.false. logical :: coarsenprimitive=.false. !> Error tolerance for refinement decision double precision, allocatable :: refine_threshold(:) double precision, allocatable :: derefine_ratio(:) !> If true, rebuild the AMR grid upon restarting logical :: reset_grid !> True for using stagger grid logical :: stagger_grid=.false. !> True for record electric field logical :: record_electric_field=.false. !> Number of cells as buffer zone integer :: nbufferx1,nbufferx2,nbufferx3 integer :: levmin integer :: levmax integer :: levmax_sub ! Miscellaneous !> problem switch allowing different setups in same usr_mod.t integer :: iprob !> Kronecker delta tensor integer :: kr(3,3) !> Levi-Civita tensor integer :: lvc(3,3,3) ! Time integration aspects double precision :: dt logical :: time_advance !> The Courant (CFL) number used for the simulation double precision :: courantpar !> How to compute the CFL-limited time step integer :: type_courant=1 !> integer switchers for type courant integer, parameter :: type_maxsum=1 integer, parameter :: type_summax=2 integer, parameter :: type_minimum=3 !> If dtpar is positive, it sets the timestep dt, otherwise courantpar is used !> to limit the time step based on the Courant condition. double precision :: dtpar !> For resistive MHD, the time step is also limited by the diffusion time: !> \f$ dt < dtdiffpar \times dx^2/eta \f$ double precision :: dtdiffpar !> The global simulation time double precision :: global_time !> Start time for the simulation double precision :: time_init !> End time for the simulation double precision :: time_max !> Ending wall time (in hours) for the simulation double precision :: wall_time_max !> Stop the simulation when the time step becomes smaller than this value double precision :: dtmin !> Force timeloop exit when final dt < dtmin logical :: final_dt_exit !> If true, reset iteration count and global_time to original values, and !> start writing snapshots at index 0 logical :: reset_time !> If true, reset iteration count to 0 logical :: reset_it !> If true, allow final dt reduction for matching time_max on output logical :: final_dt_reduction !> If true, call initonegrid_usr upon restarting logical :: firstprocess !> If true, wall time is up, modify snapshotnext for later overwrite logical :: pass_wall_time !> If true, do H-correction to fix the carbuncle problem at grid-aligned shocks logical :: H_correction=.false. !> Number of time steps taken integer :: it !> Stop the simulation after this many time steps have been taken integer :: it_max !> initial iteration count integer :: it_init !> If > 1, then in the first slowsteps-1 time steps dt is reduced !> by a factor \f$ 1 - (1- step/slowsteps)^2 \f$ integer :: slowsteps ! Method switches !> Index of the sub-step in a multi-step time integrator integer :: istep !> How many sub-steps the time integrator takes integer :: nstep !> Which flux scheme of spatial discretization to use (per grid level) integer, allocatable :: flux_method(:) !> flux schemes integer, parameter :: fs_hll=1 integer, parameter :: fs_hllc=2 integer, parameter :: fs_tvdlf=5 !> Adaptive LLF diffusion (Rempel et al. 2009): phi in [flux_ad_min, 1] per face per variable logical :: flux_adaptive_diffusion = .false. double precision :: flux_ad_min = 0.0d0 double precision :: flux_ad_scale = 1.0d0 !> time stepper type integer :: t_stepper=0 integer, parameter :: onestep=1 integer, parameter :: twostep=2 integer, parameter :: threestep=3 integer, parameter :: fourstep=4 integer, parameter :: fivestep=5 !> time integrator method integer :: t_integrator=0 integer, parameter :: Forward_Euler=1 integer, parameter :: Predictor_Corrector=2 integer, parameter :: ssprk3=3 integer, parameter :: ssprk4=4 integer, parameter :: ssprk5=5 integer, parameter :: IMEX_Euler=6 integer, parameter :: IMEX_SP=7 integer, parameter :: RK2_alf=8 integer, parameter :: ssprk2=9 integer, parameter :: IMEX_Midpoint=10 integer, parameter :: IMEX_Trapezoidal=11 integer, parameter :: IMEX_222=12 integer, parameter :: RK3_BT=13 integer, parameter :: IMEX_ARS3=14 integer, parameter :: IMEX_232=15 integer, parameter :: IMEX_CB3a=16 integer, parameter :: rk4=17 !> Type of slope limiter used for reconstructing variables on cell edges integer, allocatable :: type_limiter(:) !> Type of slope limiter used for computing gradients or divergences, when !> typegrad or typediv are set to 'limited' integer, allocatable :: type_gradient_limiter(:) !> background magnetic field location indicator integer :: b0i=0 !> Limiter used for prolongation to refined grids and ghost cells integer :: prolong_limiter=0 character(len=std_len) :: typedimsplit character(len=std_len) :: geometry_name='default' character(len=std_len) :: typepoly logical, allocatable :: loglimit(:), logflag(:) logical :: flatcd,flatsh !> Use split or unsplit way to add user's source terms, default: unsplit logical :: source_split_usr !> if any normal source term is added in split fasion logical :: any_source_split=.false. logical :: dimsplit !> RK2(alfa) method parameters from Butcher tableau double precision :: rk_a21,rk_b1,rk_b2 !> IMEX-222(lambda) one-parameter family of schemes double precision :: imex222_lambda !> SSPRK choice of methods (both threestep and fourstep, Shu-Osher 2N* implementation) !> also fivestep SSPRK54 integer :: ssprk_order double precision :: rk_beta11,rk_beta22,rk_beta33,rk_beta44,& rk_c2,rk_c3,rk_c4 double precision :: rk_alfa21,rk_alfa22,rk_alfa31,rk_alfa33,& rk_alfa41,rk_alfa44 double precision :: rk_beta54,rk_beta55,rk_alfa53,rk_alfa54,& rk_alfa55,rk_c5 !> RK3 Butcher table integer :: rk3_switch double precision :: rk3_a21,rk3_a31,rk3_a32,rk3_b1,rk3_b2,& rk3_b3,rk3_c2,rk3_c3 !> IMEX_ARS3 parameter ars_gamma double precision :: ars_gamma !> IMEX_232 choice and parameters integer :: imex_switch double precision :: imex_a21,imex_a31,imex_a32,imex_b1,imex_b2,& imex_ha21,imex_ha22 double precision :: imex_b3,imex_c2,imex_c3 !> IMEX_CB3a extra parameters double precision :: imex_a22, imex_a33, imex_ha32 !> whether IMEX in use or not logical :: use_imex_scheme character(len=std_len) :: typediv,typegrad !> global fastest wave speed needed in fd scheme and glm method double precision :: cmax_global !> global largest a2 for schmid scheme double precision :: a2max_global(ndim) !> need global maximal wave speed logical :: need_global_cmax=.false. !> global value for schmid scheme logical :: need_global_a2max=.false. ! Boundary region parameters !> True for dimensions with periodic boundaries logical :: periodB(ndim) !> Indicates whether there is a pole at a boundary logical :: poleB(2,ndim) !> True where the parameter file asked for typeboundary='pole' on a face. !> Kept separately from poleB because the two are decided independently and !> at different times - read_par_files expands the 'pole' string into !> symm/asymm entries and loses it, while set_pole derives poleB from the !> domain bounds much later - and check_pole_setup has to be able to tell !> the user when they disagree. logical :: poleB_requested(2,ndim) = .false. !> True for dimensions with aperiodic boundaries logical :: aperiodB(ndim) !> True for save physical boundary cells in dat files logical :: save_physical_boundary !> True if a block has any physical boundary logical, allocatable :: phyboundblock(:) !> Array indicating the type of boundary condition per variable and per !> physical boundary integer, allocatable :: typeboundary(:, :) !> boundary condition types integer, parameter :: bc_special=1 integer, parameter :: bc_cont=2 integer, parameter :: bc_symm=3 integer, parameter :: bc_asymm=4 integer, parameter :: bc_periodic=5 integer, parameter :: bc_aperiodic=6 integer, parameter :: bc_noinflow=7 integer, parameter :: bc_data=8 integer, parameter :: bc_character=9 integer, parameter :: bc_icarus=10 !> signal to the precompiler that we need special boundaries: logical :: specialboundary = .false. !> whether copy values instead of interpolation in ghost cells of finer blocks logical :: ghost_copy=.false. !> if there is an internal boundary logical :: internalboundary !> Base file name for synthetic EUV emission output character(len=std_len) :: filename_euv !> wavelength for output integer :: wavelength !> times for enhancing spatial resolution for EUV image/spectra double precision :: instrument_resolution_factor !> use arcsec as length unit of images/spectra logical :: activate_unit_arcsec !> Base file name for synthetic SXR emission output character(len=std_len) :: filename_sxr ! minimum and maximum energy of SXR (keV) integer :: emin_sxr,emax_sxr !> Base file name for synthetic white light character(len=std_len) :: filename_whitelight !> white light observation instrument character(len=std_len) :: whitelight_instrument !> the white light emission below it (unit=Rsun) is not visible double precision :: R_occultor !> direction of the line of sight (LOS) double precision :: LOS_theta,LOS_phi !> rotation of image double precision :: image_rotate !> where the is the origin (X=0,Y=0) of image double precision :: x_origin(1:3) !> big image logical :: big_image !> Base file name for synthetic EUV spectrum output character(len=std_len) :: filename_spectrum !> wave length for spectrum integer :: spectrum_wl !> spectral window double precision :: spectrum_window_min,spectrum_window_max !> location of the slit double precision :: location_slit !> direction of the slit (for dat resolution only) integer :: direction_slit !> for spherical coordinate, region below it (unit=Rsun) is treated as not transparent double precision :: R_opt_thick !> resolution of the images logical :: dat_resolution !> Block pointer for using one block and its previous state type(state), pointer :: block contains !> Cross product of two vectors pure subroutine cross_product(ixImin1,ixImin2,ixImin3,ixImax1,ixImax2,& ixImax3,ixOmin1,ixOmin2,ixOmin3,ixOmax1,ixOmax2,ixOmax3,a,b,axb) integer, intent(in) :: ixImin1,ixImin2,ixImin3,ixImax1,ixImax2,ixImax3,& ixOmin1,ixOmin2,ixOmin3,ixOmax1,ixOmax2,ixOmax3 double precision, intent(in) :: a(ixImin1:ixImax1,ixImin2:ixImax2,& ixImin3:ixImax3,3), b(ixImin1:ixImax1,ixImin2:ixImax2,ixImin3:ixImax3,& 3) double precision, intent(out) :: axb(ixImin1:ixImax1,ixImin2:ixImax2,& ixImin3:ixImax3,3) axb(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,1)=a(ixOmin1:ixOmax1,& ixOmin2:ixOmax2,ixOmin3:ixOmax3,2)*b(ixOmin1:ixOmax1,ixOmin2:ixOmax2,& ixOmin3:ixOmax3,3)-a(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,& 3)*b(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,2) axb(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,2)=a(ixOmin1:ixOmax1,& ixOmin2:ixOmax2,ixOmin3:ixOmax3,3)*b(ixOmin1:ixOmax1,ixOmin2:ixOmax2,& ixOmin3:ixOmax3,1)-a(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,& 1)*b(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,3) axb(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,3)=a(ixOmin1:ixOmax1,& ixOmin2:ixOmax2,ixOmin3:ixOmax3,1)*b(ixOmin1:ixOmax1,ixOmin2:ixOmax2,& ixOmin3:ixOmax3,2)-a(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,& 2)*b(ixOmin1:ixOmax1,ixOmin2:ixOmax2,ixOmin3:ixOmax3,1) end subroutine cross_product end module mod_global_parameters