1 !------------------------------------------------------------------------!
2 ! The Community Multiscale Air Quality (CMAQ) system software is in !
3 ! continuous development by various groups and is based on information !
4 ! from these groups: Federal Government employees, contractors working !
5 ! within a United States Government contract, and non-Federal sources !
6 ! including research institutions. These groups give the Government !
7 ! permission to use, prepare derivative works of, and distribute copies !
8 ! of their work in the CMAQ system to the public and to permit others !
9 ! to do so. The United States Environmental Protection Agency !
10 ! therefore grants similar permission to use the CMAQ system software, !
11 ! but users are requested to provide copies of derivative works or !
12 ! products designed to operate in the CMAQ system to the United States !
13 ! Government without restrictions as to use by others. Software !
14 ! that is used with the CMAQ system but distributed under the GNU !
15 ! General Public License or the GNU Lesser General Public License is !
16 ! subject to their copyright restrictions. !
17 !------------------------------------------------------------------------!
19 ! complex number general function
22 ! 2012/07/31 David Wong Original version
23 ! 2012/10/22 David Wong Added treatment to avoid division by 0
24 ! 2013/11/20 David Wong modified the way to compute
25 ! max(abs(c_div_cc%real_part), min_val) in subroutine
26 ! c_div_cc to satisfy absoft compiler requirement
27 ! 2015/12/16 David Wong renamed argument list for c_add_cr, c_add_rc,
28 ! c_sub_cr and c_sub_rc to avoid gfortran not able to
29 ! distinguish those routines in the interface block issue
30 ! 2016/02/23 David Wong extracted the entire module and put it in a
33 module complex_number_module
37 ! integer, parameter :: loc_real_precision = selected_real_kind(p=16, r=60)
38 integer, parameter :: loc_real_precision = 8
40 real (kind=loc_real_precision), parameter, private :: min_val = 1.0e-30_loc_real_precision
43 real(kind=loc_real_precision) :: real_part, imag_part
44 end type complex_number
47 module procedure c_add_cc, & ! z1 + z2
48 c_add_cr, & ! z1 + num, where num is a real number
49 c_add_rc ! num + z1, where num is a real number
53 module procedure c_sub_cc, & ! z1 - z2
54 c_sub_cr, & ! z1 - num, where num is a real number
55 c_sub_rc ! num - z1, where num is a real number
59 module procedure c_mul_cc, & ! z1 * z2
60 c_mul_rc ! num * z1, where num is a real number
64 module procedure c_div_cc, & ! z1 / z2
65 c_div_rc ! num / z1, where num is a real number
70 ! --------------------------------------------------------------------------
71 type (complex_number) function c_set (x, y)
73 ! initialize a complex number
75 real(kind=loc_real_precision), intent(in) :: x, y
77 character (len = 80) :: str
80 read(str, *) c_set%real_part
82 read(str, *) c_set%imag_part
86 ! --------------------------------------------------------------------------
87 type (complex_number) function c_add_cc (z1, z2)
89 type (complex_number), intent(in) :: z1, z2
91 c_add_cc%real_part = z1%real_part + z2%real_part
92 c_add_cc%imag_part = z1%imag_part + z2%imag_part
96 ! --------------------------------------------------------------------------
97 type (complex_number) function c_add_cr (z3, num1)
99 type (complex_number), intent(in) :: z3
100 real(kind=loc_real_precision), intent(in) :: num1
102 c_add_cr%real_part = z3%real_part + num1
103 c_add_cr%imag_part = z3%imag_part
105 end function c_add_cr
107 ! --------------------------------------------------------------------------
108 type (complex_number) function c_add_rc (num2, z4)
110 type (complex_number), intent(in) :: z4
111 real(kind=loc_real_precision), intent(in) :: num2
113 c_add_rc%real_part = z4%real_part + num2
114 c_add_rc%imag_part = z4%imag_part
116 end function c_add_rc
118 ! --------------------------------------------------------------------------
119 type (complex_number) function c_sub_cc (z1, z2)
121 type (complex_number), intent(in) :: z1, z2
123 c_sub_cc%real_part = z1%real_part - z2%real_part
124 c_sub_cc%imag_part = z1%imag_part - z2%imag_part
126 end function c_sub_cc
128 ! --------------------------------------------------------------------------
129 type (complex_number) function c_sub_cr (z3, num1)
131 type (complex_number), intent(in) :: z3
132 real(kind=loc_real_precision), intent(in) :: num1
134 c_sub_cr%real_part = z3%real_part - num1
135 c_sub_cr%imag_part = z3%imag_part
137 end function c_sub_cr
139 ! --------------------------------------------------------------------------
140 type (complex_number) function c_sub_rc (num2, z4)
142 type (complex_number), intent(in) :: z4
143 real(kind=loc_real_precision), intent(in) :: num2
145 c_sub_rc%real_part = num2 - z4%real_part
146 c_sub_rc%imag_part = - z4%imag_part
148 end function c_sub_rc
150 ! --------------------------------------------------------------------------
151 type (complex_number) function c_mul_cc (z1, z2)
153 type (complex_number), intent(in) :: z1, z2
155 c_mul_cc%real_part = z1%real_part * z2%real_part &
156 - z1%imag_part * z2%imag_part
157 c_mul_cc%imag_part = z1%real_part * z2%imag_part &
158 + z1%imag_part * z2%real_part
160 end function c_mul_cc
162 ! --------------------------------------------------------------------------
163 type (complex_number) function c_mul_rc (x, z1)
165 type (complex_number), intent(in) :: z1
166 real(kind=loc_real_precision), intent(in) :: x
168 c_mul_rc%real_part = z1%real_part * x
169 c_mul_rc%imag_part = z1%imag_part * x
171 end function c_mul_rc
173 ! --------------------------------------------------------------------------
174 type (complex_number) function c_div_cc (z1, z2)
176 type (complex_number), intent(in) :: z1, z2
178 real(kind=loc_real_precision) :: denom
179 real(kind=loc_real_precision) :: temp(2)
181 denom = 1.0 / ( z2%real_part * z2%real_part &
182 + z2%imag_part * z2%imag_part)
184 c_div_cc%real_part = ( z1%real_part * z2%real_part &
185 + z1%imag_part * z2%imag_part) * denom
187 temp(1) = abs(c_div_cc%real_part)
190 c_div_cc%real_part = sign(maxval(temp), c_div_cc%real_part)
192 c_div_cc%imag_part = ( z1%imag_part * z2%real_part &
193 - z1%real_part * z2%imag_part) * denom
195 temp(1) = abs(c_div_cc%imag_part)
197 c_div_cc%imag_part = sign(maxval(temp), c_div_cc%imag_part)
199 end function c_div_cc
201 ! --------------------------------------------------------------------------
202 type (complex_number) function c_div_rc (num, z1)
206 real(kind=loc_real_precision), intent(in) :: num
207 type (complex_number), intent(in) :: z1
209 real(kind=loc_real_precision) :: denom, temp
211 temp = z1%real_part * z1%real_part + z1%imag_part * z1%imag_part
212 temp = sign(max(abs(temp), min_val), temp)
215 c_div_rc%real_part = z1%real_part * denom
216 c_div_rc%imag_part = -1.0 * z1%imag_part * denom
218 end function c_div_rc
220 ! --------------------------------------------------------------------------
221 type (complex_number) function c_sin (z1)
223 ! compute sin of a complex number
225 type (complex_number), intent(in) :: z1
227 c_sin%real_part = sin(z1%real_part) * cosh(z1%imag_part)
228 c_sin%imag_part = cos(z1%real_part) * sinh(z1%imag_part)
232 ! --------------------------------------------------------------------------
233 type (complex_number) function c_cos (z1)
235 type (complex_number), intent(in) :: z1
237 c_cos%real_part = cos(z1%real_part) * cosh(z1%imag_part)
238 c_cos%imag_part = -1.0 * sin(z1%real_part) * sinh(z1%imag_part)
242 ! --------------------------------------------------------------------------
243 real(kind=loc_real_precision) function c_abs (z1)
245 ! computer absolute value of a complex number
247 type (complex_number), intent(in) :: z1
249 c_abs = sqrt(z1%real_part**2 + z1%imag_part**2)
253 end module complex_number_module