├── .gitignore
├── LICENCE.md
├── README.md
├── compile_fmcd.sh
├── mcd.py
├── mcdcomp.py
├── netcdf
├── gfortran_netcdf4_fPIC
└── gfortran_netcdf4_fpic_old
├── patch.txt
├── perso
├── ddcriterion.py
├── dunes
│ ├── add_text.txt
│ ├── dune.py
│ ├── dune_lat_long.txt
│ ├── histodune.py
│ ├── plotdune.py
│ ├── seasonal.py
│ ├── time_dune.txt
│ ├── u.txt
│ ├── v.txt
│ └── wheredune.py
├── dustdevil.py
├── gw.py
├── inimeso
│ ├── from_gcm.py
│ ├── inimeso.py
│ ├── inimeso5.py
│ ├── input_coord
│ ├── profile.py
│ ├── shift_temp.py
│ └── venus
│ │ ├── getvenus.py
│ │ └── input_coord
└── phoenix.py
├── quicktest.py
├── test_mcd
├── MCD_DATA
├── README
├── test_mcd.def
├── test_mcd.py
└── test_mcd_light.py
└── tutorial
└── mcd-python_tutorial.ipynb
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.log
3 | *.pyf
4 | *.pyc
5 | *.so
6 | input_more
7 | input_sounding
8 | input_therm
9 | input_dust
10 | input_water
11 | dustopacity.def
12 | perso/inimeso/*.png
13 | tutorial/*.png
14 | *.ipynb_checkpoints*
15 |
--------------------------------------------------------------------------------
/LICENCE.md:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **MCD-PYTHON: python-based interface to the Mars Climate Database**
2 |
3 | Open source code and contact information [available on github](https://github.com/aymeric-spiga) [no registration needed]
4 |
5 | * To get sources through git
6 | ~~~
7 | git clone https://github.com/aymeric-spiga/mcd-python
8 | ~~~
9 |
10 | * To get sources through SVN
11 | ~~~
12 | svn co https://github.com/aymeric-spiga/mcd-python/trunk mcd-python
13 | ~~~
14 |
15 | * To get a static ZIP file of the current version of the code,
16 | [click here](https://github.com/aymeric-spiga/mcd-python/archive/master.zip)
17 |
18 | ----
19 |
20 | **How to install?**
21 |
22 | It is assumed you were able to compile successfully the `mcd` sources with `gfortran`.
23 |
24 | The `netCDF` library should be installed on your system.
25 | Moreover, from our experience, it seems that it must have been build
26 | using the `-fPIC` (for `gfortran`; the name of the option changes with compilers)
27 | option which generates position independent code suitable for use in a shared library.
28 | An example script is given in the `netcdf` folder.
29 |
30 | The installation below relies on `f2py` utility, which is part of the `numpy` package.
31 |
32 | 1. Getting the environment variables right: add the `mcd-python` folder to `PYTHONPATH` in your environment file (e.g. `.bashrc`)
33 |
34 | export PYTHONPATH=$PYTHONPATH:adapt_to_your_own/mcd-python
35 |
36 | 2. Modify the compile script `compile_fmcd.sh` to link your local `netCDF` libraries and `mcd` distribution (Fortran sources)
37 |
38 | 3. Check that `f2py` is included in your `python` library suite.
39 |
40 | 4. Run `compile_fmcd.sh` and check for the created `.so` file (its size should be about 1 Mo)
41 |
42 | ----
43 |
44 | **Quick test**
45 |
46 | ~~~
47 | quicktest.py
48 | ~~~
49 |
50 | Next step is to try and learn about the use of `mcd` Python library with the `tutorial` folder.
51 |
52 | A more advanced example (direct use of `fmcd` compiled with `f2py`) is provided in the `test_mcd` folder.
53 |
54 | ----
55 |
56 | **Python 3**
57 |
58 | *Solution suggested by Aaron Berliner*
59 |
60 | This can be done using the 2to3 package and the reindent
61 |
62 | Run 2to3 -v -n -W -f all mcd.py
63 | Run 2to3 -v -n -W -f all mcdcomp.py
64 | Run reindent mcd.py
65 | Run reindent mcdcomp.py
66 |
67 | Then upgrade to the appropriate basemap in python3.
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/compile_fmcd.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ######################################################################################
4 | ###
5 | ### compile_gfortran.sh
6 | ###
7 | ### - requirements: f2py tool + netCDF librairies compiled in Fortran
8 | ###
9 | ### ---> This should be used to make MCD fortran stuff directly accessible in python
10 | ### ---> This script is for gfortran, but it is easy to adapt to your other compilers
11 | ### ---> A file fmcd.so should be created
12 | ### ---> See mcd.py for use in python. Very easy!
13 | ###
14 | ### AS. 17/04/2012.
15 | ### TP/ AB : 13/10/2022 : update for MCD6.1
16 | ######################################################################################
17 |
18 |
19 | NETCDF=/home/marshttp/NETCDF/netcdf64-4.0.1_gfortran_fPIC/
20 | wheremcd="/home/marshttp/MCD_6.1/"
21 |
22 |
23 | version="6.1"
24 |
25 | ######################################################################################
26 | ######################################################################################
27 | ######################################################################################
28 |
29 | ### LOG FILE
30 | num=""
31 | touch fmcd$num.log
32 | \rm fmcd$num.log
33 |
34 | ### COPY/PREPARE SOURCES
35 | ### perform changes that makes f2py not to fail
36 | sed s/"\!\!'"/"'"/g $wheremcd/mcd/MCD.F90 | sed s/"\!'"/"'"/g | sed -e 's/!/\'$'\n!/g' > tmp.MCD.F90
37 |
38 |
39 | ### BUILD THROUGH f2py WHAT IS NECESSARY TO CREATE THE PYTHON FUNCTIONS
40 | touch fmcd$num.pyf
41 | \rm fmcd$num.pyf
42 | echo -e " First f2py call : \n " > fmcd$num.log
43 | f2py -h fmcd$num.pyf -m fmcd$num tmp.MCD.F90 >> fmcd$num.log 2>&1
44 |
45 | ### IMPORTANT: we teach f2py about variables in the call_mcd subroutines which are intended to be out
46 | sed s/"real :: pres"/"real, intent(out) :: pres"/g fmcd$num.pyf | \
47 | sed s/"real :: dens"/"real, intent(out) :: dens"/g | \
48 | sed s/"real :: temp"/"real, intent(out) :: temp"/g | \
49 | sed s/"real :: zonwind"/"real, intent(out) :: zonwind"/g | \
50 | sed s/"real :: merwind"/"real, intent(out) :: merwind"/g | \
51 | sed s/"real dimension(5) :: meanvar"/"real dimension(5),intent(out) :: meanvar"/g | \
52 | sed s/"real dimension(100) :: extvar"/"real dimension(100),intent(out) :: extvar"/g | \
53 | sed s/"real :: seedout"/"real, intent(out) :: seedout"/g | \
54 | sed s/"integer :: ier"/"integer, intent(out) :: ier"/g > fmcd$num.pyf.modif
55 | mv fmcd$num.pyf.modif fmcd$num.pyf
56 |
57 | ### CUSTOMIZE fmcd.pyf TO ADD BUILT-IN INFO ABOUT VERSION and DATA LINKS
58 | datalink=`cd $wheremcd; pwd`"/data/"
59 | echo " usercode '''" > patchtmp.txt
60 | echo ' char dataloc[] = "'$datalink'";' >> patchtmp.txt
61 | echo ' char dataver[] = "'$version'";' >> patchtmp.txt
62 | echo " '''" >> patchtmp.txt
63 | sed '/python module fmcd ! in/r patchtmp.txt' fmcd$num.pyf > tmp ; mv tmp fmcd$num.pyf
64 | sed '/interface ! in :fmcd/r patch.txt' fmcd$num.pyf > tmp ; mv tmp fmcd$num.pyf
65 |
66 | ### BUILD
67 | echo -e " \n Second f2py call : \n " >> fmcd$num.log
68 | f2py -c fmcd$num.pyf tmp.MCD.F90 --fcompiler=gnu95 \
69 | -L$NETCDF/lib -lnetcdf -lnetcdff\
70 | -lm -I$NETCDF/include \
71 | --f90flags="-fPIC -ffree-form -ffree-line-length-none" \
72 | --f77flags="-fPIC" \
73 | --verbose \
74 | >> fmcd$num.log 2>&1
75 |
76 | #### CLEAN THE PLACE
77 | \rm tmp.MCD.F90
78 | \rm patchtmp.txt
79 |
--------------------------------------------------------------------------------
/mcd.py:
--------------------------------------------------------------------------------
1 | ####################################################
2 | ### A Python Class for the Mars Climate Database ###
3 | ### ---------------------------------------------###
4 | ### Aymeric SPIGA 17-21/04/2012 ###
5 | ### ---------------------------------------------###
6 | ### (see mcdtest.py for examples of use) ###
7 | ####################################################
8 |
9 | ###
10 | from fmcd import mcd # MCD compiled with f2py
11 | from fmcd import dataloc # location of MCD data file
12 | from fmcd import dataver # compiled version of MCD
13 | ###
14 | import numpy as np
15 | import matplotlib.pyplot as mpl
16 | ###
17 |
18 | ## default number of points for each dimension
19 | dfzon = 64 #37 # zonal dimension
20 | dfmer = 48 #19 # meridional dimension
21 | dfver = 35 #20 # vertical dimension
22 | dflct = 25 #13 # local time dimension
23 | dfsea = 25 # solar long dimension
24 | ## default names
25 | lslab = "Areocentric longitude (degrees)"
26 | latlab = "North latitude (degrees)"
27 | lonlab = "East longitude (degrees)"
28 | ltlab = "Local time (Martian hour)"
29 | #NB: vertical labels are treated by .vertlabel()
30 |
31 | def errormess(text,printvar=None):
32 | print text
33 | if printvar is not None: print printvar
34 | exit()
35 | return
36 |
37 | class mcd_class():
38 |
39 | def __repr__(self):
40 | # print out a help string when help is invoked on the object
41 | whatprint = 'MCD object. \"help(mcd)\" for more information\n'
42 | return whatprint
43 |
44 | ########################
45 | ### Default settings ###
46 | ########################
47 |
48 | def __init__(self):
49 | # default settings
50 | ## 0. general stuff
51 | self.name = "MCD_v"+dataver # this is coming from fmcd
52 | self.dset = dataloc # this is coming from fmcd
53 | self.ack = "Mars Climate Database (c) LMD/OU/IAA/ESA/CNES"
54 | ## 1. spatio-temporal coordinates
55 | self.lat = 0.
56 | self.lats = None
57 | self.late = None
58 | self.lon = 0.
59 | self.lons = None
60 | self.lone = None
61 | self.loct = 0.
62 | self.locts = None
63 | self.locte = None
64 | self.xdate = 0. # see datekey
65 | self.xdates = None
66 | self.xdatee = None
67 | self.xz = 10. # see zkey
68 | self.xzs = None
69 | self.xze = None
70 | ## 1bis. related settings
71 | self.zkey = 3 # specify that xz is the altitude above surface (m)
72 | # zkey : type of vertical coordinate xz
73 | # 1 = radius from centre of planet (m)
74 | # 2 = height above areoid (m) (MOLA zero datum)
75 | # 3 = height above surface (m)
76 | # 4 = pressure level (Pa)
77 | # 5 = altitude above mean Mars Radius(=3396000m) (m)
78 | self.datekey = 1 # 0 = "Earth time": xdate is given in Julian days (localtime must be set to zero)
79 | # 1 = "Mars date": xdate is the value of Ls
80 |
81 | ## 2. climatological options
82 |
83 | self.dust = 1 # climatological average scenario
84 | self.hrkey = 1 #set high resolution mode on (hrkey=0 to set high resolution off)
85 |
86 | ## 3. additional settings for advanced use
87 |
88 | self.extvarkey = np.ones(100) # now a table since MCD version 5
89 | self.perturkey = 0 #integer perturkey ! perturbation type (0: none)
90 | self.seedin = 1 #random number generator seed (unused if perturkey=0)
91 | self.gwlength = 0. #gravity Wave wavelength (unused if perturkey=0)
92 | ## outputs. just to define attributes.
93 | ## --> in update
94 | self.pres = None ; self.dens = None ; self.temp = None ; self.zonwind = None ; self.merwind = None ; self.meanvar = None ; self.extvar = None
95 | self.seedout = None ; self.ierr = None
96 | ## --> in prepare
97 | self.xcoord = None ; self.ycoord = None
98 | self.prestab = None ; self.denstab = None ; self.temptab = None
99 | self.zonwindtab = None ; self.merwindtab = None ; self.meanvartab = None ; self.extvartab = None
100 | ## plot stuff
101 | self.typex = None ; self.typey = None
102 | self.xlabel = None ; self.ylabel = None ; self.title = ""
103 | self.vertplot = False
104 | self.fmt = "%.1e"
105 | self.colorm = "jet"
106 | self.fixedlt = False
107 | self.averaging = None
108 | self.min2d = None
109 | self.max2d = None
110 | self.dpi = 80.
111 | self.islog = False
112 | self.proj = None
113 | self.trans = 0.0
114 | self.iscontour = False
115 | self.plat = 0.0
116 | self.plon = 0.0
117 | self.palt = None
118 | self.latpoint = None
119 | self.lonpoint = None
120 |
121 | def viking1(self): self.name = "Viking 1 site. MCD v4.3 output" ; self.lat = 22.48 ; self.lon = -49.97 ; self.xdate = 97.
122 | def viking2(self): self.name = "Viking 2 site. MCD v4.3 output" ; self.lat = 47.97 ; self.lon = -225.74 ; self.xdate = 117.6
123 |
124 | def getdustlabel(self):
125 | if self.dust == 1:
126 | self.dustlabel = "climatology average solar scenario"
127 | elif self.dust == 2:
128 | self.dustlabel = "climatology minimum solar scenario"
129 | elif self.dust == 3:
130 | self.dustlabel = "climatology maximum solar scenario"
131 | elif self.dust == 4: self.dustlabel = "dust storm minimum solar scenario"
132 | elif self.dust == 5: self.dustlabel = "dust storm average solar scenario"
133 | elif self.dust == 6: self.dustlabel = "dust storm maximum solar scenario"
134 | elif self.dust == 7: self.dustlabel = "warm scenario (dusty, maximum solar)"
135 | elif self.dust == 8: self.dustlabel = "cold scenario (low dust, minimum solar)"
136 | elif self.dust > 20: self.dustlabel = "Martian Year "+str(self.dust)+" scenario"
137 |
138 | def gettitle(self,oneline=False):
139 | self.getdustlabel()
140 | self.title = self.name + " with " + self.dustlabel + "."
141 | if self.datekey == 1:
142 | if self.xdates is None:
143 | self.title = self.title + " Ls " + str(self.xdate) + "deg."
144 | elif self.datekey == 0:
145 | self.title = self.title + " JD " + str(self.xdate) + "."
146 | if not oneline: self.title = self.title + "\n"
147 | if self.lats is None:
148 | self.title = self.title + " Latitude " + str(self.lat) + "N."
149 | if self.averaging == "lon":
150 | self.title = self.title + " Zonal mean over all longitudes."
151 | elif self.lons is None:
152 | self.title = self.title + " Longitude " + str(self.lon) + "E."
153 | if self.xzs is None:
154 | self.vertunits()
155 | self.title = self.title + " Altitude " + str(self.xz) + " " + self.vunits + "."
156 | if self.datekey == 1:
157 | if self.averaging == "loct":
158 | self.title = self.title + " Diurnal mean over all local times."
159 | else:
160 | if self.locts is None and self.averaging != "lon":
161 | self.title = self.title + " Local time " + str(self.loct) + "h"
162 | if self.lons is not None: # if longitude is a free dimension
163 | if not self.fixedlt: self.title = self.title + " (at longitude 0) "
164 | else: self.title = self.title + " (fixed at all longitudes) "
165 | if self.proj == "nsper" :
166 | if self.palt == 99999999. :
167 | self.title = self.title + "[view from lon "+str(self.plon)+"$\degree$E. lat "+str(self.plat)+"$\degree$N. infinite altitude]"
168 | else :
169 | self.title = self.title + "[view from lon "+str(self.plon)+"$\degree$E. lat "+str(self.plat)+"$\degree$N. alt "+str(self.palt)+ " km]"
170 |
171 | def getextvarlab(self,num):
172 | # MCD version 6.1 variables
173 | whichfield = { \
174 | 91: "Pressure (Pa)", \
175 | 92: "Density (kg/m3)", \
176 | 93: "Temperature (K)", \
177 | 94: "W-E wind component (m/s)", \
178 | 95: "S-N wind component (m/s)", \
179 | 96: "Horizontal wind speed (m/s)", \
180 | 1: "Radial distance from planet center (m)", \
181 | 2: "Altitude above areoid (Mars geoid) (m)", \
182 | 3: "Altitude above local surface (m)", \
183 | 4: "orographic height (m) (surface altitude above areoid)", \
184 | 5: "GCM orography (m)", \
185 | 6: "Local slope inclination (deg) (HR mode only)", \
186 | 7: "Local slope orientation (deg) (0 deg Northward) (HR mode only)", \
187 | 8: "Sun-Mars distance (in Astronomical Unit AU)", \
188 | 9: "Ls, solar longitude of Mars (deg)", \
189 | 10: "LST:Local true solar time (hrs)", \
190 | 11: "LMT:Local mean time (hrs) at sought longitude", \
191 | 12: "Universal solar time (LST at lon=0) (hrs)", \
192 | 13: "Solar zenith angle (deg)", \
193 | 14: "Surface temperature (K)", \
194 | 15: "Surface pressure (Pa)", \
195 | 16: "GCM surface pressure (Pa)", \
196 | 17: "Potential temperature (K) (reference pressure=610Pa)", \
197 | 18: "Downward Vertical wind component (m/s)", \
198 | 19: "Zonal slope wind component (m/s) (HR mode only)", \
199 | 20: "Meridional slope wind component (m/s) (HR mode only)", \
200 | 21: "Surface pressure RMS day to day variations (Pa)", \
201 | 22: "Surface temperature RMS day to day variations (K)", \
202 | 23: "Atmospheric pressure RMS day to day variations (Pa)", \
203 | 24: "Density RMS day to day variations (kg/m^3)", \
204 | 25: "Temperature RMS day to day variations (K)", \
205 | 26: "Zonal wind RMS day to day variations (m/s)", \
206 | 27: "Meridional wind RMS day to day variations (m/s)", \
207 | 28: "Vertical wind RMS day to day variations (m/s)", \
208 | 29: "Incident solar flux at top of the atmosphere (W/m2)", \
209 | 30: "solar flux reflected to space (W/m2)", \
210 | 31: "Incident solar flux on horizontal surface (W/m2)", \
211 | 32: "Incident solar flux on local slope (W/m2) (HR mode only)", \
212 | 33: "Reflected solar flux on horizontal surface (W/m2)", \
213 | 34: "thermal IR flux to space (W/m2)", \
214 | 35: "thermal IR flux on surface (W/m2)", \
215 | 36: "GCM surface roughness length z0 (m)", \
216 | 37: "GCM surface thermal inertia", \
217 | 38: "GCM surface bare ground albedo", \
218 | 39: "Monthly mean dust column visible optical depth above surface", \
219 | 40: "Daily mean dust column visible optical depth above surface", \
220 | 41: "Dust mass mixing ratio (kg/kg)", \
221 | 42: "Dust effective radius (m)", \
222 | 43: "Daily mean dust deposition rate on horizontal surface (kg m-2 s-1)", \
223 | 44: "Monthly mean surface CO2 ice layer (kg/m2)", \
224 | 45: "Monthly mean surface H2O layer (kg/m2) (non perennial frost)", \
225 | 46: "GCM perennial surface water ice (0 or 1)", \
226 | 47: "Water vapor column (kg/m2)", \
227 | 48: "Water vapor vol. mixing ratio (mol/mol)", \
228 | 49: "Water ice column (kg/m2)", \
229 | 50: "Water ice mixing ratio (mol/mol)", \
230 | 51: "Water ice effective radius (m)", \
231 | 52: "Convective Planetary Boundary Layer (PBL) height (m)", \
232 | 53: "Max. upward convective wind within the PBL (m/s)", \
233 | 54: "Max. downward convective wind within the PBL (m/s)", \
234 | 55: "Convective vertical wind variance at level z (m2/s2)", \
235 | 56: "Convective eddy vertical heat flux at level z (m/s/K)", \
236 | 57: "Surface wind stress (kg/m/s2)", \
237 | 58: "Surface sensible heat flux (W/m2) (<0 when flux from surf to atm.)", \
238 | 59: "Air heat capacity Cp (J kg-1 K-1)", \
239 | 60: "gamma=Cp/Cv Ratio of specific heats", \
240 | 61: "R:Molecular gas constant (J K-1 kg-1)", \
241 | 62: "Air viscosity estimation (N s m-2)", \
242 | 63: "Scale height H(p) (m)", \
243 | 64: "[CO2] volume mixing ratio (mol/mol)", \
244 | 65: "[N2] volume mixing ratio (mol/mol)", \
245 | 66: "[Ar] volume mixing ratio (mol/mol)", \
246 | 67: "[CO] volume mixing ratio (mol/mol)", \
247 | 68: "[O] volume mixing ratio (mol/mol)", \
248 | 69: "[O2] volume mixing ratio (mol/mol)", \
249 | 70: "[O3] volume mixing ratio (mol/mol)", \
250 | 71: "[H] volume mixing ratio (mol/mol)", \
251 | 72: "[H2] volume mixing ratio (mol/mol)", \
252 | 73: "[He] volume mixing ratio (mol/mol)", \
253 | 74: "CO2 column (kg/m2)", \
254 | 75: "N2 column (kg/m2)", \
255 | 76: "Ar column (kg/m2)", \
256 | 77: "CO column (kg/m2)", \
257 | 78: "O column (kg/m2)", \
258 | 79: "O2 column (kg/m2)", \
259 | 80: "O3 column (kg/m2)", \
260 | 81: "H column (kg/m2)", \
261 | 82: "H2 column (kg/m2)", \
262 | 83: "He column (kg/m2)", \
263 | 84: "Electron number density (particules/cm3)", \
264 | 85: "Total electonic content (TEC) (particules/m2)"
265 | }
266 |
267 | if num not in whichfield: errormess("Incorrect subscript in extvar.")
268 | dastuff = whichfield[num]
269 | expf = "%.1e"
270 | if "variations (K)" in dastuff: self.fmt="%.1f"
271 | elif "(K)" in dastuff: self.fmt="%.0f"
272 | elif "effective radius" in dastuff: self.fmt=expf
273 | elif "(Pa)" in dastuff: self.fmt=expf
274 | elif "(W/m2)" in dastuff: self.fmt="%.0f"
275 | elif "(m/s)" in dastuff: self.fmt="%.1f"
276 | elif "(mol/mol)" in dastuff: self.fmt=expf
277 | elif "(kg/m2)" in dastuff: self.fmt=expf
278 | elif "(m)" in dastuff: self.fmt="%.0f"
279 | else: self.fmt=expf
280 | return dastuff
281 |
282 | def convertlab(self,num):
283 |
284 | ## a conversion from text inquiries to extvar numbers. to be completed.
285 |
286 |
287 | if num == "p": num = 91
288 | elif num == "rho": num = 92
289 | elif num == "t": num = 93
290 | elif num == "u": num = 94
291 | elif num == "v": num = 95
292 | elif num == "wind": num = 96
293 | elif num == "zradius": num=1
294 | elif num == "zareoid" : num =2
295 | elif num == "zsurface" : num = 3
296 | elif num == "oroheight" : num = 4
297 | elif num == "oro_gcm" : num = 5
298 | elif num == "theta_s" : num = 6
299 | elif num == "psi_s" : num = 7
300 | elif num == "marsau" : num = 8
301 | elif num == "ls" : num = 9
302 | elif num == "loctime" : num = 10
303 | elif num == "lmeantime" : num = 11
304 | elif num == "utime" : num = 12
305 | elif num == "solzenang" : num = 13
306 | elif num == "tsurf" : num = 14
307 | elif num == "ps" : num = 15
308 | elif num == "ps_gcm" : num = 16
309 | elif num == "potential_temp" : num = 17
310 | elif num == "w_l" : num = 18
311 | elif num == "zonal_slope_wind" : num = 19
312 | elif num == "merid_slope_wind" : num = 20
313 | elif num == "rmsps" : num = 21
314 | elif num == "rmstsurf" : num = 22
315 | elif num == "altrmsp" : num = 23
316 | elif num == "rmsrho" : num = 24
317 | elif num == "rmst" : num = 25
318 | elif num == "rmsu" : num = 26
319 | elif num == "rmsv" : num = 27
320 | elif num == "rmsw" : num = 28
321 | elif num == "fluxtop_dn_sw" : num = 29
322 | elif num == "fluxtop_up_sw" : num = 30
323 | elif num == "fluxsurf_dn_sw" : num = 31
324 | elif num == "fluxsurf_dn_sw_hr" : num = 32
325 | elif num == "fluxsurf_up_sw" : num = 33
326 | elif num == "fluxtop_lw" : num = 34
327 | elif num == "fluxsurf_lw" : num = 35
328 | elif num == "z_0" : num = 36
329 | elif num == "thermal_inertia" : num = 37
330 | elif num == "ground_albedo" : num = 38
331 | elif num == "dod" : num = 39
332 | elif num == "tauref" : num = 40
333 | elif num == "dust_mmr" : num = 41
334 | elif num == "dust_reff" : num = 42
335 | elif num == "dust_dep" : num = 43
336 | elif num == "co2ice" : num = 44
337 | elif num == "surf_h2o_ice" : num = 45
338 | elif num == "water_cap" : num = 46
339 | elif num == "col_h2ovapor" : num = 47
340 | elif num == "vmr_h2o" : num = 48
341 | elif num == "col_h2oice" : num = 49
342 | elif num == "vmr_h2oice" : num = 50
343 | elif num == "h2oice_reff" : num = 51
344 | elif num == "zmax" : num = 52
345 | elif num == "wstar_up" : num = 53
346 | elif num == "wstar_dn" : num = 54
347 | elif num == "vvv" : num = 55
348 | elif num == "vhf" : num = 56
349 | elif num == "surfstress" : num = 57
350 | elif num == "sensib_flux" : num = 58
351 | elif num == "Cp" : num = 59
352 | elif num == "gamma" : num = 60
353 | elif num == "Rgas" : num = 61
354 | elif num == "viscosity" : num = 62
355 | elif num == "pscaleheight" : num = 63
356 | elif num == "vmr_co2" : num = 64
357 | elif num == "vmr_n2" : num = 65
358 | elif num == "vmr_ar" : num = 66
359 | elif num == "vmr_co" : num = 67
360 | elif num == "vmr_o" : num = 68
361 | elif num == "vmr_o2" : num = 69
362 | elif num == "vmr_o3" : num = 70
363 | elif num == "vmr_h" : num = 71
364 | elif num == "vmr_h2" : num = 72
365 | elif num == "vmr_he" : num = 73
366 | elif num == "col_co2" : num = 74
367 | elif num == "col_n2" : num = 75
368 | elif num == "col_ar" : num = 76
369 | elif num == "col_co" : num = 77
370 | elif num == "col_o" : num = 78
371 | elif num == "col_o2" : num = 79
372 | elif num == "col_o3" : num = 80
373 | elif num == "col_h" : num = 81
374 | elif num == "col_h2" : num = 82
375 | elif num == "col_he" : num = 83
376 | elif num == "vmr_elec" : num = 84
377 | elif num == "col_elec" : num = 85
378 | elif not isinstance(num, np.int): errormess("field reference not found.")
379 | return num
380 |
381 |
382 | ###################
383 | ### One request ###
384 | ###################
385 |
386 | def update(self):
387 | # retrieve fields from MCD (call_mcd). more info in fmcd.call_mcd.__doc__
388 | ## sanity first
389 | self.loct = abs(self.loct)%24
390 | if self.locts is not None and self.locte is not None:
391 | self.locts = abs(self.locts)%24
392 | self.locte = abs(self.locte)%24
393 | if self.locts == self.locte: self.locte = self.locts + 24
394 | ## ensure that local time = 0 when using Earth dates
395 | if self.datekey == 0: self.loct = 0.
396 | ### now MCD request
397 | (self.pres, self.dens, self.temp, self.zonwind, self.merwind, \
398 | self.meanvar, self.extvar, self.seedout, self.ierr) \
399 | = \
400 | mcd.call_mcd(self.zkey,self.xz,self.lon,self.lat,self.hrkey, \
401 | self.datekey,self.xdate,self.loct,self.dset,self.dust, \
402 | self.perturkey,self.seedin,self.gwlength,self.extvarkey )
403 | ## we use the end of extvar (unused) to store meanvar. this is convenient for getextvar(lab)
404 | self.extvar[90] = self.pres ; self.extvar[91] = self.dens
405 | self.extvar[92] = self.temp ; self.extvar[93] = self.zonwind ; self.extvar[94] = self.merwind
406 | self.extvar[95] = np.sqrt(self.extvar[93]**2 + self.extvar[94]**2) # calculate wind modulus
407 | ## treat missing values
408 | if self.temp == -999: self.extvar[:] = np.NaN ; self.meanvar[:] = np.NaN
409 |
410 | def printset(self):
411 | # print main settings
412 | print "zkey",self.zkey,"xz",self.xz,"lon",self.lon,"lat",self.lat,"hrkey",self.hrkey, \
413 | "xdate",self.xdate,"loct",self.loct,"dust",self.dust
414 |
415 | def getnameset(self):
416 | # set a name referring to settings [convenient for databases]
417 | strlat = str(self.lat)+str(self.lats)+str(self.late)
418 | strlon = str(self.lon)+str(self.lons)+str(self.lone)
419 | strxz = str(self.xz)+str(self.xzs)+str(self.xze)
420 | strloct = str(self.loct)+str(self.locts)+str(self.locte)
421 | strdate = str(self.datekey)+str(self.xdate)+str(self.xdates)+str(self.xdatee)
422 | name = str(self.zkey)+strxz+strlon+strlat+str(self.hrkey)+strdate+strloct+str(self.dust)
423 | return name
424 |
425 | def printcoord(self):
426 | # print requested space-time coordinates
427 | print "LAT",self.lat,"LON",self.lon,"LOCT",self.loct,"XDATE",self.xdate
428 |
429 | def printmeanvar(self):
430 | # print mean MCD variables
431 | print "Pressure = %5.3f pascals. " % (self.pres)
432 | print "Density = %5.3f kilograms per cubic meter. " % (self.dens)
433 | print "Temperature = %3.0f kelvins (%4.0f degrees celsius)." % (self.temp,self.temp-273.15)
434 | print "Zonal wind = %5.3f meters per second." % (self.zonwind)
435 | print "Meridional wind = %5.3f meters per second." % (self.merwind)
436 | print "Total horizontal wind = %5.3f meters per second." % ( np.sqrt(self.zonwind**2 + self.merwind**2) )
437 |
438 | def printextvar(self,num):
439 | # print extra MCD variables
440 | num = self.convertlab(num)
441 | dastr = str(self.extvar[num-1])
442 | if dastr == "nan": print "!!!! There is a problem, probably a value is requested below the surface !!!!"
443 | else: print self.getextvarlab(num) + " ..... " + dastr
444 |
445 | def printallextvar(self):
446 | # print all extra MCD variables
447 | limit=85 #mcd6 number of extravar
448 | for i in range(limit): self.printextvar(i+1)
449 |
450 | def htmlprinttabextvar(self,tabtodo):
451 | self.fixedlt = True ## local time is real local time
452 | self.gettitle()
453 | print "
"
454 | print self.title
455 | print "
"
456 | print ""
457 | for i in range(len(tabtodo)): print "- " ; self.printextvar(tabtodo[i]) ; print "
"
458 | print "
"
459 | print "
"
460 | print self.ack
461 | print "
"
462 | #print "SETTINGS
"
463 | #self.printcoord()
464 | #self.printset()
465 |
466 | def printmcd(self):
467 | # 1. call MCD 2. print settings 3. print mean vars
468 | self.update()
469 | self.printcoord()
470 | print "-------------------------------------------"
471 | self.printmeanvar()
472 |
473 | ########################
474 | ### Several requests ###
475 | ########################
476 |
477 | def prepare(self,ndx=None,ndy=None):
478 | ### --- prepare I/O arrays for 1d slices ---
479 | ### NB: use ininterv to define xcoord and ycoord, not done here
480 | if ndx is None: print "No dimension in prepare. Exit. Set at least ndx." ; exit()
481 | #else: self.xcoord = np.ones(ndx)
482 | if ndy is None: dashape = (ndx) ; dashapemean = (ndx,6) ; dashapeext = (ndx,101) #; self.ycoord = None
483 | else: dashape = (ndx,ndy) ; dashapemean = (ndx,ndy,6) ; dashapeext = (ndx,ndy,101) #; self.ycoord = np.ones(ndy)
484 | self.prestab = np.ones(dashape) ; self.denstab = np.ones(dashape) ; self.temptab = np.ones(dashape)
485 | self.zonwindtab = np.ones(dashape) ; self.merwindtab = np.ones(dashape)
486 | self.meanvartab = np.ones(dashapemean) ; self.extvartab = np.ones(dashapeext)
487 |
488 | def getextvar(self,num):
489 | ### get a given var in extvartab
490 | try: field=self.extvartab[:,:,num]
491 | except: field=self.extvartab[:,num]
492 | return field
493 |
494 | def definefield(self,choice):
495 | ### for analysis or plot purposes, set field and field label from user-defined choice
496 | choice = self.convertlab(choice)
497 | field = self.getextvar(choice); fieldlab = self.getextvarlab(choice)
498 | ## fix for possibly slightly negative tracers
499 | if "(mol/mol)" in fieldlab or "(kg/kg)" in fieldlab or "(kg/m2)" in fieldlab or "(W/m2)" in fieldlab:
500 | ind = np.where(field < 1.e-30)
501 | if ind != -1: field[ind] = 0.e0 #1.e-30 ## 0 does not work everywhere.
502 | return field,fieldlab
503 |
504 | def ininterv(self,dstart,dend,nd,start=None,end=None,yaxis=False,vertcoord=False):
505 | ### user-defined start and end are used to create xcoord (or ycoord) vector
506 | if start is not None and end is not None: first, second = self.correctbounds(start,end,vertcoord)
507 | else: first, second = self.correctbounds(dstart,dend,vertcoord)
508 | if self.zkey != 4 or not vertcoord: tabtab = np.linspace(first,second,nd)
509 | else: tabtab = np.logspace(first,second,nd)
510 | if not yaxis: self.xcoord = tabtab
511 | else: self.ycoord = tabtab
512 |
513 | def correctbounds(self,start,end,vertcoord):
514 | if self.zkey != 4 or not vertcoord:
515 | # regular altitudes
516 | if start > end: first = end ; second = start
517 | else: first = start ; second = end
518 | else:
519 | # pressure: reversed avis
520 | if start < end: first = np.log10(end) ; second = np.log10(start)
521 | else: first = np.log10(start) ; second = np.log10(end)
522 | return first, second
523 |
524 | def vertlabel(self):
525 | # if self.zkey == 1: self.xlabel = "radius from centre of planet (m)"
526 | # elif self.zkey == 2: self.xlabel = "height above areoid (m) (MOLA zero datum)"
527 | # elif self.zkey == 3: self.xlabel = "height above surface (m)"
528 | # elif self.zkey == 4: self.xlabel = "pressure level (Pa)"
529 | # elif self.zkey == 5: self.xlabel = "altitude above mean Mars Radius(=3396000m) (m)"
530 | if self.zkey == 1: self.xlabel = "radius from centre of planet (m)"
531 | elif self.zkey == 2: self.xlabel = "altitude above MOLA$_0$ (m)"
532 | elif self.zkey == 3: self.xlabel = "height above surface (m)"
533 | elif self.zkey == 4: self.xlabel = "pressure (Pa)"
534 | elif self.zkey == 5: self.xlabel = "altitude above mean Mars radius (m)"
535 |
536 | def vertunits(self):
537 | if self.zkey == 1: self.vunits = "m CP"
538 | elif self.zkey == 2: self.vunits = "m AMR"
539 | elif self.zkey == 3: self.vunits = "m ALS"
540 | elif self.zkey == 4: self.vunits = "Pa"
541 | elif self.zkey == 5: self.vunits = "m AMMRad"
542 |
543 | def vertaxis(self,number,yaxis=False):
544 | if self.zkey == 2: self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
545 | elif self.zkey == 3: self.ininterv(0.,120000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
546 | elif self.zkey == 5: self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
547 | elif self.zkey == 4: self.ininterv(1000.,0.001,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
548 | elif self.zkey == 1: self.ininterv(3396000,3596000,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
549 |
550 | ###################
551 | ### 1D analysis ###
552 | ###################
553 |
554 | def put1d(self,i):
555 | ## fill in subscript i in output arrays
556 | ## (arrays must have been correctly defined through prepare)
557 | if self.prestab is None: errormess("arrays must be prepared first through self.prepare")
558 | self.prestab[i] = self.pres ; self.denstab[i] = self.dens ; self.temptab[i] = self.temp
559 | self.zonwindtab[i] = self.zonwind ; self.merwindtab[i] = self.merwind
560 | self.meanvartab[i,1:5] = self.meanvar[0:4] ## note: var numbering according to MCD manual is kept
561 | self.extvartab[i,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
562 |
563 | def diurnal(self,nd=dflct):
564 | ### retrieve a local time slice
565 | self.fixedlt = True ## local time is real local time
566 | save = self.loct
567 | self.xlabel = ltlab
568 | self.prepare(ndx=nd) ; self.ininterv(0.,24.,nd,start=self.locts,end=self.locte)
569 | for i in range(nd): self.loct = self.xcoord[i] ; self.update() ; self.put1d(i)
570 | self.loct = save
571 |
572 | def zonal(self,nd=dfzon):
573 | ### retrieve a longitude slice
574 | save = self.lon
575 | save2 = self.loct
576 | self.xlabel = lonlab
577 | self.prepare(ndx=nd) ; self.ininterv(-180.,180.,nd,start=self.lons,end=self.lone)
578 | if not self.fixedlt: umst = self.loct
579 | for i in range(nd):
580 | self.lon = self.xcoord[i]
581 | if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24
582 | self.update() ; self.put1d(i)
583 | self.lon = save
584 | self.loct = save2
585 |
586 | def meridional(self,nd=dfmer):
587 | ### retrieve a latitude slice
588 | self.fixedlt = True ## local time is real local time
589 | save = self.lat
590 | self.xlabel = latlab
591 | self.prepare(ndx=nd) ; self.ininterv(-90.,90.,nd,start=self.lats,end=self.late)
592 | for i in range(nd): self.lat = self.xcoord[i] ; self.update() ; self.put1d(i)
593 | self.lat = save
594 |
595 | def profile(self,nd=dfver,tabperso=None):
596 | ### retrieve an altitude slice (profile)
597 | self.fixedlt = True ## local time is real local time
598 | save = self.xz
599 | self.vertlabel()
600 | self.vertplot = True
601 | if tabperso is not None: nd = len(tabperso)
602 | correct = False
603 | self.prepare(ndx=nd) ; self.vertaxis(nd)
604 | if tabperso is not None: self.xcoord = tabperso
605 | for i in range(nd): self.xz = self.xcoord[i] ; self.update() ; self.put1d(i)
606 | self.xz = save
607 |
608 | def seasonal(self,nd=dfsea):
609 | ### retrieve a seasonal slice
610 | save = self.xdate
611 | self.xlabel = lslab
612 | self.prepare(ndx=nd) ; self.ininterv(0.,360.,nd,start=self.xdates,end=self.xdatee)
613 | for i in range(nd): self.xdate = self.xcoord[i] ; self.update() ; self.put1d(i)
614 | self.xdate = save
615 |
616 | def getascii(self,tabtodo,filename="output.txt",log=None):
617 | ### print out values in an ascii file
618 | import datetime
619 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
620 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
621 | asciifile = open(filename, "w")
622 | if log is not None:
623 | logfile = open(log, "a")
624 | for i in range(len(tabtodo)):
625 | txt = "##########################################################################################\n"
626 | ### print out header
627 | (field, fieldlab) = self.definefield(tabtodo[i])
628 | self.gettitle(oneline=True)
629 | txt = txt + "### " + self.title + "\n"
630 | txt = txt.replace("scenario.","scenario.\n###")
631 | txt = txt + "### --------------------------------------------------------------------------------------\n"
632 | txt = txt + "### Column 1 is " + self.xlabel + "\n"
633 | dim = field.ndim
634 | if (dim == 1):
635 | txt = txt + "### Column 2 is " + fieldlab + "\n"
636 | data = txt
637 | elif (dim == 2):
638 | txt = txt + "### Columns 2+ are " + fieldlab + "\n"
639 | txt = txt + "### Line 1 is " + self.ylabel + "\n"
640 | txt = txt + "### --------------------------------------------------------------------------------------\n"
641 | txt = txt + "### Retrieved on: " + datetime.datetime.today().isoformat() + "\n"
642 | txt = txt + "### " + self.ack + "\n"
643 | txt = txt + "##########################################################################################\n"
644 | ### print out data
645 | data = txt
646 | if (dim == 1):
647 | for ix in range(len(self.xcoord)):
648 | data = data + "%15.5e%15.5e\n" % ( self.xcoord[ix], field[ix] )
649 | elif (dim == 2):
650 | data = data + "---- ||"
651 | for iy in range(len(self.ycoord)):
652 | data = data + "%15.5e" % ( self.ycoord[iy] )
653 | data = data + "\n-----------------------------------\n"
654 | for ix in range(len(self.xcoord)):
655 | zestr = "%+.03d ||" % (self.xcoord[ix])
656 | for iy in range(len(self.ycoord)):
657 | zestr = zestr + "%15.5e" % (field[ix,iy])
658 | data = data + zestr+"\n"
659 | asciifile.write(data)
660 | if log is not None:
661 | logfile.write(txt)
662 | asciifile.close()
663 | if log is not None:
664 | logfile.close()
665 | return
666 |
667 | def makeplot1d(self,choice):
668 | ### one 1D plot is created for the user-defined variable in choice.
669 | (field, fieldlab) = self.definefield(choice)
670 | if not self.vertplot: absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel
671 | else: ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel
672 | mpl.plot(absc,ordo,'-bo') ; mpl.ylabel(ordolab) ; mpl.xlabel(absclab) #; mpl.xticks(query.xcoord)
673 | # cases with log axis
674 | if self.zkey == 4: mpl.semilogy() ; ax = mpl.gca() ; ax.set_ylim(ax.get_ylim()[::-1])
675 | if not self.vertplot and self.islog: mpl.semilogy()
676 | if self.vertplot and self.islog: mpl.semilogx()
677 | mpl.figtext(0.5, 0.01, self.ack, ha='center')
678 |
679 | def plot1d(self,tabtodo):
680 | ### complete 1D figure with possible multiplots
681 | import mcdcomp as mcdcomp
682 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
683 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
684 | fig = mpl.figure() ; subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig )
685 | for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1).grid(True, linestyle=':', color='grey') ; self.makeplot1d(tabtodo[i])
686 | mpl.show()
687 |
688 | def htmlplot1d(self,tabtodo,figname="temp.png",title=""):
689 | ### complete 1D figure with possible multiplots
690 | ### added in 09/2012 for online MCD
691 | ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
692 | import mcdcomp as mcdcomp
693 | from matplotlib.figure import Figure
694 | from matplotlib.backends.backend_agg import FigureCanvasAgg
695 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
696 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
697 |
698 | howmanyplots = len(tabtodo)
699 | if howmanyplots == 1: fig = Figure(figsize=(16,8))
700 | elif howmanyplots == 2: fig = Figure(figsize=(8,8))
701 | elif howmanyplots == 3: fig = Figure(figsize=(8,16))
702 | elif howmanyplots == 4: fig = Figure(figsize=(16,8))
703 |
704 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig )
705 | for i in range(len(tabtodo)):
706 | yeah = fig.add_subplot(subv,subh,i+1) #.grid(True, linestyle=':', color='grey')
707 | choice = tabtodo[i]
708 | (field, fieldlab) = self.definefield(choice)
709 |
710 | # in log plots we do not show the negative values
711 | if self.islog: field[np.where(field <= 0.e0)] = np.nan
712 |
713 | if not self.vertplot: absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel
714 | else: ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel
715 |
716 | yeah.plot(absc,ordo,'-bo') #; mpl.xticks(query.xcoord)
717 | ax = fig.gca() ; ax.set_ylabel(ordolab) ; ax.set_xlabel(absclab)
718 |
719 | if self.xzs is not None and self.zkey == 4: ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1])
720 | if not self.vertplot and self.islog: ax.set_yscale('log')
721 | if self.vertplot and self.islog: ax.set_xscale('log')
722 |
723 | if self.lats is not None: ax.set_xticks(np.arange(-90,91,15)) ; ax.set_xbound(lower=self.lats, upper=self.late)
724 | elif self.lons is not None: ax.set_xticks(np.arange(-360,361,30)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
725 | elif self.locts is not None: ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte)
726 | elif self.xdates is not None: ax.set_xticks(np.arange(0,361,30)) ; ax.set_xbound(lower=self.xdates, upper=self.xdatee)
727 |
728 | ## does not work
729 | #ax.ticklabel_format(useOffset=False,axis='x')
730 | #ax.ticklabel_format(useOffset=False,axis='y')
731 |
732 | ax.grid(True, linestyle=':', color='grey')
733 |
734 | self.gettitle()
735 | fig.text(0.5, 0.95, self.title, ha='center', transform=fig.gca().transAxes, fontweight='bold')
736 | fig.text(0.5, 0.01, self.ack, ha='center')
737 | canvas = FigureCanvasAgg(fig)
738 | # The size * the dpi gives the final image size
739 | # a4"x4" image * 80 dpi ==> 320x320 pixel image
740 | canvas.print_figure(figname, dpi=self.dpi)
741 |
742 | ###################
743 | ### 2D analysis ###
744 | ###################
745 |
746 | def definetype(self,typex=None,typey=None):
747 | ### get the type of 2D plot
748 | # -- we keep a "forcing" option for retrocompatibility (e.g. for maps)
749 | # -- this is meant to ultimately disappear
750 | if typex is not None and typey is not None:
751 | self.typex = typex
752 | self.typey = typey
753 | return
754 | # -- retrieve kind of time axis
755 | if self.locts is not None:
756 | zetypet = "loct"
757 | # case of a ls/lt map (all-time plot)
758 | if self.xdates is not None:
759 | self.typex = "ls" ; self.typey = zetypet
760 | return
761 | elif self.xdates is not None:
762 | zetypet = "ls"
763 | else:
764 | zetypet = None
765 | # -- retrieve kind of spatial axis
766 | if self.lons is not None:
767 | zetypes = "lon"
768 | # case of a lat/lon map
769 | if self.lats is not None:
770 | self.typex = zetypes ; self.typey = "lat"
771 | return
772 | elif self.lats is not None:
773 | zetypes = "lat"
774 | # -- explore all possibilities
775 | if zetypet is None:
776 | # this is horizontal/vertical section
777 | self.typex = zetypes ; self.typey = "alt" # secalt
778 | else:
779 | # there is a time axis
780 | # -- first we consider that spatial could be altitude
781 | # -- others (lat & lon) were done above
782 | if self.xzs is not None:
783 | zetypes = "alt"
784 | # -- second we organize coordinates as usual
785 | if zetypet == "loct":
786 | if zetypes == "alt":
787 | self.typex = zetypet ; self.typey = zetypes # hovmoller with alt
788 | else:
789 | self.typex = zetypes ; self.typey = zetypet # hovmoller
790 | elif zetypet == "ls":
791 | self.typex = zetypet ; self.typey = zetypes # seasonal
792 | return
793 |
794 | def query2d(self,typex=None,typey=None,ndmean=32):
795 | ### retrieve a 2D slice
796 | # save query
797 | save1 = self.lon ; save2 = self.xz ; save3 = self.loct ; save4 = self.lat ; save5 = self.xdate
798 | # initialize
799 | if not self.fixedlt:
800 | umst = self.loct # local time is not fixed. user-defined local time is at longitude 0.
801 | # define the type of 2D plot
802 | # -- hard setting of typex and typey is meant to disappear
803 | self.definetype(typex=typex,typey=typey)
804 | # settings for averaging
805 | if self.averaging is not None:
806 | coordmean = self.meandim(ndmean=ndmean)
807 | if self.averaging == "lon":
808 | self.fixedlt = False
809 | umst = self.loct # shouldn't it be zero? does not matter anyways...
810 | # get coordinates
811 | self.fillcoord()
812 | # MAIN QUERY LOOP
813 | for i in range(self.xcoord.size):
814 | for j in range(self.ycoord.size):
815 | # fill in correct values for query
816 | self.filldim(self.xcoord[i],self.ycoord[j])
817 | # emulate "natural" global local time if not free dim and not fixedlt
818 | if self.locts is None:
819 | if not self.fixedlt:
820 | self.loct = (umst + self.lon/15.) % 24
821 | # get field (simple or average)
822 | if self.averaging is None:
823 | self.update()
824 | else:
825 | self.meanperform(coordmean,umst=umst)
826 | # fill in 2D array
827 | self.put2d(i,j)
828 | # reinstall init state
829 | if not self.fixedlt: self.loct = umst
830 | self.lon = save1 ; self.xz = save2 ; self.loct = save3 ; self.lat = save4 ; self.xdate = save5
831 |
832 | ################################################
833 | ### retro-compatibility functions
834 | ### -- only latlon is used now in htmlmap2d query
835 | ### -- htmlplot2d uses now query2d() in which plot type is set
836 | ### -- but what is below could be useful in interactive mode
837 | def latlon(self,typex="lon",typey="lat"):
838 | ### retrieve a latitude/longitude slice
839 | self.query2d(typex=typex,typey=typey)
840 | def secalt(self,typex="lat"):
841 | ### retrieve a coordinate/altitude slice
842 | self.query2d(typex=typex,typey="alt")
843 | def hovmoller(self,typex="lat",typey="loct"):
844 | ### retrieve a time/other coordinate slice
845 | if typey == "ls":
846 | typey = typex ; typex = "ls" #usually in seasonal plots, Ls is in x-axis
847 | self.query2d(typex=typex,typey=typey)
848 | def zonalmean(self,ndmean=32,typey="alt",typex="lat"):
849 | ### retrieve a zonalmean lat/altitude or ls/lat slice
850 | self.averaging="lon"
851 | self.query2d(typex=typex,typey=typey)
852 | ################################################
853 |
854 | def fillcoord(self):
855 | ### define coordinates. using global default values for number of points.
856 | ### prepare output arrays once coordinates are defined.
857 | # fill in coord properties // x-axis
858 | if self.typex == "lat":
859 | ndx = dfmer
860 | self.xlabel = latlab
861 | self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late) ## do we want to change ndx or just use dfzon?
862 | elif self.typex == "lon":
863 | ndx = dfzon
864 | self.xlabel = lonlab
865 | self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone)
866 | elif self.typex == "alt":
867 | ndx = dfver
868 | self.vertlabel()
869 | self.vertaxis(dfver)
870 | elif self.typex == "ls":
871 | ndx = dfsea
872 | self.xlabel = lslab
873 | self.ininterv(0.,360.,ndx,start=self.xdates,end=self.xdatee)
874 | elif self.typex == "loct":
875 | ndx = dflct
876 | self.xlabel = ltlab
877 | self.ininterv(0.,24.,ndx,start=self.locts,end=self.locte)
878 | # fill in coord properties // y-axis
879 | if self.typey == "lat":
880 | ndy = dfmer
881 | self.ylabel = latlab
882 | self.ininterv(-90.,90.,ndy,start=self.lats,end=self.late,yaxis=True)
883 | elif self.typey == "lon":
884 | ndy = dfzon
885 | self.ylabel = lonlab
886 | self.ininterv(-180.,180.,ndy,start=self.lons,end=self.lone,yaxis=True)
887 | elif self.typey == "alt":
888 | ndy = dfver
889 | sav = self.xlabel # save because used below as intermediate (to be improved)
890 | self.vertlabel() ; self.ylabel = self.xlabel
891 | self.xlabel = sav
892 | self.vertaxis(ndy,yaxis=True)
893 | elif self.typey == "ls":
894 | ndy = dfsea
895 | self.ylabel = lslab
896 | self.ininterv(0.,360.,ndy,start=self.xdates,end=self.xdatee,yaxis=True)
897 | elif self.typey == "loct":
898 | ndy = dflct
899 | self.ylabel = ltlab
900 | self.ininterv(0.,24.,ndy,start=self.locts,end=self.locte,yaxis=True)
901 | # prepare arrays with correct dimensions
902 | self.prepare(ndx=ndx,ndy=ndy)
903 |
904 | def filldim(self,xx,yy):
905 | # fill in individual values in axis
906 | tab = [[self.typex,xx],[self.typey,yy]]
907 | for ttt in tab:
908 | if "lat" in ttt[0]: self.lat = ttt[1]
909 | if "lon" in ttt[0]: self.lon = ttt[1]
910 | if "alt" in ttt[0]: self.xz = ttt[1]
911 | if "loct" in ttt[0]: self.loct = ttt[1]
912 | if "ls" in ttt[0]: self.xdate = ttt[1]
913 |
914 | def meandim(self,ndmean=32):
915 | ### define averaging dimension
916 | sav = self.xcoord #using xcoord as an intermediate
917 | if self.averaging == "lon":
918 | self.ininterv(-180.,180.,ndmean)
919 | elif self.averaging == "loct":
920 | self.ininterv(0.,24.,ndmean)
921 | coordmean = self.xcoord
922 | self.xcoord = sav
923 | return coordmean
924 |
925 | def meanperform(self,coordmean,umst=None):
926 | ndmean = coordmean.size
927 | meanpres = 0. ; meandens = 0. ; meantemp = 0. ; meanzonwind = 0. ; meanmerwind = 0. ; meanmeanvar = np.zeros(5) ; meanextvar = np.zeros(100)
928 | for ccc in coordmean:
929 | if self.averaging == "lon":
930 | # zonal averaging with forcing of local time
931 | self.lon = ccc
932 | self.loct = (umst + self.lon/15.) % 24 #fixedlt false for this case
933 | elif self.averaging == "loct":
934 | self.loct = ccc
935 | self.update()
936 | meanpres = meanpres + self.pres/float(ndmean) ; meandens = meandens + self.dens/float(ndmean) ; meantemp = meantemp + self.temp/float(ndmean)
937 | meanzonwind = meanzonwind + self.zonwind/float(ndmean) ; meanmerwind = meanmerwind + self.merwind/float(ndmean)
938 | meanmeanvar = meanmeanvar + self.meanvar/float(ndmean) ; meanextvar = meanextvar + self.extvar/float(ndmean)
939 | self.pres=meanpres ; self.dens=meandens ; self.temp=meantemp ; self.zonwind=meanzonwind ; self.merwind=meanmerwind
940 | self.meanvar=meanmeanvar ; self.extvar=meanextvar
941 |
942 | def put2d(self,i,j):
943 | ## fill in subscript i,j in output arrays
944 | ## (arrays must have been correctly defined through prepare)
945 | if self.prestab is None: errormess("arrays must be prepared first through self.prepare")
946 | self.prestab[i,j] = self.pres ; self.denstab[i,j] = self.dens ; self.temptab[i,j] = self.temp
947 | self.zonwindtab[i,j] = self.zonwind ; self.merwindtab[i,j] = self.merwind
948 | self.meanvartab[i,j,1:5] = self.meanvar[0:4] ## note: var numbering according to MCD manual is kept
949 | self.extvartab[i,j,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
950 |
951 | def makemap2d(self,choice,incwind=False,proj="cyl"):
952 | ### one 2D map is created for the user-defined variable in choice.
953 | import mcdcomp as mcdcomp
954 | self.latlon() ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d)
955 | if choice == "wind" or incwind:
956 | (windx, fieldlabwx) = self.definefield("u")
957 | (windy, fieldlabwy) = self.definefield("v")
958 | if choice == "wind":
959 | field = np.sqrt(windx*windx + windy*windy)
960 | fieldlab = "Horizontal wind speed (m/s)"
961 | else:
962 | (field, fieldlab) = self.definefield(choice)
963 | if incwind: mcdcomp.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj,vecx=windx,vecy=windy,vmin=self.min2d,vmax=self.max2d) #,stride=1)
964 | else: mcdcomp.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj,vmin=self.min2d,vmax=self.max2d)
965 | mpl.figtext(0.5, 0.0, self.ack, ha='center')
966 |
967 | def map2d(self,tabtodo,incwind=False,proj="cyl"):
968 | ### complete 2D figure with possible multiplots
969 | import mcdcomp as mcdcomp
970 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
971 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
972 | fig = mpl.figure()
973 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig )
974 | for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1) ; self.makemap2d(tabtodo[i],incwind=incwind,proj=proj)
975 | mpl.show()
976 |
977 | def makeinterv(self):
978 | self.latinterv = 30.
979 | self.loninterv = 45.
980 | if self.lats is not None:
981 | if (abs(self.late-self.lats) < 90.): self.latinterv = 10.
982 | if (abs(self.late-self.lats) < 10.): self.latinterv = 1.
983 | if self.lons is not None:
984 | if (abs(self.lone-self.lons) < 135.): self.loninterv = 15.
985 | if (abs(self.lone-self.lons) < 15.): self.loninterv = 1.
986 |
987 | def htmlmap2d(self,tabtodo,incwind=False,figname="temp.png"):
988 | ### complete 2D figure with possible multiplots
989 | ### added in 09/2012 for online MCD
990 | ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
991 | import mcdcomp as mcdcomp
992 | from matplotlib.figure import Figure
993 | from matplotlib.backends.backend_agg import FigureCanvasAgg
994 | from matplotlib.cm import get_cmap
995 | from matplotlib import rcParams
996 | import matplotlib.pyplot as plt
997 | ####
998 | isproj = (self.proj is not None)
999 | if isproj:
1000 | from mpl_toolkits.basemap import Basemap
1001 | ####
1002 | if (self.trans > 0.): isback = True
1003 | else: isback = False
1004 | if (self.trans > 0.99): self.iscontour = True
1005 | ####
1006 |
1007 | try:
1008 | from scipy.io import netcdf
1009 | filename = dataloc+"/mola32.nc" ; back = "alt"
1010 | zefile = netcdf.netcdf_file(filename, 'r')
1011 | fieldc = zefile.variables[back][::32,::32]/1000.
1012 | yc = zefile.variables['latitude'][::32]
1013 | xc = zefile.variables['longitude'][::32]
1014 | zefile.close()
1015 | havetopo = True
1016 | except:
1017 | print "Trouble with netCDF or surface.nc file. Continue without topo lines."
1018 | havetopo = False
1019 |
1020 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
1021 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
1022 |
1023 | fig = mcdcomp.setfig(len(tabtodo),proj=self.proj)
1024 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig )
1025 |
1026 | for i in range(len(tabtodo)):
1027 | yeah = fig.add_subplot(subv,subh,i+1)
1028 | choice = tabtodo[i]
1029 | self.latlon() #ndx=64,ndy=48)
1030 | ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d)
1031 | (field, fieldlab) = self.definefield(choice)
1032 | if incwind: (windx, fieldlabwx) = self.definefield("u") ; (windy, fieldlabwy) = self.definefield("v")
1033 |
1034 | ndiv = 40
1035 | vecx=None ; vecy=None ; stride=2
1036 | lon = self.xcoord ; lat = self.ycoord
1037 |
1038 | if isproj:
1039 | ##
1040 | if self.plat is None: self.plat = 0.5*(self.lats+self.late)
1041 | if self.plon is None: self.plon = 0.5*(self.lons+self.lone)
1042 | if self.palt is None: self.palt = 99999999.
1043 |
1044 | ##
1045 | if self.proj == "cyl": yeah = Basemap(projection=self.proj,\
1046 | llcrnrlat=self.lats,urcrnrlat=self.late,\
1047 | llcrnrlon=self.lons,urcrnrlon=self.lone,\
1048 | ax=yeah,resolution=None)
1049 | elif self.proj == "laea": yeah = Basemap(projection=self.proj,ax=yeah,resolution=None,\
1050 | lon_0=self.plon,lat_0=self.plat,\
1051 | llcrnrlat=self.lats,urcrnrlat=self.late,\
1052 | llcrnrlon=self.lons,urcrnrlon=self.lone)
1053 | elif self.proj == "npstere": yeah = Basemap(projection=self.proj,boundinglat=self.plat,lon_0=self.plon,resolution=None,ax=yeah)
1054 | elif self.proj == "spstere": yeah = Basemap(projection=self.proj,boundinglat=self.plat,lon_0=self.plon,resolution=None,ax=yeah)
1055 | elif self.proj == "ortho": yeah = Basemap(projection=self.proj,lat_0=self.plat,lon_0=self.plon,resolution=None,ax=yeah)
1056 | elif self.proj == "robin": yeah = Basemap(projection=self.proj,lon_0=0.,resolution=None,ax=yeah)
1057 | elif self.proj == "nsper": yeah = Basemap(projection=self.proj,lat_0=self.plat,lon_0=self.plon,satellite_height=self.palt*1000.,resolution=None,ax=yeah)
1058 |
1059 | ## NB: resolution=None is here to avoid loading coastlines which caused problems with some (plat,plon) couples
1060 | ### background
1061 | if isback:
1062 | img="/home/marshttp/www-mars/mcd_python/MarsMap_2500x1250.jpg"
1063 | yeah.warpimage(img,scale=0.75)
1064 | mertab,partab = np.r_[-180.:180.:30.],np.r_[-90.:90.:15.]
1065 | merlab,parlab = [0,0,0,1],[1,0,0,0]
1066 | #format = '%.1f'
1067 |
1068 | if(self.proj=="nsper") :
1069 | yeah.drawmeridians(mertab,color="grey")
1070 | yeah.drawparallels(partab,color="grey")
1071 | else :
1072 | yeah.drawmeridians(mertab,color="grey",labels=merlab)
1073 | yeah.drawparallels(partab,color="grey",labels=parlab)
1074 |
1075 | [lon2d,lat2d] = np.meshgrid(lon,lat)
1076 | x, y = yeah(lon2d, lat2d)
1077 | else:
1078 | x = lon ; y = lat
1079 |
1080 | ## define field. bound field.
1081 | what_I_plot = np.transpose(field)
1082 | zevmin,zevmax,limtype = mcdcomp.setbounds(what_I_plot,vmin=self.min2d,vmax=self.max2d)
1083 | ## define contour field levels. define color palette
1084 | ticks = ndiv + 1
1085 | zelevels = np.linspace(zevmin,zevmax,ticks)
1086 | if zevmin==zevmax: # handle case where all values of the array are the same
1087 | zelevels = np.linspace(zevmin*0.9,zevmax*1.1,ticks)
1088 | palette = get_cmap(name=self.colorm)
1089 |
1090 | ## topography contours
1091 | if havetopo:
1092 | rcParams['contour.negative_linestyle'] = 'solid' # negative contours solid instead of dashed
1093 | zelevc = np.linspace(-9.,20.,11.,0.)
1094 | if isproj:
1095 | [xc2,yc2] = np.meshgrid(xc,yc)
1096 | xc3,yc3 = yeah(xc2,yc2)
1097 | yeah.contour( xc3, yc3, fieldc, zelevc, colors='black',linewidths = 0.4 )
1098 | [xc2,yc2] = np.meshgrid(np.array(xc)-360.,yc)
1099 | xc3,yc3 = yeah(xc2,yc2)
1100 | yeah.contour( xc3, yc3, fieldc, zelevc, colors='black',linewidths = 0.4 )
1101 | else:
1102 | yeah.contour( np.array(xc) , yc, fieldc, zelevc, colors='black',linewidths = 0.4)
1103 | yeah.contour( np.array(xc) - 360., yc, fieldc, zelevc, colors='black',linewidths = 0.4)
1104 |
1105 | # contour field
1106 | if self.iscontour: c = yeah.contour( x, y, what_I_plot, zelevels, cmap = palette )
1107 | else: c = yeah.contourf( x, y, what_I_plot, zelevels, cmap = palette, alpha = 1.-self.trans, extend=limtype )
1108 |
1109 | # colorbar
1110 | if not isproj: orientation='vertical' ; frac = 0.15 ; pad = 0.04 ; lu = 0.5
1111 | elif self.proj in ['moll']: orientation="horizontal" ; frac = 0.08 ; pad = 0.03 ; lu = 1.0
1112 | elif self.proj in ['robin']: orientation="horizontal" ; frac = 0.07 ; pad = 0.1 ; lu = 1.0
1113 | elif self.proj in ['cyl']: orientation="vertical" ; frac = 0.023 ; pad = 0.03 ; lu = 0.5
1114 | else: orientation='vertical' ; frac = 0.05 ; pad = 0.03 ; lu = 0.5
1115 | if np.abs(zevmax) == 1e-35: zevmax=0.
1116 | if np.abs(zevmin) == 1e-35: zevmin=0.
1117 | zelevpal = np.linspace(zevmin,zevmax,num=min([ticks/2+1,21]))
1118 | clb = Figure.colorbar(fig,c,orientation=orientation,format=self.fmt,ticks=zelevpal,\
1119 | fraction=frac,pad=pad,spacing='proportional')
1120 | #clb.set_label(fieldlab)
1121 |
1122 | # wind vectors
1123 | if incwind:
1124 | if isproj: x2d,y2d = x,y
1125 | else: [x2d,y2d] = np.meshgrid(lon,lat)
1126 | wcolor = str(self.trans) # trans=0 black, trans=100 white
1127 | yeah.quiver(x2d,y2d,np.transpose(windx),np.transpose(windy),color=wcolor)
1128 |
1129 | # add a point (TBD: text, use ax.annotate)
1130 | if (self.lonpoint is not None) and (self.latpoint is not None):
1131 | xpt,ypt = yeah(self.lonpoint,self.latpoint) # compute the native map projection coordinates
1132 | yeah.plot(xpt,ypt,'go',markersize=8) # plot filled circle at the location
1133 |
1134 | # operation on axis: title, labels, ticks, etc.
1135 | ax = fig.gca()
1136 | rcParams['axes.titlesize'] = rcParams['font.size']
1137 | ax.set_title(fieldlab)
1138 | if not isproj:
1139 | ax.set_ylabel("Latitude") ; ax.set_xlabel("Longitude")
1140 | # make intervals
1141 | self.makeinterv()
1142 | ax.set_xticks(np.arange(-360,361,self.loninterv)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
1143 | ax.set_yticks(np.arange(-90,91,self.latinterv)) ; ax.set_ybound(lower=self.lats, upper=self.late)
1144 | ax.set_xlim(xmin=-180.,xmax=180.)
1145 |
1146 | ## titles and final production
1147 | self.gettitle()
1148 | #ax.set_title(self.title,x=0.5,y=1.05)
1149 | #ax.set_xlabel('\n'+self.ack,x=0.5,y=0.05)
1150 |
1151 | fig.text(0.5, 0.95, self.title, ha='center', transform=fig.gca().transAxes, fontweight='bold')
1152 | fig.text(0.5, 0.01, self.ack, ha='center')
1153 | canvas = FigureCanvasAgg(fig)
1154 | # The size * the dpi gives the final image size
1155 | # a4"x4" image * 80 dpi ==> 320x320 pixel image
1156 | canvas.print_figure(figname, dpi=self.dpi)
1157 | #, bbox_inches='tight') removes title. and ax.set_title cannot set a global title for multiplots.
1158 |
1159 |
1160 |
1161 | def htmlplot2d(self,tabtodo,figname="temp.png"):
1162 | ### complete 2D figure with possible multiplots
1163 | ### added in 10/2012 for online MCD
1164 | ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
1165 | import mcdcomp as mcdcomp
1166 | from matplotlib import rcParams
1167 | from matplotlib.figure import Figure
1168 | from matplotlib.backends.backend_agg import FigureCanvasAgg
1169 | from matplotlib.cm import get_cmap
1170 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
1171 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
1172 |
1173 | fig = mcdcomp.setfig(len(tabtodo))
1174 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig )
1175 |
1176 | #######################
1177 | self.query2d(self)
1178 | #######################
1179 |
1180 | for i in range(len(tabtodo)):
1181 | yeah = fig.add_subplot(subv,subh,i+1)
1182 | choice = tabtodo[i]
1183 |
1184 | (field, fieldlab) = self.definefield(choice)
1185 |
1186 | colorb=self.colorm ; ndiv=20
1187 |
1188 | ## define field. bound field.
1189 | what_I_plot = np.transpose(field)
1190 | zevmin,zevmax,limtype = mcdcomp.setbounds(what_I_plot,vmin=self.min2d,vmax=self.max2d)
1191 | ## define contour field levels. define color palette
1192 | ticks = ndiv + 1
1193 | zelevels = np.linspace(zevmin,zevmax,ticks)
1194 | if zevmin==zevmax: # handle case where all values of the array are the same
1195 | zelevels = np.linspace(zevmin*0.9,zevmax*1.1,ticks)
1196 | palette = get_cmap(name=colorb)
1197 | # contour field
1198 | c = yeah.contourf( self.xcoord, self.ycoord, what_I_plot, zelevels, cmap = palette, extend=limtype )
1199 | if np.abs(zevmax) == 1e-35: zevmax=0.
1200 | if np.abs(zevmin) == 1e-35: zevmin=0.
1201 | clb = Figure.colorbar(fig,c,orientation='vertical',format=self.fmt,ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])))
1202 | #clb.set_label(fieldlab)
1203 | ax = fig.gca() ; ax.set_ylabel(self.ylabel) ; ax.set_xlabel(self.xlabel)
1204 | rcParams['axes.titlesize'] = rcParams['font.size']
1205 | ax.set_title(fieldlab)
1206 |
1207 | self.makeinterv()
1208 | if self.lons is not None:
1209 | if self.xdates is not None:
1210 | ax.set_yticks(np.arange(-360,361,self.loninterv)) ; ax.set_ybound(lower=self.lons, upper=self.lone)
1211 | else:
1212 | ax.set_xticks(np.arange(-360,361,self.loninterv)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
1213 | elif self.lats is not None:
1214 | if self.xdates is not None:
1215 | ax.set_yticks(np.arange(-90,91,self.latinterv)) ; ax.set_ybound(lower=self.lats, upper=self.late)
1216 | else:
1217 | ax.set_xticks(np.arange(-90,91,self.latinterv)) ; ax.set_xbound(lower=self.lats, upper=self.late)
1218 |
1219 | if self.locts is not None:
1220 | if self.xzs is not None:
1221 | ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte)
1222 | else:
1223 | ax.set_yticks(np.arange(0,26,2)) ; ax.set_ybound(lower=self.locts, upper=self.locte)
1224 | elif self.xdates is not None:
1225 | ax.set_xticks(np.arange(0,361,30)) ; ax.set_xbound(lower=self.xdates, upper=self.xdatee)
1226 |
1227 | if self.zkey == 4 and self.xzs is not None:
1228 | ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1])
1229 | else:
1230 | #ax.set_yticks(np.arange(self.xzs,self.xze,10000.)) ;
1231 | ax.set_ybound(lower=self.xzs, upper=self.xze)
1232 |
1233 | self.gettitle()
1234 | fig.text(0.5, 0.95, self.title, ha='center', transform=fig.gca().transAxes, fontweight='bold')
1235 | fig.text(0.5, 0.01, self.ack, ha='center')
1236 | canvas = FigureCanvasAgg(fig)
1237 | # The size * the dpi gives the final image size
1238 | # a4"x4" image * 80 dpi ==> 320x320 pixel image
1239 | canvas.print_figure(figname, dpi=self.dpi)
1240 |
1241 | ### TODO: makeplot2d, plot2d, passer plot settings
1242 |
1243 |
--------------------------------------------------------------------------------
/mcdcomp.py:
--------------------------------------------------------------------------------
1 | ## set colorbar-type and value limits
2 | def setbounds(field,vmin=None,vmax=None):
3 | import numpy as np
4 | limtype = "neither"
5 | w = np.where(np.isnan(field) == False)
6 | fieldclean = field[w]
7 | if vmin is None and vmax is None:
8 | vmin = np.min(fieldclean) - 1.e-35 # epsilon to avoid blank spaces
9 | vmax = np.max(fieldclean) + 1.e-35 # epsilon to avoid blank spaces
10 | elif vmin is None:
11 | vmin = np.min(fieldclean)
12 | if vmax < np.max(fieldclean):
13 | limtype = "max"
14 | elif vmax is None:
15 | vmax = np.max(fieldclean)
16 | if vmin > np.min(fieldclean):
17 | limtype = "min"
18 | else:
19 | mintoosmall = vmin < np.min(fieldclean)
20 | maxtoohigh = vmax > np.max(fieldclean)
21 | if mintoosmall and maxtoohigh:
22 | limtype = "neither"
23 | elif mintoosmall:
24 | limtype = "max"
25 | elif maxtoohigh:
26 | limtype = "min"
27 | else:
28 | limtype = "both"
29 | return vmin,vmax,limtype
30 |
31 | ## set size of figure for optimal rendering
32 | def setfig(howmanyplots, proj=None):
33 | from matplotlib.figure import Figure
34 | ##
35 | if proj is None:
36 | squared = False
37 | else:
38 | squared = proj in ["npstere","spstere","ortho"]
39 | ##
40 | if howmanyplots == 1:
41 | if squared: fig = Figure(figsize=(10,10))
42 | else: fig = Figure(figsize=(16,8))
43 | elif howmanyplots == 2:
44 | if squared: fig = Figure(figsize=(7,14))
45 | else: fig = Figure(figsize=(10,12))
46 | elif howmanyplots == 3:
47 | if squared: fig = Figure(figsize=(7,21))
48 | else: fig = Figure(figsize=(8,16))
49 | elif howmanyplots == 4:
50 | if squared: fig = Figure(figsize=(10,10))
51 | else: fig = Figure(figsize=(24,12))
52 | return fig
53 |
54 |
55 | ################################################################
56 | ################################################################
57 |
58 |
59 | ## Those are additional functions
60 | ## Useful only for plots with mcd.py
61 | ## This is not intended to be improved
62 | ## -- instead planetoplot will be used one day
63 |
64 | def min (field,axis=None):
65 | import numpy as np
66 | if field is None: return None
67 | if type(field).__name__=='MaskedArray':
68 | field.set_fill_value(np.NaN)
69 | return np.ma.array(field).min(axis=axis)
70 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')):
71 | return np.ma.masked_invalid(field).min(axis=axis)
72 | else: return np.array(field).min(axis=axis)
73 |
74 | def max (field,axis=None):
75 | import numpy as np
76 | if field is None: return None
77 | if type(field).__name__=='MaskedArray':
78 | field.set_fill_value(np.NaN)
79 | return np.ma.array(field).max(axis=axis)
80 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')):
81 | return np.ma.masked_invalid(field).max(axis=axis)
82 | else: return np.array(field).max(axis=axis)
83 |
84 | def mean (field,axis=None):
85 | import numpy as np
86 | if field is None: return None
87 | else:
88 | if type(field).__name__=='MaskedArray':
89 | field.set_fill_value(np.NaN)
90 | zout=np.ma.array(field).mean(axis=axis)
91 | if axis is not None:
92 | zout.set_fill_value(np.NaN)
93 | return zout.filled()
94 | else:return zout
95 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')):
96 | zout=np.ma.masked_invalid(field).mean(axis=axis)
97 | if axis is not None:
98 | zout.set_fill_value([np.NaN])
99 | return zout.filled()
100 | else:return zout
101 | else:
102 | return np.array(field).mean(axis=axis)
103 |
104 | def sum (field,axis=None):
105 | import numpy as np
106 | if field is None: return None
107 | else:
108 | if type(field).__name__=='MaskedArray':
109 | field.set_fill_value(np.NaN)
110 | zout=np.ma.array(field).sum(axis=axis)
111 | if axis is not None:
112 | zout.set_fill_value(np.NaN)
113 | return zout.filled()
114 | else:return zout
115 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')):
116 | zout=np.ma.masked_invalid(field).sum(axis=axis)
117 | if axis is not None:
118 | zout.set_fill_value([np.NaN])
119 | return zout.filled()
120 | else:return zout
121 | else:
122 | return np.array(field).sum(axis=axis)
123 |
124 | #################################################################
125 | #################################################################
126 | #################################################################
127 |
128 | ## Author: AS, AC, JL
129 | def whatkindfile (nc):
130 | typefile = 'gcm' # default
131 | if 'controle' in nc.variables: typefile = 'gcm'
132 | elif 'phisinit' in nc.variables: typefile = 'gcm'
133 | elif 'phis' in nc.variables: typefile = 'gcm'
134 | elif 'time_counter' in nc.variables: typefile = 'earthgcm'
135 | elif hasattr(nc,'START_DATE'): typefile = 'meso'
136 | elif 'HGT_M' in nc.variables: typefile = 'geo'
137 | elif hasattr(nc,'institution'):
138 | if "European Centre" in getattr(nc,'institution'): typefile = 'ecmwf'
139 | return typefile
140 |
141 | ## Author: AS + TN
142 | def definesubplot ( numplot, fig, ipreferline=False):
143 | from matplotlib.pyplot import rcParams
144 | rcParams['font.size'] = 12. ## default (important for multiple calls)
145 | fc = 1.33
146 | if numplot <= 0:
147 | subv = 99999
148 | subh = 99999
149 | elif numplot == 1:
150 | subv = 1
151 | subh = 1
152 | elif numplot == 2:
153 | subv = 2 #1 #2
154 | subh = 1 #2 #1
155 | fig.subplots_adjust(wspace = 0.35*fc)
156 | fig.subplots_adjust(hspace = 0.3*fc)
157 | #rcParams['font.size'] = int( rcParams['font.size'] * 3. / 4. )
158 | elif numplot == 3:
159 | subv = 3
160 | subh = 1
161 | fig.subplots_adjust(hspace = 0.25*fc)
162 | fig.subplots_adjust(wspace = 0.35*fc)
163 | if ipreferline: subv = 1 ; subh = 3 ; fig.subplots_adjust(wspace = 0.35*fc)
164 | #rcParams['font.size'] = int( rcParams['font.size'] * 3. / 4. )
165 | elif numplot == 4:
166 | subv = 2
167 | subh = 2
168 | #fig.subplots_adjust(wspace = 0.4, hspace = 0.6)
169 | fig.subplots_adjust(wspace = 0.25*fc, hspace = 0.3*fc)
170 | #rcParams['font.size'] = int( rcParams['font.size'] * 3. / 4. )
171 | elif numplot <= 6:
172 | subv = 2
173 | subh = 3
174 | #fig.subplots_adjust(wspace = 0.4, hspace = 0.0)
175 | fig.subplots_adjust(wspace = 0.5*fc, hspace = 0.3*fc)
176 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. )
177 | elif numplot <= 8:
178 | subv = 2
179 | subh = 4
180 | fig.subplots_adjust(wspace = 0.3*fc, hspace = 0.3*fc)
181 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. )
182 | elif numplot <= 9:
183 | subv = 3
184 | subh = 3
185 | fig.subplots_adjust(wspace = 0.3*fc, hspace = 0.3*fc)
186 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. )
187 | elif numplot <= 12:
188 | subv = 3
189 | subh = 4
190 | fig.subplots_adjust(wspace = 0, hspace = 0.1*fc)
191 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. )
192 | elif numplot <= 16:
193 | subv = 4
194 | subh = 4
195 | fig.subplots_adjust(wspace = 0.3*fc, hspace = 0.3*fc)
196 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. )
197 | else:
198 | print "number of plot supported: 1 to 16"
199 | exit()
200 | return subv,subh
201 |
202 | ## Author: AS
203 | def getproj (nc):
204 | typefile = whatkindfile(nc)
205 | if typefile in ['meso','geo']:
206 | ### (il faudrait passer CEN_LON dans la projection ?)
207 | map_proj = getattr(nc, 'MAP_PROJ')
208 | cen_lat = getattr(nc, 'CEN_LAT')
209 | if map_proj == 2:
210 | if cen_lat > 10.:
211 | proj="npstere"
212 | #print "NP stereographic polar domain"
213 | else:
214 | proj="spstere"
215 | #print "SP stereographic polar domain"
216 | elif map_proj == 1:
217 | #print "lambert projection domain"
218 | proj="lcc"
219 | elif map_proj == 3:
220 | #print "mercator projection"
221 | proj="merc"
222 | else:
223 | proj="merc"
224 | elif typefile in ['gcm']: proj="cyl" ## pb avec les autres (de trace derriere la sphere ?)
225 | else: proj="ortho"
226 | return proj
227 |
228 | ## Author: AS
229 | def ptitle (name):
230 | from matplotlib.pyplot import title
231 | title(name)
232 | print name
233 |
234 | ## Author: AS
235 | def polarinterv (lon2d,lat2d):
236 | import numpy as np
237 | wlon = [np.min(lon2d),np.max(lon2d)]
238 | ind = np.array(lat2d).shape[0] / 2 ## to get a good boundlat and to get the pole
239 | wlat = [np.min(lat2d[ind,:]),np.max(lat2d[ind,:])]
240 | return [wlon,wlat]
241 |
242 | ## Author: AS
243 | def simplinterv (lon2d,lat2d):
244 | import numpy as np
245 | return [[np.min(lon2d),np.max(lon2d)],[np.min(lat2d),np.max(lat2d)]]
246 |
247 | ## Author: AS
248 | def wrfinterv (lon2d,lat2d):
249 | nx = len(lon2d[0,:])-1
250 | ny = len(lon2d[:,0])-1
251 | lon1 = lon2d[0,0]
252 | lon2 = lon2d[nx,ny]
253 | lat1 = lat2d[0,0]
254 | lat2 = lat2d[nx,ny]
255 | if abs(0.5*(lat1+lat2)) > 60.: wider = 0.5 * (abs(lon1)+abs(lon2)) * 0.1
256 | else: wider = 0.
257 | if lon1 < lon2: wlon = [lon1, lon2 + wider]
258 | else: wlon = [lon2, lon1 + wider]
259 | if lat1 < lat2: wlat = [lat1, lat2]
260 | else: wlat = [lat2, lat1]
261 | return [wlon,wlat]
262 |
263 | ## Author: AS
264 | def makeplotres (filename,res=None,pad_inches_value=0.25,folder='',disp=True,ext='png',erase=False):
265 | import matplotlib.pyplot as plt
266 | from os import system
267 | addstr = ""
268 | if res is not None:
269 | res = int(res)
270 | addstr = "_"+str(res)
271 | name = filename+addstr+"."+ext
272 | if folder != '': name = folder+'/'+name
273 | plt.savefig(name,dpi=res,bbox_inches='tight',pad_inches=pad_inches_value)
274 | if disp: display(name)
275 | if ext in ['eps','ps','svg']: system("tar czvf "+name+".tar.gz "+name+" ; rm -f "+name)
276 | if erase: system("mv "+name+" to_be_erased")
277 | return
278 |
279 | ## Author: AS + AC
280 | def getcoorddef ( nc ):
281 | import numpy as np
282 | ## getcoord2d for predefined types
283 | typefile = whatkindfile(nc)
284 | if typefile in ['meso']:
285 | if '9999' not in getattr(nc,'START_DATE') :
286 | ## regular mesoscale
287 | [lon2d,lat2d] = getcoord2d(nc)
288 | else:
289 | ## idealized mesoscale
290 | nx=getattr(nc,'WEST-EAST_GRID_DIMENSION')
291 | ny=getattr(nc,'SOUTH-NORTH_GRID_DIMENSION')
292 | dlat=getattr(nc,'DX')
293 | ## this is dirty because Martian-specific
294 | # ... but this just intended to get "lat-lon" like info
295 | falselon = np.arange(-dlat*(nx-1)/2.,dlat*(nx-1)/2.,dlat)/60000.
296 | falselat = np.arange(-dlat*(ny-1)/2.,dlat*(ny-1)/2.,dlat)/60000.
297 | [lon2d,lat2d] = np.meshgrid(falselon,falselat) ## dummy coordinates
298 | print "WARNING: domain plot artificially centered on lat,lon 0,0"
299 | elif typefile in ['gcm','earthgcm','ecmwf']:
300 | #### n est ce pas nc.variables ?
301 | if "longitude" in nc.dimensions: dalon = "longitude"
302 | elif "lon" in nc.dimensions: dalon = "lon"
303 | else: dalon = "nothing"
304 | if "latitude" in nc.dimensions: dalat = "latitude"
305 | elif "lat" in nc.dimensions: dalat = "lat"
306 | else: dalat = "nothing"
307 | [lon2d,lat2d] = getcoord2d(nc,nlat=dalat,nlon=dalon,is1d=True)
308 | elif typefile in ['geo']:
309 | [lon2d,lat2d] = getcoord2d(nc,nlat='XLAT_M',nlon='XLONG_M')
310 | return lon2d,lat2d
311 |
312 | ## Author: AS
313 | def getcoord2d (nc,nlat='XLAT',nlon='XLONG',is1d=False):
314 | import numpy as np
315 | if nlon == "nothing" or nlat == "nothing":
316 | print "NO LAT LON FIELDS. I AM TRYING MY BEST. I ASSUME GLOBAL FIELD."
317 | lon = np.linspace(-180.,180.,getdimfromvar(nc)[-1])
318 | lat = np.linspace(-90.,90.,getdimfromvar(nc)[-2])
319 | [lon2d,lat2d] = np.meshgrid(lon,lat)
320 | else:
321 | if is1d:
322 | lat = nc.variables[nlat][:]
323 | lon = nc.variables[nlon][:]
324 | [lon2d,lat2d] = np.meshgrid(lon,lat)
325 | else:
326 | lat = nc.variables[nlat][0,:,:]
327 | lon = nc.variables[nlon][0,:,:]
328 | [lon2d,lat2d] = [lon,lat]
329 | return lon2d,lat2d
330 |
331 | ## Author: AS
332 | def getdimfromvar (nc):
333 | varinfile = nc.variables.keys()
334 | dim = nc.variables[varinfile[-1]].shape ## usually the last variable is 4D or 3D
335 | return dim
336 |
337 | ## Author: AS
338 | def vectorfield (u, v, x, y, stride=3, scale=15., factor=250., color='black', csmooth=1, key=True):
339 | ## scale regle la reference du vecteur
340 | ## factor regle toutes les longueurs (dont la reference). l'AUGMENTER pour raccourcir les vecteurs.
341 | import matplotlib.pyplot as plt
342 | import numpy as np
343 | #posx = np.min(x) - np.std(x) / 10.
344 | #posy = np.min(y) - np.std(y) / 10.
345 | posx = np.min(x)
346 | posy = np.min(y) - 4.*np.std(y) / 10.
347 | widthvec = 0.003 #0.005 #0.003
348 | q = plt.quiver( x[::stride,::stride],\
349 | y[::stride,::stride],\
350 | u[::stride,::stride],\
351 | v[::stride,::stride],\
352 | angles='xy',color=color,pivot='middle',\
353 | scale=factor,width=widthvec )
354 | if color in ['white','yellow']: kcolor='black'
355 | else: kcolor=color
356 | if key: p = plt.quiverkey(q,posx,posy,scale,\
357 | str(int(scale)),coordinates='data',color=kcolor,labelpos='S',labelsep = 0.03)
358 | return
359 |
360 | ## Author: AS
361 | def display (name):
362 | from os import system
363 | system("display "+name+" > /dev/null 2> /dev/null &")
364 | return name
365 |
366 | ## Author: AS
367 | def findstep (wlon):
368 | steplon = int((wlon[1]-wlon[0])/4.) #3
369 | step = 120.
370 | while step > steplon and step > 15. : step = step / 2.
371 | if step <= 15.:
372 | while step > steplon and step > 5. : step = step - 5.
373 | if step <= 5.:
374 | while step > steplon and step > 1. : step = step - 1.
375 | if step <= 1.:
376 | step = 1.
377 | return step
378 |
379 | ## Author: AS
380 | def define_proj (char,wlon,wlat,back=None,blat=None,blon=None):
381 | from mpl_toolkits.basemap import Basemap
382 | import numpy as np
383 | import matplotlib as mpl
384 | meanlon = 0.5*(wlon[0]+wlon[1])
385 | meanlat = 0.5*(wlat[0]+wlat[1])
386 | zewidth = np.abs(wlon[0]-wlon[1])*60000.*np.cos(3.14*meanlat/180.)
387 | zeheight = np.abs(wlat[0]-wlat[1])*60000.
388 | if blat is None:
389 | ortholat=meanlat
390 | if wlat[0] >= 80.: blat = -40.
391 | elif wlat[1] <= -80.: blat = -40.
392 | elif wlat[1] >= 0.: blat = wlat[0]
393 | elif wlat[0] <= 0.: blat = wlat[1]
394 | else: ortholat=blat
395 | if blon is None: ortholon=meanlon
396 | else: ortholon=blon
397 | h = 50. ## en km
398 | radius = 3397200.
399 | if char == "cyl": m = Basemap(rsphere=radius,projection='cyl',\
400 | llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1])
401 | elif char == "moll": m = Basemap(rsphere=radius,projection='moll',lon_0=meanlon)
402 | elif char == "ortho": m = Basemap(rsphere=radius,projection='ortho',lon_0=ortholon,lat_0=ortholat)
403 | elif char == "lcc": m = Basemap(rsphere=radius,projection='lcc',lat_1=meanlat,lat_0=meanlat,lon_0=meanlon,\
404 | width=zewidth,height=zeheight)
405 | #llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1])
406 | elif char == "npstere": m = Basemap(rsphere=radius,projection='npstere', boundinglat=blat, lon_0=0.)
407 | elif char == "spstere": m = Basemap(rsphere=radius,projection='spstere', boundinglat=blat, lon_0=180.)
408 | elif char == "nplaea": m = Basemap(rsphere=radius,projection='nplaea', boundinglat=wlat[0], lon_0=meanlon)
409 | elif char == "laea": m = Basemap(rsphere=radius,projection='laea',lon_0=meanlon,lat_0=meanlat,lat_ts=meanlat,\
410 | width=zewidth,height=zeheight)
411 | #llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1])
412 | elif char == "nsper": m = Basemap(rsphere=radius,projection='nsper',lon_0=meanlon,lat_0=meanlat,satellite_height=h*1000.)
413 | elif char == "merc": m = Basemap(rsphere=radius,projection='merc',lat_ts=0.,\
414 | llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1])
415 | elif char == "geos": m = Basemap(rsphere=radius,projection='geos',lon_0=meanlon)
416 | elif char == "robin": m = Basemap(rsphere=radius,projection='robin',lon_0=0)
417 | elif char == "cass":
418 | if zewidth > 60000.: ## approx. more than one degree
419 | m = Basemap(rsphere=radius,projection='cass',\
420 | lon_0=meanlon,lat_0=meanlat,\
421 | width=zewidth,height=zeheight)
422 | else:
423 | m = Basemap(rsphere=radius,projection='cass',\
424 | lon_0=meanlon,lat_0=meanlat,\
425 | llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1])
426 | else: errormess("projection not supported.")
427 | fontsizemer = int(mpl.rcParams['font.size']*3./4.)
428 | if zewidth > 60000.:
429 | if char in ["cyl","lcc","merc","nsper","laea"]: step = findstep(wlon)
430 | else: step = 10.
431 | steplon = step*2.
432 | else:
433 | print "very small domain !"
434 | steplon = 0.5
435 | step = 0.5
436 | zecolor ='grey'
437 | zelinewidth = 1
438 | zelatmax = 80.
439 | if meanlat > 75.: zelatmax = 90. ; step = step/2. ; steplon = steplon*2.
440 | # # to show gcm grid:
441 | # #zecolor = 'r'
442 | # #zelinewidth = 1
443 | # #step = 180./48.
444 | # #steplon = 360./64.
445 | # #zelatmax = 90. - step/3
446 | # if char not in ["moll","robin"]:
447 | # if wlon[1]-wlon[0] < 2.: ## LOCAL MODE
448 | # m.drawmeridians(np.r_[-1.:1.:0.05], labels=[0,0,0,1], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, fmt='%5.2f')
449 | # m.drawparallels(np.r_[-1.:1.:0.05], labels=[1,0,0,0], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, fmt='%5.2f')
450 | # else: ## GLOBAL OR REGIONAL MODE
451 | # m.drawmeridians(np.r_[-180.:180.:steplon], labels=[0,0,0,1], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, latmax=zelatmax)
452 | # m.drawparallels(np.r_[-90.:90.:step], labels=[1,0,0,0], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, latmax=zelatmax)
453 | if back is not None:
454 | if back not in ["coast","sea"]: m.warpimage(marsmap(back),scale=0.75)
455 | elif back == "coast": m.drawcoastlines()
456 | elif back == "sea": m.drawlsmask(land_color='white',ocean_color='aqua')
457 | #if not back:
458 | # if not var: back = "mola" ## if no var: draw mola
459 | # elif typefile in ['mesoapi','meso','geo'] \
460 | # and proj not in ['merc','lcc','nsper','laea']: back = "molabw" ## if var but meso: draw molabw
461 | # else: pass ## else: draw None
462 | return m
463 |
464 | ### Author: AS
465 | #def calculate_bounds(field,vmin=None,vmax=None):
466 | # import numpy as np
467 | # ind = np.where(field < 9e+35)
468 | # fieldcalc = field[ ind ] # la syntaxe compacte ne marche si field est un tuple
469 | # ###
470 | # dev = np.std(fieldcalc)*3.0
471 | # ###
472 | # if vmin is None: zevmin = mean(fieldcalc) - dev
473 | # else: zevmin = vmin
474 | # ###
475 | # if vmax is None: zevmax = mean(fieldcalc) + dev
476 | # else: zevmax = vmax
477 | # if vmin == vmax:
478 | # zevmin = mean(fieldcalc) - dev ### for continuity
479 | # zevmax = mean(fieldcalc) + dev ### for continuity
480 | # ###
481 | # if zevmin < min(fieldcalc): zevmin = min(fieldcalc)
482 | # if zevmax > max(fieldcalc): zevmax = max(fieldcalc)
483 | # ##if zevmin < 0. and min(fieldcalc) > 0.: zevmin = 0.
484 | # ##print "BOUNDS field ", min(fieldcalc), max(fieldcalc), " //// adopted", zevmin, zevmax
485 | # return zevmin, zevmax
486 |
487 | ### Author: AS
488 | #def bounds(what_I_plot,zevmin,zevmax):
489 | # ### might be convenient to add the missing value in arguments
490 | # #what_I_plot[ what_I_plot < zevmin ] = zevmin#*(1. + 1.e-7)
491 | # if zevmin < 0: what_I_plot[ what_I_plot < zevmin*(1. - 1.e-7) ] = zevmin*(1. - 1.e-7)
492 | # else: what_I_plot[ what_I_plot < zevmin*(1. + 1.e-7) ] = zevmin*(1. + 1.e-7)
493 | # #print "NEW MIN ", min(what_I_plot)
494 | # what_I_plot[ what_I_plot > 9e+35 ] = -9e+35
495 | # what_I_plot[ what_I_plot > zevmax ] = zevmax*(1. - 1.e-7)
496 | # #print "NEW MAX ", max(what_I_plot)
497 | # return what_I_plot
498 |
499 | ## a function to solve the problem with blank bounds !
500 | ## -------------------------------
501 | #def bounds(what_I_plot,zevmin,zevmax,miss=9e+35):
502 | # import numpy as np
503 | # small_enough = 1.e-7
504 | # if zevmin < 0: what_I_plot[ what_I_plot < zevmin*(1.-small_enough) ] = zevmin*(1.-small_enough)
505 | # else: what_I_plot[ what_I_plot < zevmin*(1.+small_enough) ] = zevmin*(1.+small_enough)
506 | # what_I_plot[ what_I_plot > miss ] = -miss
507 | # what_I_plot[ what_I_plot > zevmax ] = zevmax*(1.-small_enough)
508 | # ## test
509 | # what_I_plot[ np.abs(what_I_plot) < small_enough ] = small_enough
510 | # return what_I_plot
511 |
512 | ## Author: AS
513 | def nolow(what_I_plot):
514 | lim = 0.15*0.5*(abs(max(what_I_plot))+abs(min(what_I_plot)))
515 | print "NO PLOT BELOW VALUE ", lim
516 | what_I_plot [ abs(what_I_plot) < lim ] = 1.e40
517 | return what_I_plot
518 |
519 | ## Author: AS
520 | def zoomset (wlon,wlat,zoom):
521 | dlon = abs(wlon[1]-wlon[0])/2.
522 | dlat = abs(wlat[1]-wlat[0])/2.
523 | [wlon,wlat] = [ [wlon[0]+zoom*dlon/100.,wlon[1]-zoom*dlon/100.],\
524 | [wlat[0]+zoom*dlat/100.,wlat[1]-zoom*dlat/100.] ]
525 | print "ZOOM %",zoom,wlon,wlat
526 | return wlon,wlat
527 |
528 | ## Author: AS
529 | def definecolorvec (whichone="def"):
530 | whichcolor = { \
531 | "def": "black",\
532 | "vis": "yellow",\
533 | "vishires": "green",\
534 | "molabw": "yellow",\
535 | "mola": "black",\
536 | "gist_heat": "white",\
537 | "hot": "tk",\
538 | "gist_rainbow": "black",\
539 | "spectral": "black",\
540 | "gray": "red",\
541 | "PuBu": "black",\
542 | "titan": "red",\
543 | }
544 | if whichone not in whichcolor:
545 | whichone = "def"
546 | return whichcolor[whichone]
547 |
548 | ## Author: AS
549 | def marsmap (whichone="vishires"):
550 | from os import uname
551 | mymachine = uname()[1]
552 | ### not sure about speed-up with this method... looks the same
553 | if "lmd.jussieu.fr" in mymachine: domain = "/u/aslmd/WWW/maps/"
554 | elif "aymeric-laptop" in mymachine: domain = "/home/aymeric/Dropbox/Public/"
555 | else: domain = "http://www.lmd.jussieu.fr/~aslmd/maps/"
556 | whichlink = { \
557 | #"vis": "http://maps.jpl.nasa.gov/pix/mar0kuu2.jpg",\
558 | #"vishires": "http://www.lmd.jussieu.fr/~aslmd/maps/MarsMap_2500x1250.jpg",\
559 | #"geolocal": "http://dl.dropbox.com/u/11078310/geolocal.jpg",\
560 | #"mola": "http://www.lns.cornell.edu/~seb/celestia/mars-mola-2k.jpg",\
561 | #"molabw": "http://dl.dropbox.com/u/11078310/MarsElevation_2500x1250.jpg",\
562 | "thermalday": domain+"thermalday.jpg",\
563 | "thermalnight": domain+"thermalnight.jpg",\
564 | "tesalbedo": domain+"tesalbedo.jpg",\
565 | "vis": domain+"mar0kuu2.jpg",\
566 | "vishires": domain+"MarsMap_2500x1250.jpg",\
567 | "geolocal": domain+"geolocal.jpg",\
568 | "mola": domain+"mars-mola-2k.jpg",\
569 | "molabw": domain+"MarsElevation_2500x1250.jpg",\
570 | "clouds": "http://www.johnstonsarchive.net/spaceart/marswcloudmap.jpg",\
571 | "jupiter": "http://www.mmedia.is/~bjj/data/jupiter_css/jupiter_css.jpg",\
572 | "jupiter_voy": "http://www.mmedia.is/~bjj/data/jupiter/jupiter_vgr2.jpg",\
573 | #"bw": domain+"EarthElevation_2500x1250.jpg",\
574 | "bw": "http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthElevation_2500x1250.jpg",\
575 | "contrast": "http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthMapAtmos_2500x1250.jpg",\
576 | "nice": "http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/earthmap1k.jpg",\
577 | "blue": "http://eoimages.gsfc.nasa.gov/ve/2430/land_ocean_ice_2048.jpg",\
578 | "blueclouds": "http://eoimages.gsfc.nasa.gov/ve/2431/land_ocean_ice_cloud_2048.jpg",\
579 | "justclouds": "http://eoimages.gsfc.nasa.gov/ve/2432/cloud_combined_2048.jpg",\
580 | "pluto": "http://www.boulder.swri.edu/~buie/pluto/pluto_all.png",\
581 | "triton": "http://laps.noaa.gov/albers/sos/neptune/triton/triton_rgb_cyl_www.jpg",\
582 | "titan": "http://laps.noaa.gov/albers/sos/saturn/titan/titan_rgb_cyl_www.jpg",\
583 | #"titan": "http://laps.noaa.gov/albers/sos/celestia/titan_50.jpg",\
584 | "titanuni": "http://maps.jpl.nasa.gov/pix/sat6fss1.jpg",\
585 | "venus": "http://laps.noaa.gov/albers/sos/venus/venus4/venus4_rgb_cyl_www.jpg",\
586 | "cosmic": "http://laps.noaa.gov/albers/sos/universe/wmap/wmap_rgb_cyl_www.jpg",\
587 | }
588 | ### see http://www.mmedia.is/~bjj/planetary_maps.html
589 | if whichone not in whichlink:
590 | print "marsmap: choice not defined... you'll get the default one... "
591 | whichone = "vishires"
592 | return whichlink[whichone]
593 |
594 | #def earthmap (whichone):
595 | # if whichone == "contrast": whichlink="http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthMapAtmos_2500x1250.jpg"
596 | # elif whichone == "bw": whichlink="http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthElevation_2500x1250.jpg"
597 | # elif whichone == "nice": whichlink="http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/earthmap1k.jpg"
598 | # return whichlink
599 |
600 | ## Author: AS
601 | def latinterv (area="Whole"):
602 | list = { \
603 | "Europe": [[ 20., 80.],[- 50., 50.]],\
604 | "Central_America": [[-10., 40.],[ 230., 300.]],\
605 | "Africa": [[-20., 50.],[- 50., 50.]],\
606 | "Whole": [[-90., 90.],[-180., 180.]],\
607 | "Southern_Hemisphere": [[-90., 60.],[-180., 180.]],\
608 | "Northern_Hemisphere": [[-60., 90.],[-180., 180.]],\
609 | "Tharsis": [[-30., 60.],[-170.,- 10.]],\
610 | "Whole_No_High": [[-60., 60.],[-180., 180.]],\
611 | "Chryse": [[-60., 60.],[- 60., 60.]],\
612 | "North_Pole": [[ 50., 90.],[-180., 180.]],\
613 | "Close_North_Pole": [[ 75., 90.],[-180., 180.]],\
614 | "Far_South_Pole": [[-90.,-40.],[-180., 180.]],\
615 | "South_Pole": [[-90.,-50.],[-180., 180.]],\
616 | "Close_South_Pole": [[-90.,-75.],[-180., 180.]],\
617 | "Sirenum_Crater_large": [[-46.,-34.],[-166.,-151.]],\
618 | "Sirenum_Crater_small": [[-36.,-26.],[-168.,-156.]],\
619 | "Rupes": [[ 72., 90.],[-120.,- 20.]],\
620 | "Xanadu": [[-40., 20.],[ 40., 120.]],\
621 | "Hyperboreae": [[ 80., 87.],[- 70.,- 10.]],\
622 | }
623 | if area not in list: area = "Whole"
624 | [olat,olon] = list[area]
625 | return olon,olat
626 |
627 | ## Author : AS
628 | def maplatlon( lon,lat,field,\
629 | proj="cyl",colorb="jet",ndiv=10,zeback=None,trans=0.6,title="",\
630 | vecx=None,vecy=None,stride=2,vmin=None,vmax=None):
631 | ### an easy way to map a field over lat/lon grid
632 | import numpy as np
633 | import matplotlib.pyplot as mpl
634 | from matplotlib.cm import get_cmap
635 | ## get lon and lat in 2D version. get lat/lon intervals
636 | numdim = len(np.array(lon).shape)
637 | if numdim == 2: [lon2d,lat2d] = [lon,lat]
638 | elif numdim == 1: [lon2d,lat2d] = np.meshgrid(lon,lat)
639 | else: errormess("lon and lat arrays must be 1D or 2D")
640 | #[wlon,wlat] = latinterv()
641 | [wlon,wlat] = simplinterv(lon2d,lat2d)
642 | ## define projection and background. define x and y given the projection
643 | m = define_proj(proj,wlon,wlat,back=zeback,blat=None,blon=None)
644 | x, y = m(lon2d, lat2d)
645 | ## define field. bound field.
646 | what_I_plot = np.transpose(field)
647 | zevmin,zevmax,limtype = setbounds(what_I_plot,vmin=vmin,vmax=vmax)
648 | ## define contour field levels. define color palette
649 | ticks = ndiv + 1
650 | zelevels = np.linspace(zevmin,zevmax,ticks)
651 | palette = get_cmap(name=colorb)
652 | ## contour field
653 | m.contourf( x, y, what_I_plot, zelevels, cmap = palette, alpha = trans )
654 | ## draw colorbar
655 | if proj in ['moll','cyl']: zeorientation="horizontal" ; zepad = 0.07
656 | else: zeorientation="vertical" ; zepad = 0.03
657 | daformat = "%.0f"
658 | zecb = mpl.colorbar( fraction=0.05,pad=zepad,format=daformat,orientation=zeorientation,\
659 | ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])),extend='neither',spacing='proportional' )
660 | ## give a title
661 | if zeorientation == "horizontal": zecb.ax.set_xlabel(title)
662 | else: ptitle(title)
663 | ## draw vector
664 | if vecx is not None and vecy is not None:
665 | [vecx_frame,vecy_frame] = m.rotate_vector( np.transpose(vecx), np.transpose(vecy), lon2d, lat2d ) ## for metwinds
666 | vectorfield(vecx_frame, vecy_frame, x, y, stride=stride, csmooth=2,\
667 | scale=30., factor=500., color=definecolorvec(colorb), key=True)
668 | ## scale regle la reference du vecteur. factor regle toutes les longueurs (dont la reference). l'AUGMENTER pour raccourcir les vecteurs.
669 | return
670 |
--------------------------------------------------------------------------------
/netcdf/gfortran_netcdf4_fPIC:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ze_netcdf=netcdf-4.0.1
4 | #ze_netcdf=netcdf-3.6.1
5 |
6 | #wget ftp://ftp.unidata.ucar.edu/pub/netcdf/$ze_netcdf.tar.gz
7 | wget ftp://ftp.unidata.ucar.edu/pub/netcdf/old/$ze_netcdf.tar.gz
8 | tar xzvf $ze_netcdf.tar.gz
9 | \rm $ze_netcdf.tar.gz
10 |
11 | export FC=gfortran
12 | export FFLAGS=" -O2 -fPIC"
13 | export F90=gfortran
14 | export FCFLAGS="-O2 -ffree-form -fPIC"
15 | export CPPFLAGS=""
16 | export CC=gcc
17 | export CFLAGS="-O2 -fPIC"
18 | export CXX=g++
19 | export CXXFLAGS="-O2 -fPIC"
20 |
21 | mv $ze_netcdf gfortran_$ze_netcdf
22 | cd gfortran_$ze_netcdf
23 | PREFIX=$PWD
24 | if [[ "$ze_netcdf" == "netcdf-3.6.1" ]]
25 | then
26 | cd src
27 | fi
28 |
29 | ./configure --prefix=${PREFIX} #--disable-cxx
30 | make > make.log 2>&1
31 | make test > make.log 2>&1
32 | make install > make.log 2>&1
33 |
--------------------------------------------------------------------------------
/netcdf/gfortran_netcdf4_fpic_old:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | fd="./"
4 |
5 | ##################
6 |
7 | # get absolute path
8 | here=$PWD
9 | cd $fd
10 | installfd=$PWD
11 | echo install in $installfd
12 | cd $here
13 |
14 | # download
15 | \rm -rf netcdf-4.0.1.tar.gz*
16 | \rm -rf netcdf-4.0.1
17 | wget ftp://ftp.unidata.ucar.edu/pub/netcdf/old/netcdf-4.0.1.tar.gz
18 | tar xzvf netcdf-4.0.1.tar.gz > /dev/null 2>&1
19 |
20 | # make netcdf library
21 | cd netcdf-4.0.1
22 | pwd
23 |
24 | export FC=gfortran
25 | export FFLAGS=" -O2"
26 | export F90=gfortran
27 | export FCFLAGS="-O2 -ffree-form"
28 | export CPPFLAGS=""
29 | export CC=gcc
30 | export CFLAGS="-O2"
31 | export CXX=g++
32 | export CXXFLAGS="-O2"
33 |
34 | \rm -rf *.log
35 | echo ...configure
36 | ./configure --with-pic --prefix=$installfd > $installfd/configure.log 2>&1
37 | echo ...make
38 | make > $installfd/make.log 2>&1
39 | echo ...test
40 | make test > $installfd/make_test.log 2>&1
41 | echo ...install
42 | make install > $installfd/make_install.log 2>&1
43 |
44 |
45 |
--------------------------------------------------------------------------------
/patch.txt:
--------------------------------------------------------------------------------
1 | usercode '''
2 | PyDict_SetItem(d,PyString_FromString("dataloc"),PyString_FromString(dataloc));
3 | PyDict_SetItem(d,PyString_FromString("dataver"),PyString_FromString(dataver));
4 | '''
5 |
--------------------------------------------------------------------------------
/perso/ddcriterion.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | from mcd import mcd
3 | import numpy as np
4 | import ppplot
5 |
6 | dd = mcd()
7 | dd.toversion5()
8 | dd.fixedlt = True
9 | dd.loct = 13.
10 | dd.zkey = 3
11 | dd.xz = 20.
12 |
13 | for ls in [45,90,135,180,225,270]:
14 |
15 | print ls
16 | dd.xdate = ls
17 | dd.latlon(ndx=64,ndy=48)
18 |
19 | maxw = dd.extvartab[:,:,47]
20 | z0 = dd.extvartab[:,:,29]
21 | stress = dd.extvartab[:,:,51]
22 | rho = dd.extvartab[:,:,92]
23 | hgt = dd.extvartab[:,:,4]
24 |
25 | tsurf = dd.extvartab[:,:,15]
26 | temp = dd.extvartab[:,:,93]
27 |
28 |
29 | ustar = np.sqrt(stress/rho)
30 | wstar = maxw / 2.75
31 |
32 | limsmall = 0.5
33 | ustar[np.where(ustar 5.)
40 | #there was an error here!
41 | tol = 50.
42 | ind = np.where(100. * ddwinderror / ddwind > tol) ; ddwind[ind] = np.NaN
43 | print "2. error on wind too large"
44 | print yorgl[0][ind]
45 | print ddwinderror[ind]
46 | ind = np.where(100. * ddheighterror / ddheight > tol) ; ddwind[ind] = np.NaN
47 | print "3. error on height too large"
48 | print yorgl[0][ind]
49 | print ddheighterror[ind]
50 | ## one record is doubtful according to Reiss
51 | ind = np.where( yorgl[0] == 3 ) ; ddwind[ind] = np.NaN #; ddwinddir[ind] = np.NaN ; ddwinderror[ind] = np.NaN
52 | print "4. doubtful", yorgl[0][ind]
53 |
54 | #exit()
55 |
56 | ## constant_heights
57 | #for heights in [20.,100.,500.,1000.,2000.,5000.,7000.,10000.,20000.]:
58 | #for heights in [10.]:
59 |
60 | ## multiple_obsheight
61 | #for heights in [0.1,0.2,0.5,0.75,1.0,1.5,2.0,10.]:
62 | for heights in [1.0]:
63 |
64 | query = mcd()
65 | mcdwind = [] ; mcdwindle = [] ; mcdwindhe = [] ; mcdangle = [] ; mcdanglele = [] ; mcdanglehe = []
66 |
67 | for i in yorgl[0]:
68 |
69 | if not isnan(ddwind[i-1]):
70 | query.lat = yorgl[1][i-1]
71 | query.lon = yorgl[2][i-1]
72 | query.xdate = yorgl[3][i-1]
73 | query.loct = yorgl[4][i-1]
74 |
75 | query.xz = ddheight[i-1] #ddheight is really the one that works best
76 |
77 | ## constant_heights
78 | #query.xz = heights
79 | ## multiple_obsheight
80 | query.xz = ddheight[i-1]*heights
81 |
82 | query.update() ; uu = query.zonwind ; vv = query.merwind
83 | if uu == -999. or vv == -999.:
84 | speed = np.NaN ; speedmin = np.NaN ; speedmax = np.NaN
85 | angle = np.NaN ; anglemin = np.NaN ; anglemax = np.NaN
86 | else:
87 | speed = np.sqrt(uu*uu+vv*vv) ; speedmin = speed ; speedmax = speed
88 |
89 | angle = 90. - np.arctan2(vv,uu) * 180. / np.pi
90 | if angle < 0.: angle = angle + 360.
91 |
92 | ## multiple_obsheight
93 | query.xzs = max(ddheight[i-1] - 2.*ddheighterror[i-1],10.)
94 | query.xze = ddheight[i-1] + 2.*ddheighterror[i-1]
95 | ## constant_heights
96 | #query.xzs = max(query.xz - 0.1*query.xz,10.)
97 | #query.xze = query.xz + 0.1*query.xz
98 |
99 | query.profile()
100 | tab = np.sqrt(query.zonwindtab*query.zonwindtab + query.merwindtab*query.merwindtab)
101 | tab2 = 90. - np.arctan2(query.merwindtab,query.zonwindtab) * 180. / np.pi
102 | tab2[np.where(tab2 < 0.)] = tab2[np.where(tab2 < 0.)] + 360.
103 | speedmin = min(tab)
104 | speedmax = max(tab)
105 | anglemin = min(tab2)-5.
106 | anglemax = max(tab2)+5.
107 | if anglemin < 0.: anglemin = angle - (anglemax - angle)
108 | print int(i), speed, speedmin, speedmax
109 | print int(i), angle, anglemin, anglemax
110 | else:
111 | #print "removed ",i,ddwinderror[i-1],ddheighterror[i-1]
112 | speed = -999. ; speedmin = -1000. ; speedmax = -998. ; angle = -999. ; anglemin = -1000. ; anglemax = -998.
113 |
114 | mcdwind.append(speed)
115 | mcdwindle.append(speed-speedmin)
116 | mcdwindhe.append(speedmax-speed)
117 | mcdangle.append(angle)
118 | mcdanglele.append(angle-anglemin)
119 | mcdanglehe.append(anglemax-angle)
120 |
121 | mcdwind = np.array(mcdwind)
122 | mcdwindle = np.array(mcdwindle)
123 | mcdwindhe = np.array(mcdwindhe)
124 |
125 | mcdangle = np.array(mcdangle)
126 | mcdanglele = np.array(mcdanglele)
127 | mcdanglehe = np.array(mcdanglehe)
128 |
129 |
130 | mpl.figure(figsize=(12,10))
131 | mpl.plot([0,30], [stddev,stddev+30], 'g--')
132 | mpl.plot([0,30], [-stddev,-stddev+30], 'g--')
133 | mpl.plot([0,30], [0,30], 'g-')
134 |
135 | writeascii(field=mcdwind,absc=ddwind,name=str(heights)+'.txt')
136 |
137 | #ind = np.isnan(ddwind)
138 | #y = ddwind
139 | #y[ind] = -9999.
140 | #xi = mcdwind[y > -9999.]
141 | #y = ddwind[y > -9999.]
142 | #slope, intercept, r_value, p_value, std_err = stats.linregress(xi,y)
143 | #linear = slope*xi+intercept
144 | #mpl.plot(xi,linear)
145 | #ecart = y - linear
146 | #print np.std(ecart)
147 |
148 | mpl.errorbar(mcdwind, ddwind, yerr=[ddwinderror,ddwinderror], xerr=[mcdwindle,mcdwindhe], fmt='bo')
149 | # mpl.xlim(xmin=0.,xmax=17.)
150 | # mpl.ylim(ymin=0.,ymax=30.)
151 | mpl.xlim(xmin=0.,xmax=30.)
152 | mpl.ylim(ymin=0.,ymax=30.)
153 |
154 |
155 | mpl.xlabel('MCD horizontal wind speed (m/s)')
156 | mpl.ylabel('Dust devil observed drift speed (m/s)')
157 |
158 |
159 | for i in yorgl[0]:
160 | ## on multiplie stddev par 1.2 de facon a enlever les points tres au bord
161 | ## qui sont in si on considere l error bar
162 | if abs(ddwind[i-1] - mcdwind[i-1]) > stddev*1.2:
163 | mpl.annotate(str(int(i)), xy=(mcdwind[i-1], ddwind[i-1]), xytext=(10,2),
164 | textcoords='offset points', ha='center', va='bottom' )#,
165 | #bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
166 | #arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.3',
167 | #color='red'))
168 |
169 |
170 | #mpl.show()
171 | mpl.savefig("speed"+str(heights)+".eps")
172 | mpl.savefig("speed"+str(heights)+".png")
173 | ##mpl.savefig("comp4.eps")
174 | ##mpl.savefig("comp4.png")
175 |
176 | ddwinddirerror = mcdanglele*0. + 15.
177 |
178 | mpl.figure(figsize=(12,10))
179 | mpl.errorbar(mcdangle,ddwinddir,yerr=[ddwinddirerror,ddwinddirerror],xerr=[mcdanglele,mcdanglehe],fmt='bo')
180 | mpl.plot(mcdangle,ddwinddir,'bo')
181 | mpl.xlim(xmin=0.,xmax=360.)
182 | mpl.ylim(ymin=0.,ymax=360.)
183 |
184 | mpl.xlabel('MCD horizontal wind orientation (deg)')
185 | mpl.ylabel('Dust devil observed drift orientation (deg)')
186 |
187 |
188 | stddev2 = 50. ## voir e.g. 8 9 10
189 | mpl.plot([0,360], [stddev2,stddev2+360], 'g--')
190 | mpl.plot([0,360], [-stddev2,-stddev2+360], 'g--')
191 | mpl.plot([0,360], [0,360], 'g-')
192 |
193 |
194 | for i in yorgl[0]:
195 | ## on multiplie stddev par 1.2 de facon a enlever les points tres au bord
196 | ## qui sont in si on considere l error bar
197 | if abs(ddwinddir[i-1] - mcdangle[i-1]) > stddev2*1.2:
198 | mpl.annotate(str(int(i)), xy=(mcdangle[i-1], ddwinddir[i-1]), xytext=(10,2),
199 | textcoords='offset points', ha='center', va='bottom')#,
200 | #bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3),
201 | #arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.3',
202 | #color='red'))
203 |
204 | ##xytext=(18,30)
205 |
206 | #mpl.show()
207 | mpl.savefig("angle"+str(heights)+".eps")
208 | mpl.savefig("angle"+str(heights)+".png")
209 | #mpl.savefig("comp3.eps")
210 | #mpl.savefig("comp3.png")
211 |
212 | #exit()
213 | #
214 | #
215 | #dd = mcd()
216 | #
217 | #
218 | #
219 | #
220 | #
221 | ##dd.zkey = 4
222 | ##dd.xzs = 600.
223 | ##dd.xze = 0.1
224 | ##dd.profile()
225 | ##dd.plot1d(["t","p"])
226 | ##mpl.show()
227 | ##exit()
228 | #
229 | ### CASE 1
230 | #dd.lat = -14.6584
231 | #dd.lon = 175.54
232 | #dd.xdate = 265.278792
233 | #dd.loct = 14.8487
234 | #dd.xz = 130.4
235 | #
236 | #dd.update()
237 | #dd.printmcd()
238 | #
239 | #dd.lats = -5.
240 | #dd.late = -25.
241 | #dd.lons = 160.
242 | #dd.lone = 190.
243 | #dd.map2d(["wind"],incwind=True,fixedlt=True)
244 | ### il y a un piege pour les cartes locales il faut fixedlt=True
245 | #mpl.savefig("case1.png",dpi=110,bbox_inches='tight',pad_inches=0.4)
246 | #
247 | ### CASE 2
248 | #dd.lat = -68.6125
249 | #dd.lon = 11.4303
250 | #dd.xdate = 286.507293
251 | #dd.loct = 15.129030
252 | #dd.xz = 872.8
253 | ##dd.xz = 10000.0
254 | #
255 | #dd.update()
256 | #dd.printmcd()
257 | #
258 | #dd.lats = -75.
259 | #dd.late = -60.
260 | #dd.lons = 0.
261 | #dd.lone = 20.
262 | #dd.map2d(["wind"],incwind=True,fixedlt=True)
263 | #mpl.savefig("case2.png",dpi=110,bbox_inches='tight',pad_inches=0.4)
264 | #
265 | ###3 25,1306 314,4842 60,8946 14,9971 30,89575722 232 250,217961736111
266 | #
267 | ### CASE 3
268 | #dd.lat = 25.1306
269 | #dd.lon = 314.4842
270 | #dd.xdate = 60.8946
271 | #dd.loct = 14.9971
272 | #dd.xz = 250.218
273 | #
274 | #dd.update()
275 | #dd.printmcd()
276 | #
277 | ###4 35,564 199,486 60,5883 14,9949 12,2972688101353 125 895,247012611329
278 | #
279 | ### CASE 4
280 | #dd.lat = 35.564
281 | #dd.lon = 199.486
282 | #dd.xdate = 60.5883
283 | #dd.loct = 14.9949
284 | #dd.xz = 895.247
285 | #
286 | #dd.update()
287 | #dd.printmcd()
288 | #
289 | ###5 68,346 234,396 142,828 15,1777 13,4079899322222 83 1128,06581216829
290 | ###6 68,316 234,462 142,828 15,1819 16,1939071396022 85 582,624074786015
291 | ###7 68,302 234,144 142,828 15,1607 17,3354121022885 112 262,299040101764
292 | #
293 | ### CASE 5
294 | #dd.lat = 68.32
295 | #dd.lon = 234.3
296 | #dd.xdate = 142.828
297 | #dd.loct = 15.2
298 | #
299 | #dd.xz = 1128.066
300 | #dd.update()
301 | #dd.printmcd()
302 | #
303 | #dd.xz = 582.624
304 | #dd.update()
305 | #dd.printmcd()
306 | #
307 | #dd.xz = 262.299
308 | #dd.update()
309 | #dd.printmcd()
310 | #
311 | #
312 | ###19 27,055 129,614 13,5818 14,444 42,6488205391137 302 1395,96076100437
313 | #
314 | ### CASE 19
315 | #dd.lat = 27.055
316 | #dd.lon = 129.614
317 | #dd.xdate = 13.5818
318 | #dd.loct = 14.444
319 | #
320 | #dd.xz = 1395.961
321 | #dd.update()
322 | #dd.printmcd()
323 | #
324 | #dd.lats = 20.
325 | #dd.late = 30.
326 | #dd.lons = 125.
327 | #dd.lone = 135.
328 | #dd.map2d(["wind"],incwind=True,fixedlt=True)
329 | #mpl.savefig("case19.png",dpi=110,bbox_inches='tight',pad_inches=0.4)
330 | #
331 | #
332 |
--------------------------------------------------------------------------------
/perso/gw.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | import numpy as np # numerics
3 | from mcd import mcd # MCD python wrapper
4 | import ppplot # for plots
5 | import ppcompute # for derivatives
6 | import planets # for N2 computation
7 |
8 | ##############################
9 | # this script computes #
10 | # GW saturation ratio #
11 | # from MCD field #
12 | # see Spiga et al. GRL 2012 #
13 | ##############################
14 | Ls = 30.
15 | Ls = 90.
16 | Ls = 270.
17 | ##############
18 |
19 | # the constant in the saturation ratio
20 | # ... see Spiga et al. GRL 2012
21 | lambdah = 150e3
22 | fzero = 7.5e-7
23 | alpha = fzero*lambdah/(2.*np.pi)
24 |
25 | # prepare MCD request
26 | rq = mcd()
27 | rq.xdate = Ls
28 | # xzs should not be 0 otherwise divide by u=0
29 | rq.xzs,rq.xze = 40000.,180000.
30 |
31 | # request zonal mean
32 | #rq.zonalmean()
33 | rq.lon = 0. ; rq.secalt()
34 |
35 | # coordinates
36 | z = rq.ycoord
37 | lat = rq.xcoord
38 | # zonal wind
39 | u = np.transpose(rq.zonwindtab)
40 | # density
41 | rho = np.transpose(rq.denstab)
42 | # static stability
43 | temp = np.transpose(rq.temptab)
44 | dummy,dTdz = ppcompute.deriv2d(temp,lat,z)
45 | bv = planets.Mars.N2(T0=temp,dTdz=dTdz)
46 |
47 | # compute saturation ratio
48 | s = np.sqrt(alpha*bv/(rho*np.abs(u)*u*u))
49 | w = np.where(s>1) ; s[w] = 1. # S ratio is <= 1
50 |
51 | # plot bounds -- same as Spiga et al. 2012
52 | lb,ub = -2.,-0.5
53 | w = np.where(np.log10(s)ub) ; s[w] = 10.**(ub)
55 |
56 | # plot
57 | pl = ppplot.plot2d()
58 | pl.f = np.log10(s)
59 | pl.x = lat ; pl.xlabel = "Latitude"
60 | pl.y = z/1000. ; pl.ylabel = "Altitude (km)"
61 | pl.c = u
62 | pl.colorbar = "hot_r"
63 | pl.fmt = "%.1f"
64 | pl.units = r'$\log_{10}\mathcal{S}$'
65 | pl.makesave(mode="png",filename="saturatio_%.0f" % (Ls))
66 |
--------------------------------------------------------------------------------
/perso/inimeso/from_gcm.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | from string import split
3 | import numpy as np
4 | from ppclass import pp
5 | import ppplot
6 |
7 |
8 | shiftday = 258 + 27
9 | shiftday = 258
10 |
11 | ### GET COORDINATES
12 | lines = open("input_coord", "r").readlines()
13 | lon = float(split(lines[0])[0]) ; lat = float(split(lines[1])[0])
14 | xdate = float(split(lines[2])[0]) ; loct = float(split(lines[3])[0])
15 | utc = loct - lon/15.
16 |
17 | ### GCM
18 | req = pp()
19 | req.file = "diagfi.nc"
20 | req.var = "vmr_h2ovap"
21 | req.var = "temp"
22 | req.x = lon
23 | req.y = lat
24 | req.t = shiftday + utc/24.
25 | req.verbose = True
26 | req.changetime = "mars_dayini"
27 | #prof,xx,yy,zz,tt = req.getfd()
28 |
29 | ### MCD
30 | z,tpot,q,u,v = np.loadtxt("input_sounding",skiprows=1,unpack=True)
31 | r,cp,p,rho,t = np.loadtxt("input_therm",unpack=True)
32 | hgt,tsurf = np.loadtxt("input_more",unpack=True)
33 | q = 0.001*q
34 |
35 | ### PLOT
36 |
37 | nnn=60
38 | dd=10
39 | ppplot.rainbow(cb="jet",num=1+(nnn/dd))
40 |
41 | sdg = ppplot.plot1d()
42 | sdg.f = z-hgt
43 | sdg.x = q
44 | sdg.x = t
45 | sdg.legend = 'mcd'
46 | sdg.marker = 's'
47 | sdg.color = 'w'
48 | sdg.make()
49 |
50 |
51 | nnn=60
52 | dd=10
53 | ppplot.rainbow(cb="jet",num=nnn/dd)
54 |
55 | ppp = ppplot.plot1d()
56 | ppp.marker = '.'
57 | ppp.ymax = 9000.
58 | ppp.xlabel = 'temperature (K)'
59 | ppp.ylabel = 'altitude (m)'
60 |
61 | for iii in range(0,nnn,dd):
62 | if iii == 0:
63 | sdg.verbose = True
64 | req.t = 258 + iii + utc/24.
65 | prof,xx,yy,zz,tt = req.getfd()
66 | ppp.x = prof
67 | ppp.f = zz*1000.
68 | ppp.legend = 'gcm sol 258+'+str(iii)
69 | ppp.make()
70 |
71 | ppplot.save(mode="png",filename="comp")
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/perso/inimeso/inimeso.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | ### AS 10/05/2012. A python script to prepare initial state for idealized mesoscale runs.
4 | ### use : ensure mcd class is working. fill in input_coord. execute inimeso.
5 |
6 | from string import split ; import numpy as np ; import matplotlib.pyplot as mpl
7 | from mcd import mcd
8 |
9 | ### MCD INSTANCE and SETTINGS (actually, default. but one never knows)
10 | query = mcd() ; query.zkey = 3 ; query.hrkey = 1
11 | query.dust = 2 #29
12 |
13 | ### GET COORDINATES
14 | lines = open("input_coord", "r").readlines()
15 | query.lon = float(split(lines[0])[0]) ; query.lat = float(split(lines[1])[0])
16 | query.xdate = float(split(lines[2])[0]) ; query.loct = float(split(lines[3])[0])
17 | query.printcoord()
18 |
19 | ### OPEN FILES TO BE WRITTEN
20 | sounding = open("input_sounding", "w") ; additional = open("input_therm", "w") ; more = open("input_more", "w")
21 |
22 | ### GET and WRITE SURFACE VALUES
23 | query.xz = 0. ; query.update() ; query.printmeanvar()
24 | sounding.write( "%10.2f%12.2f%12.2f\n" % (query.pres/100.,query.temp*(610./query.pres)**(1.0/3.9),0.) )
25 | more.write( "%10.2f%10.2f" % (query.extvar[1],query.extvar[14]) ) ; more.close()
26 |
27 | ### GET and WRITE VERTICAL PROFILE
28 | query.profile( tabperso = np.append([0,1,5,10,20,50,100],np.linspace(200.,float(split(lines[4])[0])*1000.,float(split(lines[5])[0]))) )
29 | for iz in range(len(query.prestab)):
30 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % ( \
31 | query.extvartab[iz,2],query.temptab[iz]*(610./query.prestab[iz])**(1.0/3.9),\
32 | 0.,query.zonwindtab[iz],query.merwindtab[iz]) )
33 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % ( \
34 | query.extvartab[iz,49],query.extvartab[iz,8],\
35 | query.prestab[iz],query.denstab[iz],query.temptab[iz]) )
36 |
37 | ### FINISH
38 | sounding.close() ; additional.close()
39 | query.plot1d(["p","t","u","v"]) ; mpl.show()
40 |
41 | ### Add information about dust opacity
42 | dod = open("dustopacity.def", "w")
43 | dod.write( "%4.2f" %(query.extvartab[iz,36]) )
44 | dod.close()
45 |
--------------------------------------------------------------------------------
/perso/inimeso/inimeso5.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | ### AS 10/05/2012. A python script to prepare initial state for idealized mesoscale runs.
4 | ### use : ensure mcd class is working. fill in input_coord. execute inimeso.
5 |
6 | from string import split ; import numpy as np ; import matplotlib.pyplot as mpl
7 | from mcd import mcd
8 |
9 | rho_dust = 2500. # Mars dust density (kg.m-3)
10 | grav = 3.72
11 | ksi = 3. / 4. / rho_dust / grav
12 | nueff = 0.5
13 |
14 | ### MCD INSTANCE and SETTINGS (actually, default. but one never knows)
15 | query = mcd() ; query.zkey = 3 ; query.hrkey = 1
16 | #query.toversion5(version="5.2")
17 |
18 | ### GET COORDINATES
19 | lines = open("input_coord", "r").readlines()
20 | query.lon = float(split(lines[0])[0]) ; query.lat = float(split(lines[1])[0])
21 | query.xdate = float(split(lines[2])[0]) ; query.loct = float(split(lines[3])[0])
22 | query.dust = float(split(lines[6])[0])
23 | query.printcoord()
24 |
25 | ### OPEN FILES TO BE WRITTEN
26 | sounding = open("input_sounding", "w") ; additional = open("input_therm", "w") ; more = open("input_more", "w")
27 | dust = open("input_dust", "w") ; water = open("input_water", "w")
28 |
29 | ### GET and WRITE SURFACE VALUES
30 | query.xz = 0.1 ; query.update() ; query.printmeanvar()
31 | wvapor = query.extvar[42] #1.5*1e-3
32 | wice = query.extvar[44] #0.0
33 | sounding.write( "%10.2f%12.2f%12.2f\n" % (query.pres/100.,query.temp*(610./query.pres)**(1.0/3.9),(wvapor+wice)*1e3) )
34 | more.write( "%10.2f%10.2f" % (query.extvar[1],query.extvar[14]) ) ; more.close()
35 |
36 | ### GET and WRITE VERTICAL PROFILE
37 | #closesurf = [0.1,5,10,20,50,100]
38 | closesurf = [0.1,0.5,1,2,5,10,20,50,100]
39 | query.profile( tabperso = np.append(closesurf,np.linspace(200.,float(split(lines[4])[0])*1000.,float(split(lines[5])[0]))) )
40 | for iz in range(len(query.prestab)):
41 |
42 | wvapor = query.extvartab[iz,42] #1.5*1e-3
43 | wice = query.extvartab[iz,44] #0.0
44 |
45 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % ( \
46 | query.extvartab[iz,2],query.temptab[iz]*(610./query.prestab[iz])**(1.0/3.9),\
47 | (wvapor+wice)*1e3,\
48 | query.zonwindtab[iz],query.merwindtab[iz]) )
49 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % ( \
50 | query.extvartab[iz,53],query.extvartab[iz,8],\
51 | query.prestab[iz],query.denstab[iz],query.temptab[iz]) )
52 | water.write( "%18.6e%18.6e\n" % (wvapor*1e3,wice*1e3) )
53 |
54 | ### DUST PROFILES
55 | q = query.extvartab[iz,38] # extvar(38)= Dust mass mixing ratio (kg/kg)
56 | reff = query.extvartab[iz,39] # extvar(39)= Dust effective radius (m)
57 | print q,reff
58 | N = (grav*ksi*((1+nueff)**3)/np.pi)*q/(reff**3)
59 | dust.write( "%18.6e%18.6e\n" % (q,N) )
60 |
61 | ### FINISH
62 | sounding.close() ; additional.close() ; dust.close() ; water.close()
63 | query.plot1d(["p","t","u","v","h2ovap","h2oice"]) ; mpl.show()
64 |
65 |
66 |
67 |
68 |
69 |
70 | ##### ESTIMATE CCNs
71 | #dustq,dustn = np.loadtxt("input_dust",unpack=True)
72 | #############################################################################
73 | #############################################################################
74 | ##fqdust = np.squeeze(query.extvartab[:,38])
75 | #fwice = np.squeeze(query.extvartab[:,44])
76 | #####
77 | ##### I: fwice, fqdust --> O: finter
78 | #####
79 | ##import numpy as np
80 | #from scipy.interpolate import InterpolatedUnivariateSpline
81 | ### remove profile points with a cloud
82 | #x = np.arange(fwice.size)
83 | #w = np.where(fwice < np.mean(fwice)/10.)
84 | ### spline-interpolate with remaining points
85 | #yyq = dustq[w]
86 | #xxq = x[w]
87 | #splq = InterpolatedUnivariateSpline(xxq, yyq)
88 | #yyn = dustn[w]
89 | #xxn = x[w]
90 | #spln = InterpolatedUnivariateSpline(xxn, yyn)
91 | ### get interpolated profile
92 | ### -- a good match for qdust + qccn
93 | ### -- treat negative values because of spline
94 | #finterq = splq(x) - dustq
95 | #finterq[np.where(finterq < 0.)] = -finterq[np.where(finterq < 0.)]
96 | #fintern = spln(x) - dustn
97 | #fintern[np.where(fintern < 0.)] = -fintern[np.where(fintern < 0.)]
98 | ### plot
99 | #mpl.figure()
100 | #mpl.plot(yyn,xxn,'bo')
101 | #mpl.plot(dustn,x)
102 | #mpl.plot(fintern,x)
103 | #mpl.figure()
104 | #mpl.plot(yyq,xxq,'bo')
105 | #mpl.plot(dustq,x)
106 | #mpl.plot(finterq,x)
107 | #mpl.figure()
108 | #mpl.plot(fwice,x,'b.')
109 | #mpl.show()
110 | #############################################################################
111 | #############################################################################
112 | #
113 | #ccn = open("input_ccn", "w")
114 | #for iz in range(len(query.prestab)):
115 | # print iz,dustq[iz],finterq[iz]
116 | # #ccn.write( "%18.6e%18.6e\n" % (finterq[iz],fintern[iz]) )
117 | # ccn.write( "%18.6e%18.6e\n" % (np.max(finterq),np.max(fintern)) )
118 | #ccn.close()
119 |
--------------------------------------------------------------------------------
/perso/inimeso/input_coord:
--------------------------------------------------------------------------------
1 | -125.75 lon
2 | 68.22 lat
3 | 122. ls
4 | 23. lct
5 | 25 ztop
6 | 100. nz
7 | 8 dust_scenario
8 |
9 | c 1 = Climatology ave solar
10 | c 2 = Climatology min solar
11 | c 3 = Climatology max solar
12 | c 4 = dust storm tau=5 (dark dust) min solar
13 | c 5 = dust storm tau=5 (dark dust) ave solar
14 | c 6 = dust storm tau=5 (dark dust) max solar
15 | c 7 = warm scenario - dusty, max solar
16 | c 8 = cold scenario - low dust, min solar
17 | c 24 = Mars Year 24, with associated solar EUV
18 | c 25 = Mars Year 25, with associated solar EUV
19 | c 26 = Mars Year 26, with associated solar EUV
20 | c 27 = Mars Year 27, with associated solar EUV
21 | c 28 = Mars Year 28, with associated solar EUV
22 | c 29 = Mars Year 29, with associated solar EUV
23 | c 30 = Mars Year 30, with associated solar EUV
24 | c 31 = Mars Year 31, with associated solar EUV
25 |
26 |
27 | 136.0 lon
28 | 4.4 lat
29 | 295.0 ls
30 | 7. lct
31 | 20 ztop
32 | 100. nz
33 |
34 | 326.0 lon
35 | -26.1 lat
36 | 348. ls
37 | 08. lct
38 | 20. ztop
39 | 100. nz
40 |
41 |
42 | -195.5 lon
43 | 73. lat
44 | 90.0 ls
45 | 08. lct
46 | 60. ztop
47 | 100. nz
48 |
49 | 204.6 lon
50 | 13.7 lat
51 | 140.0 ls
52 | 08. lct
53 | 20. ztop
54 | 100. nz
55 |
56 | 04.6 lon
57 | 13.7 lat
58 | 140.0 ls
59 | 08. lct
60 | 20. ztop
61 | 100. nz
62 |
63 | -195.5 lon
64 | 73. lat
65 | 90.0 ls
66 | 08. lct
67 | 20. ztop
68 | 100. nz
69 |
70 | 353.87 lon
71 | -1.88 lat
72 | 244. ls
73 | 06. lct
74 | 20 ztop
75 | 100. nz
76 |
--------------------------------------------------------------------------------
/perso/inimeso/profile.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | # get a multicolumn file with profiles of z,P,T,rho
4 |
5 | from string import split
6 | import numpy as np
7 | import matplotlib.pyplot as mpl
8 | from mcd import mcd
9 |
10 | ### MCD INSTANCE and SETTINGS (actually, default. but one never knows)
11 | query = mcd() ; query.zkey = 3 ; query.dust = 2 ; query.hrkey = 1
12 | query.dust = 29
13 | #query.dust = 24
14 | query.toversion5(version="5.2")
15 |
16 | ### GET COORDINATES
17 | lines = open("input_coord", "r").readlines()
18 | query.lon = float(split(lines[0])[0])
19 | query.lat = float(split(lines[1])[0])
20 | query.xdate = float(split(lines[2])[0])
21 | query.loct = float(split(lines[3])[0])
22 | query.printcoord()
23 |
24 | ### OPEN FILES TO BE WRITTEN
25 | zefile = open("profile.txt", "w")
26 |
27 | ### HEADER
28 | query.gettitle()
29 | zefile.write(query.ack + "\n")
30 | zefile.write(query.title+"\n")
31 | zefile.write("------------------------------\n")
32 | zefile.write("altitude (m) // pressure (Pa) // density (kg/m3) // temperature (K)\n")
33 | zefile.write("------------------------------\n")
34 |
35 | ### GET AND WRITE PROFILE
36 | query.profile( tabperso = np.append([0.1,5,10,20,50,100],np.linspace(200.,float(split(lines[4])[0])*1000.,float(split(lines[5])[0]))) )
37 |
38 |
39 | for iz in range(len(query.prestab)):
40 | zefile.write( "%15.4e%15.4e%15.4e%15.4e\n" % ( \
41 | query.xcoord[iz],query.prestab[iz],query.denstab[iz],query.temptab[iz]) )
42 |
43 | ### FINISH
44 | zefile.close()
45 | query.plot1d(["p","t","rho"]) ; mpl.show()
46 |
47 |
--------------------------------------------------------------------------------
/perso/inimeso/shift_temp.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | import numpy as np
3 |
4 | shift = -10.
5 |
6 | # load data
7 | # http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html
8 | yy,yyy = np.loadtxt("input_more",unpack=True)
9 | gg,ggg,gggg = np.loadtxt("input_sounding",unpack=True)
10 | z,tpot,q,u,v = np.loadtxt("input_sounding",skiprows=1,unpack=True)
11 | r,cp,p,rho,t = np.loadtxt("input_therm",unpack=True)
12 |
13 |
14 | tpot_save = tpot
15 | t = t + shift
16 | tpot = t*(610./p)**(1.0/3.9)
17 |
18 | print "------------------------------------"
19 | print "shifts in potential temperature are:"
20 | print tpot-tpot_save
21 |
22 | more = open("input_more", "w")
23 | more.write( "%10.2f%10.2f" % (yy,t[0]) )
24 | more.close()
25 | sounding = open("input_sounding", "w")
26 | additional = open("input_therm", "w")
27 | sounding.write( "%10.2f%12.2f%12.2f\n" % (gg[0],tpot[0],gggg[0]) )
28 | for iz in range(len(p)):
29 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % (z[iz],tpot[iz],q[iz],u[iz],v[iz]) )
30 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % ( r[iz],cp[iz],p[iz],rho[iz],t[iz] ) )
31 | sounding.close()
32 | additional.close()
33 |
--------------------------------------------------------------------------------
/perso/inimeso/venus/getvenus.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | from string import split
3 | import numpy as np
4 | from ppclass import pp
5 | import ppplot
6 | from planets import Venus
7 |
8 | ############################
9 | zefile = "yorgl.nc"
10 | ttt = 1
11 | ############################
12 |
13 | ### GET COORDINATES
14 | lines = open("input_coord", "r").readlines()
15 | lon = float(split(lines[0])[0]) ; lat = float(split(lines[1])[0])
16 | xdate = float(split(lines[2])[0]) ; loct = float(split(lines[3])[0])
17 |
18 | ### GCM
19 | temp = pp(file=zefile,t=ttt,x=lon,y=lat,var="temp" ).getf()
20 | pres = pp(file=zefile,t=ttt,x=lon,y=lat,var="pres" ).getf()
21 | vitu = pp(file=zefile,t=ttt,x=lon,y=lat,var="vitu" ).getf()
22 | vitv = pp(file=zefile,t=ttt,x=lon,y=lat,var="vitv" ).getf()
23 | dtlwr = pp(file=zefile,t=ttt,x=lon,y=lat,var="dtlwr").getf()
24 | dtswr = pp(file=zefile,t=ttt,x=lon,y=lat,var="dtswr").getf()
25 | geop = pp(file=zefile,t=ttt,x=lon,y=lat,var="geop").getf()
26 |
27 | ### COMPUTATIONS
28 | refpres = pres[0] ; surftpot = temp[0] ; surfh = 0.
29 | ### -- tpot
30 | tpot = temp*(refpres/pres)**(Venus.R()/Venus.cp)
31 | ### -- alt
32 | #alt = Venus.H(T0=temp)*np.log(refpres/pres)
33 | alt = geop / Venus.g
34 | ### -- rho
35 | rho = pres / Venus.R() / temp
36 |
37 | ### CHECK WITH A PLOT
38 | pl = ppplot.plot1d(f=alt,x=tpot).makeshow()
39 | pl = ppplot.plot1d(f=alt,x=rho).makeshow()
40 | pl = ppplot.plot1d(f=alt,x=temp).makeshow()
41 |
42 | ### OPEN FILES TO BE WRITTEN
43 | sounding = open("input_sounding", "w")
44 | additional = open("input_therm", "w")
45 | more = open("input_more", "w")
46 | hr = open("input_hr", "w")
47 |
48 | ### GET and WRITE SURFACE VALUES
49 | sounding.write( "%10.2f%12.2f%12.2f\n" % (refpres/100.,surftpot,0.) )
50 | more.write( "%10.2f%10.2f" % (surfh,surftpot) )
51 |
52 | ### GET and WRITE VERTICAL PROFILE
53 | nz = len(pres)
54 | for iz in range(nz):
55 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % (alt[iz],tpot[iz],0.,vitu[iz],vitv[iz]) )
56 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % (Venus.R(),Venus.cp,pres[iz],rho[iz],temp[iz]) )
57 | hr.write( "%18.6e%18.6e\n" % (dtswr[iz],dtlwr[iz]) )
58 |
59 | ### CLOSE FILES
60 | sounding.close()
61 | additional.close()
62 | more.close()
63 | hr.close()
64 |
--------------------------------------------------------------------------------
/perso/inimeso/venus/input_coord:
--------------------------------------------------------------------------------
1 | 180.0 lon
2 | 30.0 lat
3 | 0.0 ls
4 | 00. lct
5 | 999. ztop
6 | 999. nz
7 |
8 |
--------------------------------------------------------------------------------
/perso/phoenix.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | from mcd import mcd
3 | import numpy as np
4 |
5 | ##122 127
6 |
7 | ph = mcd()
8 |
9 | ph.lat = 68.22
10 | ph.lon = 234.25
11 | ph.xdate = 122.
12 | ph.xz = 5000.
13 | ph.loct = 3.
14 | ph.zkey = 3
15 |
16 | yy = []
17 | for iii in np.arange(-50,50,1):
18 | ph.perturkey = 4 # large-scale + small-scale
19 | ph.seedin = iii #random number generator seed (unused if perturkey=0)
20 | ph.update()
21 | yy.append(ph.temp)
22 |
23 | print np.mean(yy)
24 | print np.std(yy)
25 |
--------------------------------------------------------------------------------
/quicktest.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | from mcd import mcd_class
4 | req = mcd_class()
5 | req.lat = -4.6
6 | req.lon = 137.4
7 | req.loct = 15
8 | req.xz = 1
9 | req.xdate = 150.6
10 | req.update()
11 | req.printmeanvar()
12 |
13 |
--------------------------------------------------------------------------------
/test_mcd/MCD_DATA:
--------------------------------------------------------------------------------
1 | ../../../MCD_v5.2/data
--------------------------------------------------------------------------------
/test_mcd/README:
--------------------------------------------------------------------------------
1 | ### TEST_MCD: a simple example of requesting fields from the MCD
2 |
3 | CONTENTS:
4 | =========
5 | test_mcd.py Example of a python script calling the mcd
6 | test_mcd.def Example of user inputs to test_mcd.py
7 |
8 | GENERAL DESCRIPTION:
9 | ====================
10 | The test_mcd.py python script is an illustrative example of how one may
11 | call upon the fortran routine call_mcd.F (as well as the Julian.F routine)
12 | to retreive data from the Mars Climate Database.
13 |
14 | USAGE:
15 | ======
16 | The "test_mcd.py" script provides a simple and straightforward example of
17 | how one can call the mcd from within a python script. When run it requires
18 | some input from the user (hence the "test_mcd.def" file, for those who prefer
19 | to redirect input from a file rather than type as the program proceeds).
20 |
21 | WARNING:
22 | ========
23 | Either set the link MCD_DATA in this folder
24 | Or change the dset variable in the scripts
25 |
--------------------------------------------------------------------------------
/test_mcd/test_mcd.def:
--------------------------------------------------------------------------------
1 | m
2 | 315
3 | 0.0
4 | 3
5 | 500
6 | 0
7 | 0.
8 | 0.
9 | 1
10 | 1
11 | 1
12 |
13 |
14 | This file can be use as an input to the example program test_mcd. Just type:
15 |
16 | test_mcd.py < test_mcd.def
17 |
--------------------------------------------------------------------------------
/test_mcd/test_mcd.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | # This python program illustrates how the Mars Climate Database
4 | # fortran routines can be called interactively from python
5 |
6 | from fmcd import call_mcd,julian
7 | import numpy as np
8 |
9 | # 1. Inputs:
10 | dset = '' # default to 'MCD_DATA'
11 | perturkey = 1 # default to no perturbation
12 | seedin = 0 # perturbation seed (unused if perturkey=1)
13 | gwlength = 0 # Gravity Wave length for perturbations (unused if perturkey=1)
14 |
15 | # 1.1 Dates
16 | choice_date=raw_input('Use Earth date (e) or Mars date (m)?')
17 | if (choice_date == "e") :
18 | datekey=0 # Earth date
19 | loct=0 # local time must then also be set to zero
20 | day,month,year,hour,minute,second = \
21 | raw_input("Enter date: day/month/year/hour/minute/second: ").split('/')
22 | day=int(day)
23 | month=int(month)
24 | year=int(year)
25 | hour=int(hour)
26 | minute=int(minute)
27 | second=int(second)
28 | # now call Julian routine to convert to julian date
29 | (ier,xdate)=julian(month,day,year,hour,minute,second)
30 | print " Julian date %16.8f" % xdate
31 | else :
32 | datekey=1 # Mars date
33 | xdate=float(raw_input("Enter solar longitude Ls (deg.):"))
34 | loct=float(raw_input("Local time (0 < time < 24)?"))
35 |
36 | # 1.2 Vertical coordinate
37 | zkey=int(raw_input("Select verical coordinate type (1: distance to center of planet, 2: height above areoid, 3: height above surface, 4: Pressure) "))
38 | if (zkey == 1) :
39 | xz=float(raw_input("Enter distance to planet center (m) "))
40 | if (zkey == 2) :
41 | xz=float(raw_input("Enter altitude above areoid (m) "))
42 | if (zkey == 3) :
43 | xz=float(raw_input("Enter altitude above surface (m) "))
44 | if (zkey == 4) :
45 | xz=float(raw_input("Enter pressure value (Pa) "))
46 |
47 | # high resolution mode
48 | hrkey=int(raw_input("High resolution? (1: yes, 0: no) "))
49 |
50 | # 1.3 Position
51 | lat = float(raw_input('Latitude (deg)?'))
52 | lon = float(raw_input('Longitude (deg)?'))
53 |
54 | # 1.4 Dust and solar scenario
55 | print "Dust scenario?"
56 | print "1= Climatology typical Mars year dust scenario"
57 | print " average solar EUV conditions"
58 | print "2= Climatology typical Mars year dust scenario"
59 | print " minimum solar EUV conditions"
60 | print "3= Climatology typical Mars year dust scenario"
61 | print " maximum solar EUV conditions"
62 | print "4= dust storm constant dust opacity = 5 (dark dust)"
63 | print " minimum solar EUV conditions"
64 | print "5= dust storm constant dust opacity = 5 (dark dust)"
65 | print " average solar EUV conditions"
66 | print "6= dust storm constant dust opacity = 5 (dark dust)"
67 | print " maximum solar EUV conditions"
68 | print "7= warm scenario dustier than Climatology scenario"
69 | print " maximum solar EUV conditions"
70 | print "8= cold scenario clearer than Climatology scenario"
71 | print " minimum solar EUV conditions"
72 | dust=int(raw_input(''))
73 |
74 | # 1.5 perturbations
75 | perturkey=int(raw_input("Perturbation? (1:none, 2: large scale, 3: small scale, 4: small+large, 5: n sigmas) "))
76 | if (perturkey > 1) :
77 | seedin=int(raw_input("seedin? (only matters if adding perturbations) "))
78 | if ((perturkey == 3) or (perturkey == 4)) :
79 | gwlength=float(raw_input("Gravity wave length? (for small scale perturbations) "))
80 |
81 | # 1.6 extra outputs
82 | # here we only implement an all-or-nothing case
83 | extvarkey=int(raw_input("Output the extra variables? (yes==1; no==0) "))
84 | if (extvarkey == 0) :
85 | extvarkeys = np.zeros(100)
86 | else :
87 | extvarkeys = np.ones(100)
88 |
89 | # 2. Call MCD
90 | (pres, dens, temp, zonwind, merwind, \
91 | meanvar, extvar, seedout, ierr) \
92 | = \
93 | call_mcd(zkey,xz,lon,lat,hrkey, \
94 | datekey,xdate,loct,dset,dust, \
95 | perturkey,seedin,gwlength,extvarkeys )
96 |
97 | # 3. Write outputs
98 | print "temperature is %.0f K, pressure is %.0f Pa, density is %5.3e kg/m3, zonal wind is %.1f m/s, meridional wind is %.1f m/s" % (temp,pres,dens,zonwind,merwind)
99 |
100 |
--------------------------------------------------------------------------------
/test_mcd/test_mcd_light.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | from fmcd import call_mcd
4 | import numpy as np
5 |
6 | lon = float(raw_input('Longitude?'))
7 | lat = float(raw_input('Latitude?'))
8 | xdate = float(raw_input('Ls?'))
9 | loct = float(raw_input('Local time?'))
10 | xz = float(raw_input('Altitude?'))
11 |
12 | #dset = '/home/aymeric/Science/MCD_v4.3/data/'
13 | dset = './MCD_DATA/'
14 |
15 | zkey = 3 # specify that xz is the altitude above surface (m)
16 | datekey = 1 # 1 = "Mars date": xdate is the value of Ls
17 | dust = 2 #our best guess MY24 scenario, with solar average conditions
18 | hrkey = 1 #set high resolution mode on (hrkey=0 to set high resolution off)
19 | perturkey = 0 #integer perturkey ! perturbation type (0: none)
20 | seedin = 1 #random number generator seed (unused if perturkey=0)
21 | gwlength = 0. #gravity Wave wavelength (unused if perturkey=0)
22 | #extvarkey = 1
23 | #extvarkeys = np.ones(100)
24 | extvarkeys = np.zeros(100)
25 |
26 | (pres, dens, temp, zonwind, merwind, \
27 | meanvar, extvar, seedout, ierr) \
28 | = \
29 | call_mcd(zkey,xz,lon,lat,hrkey, \
30 | datekey,xdate,loct,dset,dust, \
31 | perturkey,seedin,gwlength,extvarkeys )
32 |
33 | print "temperature is %.0f K, pressure is %.0f Pa, density is %5.3e kg/m3, zonal wind is %.1f m/s, meridional wind is %.1f m/s" % (temp,pres,dens,zonwind,merwind)
34 |
35 |
--------------------------------------------------------------------------------