!! The CARMA module contains an interface to the Community Aerosol and Radiation !! Model for Atmospheres (CARMA) bin microphysical model [Turco et al. 1979; !! Toon et al. 1988]. This implementation has been customized to work within !! other model frameworks, so although it can be provided with an array of !! columns, it does not do horizontal transport and just does independent 1-D !! calculations upon each column. !! !! The typical usage for the CARMA and CARMASTATE objects within a model would be: !!> !! ! This first section of code is done during the parent model's initialzation, !! ! and there should be a unique CARMA object created for each thread of !! ! execution. !! !! ! Create the CARMA object. !! call CARMA_Create(carma, ...) !! !! ! Define the microphysical components. !! call CARMAGROUP_Create(carma, ...) ! One or more calls !! !! call CARMAELEMENT_Create(carma, ...) ! One or more calls !! !! call CARMASOLUTE_Create(carma, ...) ! Zero or more calls !! !! call CARMAGAS_Create(carma, ...) ! Zero or more calls !! !! ! Define the relationships for the microphysical processes. !! call CARMA_AddCoagulation(carma, ...) ! Zero or more calls !! call CARMA_AddGrowth(carma, ...) ! Zero or more calls !! call CARMA_AddNucleation(carma, ...) ! Zero or more calls !! !! ! Initialize things that are state and timestep independent. !! call CARMA_Initialize(carma, ...) !! !! ... !! !! ! This section of code is within the parent model's timing loop. !! ! !! ! NOTE: If using OPEN/MP, then each thread will execute one of !! ! of these loops per column of data. To avoid having to destroy !! ! the CARMASTATE object, a pool of CARMASTATE objects could be !! ! created so that there is one per thread and then the !! ! CARMA_Destroy() could be called after all columns have been !! ! processed. !! !! ! Initialize CARMA for this model state and timestep. !! call CARMASTATE_Create(cstate, carma, ...) !! !! ! Set the model state for each bin and gas. !! call CARMASTATE_SetBin(cstate, ...) ! One call for each bin !! call CARMASTATE_SetGas(cstate, ...) ! One call for each gas !! !! ! Calculate the new state !! call CARMASTATE_Step(cstate, ...) !! !! ! Get the results to return back to the parent model. !! call CARMASTATE_GetBin(cstate, ...) ! One call for each Bin !! call CARMASTATE_GetGas(cstate, ...) ! One call for each gas !! call CARMASTATE_GetState(cstate, ...) ! Zero or one calls !! !! ! (optional) Deallocate arrays that are not needed beyond this timestep. !! call CARMASTATE_Destroy(cstate) !! !! ... !! !! ! This section of code is done during the parent model's cleanup. !! !! ! Deallocate all arrays. !! call CARMA_Destroy(carma) !!< !! !! @version Feb-2009 !! @author Chuck Bardeen, Pete Colarco, Jamie Smith ! ! NOTE: Documentation for this code can be generated automatically using f90doc, ! which is freely available from: ! http://erikdemaine.org/software/f90doc/ ! Comment lines with double comment characters are processed by f90doc, and there are ! some special characters added to the comments to control the documentation process. ! In addition to the special characters mentioned in the f990doc documentation, html ! formatting tags (e.g. , , ...) can also be added to the f90doc ! comments. module carma_mod ! This module maps the parents models constants into the constants need by CARMA. NOTE: CARMA ! constants are in CGS units, while the parent models are typically in MKS units. use carma_precision_mod use carma_enums_mod use carma_constants_mod use carma_types_mod ! CARMA explicitly declares all variables. implicit none ! All CARMA variables and procedures are private except those explicitly declared to be public. private ! Declare the public methods. public CARMA_AddCoagulation public CARMA_AddGrowth public CARMA_AddNucleation public CARMA_Create public CARMA_Destroy public CARMA_Get public CARMA_Initialize contains ! These are the methods that provide the interface between the parent model and the CARMA ! microphysical model. There are many other methods that are not in this file that are ! used to implement the microphysical calculations needed by the CARMA model. These other ! methods are in effect private methods of the CARMA module, but are in individual files ! since that is the way that CARMA has traditionally been structured and where users may ! want to extend or replace code to affect the microphysics. !! Creates the CARMA object and allocates arrays to store configuration information !! that will follow from the CARMA_AddXXX() methods. When the CARMA object is no longer !! needed, the CARMA_Destroy() method should be used to clean up any allocations !! that have happened. If LUNOPRT is specified, then the logical unit should be open and !! ready for output. The caller is responsible for closing the LUNOPRT logical unit !! after the CARMA object has been destroyed. !! !! @version Feb-2009 !! @author Chuck Bardeen subroutine CARMA_Create(carma, NBIN, NELEM, NGROUP, NSOLUTE, NGAS, NWAVE, rc, & LUNOPRT, wave, dwave, do_wave_emit) type(carma_type), intent(out) :: carma !! the carma object integer, intent(in) :: NBIN !! number of radius bins per group integer, intent(in) :: NELEM !! total number of elements integer, intent(in) :: NGROUP !! total number of groups integer, intent(in) :: NSOLUTE !! total number of solutes integer, intent(in) :: NGAS !! total number of gases integer, intent(in) :: NWAVE !! number of wavelengths integer, intent(out) :: rc !! return code, negative indicates failure integer, intent(in), optional :: LUNOPRT !! logical unit number for output real(kind=f), intent(in), optional :: wave(NWAVE) !! wavelength centers (cm) real(kind=f), intent(in), optional :: dwave(NWAVE) !! wavelength width (cm) logical, intent(in), optional :: do_wave_emit(NWAVE) !! do emission in band? ! Local Varaibles integer :: ier ! Assume success. rc = RC_OK ! Save off the logic unit used for output if one was provided. If one was provided, ! then assume that CARMA can print output. if (present(LUNOPRT)) then carma%f_LUNOPRT = LUNOPRT carma%f_do_print = .TRUE. end if ! Save the defintion of the number of comonents involved in the microphysics. carma%f_NGROUP = NGROUP carma%f_NELEM = NELEM carma%f_NBIN = NBIN carma%f_NGAS = NGAS carma%f_NSOLUTE = NSOLUTE carma%f_NWAVE = NWAVE ! Allocate tables for the groups. allocate( & carma%f_group(NGROUP), & carma%f_icoag(NGROUP, NGROUP), & carma%f_inucgas(NGROUP), & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Create: ERROR allocating groups, NGROUP=", & carma%f_NGROUP, ", status=", ier rc = RC_ERROR return endif ! Initialize carma%f_icoag(:, :) = 0 carma%f_inucgas(:) = 0 ! Allocate tables for the elements. allocate( & carma%f_element(NELEM), & carma%f_igrowgas(NELEM), & carma%f_inuc2elem(NELEM, NELEM), & carma%f_inucproc(NELEM, NELEM), & carma%f_ievp2elem(NELEM), & carma%f_nnuc2elem(NELEM), & carma%f_nnucelem(NELEM), & carma%f_inucelem(NELEM,NELEM*NGROUP), & carma%f_if_nuc(NELEM,NELEM), & carma%f_rlh_nuc(NELEM, NELEM), & carma%f_icoagelem(NELEM, NGROUP), & carma%f_icoagelem_cm(NELEM, NGROUP), & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Create: ERROR allocating elements, NELEM=", & carma%f_NELEM, ", status=", ier rc = RC_ERROR return endif ! Initialize carma%f_igrowgas(:) = 0 carma%f_inuc2elem(:,:) = 0 carma%f_inucproc(:,:) = 0 carma%f_ievp2elem(:) = 0 carma%f_nnuc2elem(:) = 0 carma%f_nnucelem(:) = 0 carma%f_inucelem(:,:) = 0 carma%f_if_nuc(:,:) = .FALSE. carma%f_rlh_nuc(:,:) = 0._f carma%f_icoagelem(:,:) = 0 carma%f_icoagelem_cm(:,:) = 0 ! Allocate tables for the bins. allocate( & carma%f_inuc2bin(NBIN,NGROUP,NGROUP), & carma%f_ievp2bin(NBIN,NGROUP,NGROUP), & carma%f_nnucbin(NGROUP,NBIN,NGROUP), & carma%f_inucbin(NBIN*NGROUP,NGROUP,NBIN,NGROUP), & carma%f_diffmass(NBIN, NGROUP, NBIN, NGROUP), & carma%f_volx(NGROUP,NGROUP,NGROUP,NBIN,NBIN), & carma%f_ilow(NGROUP,NBIN,NBIN*NBIN), & carma%f_jlow(NGROUP,NBIN,NBIN*NBIN), & carma%f_iup(NGROUP,NBIN,NBIN*NBIN), & carma%f_jup(NGROUP,NBIN,NBIN*NBIN), & carma%f_npairl(NGROUP,NBIN), & carma%f_npairu(NGROUP,NBIN), & carma%f_iglow(NGROUP,NBIN,NBIN*NBIN), & carma%f_jglow(NGROUP,NBIN,NBIN*NBIN), & carma%f_igup(NGROUP,NBIN,NBIN*NBIN), & carma%f_jgup(NGROUP,NBIN,NBIN*NBIN), & carma%f_kbin(NGROUP,NGROUP,NGROUP,NBIN,NBIN), & carma%f_pkernel(NBIN,NBIN,NGROUP,NGROUP,NGROUP,6), & carma%f_pratt(3,NBIN,NGROUP), & carma%f_prat(4,NBIN,NGROUP), & carma%f_pden1(NBIN,NGROUP), & carma%f_palr(4,NGROUP), & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Create: ERROR allocating bins, NBIN=", & carma%f_NBIN, ", status=", ier rc = RC_ERROR return endif ! Initialize carma%f_inuc2bin(:,:,:) = 0 carma%f_ievp2bin(:,:,:) = 0 carma%f_nnucbin(:,:,:) = 0 carma%f_inucbin(:,:,:,:) = 0 carma%f_diffmass(:, :, :, :) = 0._f carma%f_volx(:,:,:,:,:) = 0._f carma%f_ilow(:,:,:) = 0 carma%f_jlow(:,:,:) = 0 carma%f_iup(:,:,:) = 0 carma%f_jup(:,:,:) = 0 carma%f_npairl(:,:) = 0 carma%f_npairu(:,:) = 0 carma%f_iglow(:,:,:) = 0 carma%f_jglow(:,:,:) = 0 carma%f_igup(:,:,:) = 0 carma%f_jgup(:,:,:) = 0 carma%f_kbin(:,:,:,:,:) = 0._f carma%f_pkernel(:,:,:,:,:,:) = 0._f carma%f_pratt(:,:,:) = 0._f carma%f_prat(:,:,:) = 0._f carma%f_pden1(:,:) = 0._f carma%f_palr(:,:) = 0._f ! Allocate tables for solutes, if any are needed. if (NSOLUTE > 0) then allocate( & carma%f_solute(NSOLUTE), & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Create: ERROR allocating solutes, NSOLUTE=", & carma%f_NSOLUTE, ", status=", ier rc = RC_ERROR return endif end if ! Allocate tables for gases, if any are needed. if (NGAS > 0) then allocate( & carma%f_gas(NGAS), & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Create: ERROR allocating gases, NGAS=", & carma%f_NGAS, ", status=", ier rc = RC_ERROR return endif end if ! Allocate tables for optical properties, if any are needed. if (NWAVE > 0) then allocate( & carma%f_wave(NWAVE), & carma%f_dwave(NWAVE), & carma%f_do_wave_emit(NWAVE), & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Create: ERROR allocating wavelengths, NWAVE=", & carma%f_NWAVE, ", status=", ier rc = RC_ERROR return endif ! Initialize carma%f_do_wave_emit(:) = .TRUE. if (present(wave)) carma%f_wave(:) = wave(:) if (present(dwave)) carma%f_dwave(:) = dwave(:) if (present(do_wave_emit)) carma%f_do_wave_emit(:) = do_wave_emit(:) end if return end subroutine CARMA_Create !! Called after the CARMA object has been created and the microphysics description has been !! configured. The optional flags control which microphysical processes are enabled and all of !! them default to FALSE. For a microphysical process to be active it must have been both !! configured (using a CARMA_AddXXX() method) and enabled here. !! !! NOTE: After initialization, the structure of the particle size bins is determined, and !! the resulting r, dr, rmass and dm can be retrieved with the CARMA_GetGroup() method. !! !! @version Feb-2009 !! @author Chuck Bardeen subroutine CARMA_Initialize(carma, rc, do_cnst_rlh, do_coag, do_detrain, do_fixedinit, & do_grow, do_incloud, do_explised, do_print_init, do_substep, do_thermo, do_vdiff, & do_vtran, do_drydep, vf_const, minsubsteps, maxsubsteps, maxretries, conmax, & do_pheat, do_pheatatm, dt_threshold, cstick, gsticki, gstickl, tstick, do_clearsky) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure logical, intent(in), optional :: do_cnst_rlh !! use constant values for latent heats (instead of varying with temperature)? logical, intent(in), optional :: do_coag !! do coagulation? logical, intent(in), optional :: do_detrain !! do detrainement? logical, intent(in), optional :: do_fixedinit !! do initialization from reference atm? logical, intent(in), optional :: do_grow !! do nucleation, growth and evaporation? logical, intent(in), optional :: do_incloud !! do incloud growth and coagulation? logical, intent(in), optional :: do_explised !! do sedimentation with substepping logical, intent(in), optional :: do_substep !! do substepping logical, intent(in), optional :: do_print_init !! do prinit initializtion information logical, intent(in), optional :: do_thermo !! do thermodynamics logical, intent(in), optional :: do_vdiff !! do Brownian diffusion logical, intent(in), optional :: do_vtran !! do sedimentation logical, intent(in), optional :: do_drydep !! do dry deposition real(kind=f), intent(in), optional :: vf_const !! if specified and non-zero, constant fall velocity for all particles [cm/s] integer, intent(in), optional :: minsubsteps !! minimum number of substeps, default = 1 integer, intent(in), optional :: maxsubsteps !! maximum number of substeps, default = 1 integer, intent(in), optional :: maxretries !! maximum number of substep retries, default = 5 real(kind=f), intent(in), optional :: conmax !! minimum relative concentration to consider, default = 1e-1 logical, intent(in), optional :: do_pheat !! do particle heating logical, intent(in), optional :: do_pheatatm !! do particle heating of atmosphere real(kind=f), intent(in), optional :: dt_threshold !! convergence criteria for temperature [fraction] real(kind=f), intent(in), optional :: cstick !! accommodation coefficient - coagulation, default = 1.0 real(kind=f), intent(in), optional :: gsticki !! accommodation coefficient - growth (ice), default = 0.93 real(kind=f), intent(in), optional :: gstickl !! accommodation coefficient - growth (liquid), default = 1.0 real(kind=f), intent(in), optional :: tstick !! accommodation coefficient - temperature, default = 1.0 logical, intent(in), optional :: do_clearsky !! do clear sky growth and coagulation? ! Assume success. rc = RC_OK ! Set default values for control flags. carma%f_do_cnst_rlh = .FALSE. carma%f_do_coag = .FALSE. carma%f_do_detrain = .FALSE. carma%f_do_fixedinit = .FALSE. carma%f_do_grow = .FALSE. carma%f_do_incloud = .FALSE. carma%f_do_explised = .FALSE. carma%f_do_pheat = .FALSE. carma%f_do_pheatatm = .FALSE. carma%f_do_print_init = .FALSE. carma%f_do_substep = .FALSE. carma%f_do_thermo = .FALSE. carma%f_do_vdiff = .FALSE. carma%f_do_vtran = .FALSE. carma%f_do_drydep = .FALSE. carma%f_dt_threshold = 0._f carma%f_cstick = 1._f carma%f_gsticki = 0.93_f carma%f_gstickl = 1._f carma%f_tstick = 1._f carma%f_do_clearsky = .FALSE. ! Store off any control flag values that have been supplied. if (present(do_cnst_rlh)) carma%f_do_cnst_rlh = do_cnst_rlh if (present(do_coag)) carma%f_do_coag = do_coag if (present(do_detrain)) carma%f_do_detrain = do_detrain if (present(do_fixedinit)) carma%f_do_fixedinit = do_fixedinit if (present(do_grow)) carma%f_do_grow = do_grow if (present(do_incloud)) carma%f_do_incloud = do_incloud if (present(do_explised)) carma%f_do_explised = do_explised if (present(do_pheat)) carma%f_do_pheat = do_pheat if (present(do_pheatatm)) carma%f_do_pheatatm = do_pheatatm if (present(do_print_init)) carma%f_do_print_init = (do_print_init .and. carma%f_do_print) if (present(do_substep)) carma%f_do_substep = do_substep if (present(do_thermo)) carma%f_do_thermo = do_thermo if (present(do_vdiff)) carma%f_do_vdiff = do_vdiff if (present(do_vtran)) carma%f_do_vtran = do_vtran if (present(do_drydep)) carma%f_do_drydep = do_drydep if (present(dt_threshold)) carma%f_dt_threshold = dt_threshold if (present(cstick)) carma%f_cstick = cstick if (present(gsticki)) carma%f_gsticki = gsticki if (present(gstickl)) carma%f_gstickl = gstickl if (present(tstick)) carma%f_tstick = tstick if (present(do_clearsky)) carma%f_do_clearsky = do_clearsky ! Setup the bin structure. call setupbins(carma, rc) if (rc < 0) return ! Substepping carma%f_minsubsteps = 1 ! minimum number of substeps carma%f_maxsubsteps = 1 ! maximum number of substeps carma%f_maxretries = 1 ! maximum number of retries carma%f_conmax = 1.e-1_f if (present(minsubsteps)) carma%f_minsubsteps = minsubsteps if (present(maxsubsteps)) carma%f_maxsubsteps = maxsubsteps if (present(maxretries)) carma%f_maxretries = maxretries if (present(conmax)) carma%f_conmax = conmax carma%f_do_step = .TRUE. ! Calculate the Optical Properties call CARMA_InitializeOptics(carma, rc) if (rc < 0) return ! If any of the processes have initialization that can be done without the state ! information, then perform that now. This will mostly be checking the configuration ! and setting up any tables based upon the configuration. if (carma%f_do_vtran .or. carma%f_do_coag) then call CARMA_InitializeVertical(carma, rc, vf_const) if (rc < 0) return end if if (carma%f_do_coag) then call setupcoag(carma, rc) if (rc < 0) return end if if (carma%f_do_grow) then call CARMA_InitializeGrowth(carma, rc) if (rc < 0) return end if if (carma%f_do_thermo) then call CARMA_InitializeThermo(carma, rc) if (rc < 0) return end if return end subroutine CARMA_Initialize subroutine CARMA_InitializeGrowth(carma, rc) type(carma_type), intent(inout) :: carma integer, intent(out) :: rc ! Local Variables integer :: i logical :: bad_grid integer :: igroup ! group index integer :: igas ! gas index integer :: isol ! solute index integer :: ielem ! element index integer :: ibin ! bin index integer :: igfrom integer :: igto integer :: ibto integer :: ieto integer :: ifrom integer :: iefrom integer :: jefrom integer :: ip integer :: jcore integer :: iecore integer :: im integer :: jnucelem integer :: inuc2 integer :: neto integer :: jfrom integer :: j integer :: nnucb ! Define formats 1 format(a,': ',12i6) 2 format(/,a,': ',i6) 3 format(a,a) 4 format(a,': ',1pe12.3) 5 format(/,'Particle nucleation mapping arrays (setupnuc):') 7 format(/,'Warning: nucleation cannot occur from group',i3, & ' bin',i3,' into group',i3,' ( is zero)') ! Assume success. rc = RC_OK ! Compute radius-dependent terms used in PPM advection scheme do igroup = 1, carma%f_NGROUP do i = 2,carma%f_NBIN-1 carma%f_pratt(1,i,igroup) = carma%f_group(igroup)%f_dm(i) / & ( carma%f_group(igroup)%f_dm(i-1) + carma%f_group(igroup)%f_dm(i) + carma%f_group(igroup)%f_dm(i+1) ) carma%f_pratt(2,i,igroup) = ( 2._f*carma%f_group(igroup)%f_dm(i-1) + carma%f_group(igroup)%f_dm(i) ) / & ( carma%f_group(igroup)%f_dm(i+1) + carma%f_group(igroup)%f_dm(i) ) carma%f_pratt(3,i,igroup) = ( 2._f*carma%f_group(igroup)%f_dm(i+1) + carma%f_group(igroup)%f_dm(i) ) / & ( carma%f_group(igroup)%f_dm(i-1) + carma%f_group(igroup)%f_dm(i) ) enddo do i = 2,carma%f_NBIN-2 carma%f_prat(1,i,igroup) = carma%f_group(igroup)%f_dm(i) / & ( carma%f_group(igroup)%f_dm(i) + carma%f_group(igroup)%f_dm(i+1) ) carma%f_prat(2,i,igroup) = 2._f * carma%f_group(igroup)%f_dm(i+1) * carma%f_group(igroup)%f_dm(i) / & ( carma%f_group(igroup)%f_dm(i) + carma%f_group(igroup)%f_dm(i+1) ) carma%f_prat(3,i,igroup) = ( carma%f_group(igroup)%f_dm(i-1) + carma%f_group(igroup)%f_dm(i) ) / & ( 2._f*carma%f_group(igroup)%f_dm(i) + carma%f_group(igroup)%f_dm(i+1) ) carma%f_prat(4,i,igroup) = ( carma%f_group(igroup)%f_dm(i+2) + carma%f_group(igroup)%f_dm(i+1) ) / & ( 2._f*carma%f_group(igroup)%f_dm(i+1) + carma%f_group(igroup)%f_dm(i) ) carma%f_pden1(i,igroup) = carma%f_group(igroup)%f_dm(i-1) + carma%f_group(igroup)%f_dm(i) + & carma%f_group(igroup)%f_dm(i+1) + carma%f_group(igroup)%f_dm(i+2) enddo if( carma%f_NBIN .gt. 1 )then carma%f_palr(1,igroup) = & (carma%f_group(igroup)%f_rmassup(1)-carma%f_group(igroup)%f_rmass(1)) / & (carma%f_group(igroup)%f_rmass(2)-carma%f_group(igroup)%f_rmass(1)) carma%f_palr(2,igroup) = & (carma%f_group(igroup)%f_rmassup(1)/carma%f_group(igroup)%f_rmrat-carma%f_group(igroup)%f_rmass(1)) / & (carma%f_group(igroup)%f_rmass(2)-carma%f_group(igroup)%f_rmass(1)) carma%f_palr(3,igroup) = & (carma%f_group(igroup)%f_rmassup(carma%f_NBIN-1)-carma%f_group(igroup)%f_rmass(carma%f_NBIN-1)) & / (carma%f_group(igroup)%f_rmass(carma%f_NBIN)-carma%f_group(igroup)%f_rmass(carma%f_NBIN-1)) carma%f_palr(4,igroup) = & (carma%f_group(igroup)%f_rmassup(carma%f_NBIN)-carma%f_group(igroup)%f_rmass(carma%f_NBIN-1)) & / (carma%f_group(igroup)%f_rmass(carma%f_NBIN)-carma%f_group(igroup)%f_rmass(carma%f_NBIN-1)) endif end do ! Check the nucleation mapping. ! ! NOTE: This code was moved from setupnuc, because it is not dependent on the model's ! state. A small part of setupnuc which deals with scrit is state specific, and that was ! left in setupnuc. ! Bin mapping for nucleation : nucleation would transfer mass from particles ! in into target bin in group ! . The target bin is the smallest bin in the target size grid with ! mass exceeding that of nucleated particle. do igfrom = 1,carma%f_NGROUP ! nucleation source group do igto = 1,carma%f_NGROUP ! nucleation target group do ifrom = 1,carma%f_NBIN ! nucleation source bin carma%f_inuc2bin(ifrom,igfrom,igto) = 0 do ibto = carma%f_NBIN,1,-1 ! nucleation target bin if( carma%f_group(igto)%f_rmass(ibto) .ge. carma%f_group(igfrom)%f_rmass(ifrom) )then carma%f_inuc2bin(ifrom,igfrom,igto) = ibto endif enddo enddo enddo enddo ! Mappings for nucleation sources: ! ! is the number of particle elements that nucleate to ! particle element . ! ! are the particle elements that ! nucleate to particle element , where ! jefrom = 1,nnucelem(ielem). ! ! is true if nucleation transfers mass from element ! to element . ! ! is the number of particle bins that nucleate ! to particles in bin from group . ! ! are the particle bins ! that nucleate to particles in bin , where ! jfrom = 1,nnucbin(igfrom,ibin,igto). ! ! ! First, calculate and ! based on do iefrom = 1,carma%f_NELEM do ieto = 1,carma%f_NELEM carma%f_if_nuc(iefrom,ieto) = .false. enddo enddo do ielem = 1,carma%f_NELEM carma%f_nnuc2elem(ielem) = 0 do jefrom = 1,carma%f_NGROUP if( carma%f_inuc2elem(jefrom,ielem) .ne. 0 ) then carma%f_nnuc2elem(ielem) = carma%f_nnuc2elem(ielem) + 1 carma%f_if_nuc(ielem,carma%f_inuc2elem(jefrom,ielem)) = .true. ! Also check for cases where neither the source or destinaton don't have cores (e.g. ! melting ice to water drops). if ((carma%f_group(carma%f_element(ielem)%f_igroup)%f_ncore .eq. 0) .and. & (carma%f_group(carma%f_element(carma%f_inuc2elem(jefrom,ielem))%f_igroup)%f_ncore .eq. 0)) then ! For particle concentration target elements, only count source elements ! that are also particle concentrations. carma%f_nnucelem(carma%f_inuc2elem(jefrom,ielem)) = carma%f_nnucelem(carma%f_inuc2elem(jefrom,ielem)) + 1 carma%f_inucelem(carma%f_nnucelem(carma%f_inuc2elem(jefrom,ielem)),carma%f_inuc2elem(jefrom,ielem)) = ielem end if endif enddo enddo ! Next, enumerate and count elements that nucleate to cores. do igroup = 1,carma%f_NGROUP ip = carma%f_group(igroup)%f_ienconc ! target particle number concentration element do jcore = 1,carma%f_group(igroup)%f_ncore iecore = carma%f_group(igroup)%f_icorelem(jcore) ! target core element ! carma%f_nnucelem(iecore) = 0 do iefrom = 1,carma%f_NELEM if( carma%f_if_nuc(iefrom,iecore) ) then carma%f_nnucelem(iecore) = carma%f_nnucelem(iecore) + 1 carma%f_inucelem(carma%f_nnucelem(iecore),iecore) = iefrom endif enddo ! iefrom=1,NELEM enddo ! jcore=1,ncore enddo ! igroup=1,NGROUP ! Now enumerate and count elements nucleating to particle concentration ! (itype=I_INVOLATILE and itype=I_VOLATILE) and core second moment ! (itype=I_COREMASS). Elements with itype = I_VOLATILE are special because all ! nucleation sources for core elements in same group are also sources ! for the itype = I_VOLATILE element. do igroup = 1,carma%f_NGROUP ip = carma%f_group(igroup)%f_ienconc ! target particle number concentration element im = carma%f_group(igroup)%f_imomelem ! target core second moment element ! carma%f_nnucelem(ip) = 0 ! if( im .ne. 0 )then ! carma%f_nnucelem(im) = 0 ! endif do jcore = 1,carma%f_group(igroup)%f_ncore iecore = carma%f_group(igroup)%f_icorelem(jcore) ! target core mass element do jnucelem = 1,carma%f_nnucelem(iecore) ! elements nucleating to cores iefrom = carma%f_inucelem(jnucelem,iecore) ! source ! For particle concentration target elements, only count source elements ! that are also particle concentrations. carma%f_nnucelem(ip) = carma%f_nnucelem(ip) + 1 carma%f_inucelem(carma%f_nnucelem(ip),ip) = carma%f_group(carma%f_element(iefrom)%f_igroup)%f_ienconc if( im .ne. 0 )then carma%f_nnucelem(im) = carma%f_nnucelem(im) + 1 carma%f_inucelem(carma%f_nnucelem(im),im) = iefrom endif enddo enddo ! jcore=1,ncore enddo ! igroup=1,NGROUP ! Now enumerate and count nucleating bins. do igroup = 1,carma%f_NGROUP ! target group do ibin = 1,carma%f_NBIN ! target bin do igfrom = 1,carma%f_NGROUP ! source group carma%f_nnucbin(igfrom,ibin,igroup) = 0 do ifrom = 1,carma%f_NBIN ! source bin if( carma%f_inuc2bin(ifrom,igfrom,igroup) .eq. ibin ) then carma%f_nnucbin(igfrom,ibin,igroup) = carma%f_nnucbin(igfrom,ibin,igroup) + 1 carma%f_inucbin(carma%f_nnucbin(igfrom,ibin,igroup),igfrom,ibin,igroup) = ifrom endif enddo enddo ! igfrom=1,NGROUP enddo ! ibin=1,NBIN=1,NGROUP enddo ! igroup=1,NGROUP if (carma%f_do_print_init) then ! Report nucleation mapping arrays (should be 'write' stmts, of course) write(carma%f_LUNOPRT,*) ' ' write(carma%f_LUNOPRT,*) 'Nucleation mapping arrays (setupnuc):' write(carma%f_LUNOPRT,*) ' ' write(carma%f_LUNOPRT,*) 'Elements mapping:' do ielem = 1,carma%f_NELEM write(carma%f_LUNOPRT,*) 'ielem,nnucelem=',ielem,carma%f_nnucelem(ielem) if(carma%f_nnucelem(ielem) .gt. 0) then do jfrom = 1,carma%f_nnucelem(ielem) write(carma%f_LUNOPRT,*) 'jfrom,inucelem= ',jfrom,carma%f_inucelem(jfrom,ielem) enddo endif enddo write(carma%f_LUNOPRT,*) ' ' write(carma%f_LUNOPRT,*) 'Bin mapping:' do igfrom = 1,carma%f_NGROUP do igroup = 1,carma%f_NGROUP write(carma%f_LUNOPRT,*) ' ' write(carma%f_LUNOPRT,*) 'Groups (from, to) = ', igfrom, igroup do ibin = 1,carma%f_NBIN nnucb = carma%f_nnucbin(igfrom,ibin,igroup) if(nnucb .eq. 0) write(carma%f_LUNOPRT,*) ' None for bin ',ibin if(nnucb .gt. 0) then write(carma%f_LUNOPRT,*) ' ibin,nnucbin=',ibin,nnucb write(carma%f_LUNOPRT,*) ' inucbin=',(carma%f_inucbin(j,igfrom,ibin,igroup),j=1,nnucb) endif enddo enddo enddo endif ! Check that values are valid. do ielem = 1, carma%f_NELEM if( carma%f_element(ielem)%f_isolute .gt. carma%f_NSOLUTE )then if (carma%f_do_print) write(carma%f_LUNOPRT,*) 'CARMA_InitializeGrowth::ERROR - component of isolute > NSOLUTE' rc = RC_ERROR return endif if( carma%f_ievp2elem(ielem) .gt. carma%f_NELEM )then if (carma%f_do_print) write(carma%f_LUNOPRT,*) 'CARMA_InitializeGrowth::ERROR - component of ievp2elem > NELEM' rc = RC_ERROR return endif ! Check that is consistent with . if( carma%f_ievp2elem(ielem) .ne. 0 .and. carma%f_element(ielem)%f_itype .eq. I_COREMASS )then if( carma%f_element(ielem)%f_isolute .ne. carma%f_element(carma%f_ievp2elem(ielem))%f_isolute)then if (carma%f_do_print) write(carma%f_LUNOPRT,*) 'CARMA_InitializeGrowth::ERROR - isolute and ievp2elem are inconsistent' rc = RC_ERROR return endif endif ! Check that is consistent with . igas = carma%f_inucgas( carma%f_element(ielem)%f_igroup ) if( igas .ne. 0 )then if( carma%f_element(ielem)%f_itype .eq. I_COREMASS .and. carma%f_element(ielem)%f_isolute .eq. 0 )then if (carma%f_do_print) write(carma%f_LUNOPRT,*) 'CARMA_InitializeGrowth::ERROR - inucgas ne 0 but isolute eq 0' rc = RC_ERROR return endif endif enddo do ielem = 1, carma%f_NELEM if( carma%f_nnuc2elem(ielem) .gt. 0 ) then do inuc2 = 1, carma%f_nnuc2elem(ielem) if( carma%f_inuc2elem(inuc2,ielem) .gt. carma%f_NELEM )then if (carma%f_do_print) write(carma%f_LUNOPRT,*) 'CARMA_InitializeGrowth::ERROR - component of inuc2elem > NELEM' rc = RC_ERROR return endif enddo endif enddo ! Particle grids are incompatible if there is no target bin with enough ! mass to accomodate nucleated particle. bad_grid = .false. do iefrom = 1,carma%f_NELEM ! source element igfrom = carma%f_element(iefrom)%f_igroup neto = carma%f_nnuc2elem(iefrom) if( neto .gt. 0 )then do inuc2 = 1,neto ieto = carma%f_inuc2elem(inuc2,iefrom) igto = carma%f_element(ieto)%f_igroup do ifrom = 1,carma%f_NBIN ! source bin if( carma%f_inuc2bin(ifrom,igfrom,igto) .eq. 0 )then if (carma%f_do_print) write(carma%f_LUNOPRT,7) igfrom,ifrom,igto bad_grid = .true. endif enddo enddo endif enddo if( bad_grid )then if (carma%f_do_print) write(carma%f_LUNOPRT,*) 'CARMA_InitializeGrowth::ERROR - incompatible grids for nucleation' rc = RC_ERROR return endif if (carma%f_do_print_init) then ! Report some initialization values! write(carma%f_LUNOPRT,5) write(carma%f_LUNOPRT,1) 'inucgas ',(carma%f_inucgas(i),i=1,carma%f_NGROUP) write(carma%f_LUNOPRT,1) 'inuc2elem',(carma%f_inuc2elem(1,i),i=1,carma%f_NELEM) write(carma%f_LUNOPRT,1) 'ievp2elem',(carma%f_ievp2elem(i),i=1,carma%f_NELEM) write(carma%f_LUNOPRT,1) 'isolute ',(carma%f_element(i)%f_isolute,i=1,carma%f_NELEM) do isol = 1,carma%f_NSOLUTE write(carma%f_LUNOPRT,2) 'solute number ',isol write(carma%f_LUNOPRT,3) 'solute name: ',carma%f_solute(isol)%f_name write(carma%f_LUNOPRT,4) 'molecular weight',carma%f_solute(isol)%f_wtmol write(carma%f_LUNOPRT,4) 'mass density ',carma%f_solute(isol)%f_rho enddo endif ! Initialize indexes for the gases and check to make sure if H2SO4 is used ! that it occurs after H2O. This is necessary for supersaturation calculations. carma%f_igash2o = 0 carma%f_igash2so4 = 0 carma%f_igasso2 = 0 do igas = 1, carma%f_NGAS if (carma%f_gas(igas)%f_icomposition == I_GCOMP_H2O) then carma%f_igash2o = igas else if (carma%f_gas(igas)%f_icomposition == I_GCOMP_H2SO4) then carma%f_igash2so4 = igas else if (carma%f_gas(igas)%f_icomposition == I_GCOMP_SO2) then carma%f_igasso2 = igas end if end do if ((carma%f_igash2so4 /= 0) .and. (carma%f_igash2o > carma%f_igash2so4)) then if (carma%f_do_print) write(carma%f_LUNOPRT,*) 'CARMA_InitializeGrowth::ERROR - H2O gas must come before H2SO4.' rc = RC_ERROR return end if return end subroutine CARMA_InitializeGrowth !! Calculate the optical properties for each particle bin at each of !! the specified wavelengths. The optical properties include the !! extinction efficiency, the single scattering albedo and the !! asymmetry factor. !! !! NOTE: For these calculations, the particles are assumed to be spheres and !! Mie code is used to calculate the optical properties. !! !! @author Chuck Bardeen !! @version May-2009 subroutine CARMA_InitializeOptics(carma, rc) type(carma_type), intent(inout) :: carma integer, intent(out) :: rc integer :: igroup ! group index integer :: iwave ! wavelength index integer :: ibin ! bin index real(kind=f) :: Qext real(kind=f) :: Qsca real(kind=f) :: asym ! Assume success. rc = RC_OK ! Were any wavelengths specified? do iwave = 1, carma%f_NWAVE do igroup = 1, carma%f_NGROUP ! Should we calculate mie properties for this group? if (carma%f_group(igroup)%f_do_mie) then do ibin = 1, carma%f_NBIN ! Assume the particle is homogeneous (no core). ! ! NOTE: The miess does not converge over as broad a ! range of input parameters as bhmie, but it can handle ! coated spheres. call mie(carma, & carma%f_group(igroup)%f_imiertn, & carma%f_group(igroup)%f_r(ibin), & carma%f_wave(iwave), & carma%f_group(igroup)%f_refidx(iwave), & Qext, & Qsca, & asym, & rc) if (rc < RC_OK) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_InitializeOptics:: Mie failed for (band, wavelength, group, bin)", iwave, carma%f_wave(iwave), igroup, ibin return end if carma%f_group(igroup)%f_qext(iwave, ibin) = Qext carma%f_group(igroup)%f_ssa(iwave, ibin) = Qsca / Qext carma%f_group(igroup)%f_asym(iwave, ibin) = asym end do end if end do end do return end subroutine CARMA_InitializeOptics !! Perform initialization of variables related to thermodynamical calculations that !! are not dependent on the model state. !! !! @author Chuck Bardeen !! @version May-2009 subroutine CARMA_InitializeThermo(carma, rc) type(carma_type), intent(inout) :: carma integer, intent(out) :: rc ! Assume success. rc = RC_OK return end subroutine CARMA_InitializeThermo !! Perform initialization of variables related to vertical transport that are not dependent !! on the model state. !! !! @author Chuck Bardeen !! @version May-2009 subroutine CARMA_InitializeVertical(carma, rc, vf_const) type(carma_type), intent(inout) :: carma integer, intent(out) :: rc real(kind=f), intent(in), optional :: vf_const ! Assume success. rc = RC_OK ! Was a constant vertical velocity specified? carma%f_ifall = 1 carma%f_vf_const = 0._f if (present(vf_const)) then if (vf_const /= 0._f) then carma%f_ifall = 0 carma%f_vf_const = vf_const end if end if ! Specify the boundary conditions for vertical transport. carma%f_itbnd_pc = I_FIXED_CONC carma%f_ibbnd_pc = I_FIXED_CONC return end subroutine CARMA_InitializeVertical !! The routine should be called when the carma object is no longer needed. It deallocates !! any memory allocations made by CARMA (during CARMA_Create()), and failure to call this !!routine could result in memory leaks. !! !! @author Chuck Bardeen !! @version May-2009 !! !! @see CARMA_Create subroutine CARMA_Destroy(carma, rc) use carmaelement_mod use carmagas_mod use carmagroup_mod use carmasolute_mod type(carma_type), intent(inout) :: carma integer, intent(out) :: rc ! Local variables integer :: ier integer :: igroup integer :: ielem integer :: isolute integer :: igas ! Assume success. rc = RC_OK ! If allocated, deallocate all the variables that were allocated in the Create() method. if (allocated(carma%f_group)) then do igroup = 1, carma%f_NGROUP call CARMAGROUP_Destroy(carma, igroup, rc) if (rc < 0) return end do deallocate( & carma%f_group, & carma%f_icoag, & carma%f_inucgas, & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Destroy: ERROR deallocating groups, status=", ier rc = RC_ERROR endif endif if (allocated(carma%f_element)) then do ielem = 1, carma%f_NELEM call CARMAELEMENT_Destroy(carma, ielem, rc) if (rc < RC_OK) return end do deallocate( & carma%f_element, & carma%f_igrowgas, & carma%f_inuc2elem, & carma%f_inucproc, & carma%f_ievp2elem, & carma%f_nnuc2elem, & carma%f_nnucelem, & carma%f_inucelem, & carma%f_if_nuc, & carma%f_rlh_nuc, & carma%f_icoagelem, & carma%f_icoagelem_cm, & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Destroy: ERROR deallocating elements, status=", ier rc = RC_ERROR endif endif if (allocated(carma%f_inuc2bin)) then deallocate( & carma%f_inuc2bin, & carma%f_ievp2bin, & carma%f_nnucbin, & carma%f_inucbin, & carma%f_diffmass, & carma%f_volx, & carma%f_ilow, & carma%f_jlow, & carma%f_iup, & carma%f_jup, & carma%f_npairl, & carma%f_npairu, & carma%f_iglow, & carma%f_jglow, & carma%f_igup, & carma%f_jgup, & carma%f_kbin, & carma%f_pkernel, & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Destroy: ERROR deallocating bins, status=", ier rc = RC_ERROR endif endif if (carma%f_NSOLUTE > 0) then do isolute = 1, carma%f_NSOLUTE call CARMASOLUTE_Destroy(carma, isolute, rc) if (rc < RC_OK) return end do if (allocated(carma%f_solute)) then deallocate( & carma%f_solute, & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Destroy: ERROR deallocating solutes, status=", ier rc = RC_ERROR endif endif end if if (carma%f_NGAS > 0) then do igas = 1, carma%f_NGAS call CARMAGAS_Destroy(carma, igas, rc) if (rc < RC_OK) return end do if (allocated(carma%f_gas)) then deallocate( & carma%f_gas, & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Destroy: ERROR deallocating gases, status=", ier rc = RC_ERROR endif endif end if if (carma%f_NWAVE > 0) then if (allocated(carma%f_wave)) then deallocate( & carma%f_wave, & carma%f_dwave, & carma%f_do_wave_emit, & stat=ier) if(ier /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_Destroy: ERROR deallocating wavelengths, status=", ier rc = RC_ERROR return endif endif endif return end subroutine CARMA_Destroy ! Configuration !! Add a coagulation process between two groups (igroup1 and igroup2), with the resulting !! particle being in the destination group (igroup3). If ck0 is specifed, then a constant !! coagulation kernel will be used. subroutine CARMA_AddCoagulation(carma, igroup1, igroup2, igroup3, icollec, rc, ck0, grav_e_coll0) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(in) :: igroup1 !! first source group integer, intent(in) :: igroup2 !! second source group integer, intent(in) :: igroup3 !! destination group integer, intent(in) :: icollec !! collection technique [I_COLLEC_CONST | I_COLLEC_FUCHS | I_COLLEC_DATA] integer, intent(out) :: rc !! return code, negative indicates failure real(kind=f), intent(in), optional :: ck0 !! if specified, forces a constant coagulation kernel real(kind=f), intent(in), optional :: grav_e_coll0 !! if icollec is I_COLLEC_CONST, the constant gravitational collection efficiency ! Assume success. rc = RC_OK ! Make sure the groups exists. if (igroup1 > carma%f_NGROUP) then if (carma%f_do_print) write(carma%f_LUNOPRT, '(a,i3,a,i3,a)') "CARMA_AddCoagulation:: ERROR - The specifed group (", & igroup1, ") is larger than the number of groups (", carma%f_NGROUP, ")." rc = RC_ERROR return end if if (igroup2 > carma%f_NGROUP) then if (carma%f_do_print) write(carma%f_LUNOPRT, '(a,i3,a,i3,a)') "CARMA_AddCoagulation:: ERROR - The specifed group (", & igroup2, ") is larger than the number of groups (", carma%f_NGROUP, ")." rc = RC_ERROR return end if if (igroup3 > carma%f_NGROUP) then if (carma%f_do_print) write(carma%f_LUNOPRT, '(a,i3,a,i3,a)') "CARMA_AddCoagulation:: ERROR - The specifed group (", & igroup3, ") is larger than the number of groups (", carma%f_NGROUP, ")." rc = RC_ERROR return end if ! Indicate that the groups coagulate together. carma%f_icoag(igroup1, igroup2) = igroup3 ! If ck0 was specified, then we use a fixed coagulation rate of ck0. if (present(ck0)) then carma%f_ck0 = ck0 carma%f_icoagop = I_COAGOP_CONST else carma%f_icoagop = I_COAGOP_CALC end if ! What collection technique is specified. if (icollec > I_COLLEC_DATA) then if (carma%f_do_print) write(carma%f_LUNOPRT, '(a,i3,a)') "CARMA_AddCoagulation:: ERROR - The specifed collection method (", & icollec, ") is unknown." rc = RC_ERROR return end if if (icollec == I_COLLEC_CONST) then if (present(grav_e_coll0)) then carma%f_grav_e_coll0 = grav_e_coll0 else if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddCoagulation:: ERROR - A constant gravitational collection was requests, but grav_e_coll0 was not provided." rc = RC_ERROR return end if end if carma%f_icollec = icollec return end subroutine CARMA_AddCoagulation !! Add a growth process between the element (ielem) and gas (igas) specifed. The element !! and gas should have already been defined using CARMA_AddElement() and CARMA_AddGas(). !! !! NOTE: Each element can only have one volatile component. !! !! @author Chuck Bardeen !! @version May-2009 !! !! @see CARMA_AddElement !! @see CARMA_AddGas subroutine CARMA_AddGrowth(carma, ielem, igas, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(in) :: ielem !! the element index integer, intent(in) :: igas !! the gas index integer, intent(out) :: rc !! return code, negative indicates failure ! Assume success. rc = RC_OK ! Make sure the element exists. if (ielem > carma%f_NELEM) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddGrowth:: ERROR - The specifed element (", & ielem, ") is larger than the number of elements (", carma%f_NELEM, ")." rc = RC_ERROR return end if ! Make sure there are enough gases allocated. if (igas > carma%f_NGAS) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddGrowth:: ERROR - The specifed gas (", & igas, ") is larger than the number of gases (", carma%f_NGAS, ")." rc = RC_ERROR return end if ! If not already defined, indicate that the element can grow with the specified gas. if (carma%f_igrowgas(ielem) /= 0) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddGrowth:: ERROR - The specifed element (", & ielem, ") already has gas (", carma%f_igrowgas(ielem), ") condensing on it." rc = RC_ERROR return else carma%f_igrowgas(ielem) = igas end if return end subroutine CARMA_AddGrowth !! Add a nucleation process that nucleates one element (elemfrom) to another element (elemto) !! using the specified gas (igas). The elements and gas should have already been defined !! using CARMA_AddElement() and CARMA_AddGas(). The nucleation scheme is indicated by !! inucproc, and can be one of: !! !! - I_DROPACT !! - I_AERFREEZE !! - I_DROPFREEZE !! - I_ICEMELT !! - I_HETNUC !! - I_HOMNUC !! !! There are multiple parameterizations for I_AERFREEZE, so when that is selected the !! particular parameterization needs to be indicated by adding it to I_AERFREEZE. The !! specific routines are: !! !! - I_AF_TABAZADEH_2000 !! - I_AF_KOOP_2000 !! - I_AF_MOHLER_2010 !! - I_AF_MURRAY_2010 !! !! One or more of these routines may be selected, but in general one of the first !! three should be selected and then it can optionally be combined with the glassy !! aerosols (I_AF_MURRAY_2010). !! !! Total evaporation transfers particle mass from the destination element back to the !! element indicated by ievp2elem. This relationship is not automatically generated, !! because multiple elements can nucleate to a particular element and therefore the !! reverse mapping is not unique. !! !! NOTE: The gas used for nucleation must be the same for all nucleation defined from !! elements of the same group. !! !! @author Chuck Bardeen !! @version Feb-2009 !! @see I_DROPACT !! @see I_AERFREEZE !! @see I_DROPFREEZE !! @see I_ICEMELT !! @see I_HETNUC !! @see I_HOMNUC !! @see I_AF_TABAZADEH_2000 !! @see I_AF_KOOP_2000 !! @see I_AF_MOHLER_2010 !! @see I_AF_MURRAY_2010 !! @see CARMA_AddElement !! @see CARMA_AddGas subroutine CARMA_AddNucleation(carma, ielemfrom, ielemto, inucproc, & rlh_nuc, rc, igas, ievp2elem) use carmaelement_mod, only : CARMAELEMENT_Get type(carma_type), intent(inout) :: carma !! the carma object integer, intent(in) :: ielemfrom !! the source element integer, intent(in) :: ielemto !! the destination element integer, intent(in) :: inucproc !! the nucleation process [I_DROPACT | I_AERFREEZE | I_ICEMELT | I_HETNUC | I_HOMNUC] real(kind=f), intent(in) :: rlh_nuc !! the latent heat of nucleation [cm2/s2] integer, intent(out) :: rc !! return code, negative indicated failure integer, optional, intent(in) :: igas !! the gas integer, optional, intent(in) :: ievp2elem !! the element created upon evaporation integer :: igroup !! group for source element ! Assume success. rc = RC_OK ! Make sure the elements exist. if (ielemfrom > carma%f_NELEM) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddNucleation:: ERROR - The specifed element (", & ielemfrom, ") is larger than the number of elements (", carma%f_NELEM, ")." rc = RC_ERROR return end if if (ielemto > carma%f_NELEM) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddNucleation:: ERROR - The specifed element (", & ielemto, ") is larger than the number of elements (", carma%f_NELEM, ")." rc = RC_ERROR return end if if (present(ievp2elem)) then if (ievp2elem > carma%f_NELEM) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddNucleation:: ERROR - The specifed element (", & ievp2elem, ") is larger than the number of elements (", carma%f_NELEM, ")." rc = RC_ERROR return end if end if ! Make sure there are enough gases allocated. if (present(igas)) then if (igas > carma%f_NGAS) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddNucleation:: ERROR - The specifed gas (", & igas, ") is larger than the number of gases (", carma%f_NGAS, ")." rc = RC_ERROR return end if end if ! If aerosol freezing is selected, but no I_AF_xxx sub-method is selected, then indicate an error. if (inucproc == I_AERFREEZE) then if (carma%f_do_print) write(carma%f_LUNOPRT, *) "CARMA_AddNucleation:: ERROR - I_AERFREEZE was specified without an I_AF_xxx value." return end if ! Array maps a particle group to its associated gas for nucleation: ! Nucleation from group is associated with gas ! Set to zero if particles are not subject to nucleation. if (present(igas)) then call CARMAELEMENT_Get(carma, ielemfrom, rc, igroup=igroup) if (rc >= RC_OK) then carma%f_inucgas(igroup) = igas end if end if ! Nucleation transfers particle mass from element to element ! , where ranges from 0 to the number of elements ! nucleating from . ! carma%f_nnucelem(ielemto) = carma%f_nnucelem(ielemto) + 1 ! carma%f_inucelem(carma%f_nnucelem(ielemto), ielemto) = ielemfrom carma%f_nnuc2elem(ielemfrom) = carma%f_nnuc2elem(ielemfrom) + 1 carma%f_inuc2elem(carma%f_nnuc2elem(ielemfrom), ielemfrom) = ielemto ! carma%f_if_nuc(ielemfrom,carma%f_inuc2elem(carma%f_nnuc2elem(ielemfrom), ielemfrom)) = .true. ! specifies what nucleation process nucleates ! particles from element to element : ! I_DROPACT: Aerosol activation to droplets ! I_AERFREEZE: Aerosol homogeneous freezing ! I_DROPFREEZE: Droplet homogeneous freezing ! I_GLFREEZE: Glassy Aerosol heteroogeneous freezing ! I_GLAERFREEZE: Glassy & Aerosol freezing carma%f_inucproc(ielemfrom, ielemto) = inucproc ! Total evaporation mapping: total evaporation transfers particle mass from ! element to element . ! ! NOTE: This array is not automatically derived from because multiple ! elements can nucleate to a particular element (reverse mapping is not ! unique). if (present(ievp2elem)) carma%f_ievp2elem(ielemto) = ievp2elem ! is the latent heat released by nucleation ! from element to element [cm^2/s^2]. carma%f_rlh_nuc(ielemfrom,ielemto) = rlh_nuc return end subroutine ! Query, Control and State I/O !! Gets the information about the carma object. !! !! @author Chuck Bardeen !! @version May-2009 !! !! @see CARMA_Create subroutine CARMA_Get(carma, rc, LUNOPRT, NBIN, NELEM, NGAS, NGROUP, NSOLUTE, NWAVE, do_detrain, & do_drydep, do_fixedinit, do_grow, do_print, do_print_init, do_thermo, wave, dwave, do_wave_emit) type(carma_type), intent(in) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure integer, optional, intent(out) :: NBIN !! number of radius bins per group integer, optional, intent(out) :: NELEM !! total number of elements integer, optional, intent(out) :: NGROUP !! total number of groups integer, optional, intent(out) :: NSOLUTE !! total number of solutes integer, optional, intent(out) :: NGAS !! total number of gases integer, optional, intent(out) :: NWAVE !! number of wavelengths integer, optional, intent(out) :: LUNOPRT !! logical unit number for output logical, optional, intent(out) :: do_detrain !! do detrainement? logical, optional, intent(out) :: do_drydep !! do dry deposition? logical, optional, intent(out) :: do_fixedinit !! do initialization from reference atm? logical, optional, intent(out) :: do_grow !! do condensational growth? logical, optional, intent(out) :: do_print !! do print output? logical, optional, intent(out) :: do_print_init !! do print initialization output? logical, optional, intent(out) :: do_thermo !! do thermodynamics? real(kind=f), optional, intent(out) :: wave(carma%f_NWAVE) !! the wavelengths centers (cm) real(kind=f), optional, intent(out) :: dwave(carma%f_NWAVE) !! the wavelengths widths (cm) logical, optional, intent(out) :: do_wave_emit(carma%f_NWAVE) !! do emission in this band? ! Assume success. rc = RC_OK if (present(LUNOPRT)) LUNOPRT = carma%f_LUNOPRT if (present(NBIN)) NBIN = carma%f_NBIN if (present(NELEM)) NELEM = carma%f_NELEM if (present(NGAS)) NGAS = carma%f_NGAS if (present(NGROUP)) NGROUP = carma%f_NGROUP if (present(NSOLUTE)) NSOLUTE = carma%f_NSOLUTE if (present(NWAVE)) NWAVE = carma%f_NWAVE if (present(do_detrain)) do_detrain = carma%f_do_detrain if (present(do_drydep)) do_drydep = carma%f_do_drydep if (present(do_grow)) do_grow = carma%f_do_grow if (present(do_fixedinit)) do_fixedinit = carma%f_do_fixedinit if (present(do_print)) do_print = carma%f_do_print if (present(do_print_init)) do_print_init = carma%f_do_print_init if (present(do_thermo)) do_thermo = carma%f_do_thermo if (present(wave)) wave(:) = carma%f_wave(:) if (present(dwave)) dwave(:) = carma%f_dwave(:) if (present(do_wave_emit)) do_wave_emit(:) = carma%f_do_wave_emit(:) return end subroutine CARMA_Get end module