├── .gitignore
├── LICENSE
├── README.md
├── config
├── grid_coords.yaml
├── grid_coords_dipole.yaml
├── grid_coords_dipole_valid.yaml
├── grid_coords_gabor_rand.yaml
├── grid_coords_gabor_small.yaml
├── grid_coords_squares.yaml
├── grid_coords_squares_utah.yaml
├── grid_coords_valid.yaml
├── grid_coords_valid_2.yaml
├── grid_coords_valid_3.yaml
└── params.yaml
├── dynaphos
├── __init__.py
├── cortex_models.py
├── image_processing.py
├── plotting.py
├── simulator.py
└── utils.py
├── examples
├── __init__.py
├── demo_simulator.ipynb
├── demo_webcam.py
├── example_video.mp4
├── example_video_gaze_contingent_object_grabbing.mp4
├── example_video_gaze_contingent_walking.mp4
├── eye_tracked_i1344739819_subject_hp.mp4
├── eye_tracked_i1344739819_subject_hp_orig.mp4
└── readme.md
├── pyproject.toml
├── requirements.txt
├── setup.py
└── test
├── __init__.py
├── benchmark.pkl
├── benchmark.png
├── benchmark.py
├── data
├── Fernandez_2021_fig6A.csv
├── activation.npy
├── coordinates_dipole.npz
├── coordinates_monopole.npz
├── coordinates_wedge-dipole.npz
├── donders.png
├── fernandez_activation_fit.npy
├── fernandez_brightness_fit.npy
├── output.npy
├── phosphene_map.npy
├── phosphenes_donders.npy
├── results_dynamics.pkl
├── sigma.npy
├── stimulus.npy
├── trace.npy
├── valid_electrodes.npy
└── z_full_view.npy
└── test_all.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .ipynb_checkpoints
2 | __pycache__
3 |
4 | clips/
5 | **[Aa]rchived
6 | .idea/
7 |
8 | /dist/
9 | /dynaphos.egg-info/
10 | *.mp4
11 | *.avi
12 | /scratch/
13 | *.pickle
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # About the project
2 | A fully differentiable and biologically plausible simulation of cortical prosthetic vision, which can be used for end-to-end optimization.
3 |
4 | ## Installation
5 | `pip install dynaphos`
6 |
7 | ## Getting Started
8 | - Download the default configuration file (config/params.yaml) from [our repository](https://github.com/neuralcodinglab/dynaphos/) and adjust according to needs.
9 | - Run the `test` suite.
10 | - See the `examples` directory for simple use cases.
11 |
12 | ## Citation
13 | van der Grinten, M., van Steveninck, J. D. R., Lozano, A., Pijnacker, L., Rueckauer, B., Roelfsema, P., Marcel van Gerven, Richard van Wezel, Umut Güçlü & Güçlütürk, Y. (2024). Towards biologically plausible phosphene simulation for the differentiable optimization of visual cortical prostheses. eLife, 13, e85812. [https://doi.org/10.7554/eLife.85812](https://doi.org/10.7554/eLife.85812).
14 |
15 | ## Experiments
16 | For the end-to-end optimization experiments in our publication see [this repository](https://github.com/neuralcodinglab/viseon/tree/dynaphos-paper). The code for the experiments described in our publication (using this simulator) can be found in [this repository](https://github.com/neuralcodinglab/dynaphos-experiments). All other code that was used in our publication can be made available on request.
17 |
18 | ## Contact
19 | Feel free to submit an issue, we're happy to help.
20 |
--------------------------------------------------------------------------------
/config/grid_coords_gabor_rand.yaml:
--------------------------------------------------------------------------------
1 | x: [ 6.41 , 14.791, 7.007, 22.26 , 8.291, 14.558, 11.211, 6.375,
2 | 6.542, 6.305, 8.344, 6.866, 14.643, 23.202, 11.439, 8.952,
3 | 6.318, 7.669, 7.42 , 7.331, 9.939, 7.542, 11.093, 6.951,
4 | 14.417, 11.031, 13.24 , 17.014, 9.033, 14.756, 7.671, 20.991,
5 | 9.628, 14.41 , 12.996, 10.432, 22.556, 10.996, 18.598, 18.658,
6 | 21.492, 6.868, 12.74 , 8.871, 13.954, 15.865, 19.115, 19.461,
7 | 10.761, 16.771]
8 | y: [ 8.152, 13.758, 18.18 , 8.972, 21.359, 6.433, 22.803, 11.561,
9 | 17.659, 6.464, 7.881, 13.841, 17.692, 15.068, 9.701, 10.122,
10 | 9.534, 6.591, 15.323, 12.834, 23.457, 7.257, 14.056, 9.216,
11 | 10.548, 19.329, 11.045, 15.187, 20.45 , 22.486, 21.444, 21.898,
12 | 11.422, 18.84 , 8.94 , 16.333, 16.636, 7.699, 10.073, 14.845,
13 | 23.055, 15.687, 16.141, 12.807, 11.27 , 8.267, 6.681, 13.075,
14 | 10.66 , 6.627]
15 | theta: [1.68 , 3.13 , 1.491, 2.564, 1.357, 2.502, 1.871, 2.785, 1.291,
16 | 1.898, 1.979, 1.311, 0.453, 0.294, 0.052, 2.744, 0.743, 0.664,
17 | 2.312, 1.005, 1.59 , 0.511, 3.015, 2.675, 2.714, 1.278, 2.395,
18 | 0.452, 0.027, 0.063, 1.843, 1.431, 1.627, 0.023, 1.328, 2.256,
19 | 1.391, 2.3 , 0.732, 2.555, 1.849, 0.662, 0.744, 1.973, 2.607,
20 | 1.306, 0.811, 2.724, 2.103, 1.408]
--------------------------------------------------------------------------------
/config/grid_coords_gabor_small.yaml:
--------------------------------------------------------------------------------
1 | x: [15,15,15, 12,12,12, 18,18,18]
2 | y: [3, 0, -3, 3, 0, -3, 3, 0, -3]
3 | theta: [0, 1.57079633,0, 1.57079633, 0, 1.57079633, 1.57079633, 0, 1.57079633]
--------------------------------------------------------------------------------
/config/grid_coords_squares.yaml:
--------------------------------------------------------------------------------
1 | x:
2 | - 35.0
3 | - 35.55555555555556
4 | - 36.111111111111114
5 | - 36.666666666666664
6 | - 37.22222222222222
7 | - 37.77777777777778
8 | - 38.333333333333336
9 | - 38.888888888888886
10 | - 39.44444444444444
11 | - 40.0
12 | - 35.0
13 | - 35.55555555555556
14 | - 36.111111111111114
15 | - 36.666666666666664
16 | - 37.22222222222222
17 | - 37.77777777777778
18 | - 38.333333333333336
19 | - 38.888888888888886
20 | - 39.44444444444444
21 | - 40.0
22 | - 35.0
23 | - 35.55555555555556
24 | - 36.111111111111114
25 | - 36.666666666666664
26 | - 37.22222222222222
27 | - 37.77777777777778
28 | - 38.333333333333336
29 | - 38.888888888888886
30 | - 39.44444444444444
31 | - 40.0
32 | - 35.0
33 | - 35.55555555555556
34 | - 36.111111111111114
35 | - 36.666666666666664
36 | - 37.22222222222222
37 | - 37.77777777777778
38 | - 38.333333333333336
39 | - 38.888888888888886
40 | - 39.44444444444444
41 | - 40.0
42 | - 35.0
43 | - 35.55555555555556
44 | - 36.111111111111114
45 | - 36.666666666666664
46 | - 37.22222222222222
47 | - 37.77777777777778
48 | - 38.333333333333336
49 | - 38.888888888888886
50 | - 39.44444444444444
51 | - 40.0
52 | - 35.0
53 | - 35.55555555555556
54 | - 36.111111111111114
55 | - 36.666666666666664
56 | - 37.22222222222222
57 | - 37.77777777777778
58 | - 38.333333333333336
59 | - 38.888888888888886
60 | - 39.44444444444444
61 | - 40.0
62 | - 35.0
63 | - 35.55555555555556
64 | - 36.111111111111114
65 | - 36.666666666666664
66 | - 37.22222222222222
67 | - 37.77777777777778
68 | - 38.333333333333336
69 | - 38.888888888888886
70 | - 39.44444444444444
71 | - 40.0
72 | - 35.0
73 | - 35.55555555555556
74 | - 36.111111111111114
75 | - 36.666666666666664
76 | - 37.22222222222222
77 | - 37.77777777777778
78 | - 38.333333333333336
79 | - 38.888888888888886
80 | - 39.44444444444444
81 | - 40.0
82 | - 35.0
83 | - 35.55555555555556
84 | - 36.111111111111114
85 | - 36.666666666666664
86 | - 37.22222222222222
87 | - 37.77777777777778
88 | - 38.333333333333336
89 | - 38.888888888888886
90 | - 39.44444444444444
91 | - 40.0
92 | - 35.0
93 | - 35.55555555555556
94 | - 36.111111111111114
95 | - 36.666666666666664
96 | - 37.22222222222222
97 | - 37.77777777777778
98 | - 38.333333333333336
99 | - 38.888888888888886
100 | - 39.44444444444444
101 | - 40.0
102 | - 2.0
103 | - 2.5555555555555554
104 | - 3.111111111111111
105 | - 3.666666666666667
106 | - 4.222222222222222
107 | - 4.777777777777778
108 | - 5.333333333333334
109 | - 5.888888888888889
110 | - 6.444444444444445
111 | - 7.0
112 | - 2.0
113 | - 2.5555555555555554
114 | - 3.111111111111111
115 | - 3.666666666666667
116 | - 4.222222222222222
117 | - 4.777777777777778
118 | - 5.333333333333334
119 | - 5.888888888888889
120 | - 6.444444444444445
121 | - 7.0
122 | - 2.0
123 | - 2.5555555555555554
124 | - 3.111111111111111
125 | - 3.666666666666667
126 | - 4.222222222222222
127 | - 4.777777777777778
128 | - 5.333333333333334
129 | - 5.888888888888889
130 | - 6.444444444444445
131 | - 7.0
132 | - 2.0
133 | - 2.5555555555555554
134 | - 3.111111111111111
135 | - 3.666666666666667
136 | - 4.222222222222222
137 | - 4.777777777777778
138 | - 5.333333333333334
139 | - 5.888888888888889
140 | - 6.444444444444445
141 | - 7.0
142 | - 2.0
143 | - 2.5555555555555554
144 | - 3.111111111111111
145 | - 3.666666666666667
146 | - 4.222222222222222
147 | - 4.777777777777778
148 | - 5.333333333333334
149 | - 5.888888888888889
150 | - 6.444444444444445
151 | - 7.0
152 | - 2.0
153 | - 2.5555555555555554
154 | - 3.111111111111111
155 | - 3.666666666666667
156 | - 4.222222222222222
157 | - 4.777777777777778
158 | - 5.333333333333334
159 | - 5.888888888888889
160 | - 6.444444444444445
161 | - 7.0
162 | - 2.0
163 | - 2.5555555555555554
164 | - 3.111111111111111
165 | - 3.666666666666667
166 | - 4.222222222222222
167 | - 4.777777777777778
168 | - 5.333333333333334
169 | - 5.888888888888889
170 | - 6.444444444444445
171 | - 7.0
172 | - 2.0
173 | - 2.5555555555555554
174 | - 3.111111111111111
175 | - 3.666666666666667
176 | - 4.222222222222222
177 | - 4.777777777777778
178 | - 5.333333333333334
179 | - 5.888888888888889
180 | - 6.444444444444445
181 | - 7.0
182 | - 2.0
183 | - 2.5555555555555554
184 | - 3.111111111111111
185 | - 3.666666666666667
186 | - 4.222222222222222
187 | - 4.777777777777778
188 | - 5.333333333333334
189 | - 5.888888888888889
190 | - 6.444444444444445
191 | - 7.0
192 | - 2.0
193 | - 2.5555555555555554
194 | - 3.111111111111111
195 | - 3.666666666666667
196 | - 4.222222222222222
197 | - 4.777777777777778
198 | - 5.333333333333334
199 | - 5.888888888888889
200 | - 6.444444444444445
201 | - 7.0
202 | - 20.0
203 | - 20.555555555555557
204 | - 21.11111111111111
205 | - 21.666666666666668
206 | - 22.22222222222222
207 | - 22.77777777777778
208 | - 23.333333333333332
209 | - 23.88888888888889
210 | - 24.444444444444443
211 | - 25.0
212 | - 20.0
213 | - 20.555555555555557
214 | - 21.11111111111111
215 | - 21.666666666666668
216 | - 22.22222222222222
217 | - 22.77777777777778
218 | - 23.333333333333332
219 | - 23.88888888888889
220 | - 24.444444444444443
221 | - 25.0
222 | - 20.0
223 | - 20.555555555555557
224 | - 21.11111111111111
225 | - 21.666666666666668
226 | - 22.22222222222222
227 | - 22.77777777777778
228 | - 23.333333333333332
229 | - 23.88888888888889
230 | - 24.444444444444443
231 | - 25.0
232 | - 20.0
233 | - 20.555555555555557
234 | - 21.11111111111111
235 | - 21.666666666666668
236 | - 22.22222222222222
237 | - 22.77777777777778
238 | - 23.333333333333332
239 | - 23.88888888888889
240 | - 24.444444444444443
241 | - 25.0
242 | - 20.0
243 | - 20.555555555555557
244 | - 21.11111111111111
245 | - 21.666666666666668
246 | - 22.22222222222222
247 | - 22.77777777777778
248 | - 23.333333333333332
249 | - 23.88888888888889
250 | - 24.444444444444443
251 | - 25.0
252 | - 20.0
253 | - 20.555555555555557
254 | - 21.11111111111111
255 | - 21.666666666666668
256 | - 22.22222222222222
257 | - 22.77777777777778
258 | - 23.333333333333332
259 | - 23.88888888888889
260 | - 24.444444444444443
261 | - 25.0
262 | - 20.0
263 | - 20.555555555555557
264 | - 21.11111111111111
265 | - 21.666666666666668
266 | - 22.22222222222222
267 | - 22.77777777777778
268 | - 23.333333333333332
269 | - 23.88888888888889
270 | - 24.444444444444443
271 | - 25.0
272 | - 20.0
273 | - 20.555555555555557
274 | - 21.11111111111111
275 | - 21.666666666666668
276 | - 22.22222222222222
277 | - 22.77777777777778
278 | - 23.333333333333332
279 | - 23.88888888888889
280 | - 24.444444444444443
281 | - 25.0
282 | - 20.0
283 | - 20.555555555555557
284 | - 21.11111111111111
285 | - 21.666666666666668
286 | - 22.22222222222222
287 | - 22.77777777777778
288 | - 23.333333333333332
289 | - 23.88888888888889
290 | - 24.444444444444443
291 | - 25.0
292 | - 20.0
293 | - 20.555555555555557
294 | - 21.11111111111111
295 | - 21.666666666666668
296 | - 22.22222222222222
297 | - 22.77777777777778
298 | - 23.333333333333332
299 | - 23.88888888888889
300 | - 24.444444444444443
301 | - 25.0
302 | - 20.0
303 | - 20.555555555555557
304 | - 21.11111111111111
305 | - 21.666666666666668
306 | - 22.22222222222222
307 | - 22.77777777777778
308 | - 23.333333333333332
309 | - 23.88888888888889
310 | - 24.444444444444443
311 | - 25.0
312 | - 20.0
313 | - 20.555555555555557
314 | - 21.11111111111111
315 | - 21.666666666666668
316 | - 22.22222222222222
317 | - 22.77777777777778
318 | - 23.333333333333332
319 | - 23.88888888888889
320 | - 24.444444444444443
321 | - 25.0
322 | - 20.0
323 | - 20.555555555555557
324 | - 21.11111111111111
325 | - 21.666666666666668
326 | - 22.22222222222222
327 | - 22.77777777777778
328 | - 23.333333333333332
329 | - 23.88888888888889
330 | - 24.444444444444443
331 | - 25.0
332 | - 20.0
333 | - 20.555555555555557
334 | - 21.11111111111111
335 | - 21.666666666666668
336 | - 22.22222222222222
337 | - 22.77777777777778
338 | - 23.333333333333332
339 | - 23.88888888888889
340 | - 24.444444444444443
341 | - 25.0
342 | - 20.0
343 | - 20.555555555555557
344 | - 21.11111111111111
345 | - 21.666666666666668
346 | - 22.22222222222222
347 | - 22.77777777777778
348 | - 23.333333333333332
349 | - 23.88888888888889
350 | - 24.444444444444443
351 | - 25.0
352 | - 20.0
353 | - 20.555555555555557
354 | - 21.11111111111111
355 | - 21.666666666666668
356 | - 22.22222222222222
357 | - 22.77777777777778
358 | - 23.333333333333332
359 | - 23.88888888888889
360 | - 24.444444444444443
361 | - 25.0
362 | - 20.0
363 | - 20.555555555555557
364 | - 21.11111111111111
365 | - 21.666666666666668
366 | - 22.22222222222222
367 | - 22.77777777777778
368 | - 23.333333333333332
369 | - 23.88888888888889
370 | - 24.444444444444443
371 | - 25.0
372 | - 20.0
373 | - 20.555555555555557
374 | - 21.11111111111111
375 | - 21.666666666666668
376 | - 22.22222222222222
377 | - 22.77777777777778
378 | - 23.333333333333332
379 | - 23.88888888888889
380 | - 24.444444444444443
381 | - 25.0
382 | - 20.0
383 | - 20.555555555555557
384 | - 21.11111111111111
385 | - 21.666666666666668
386 | - 22.22222222222222
387 | - 22.77777777777778
388 | - 23.333333333333332
389 | - 23.88888888888889
390 | - 24.444444444444443
391 | - 25.0
392 | - 20.0
393 | - 20.555555555555557
394 | - 21.11111111111111
395 | - 21.666666666666668
396 | - 22.22222222222222
397 | - 22.77777777777778
398 | - 23.333333333333332
399 | - 23.88888888888889
400 | - 24.444444444444443
401 | - 25.0
402 | y:
403 | - 1.0
404 | - 1.0
405 | - 1.0
406 | - 1.0
407 | - 1.0
408 | - 1.0
409 | - 1.0
410 | - 1.0
411 | - 1.0
412 | - 1.0
413 | - 1.5555555555555556
414 | - 1.5555555555555556
415 | - 1.5555555555555556
416 | - 1.5555555555555556
417 | - 1.5555555555555556
418 | - 1.5555555555555556
419 | - 1.5555555555555556
420 | - 1.5555555555555556
421 | - 1.5555555555555556
422 | - 1.5555555555555556
423 | - 2.111111111111111
424 | - 2.111111111111111
425 | - 2.111111111111111
426 | - 2.111111111111111
427 | - 2.111111111111111
428 | - 2.111111111111111
429 | - 2.111111111111111
430 | - 2.111111111111111
431 | - 2.111111111111111
432 | - 2.111111111111111
433 | - 2.666666666666667
434 | - 2.666666666666667
435 | - 2.666666666666667
436 | - 2.666666666666667
437 | - 2.666666666666667
438 | - 2.666666666666667
439 | - 2.666666666666667
440 | - 2.666666666666667
441 | - 2.666666666666667
442 | - 2.666666666666667
443 | - 3.2222222222222223
444 | - 3.2222222222222223
445 | - 3.2222222222222223
446 | - 3.2222222222222223
447 | - 3.2222222222222223
448 | - 3.2222222222222223
449 | - 3.2222222222222223
450 | - 3.2222222222222223
451 | - 3.2222222222222223
452 | - 3.2222222222222223
453 | - 3.7777777777777777
454 | - 3.7777777777777777
455 | - 3.7777777777777777
456 | - 3.7777777777777777
457 | - 3.7777777777777777
458 | - 3.7777777777777777
459 | - 3.7777777777777777
460 | - 3.7777777777777777
461 | - 3.7777777777777777
462 | - 3.7777777777777777
463 | - 4.333333333333334
464 | - 4.333333333333334
465 | - 4.333333333333334
466 | - 4.333333333333334
467 | - 4.333333333333334
468 | - 4.333333333333334
469 | - 4.333333333333334
470 | - 4.333333333333334
471 | - 4.333333333333334
472 | - 4.333333333333334
473 | - 4.888888888888889
474 | - 4.888888888888889
475 | - 4.888888888888889
476 | - 4.888888888888889
477 | - 4.888888888888889
478 | - 4.888888888888889
479 | - 4.888888888888889
480 | - 4.888888888888889
481 | - 4.888888888888889
482 | - 4.888888888888889
483 | - 5.444444444444445
484 | - 5.444444444444445
485 | - 5.444444444444445
486 | - 5.444444444444445
487 | - 5.444444444444445
488 | - 5.444444444444445
489 | - 5.444444444444445
490 | - 5.444444444444445
491 | - 5.444444444444445
492 | - 5.444444444444445
493 | - 6.0
494 | - 6.0
495 | - 6.0
496 | - 6.0
497 | - 6.0
498 | - 6.0
499 | - 6.0
500 | - 6.0
501 | - 6.0
502 | - 6.0
503 | - 1.0
504 | - 1.0
505 | - 1.0
506 | - 1.0
507 | - 1.0
508 | - 1.0
509 | - 1.0
510 | - 1.0
511 | - 1.0
512 | - 1.0
513 | - 1.5555555555555556
514 | - 1.5555555555555556
515 | - 1.5555555555555556
516 | - 1.5555555555555556
517 | - 1.5555555555555556
518 | - 1.5555555555555556
519 | - 1.5555555555555556
520 | - 1.5555555555555556
521 | - 1.5555555555555556
522 | - 1.5555555555555556
523 | - 2.111111111111111
524 | - 2.111111111111111
525 | - 2.111111111111111
526 | - 2.111111111111111
527 | - 2.111111111111111
528 | - 2.111111111111111
529 | - 2.111111111111111
530 | - 2.111111111111111
531 | - 2.111111111111111
532 | - 2.111111111111111
533 | - 2.666666666666667
534 | - 2.666666666666667
535 | - 2.666666666666667
536 | - 2.666666666666667
537 | - 2.666666666666667
538 | - 2.666666666666667
539 | - 2.666666666666667
540 | - 2.666666666666667
541 | - 2.666666666666667
542 | - 2.666666666666667
543 | - 3.2222222222222223
544 | - 3.2222222222222223
545 | - 3.2222222222222223
546 | - 3.2222222222222223
547 | - 3.2222222222222223
548 | - 3.2222222222222223
549 | - 3.2222222222222223
550 | - 3.2222222222222223
551 | - 3.2222222222222223
552 | - 3.2222222222222223
553 | - 3.7777777777777777
554 | - 3.7777777777777777
555 | - 3.7777777777777777
556 | - 3.7777777777777777
557 | - 3.7777777777777777
558 | - 3.7777777777777777
559 | - 3.7777777777777777
560 | - 3.7777777777777777
561 | - 3.7777777777777777
562 | - 3.7777777777777777
563 | - 4.333333333333334
564 | - 4.333333333333334
565 | - 4.333333333333334
566 | - 4.333333333333334
567 | - 4.333333333333334
568 | - 4.333333333333334
569 | - 4.333333333333334
570 | - 4.333333333333334
571 | - 4.333333333333334
572 | - 4.333333333333334
573 | - 4.888888888888889
574 | - 4.888888888888889
575 | - 4.888888888888889
576 | - 4.888888888888889
577 | - 4.888888888888889
578 | - 4.888888888888889
579 | - 4.888888888888889
580 | - 4.888888888888889
581 | - 4.888888888888889
582 | - 4.888888888888889
583 | - 5.444444444444445
584 | - 5.444444444444445
585 | - 5.444444444444445
586 | - 5.444444444444445
587 | - 5.444444444444445
588 | - 5.444444444444445
589 | - 5.444444444444445
590 | - 5.444444444444445
591 | - 5.444444444444445
592 | - 5.444444444444445
593 | - 6.0
594 | - 6.0
595 | - 6.0
596 | - 6.0
597 | - 6.0
598 | - 6.0
599 | - 6.0
600 | - 6.0
601 | - 6.0
602 | - 6.0
603 | - 10.0
604 | - 10.0
605 | - 10.0
606 | - 10.0
607 | - 10.0
608 | - 10.0
609 | - 10.0
610 | - 10.0
611 | - 10.0
612 | - 10.0
613 | - 10.555555555555555
614 | - 10.555555555555555
615 | - 10.555555555555555
616 | - 10.555555555555555
617 | - 10.555555555555555
618 | - 10.555555555555555
619 | - 10.555555555555555
620 | - 10.555555555555555
621 | - 10.555555555555555
622 | - 10.555555555555555
623 | - 11.11111111111111
624 | - 11.11111111111111
625 | - 11.11111111111111
626 | - 11.11111111111111
627 | - 11.11111111111111
628 | - 11.11111111111111
629 | - 11.11111111111111
630 | - 11.11111111111111
631 | - 11.11111111111111
632 | - 11.11111111111111
633 | - 11.666666666666666
634 | - 11.666666666666666
635 | - 11.666666666666666
636 | - 11.666666666666666
637 | - 11.666666666666666
638 | - 11.666666666666666
639 | - 11.666666666666666
640 | - 11.666666666666666
641 | - 11.666666666666666
642 | - 11.666666666666666
643 | - 12.222222222222221
644 | - 12.222222222222221
645 | - 12.222222222222221
646 | - 12.222222222222221
647 | - 12.222222222222221
648 | - 12.222222222222221
649 | - 12.222222222222221
650 | - 12.222222222222221
651 | - 12.222222222222221
652 | - 12.222222222222221
653 | - 12.777777777777779
654 | - 12.777777777777779
655 | - 12.777777777777779
656 | - 12.777777777777779
657 | - 12.777777777777779
658 | - 12.777777777777779
659 | - 12.777777777777779
660 | - 12.777777777777779
661 | - 12.777777777777779
662 | - 12.777777777777779
663 | - 13.333333333333334
664 | - 13.333333333333334
665 | - 13.333333333333334
666 | - 13.333333333333334
667 | - 13.333333333333334
668 | - 13.333333333333334
669 | - 13.333333333333334
670 | - 13.333333333333334
671 | - 13.333333333333334
672 | - 13.333333333333334
673 | - 13.88888888888889
674 | - 13.88888888888889
675 | - 13.88888888888889
676 | - 13.88888888888889
677 | - 13.88888888888889
678 | - 13.88888888888889
679 | - 13.88888888888889
680 | - 13.88888888888889
681 | - 13.88888888888889
682 | - 13.88888888888889
683 | - 14.444444444444445
684 | - 14.444444444444445
685 | - 14.444444444444445
686 | - 14.444444444444445
687 | - 14.444444444444445
688 | - 14.444444444444445
689 | - 14.444444444444445
690 | - 14.444444444444445
691 | - 14.444444444444445
692 | - 14.444444444444445
693 | - 15.0
694 | - 15.0
695 | - 15.0
696 | - 15.0
697 | - 15.0
698 | - 15.0
699 | - 15.0
700 | - 15.0
701 | - 15.0
702 | - 15.0
703 | - -10.0
704 | - -10.0
705 | - -10.0
706 | - -10.0
707 | - -10.0
708 | - -10.0
709 | - -10.0
710 | - -10.0
711 | - -10.0
712 | - -10.0
713 | - -10.555555555555555
714 | - -10.555555555555555
715 | - -10.555555555555555
716 | - -10.555555555555555
717 | - -10.555555555555555
718 | - -10.555555555555555
719 | - -10.555555555555555
720 | - -10.555555555555555
721 | - -10.555555555555555
722 | - -10.555555555555555
723 | - -11.11111111111111
724 | - -11.11111111111111
725 | - -11.11111111111111
726 | - -11.11111111111111
727 | - -11.11111111111111
728 | - -11.11111111111111
729 | - -11.11111111111111
730 | - -11.11111111111111
731 | - -11.11111111111111
732 | - -11.11111111111111
733 | - -11.666666666666666
734 | - -11.666666666666666
735 | - -11.666666666666666
736 | - -11.666666666666666
737 | - -11.666666666666666
738 | - -11.666666666666666
739 | - -11.666666666666666
740 | - -11.666666666666666
741 | - -11.666666666666666
742 | - -11.666666666666666
743 | - -12.222222222222221
744 | - -12.222222222222221
745 | - -12.222222222222221
746 | - -12.222222222222221
747 | - -12.222222222222221
748 | - -12.222222222222221
749 | - -12.222222222222221
750 | - -12.222222222222221
751 | - -12.222222222222221
752 | - -12.222222222222221
753 | - -12.777777777777779
754 | - -12.777777777777779
755 | - -12.777777777777779
756 | - -12.777777777777779
757 | - -12.777777777777779
758 | - -12.777777777777779
759 | - -12.777777777777779
760 | - -12.777777777777779
761 | - -12.777777777777779
762 | - -12.777777777777779
763 | - -13.333333333333334
764 | - -13.333333333333334
765 | - -13.333333333333334
766 | - -13.333333333333334
767 | - -13.333333333333334
768 | - -13.333333333333334
769 | - -13.333333333333334
770 | - -13.333333333333334
771 | - -13.333333333333334
772 | - -13.333333333333334
773 | - -13.88888888888889
774 | - -13.88888888888889
775 | - -13.88888888888889
776 | - -13.88888888888889
777 | - -13.88888888888889
778 | - -13.88888888888889
779 | - -13.88888888888889
780 | - -13.88888888888889
781 | - -13.88888888888889
782 | - -13.88888888888889
783 | - -14.444444444444445
784 | - -14.444444444444445
785 | - -14.444444444444445
786 | - -14.444444444444445
787 | - -14.444444444444445
788 | - -14.444444444444445
789 | - -14.444444444444445
790 | - -14.444444444444445
791 | - -14.444444444444445
792 | - -14.444444444444445
793 | - -15.0
794 | - -15.0
795 | - -15.0
796 | - -15.0
797 | - -15.0
798 | - -15.0
799 | - -15.0
800 | - -15.0
801 | - -15.0
802 | - -15.0
803 |
--------------------------------------------------------------------------------
/config/grid_coords_squares_utah.yaml:
--------------------------------------------------------------------------------
1 | x:
2 | - 30.0
3 | - 30.0
4 | - 30.0
5 | - 30.0
6 | - 30.0
7 | - 30.0
8 | - 30.0
9 | - 30.0
10 | - 30.0
11 | - 30.0
12 | - 30.4
13 | - 30.4
14 | - 30.4
15 | - 30.4
16 | - 30.4
17 | - 30.4
18 | - 30.4
19 | - 30.4
20 | - 30.4
21 | - 30.4
22 | - 30.8
23 | - 30.8
24 | - 30.8
25 | - 30.8
26 | - 30.8
27 | - 30.8
28 | - 30.8
29 | - 30.8
30 | - 30.8
31 | - 30.8
32 | - 31.2
33 | - 31.2
34 | - 31.2
35 | - 31.2
36 | - 31.2
37 | - 31.2
38 | - 31.2
39 | - 31.2
40 | - 31.2
41 | - 31.2
42 | - 31.6
43 | - 31.6
44 | - 31.6
45 | - 31.6
46 | - 31.6
47 | - 31.6
48 | - 31.6
49 | - 31.6
50 | - 31.6
51 | - 31.6
52 | - 32.0
53 | - 32.0
54 | - 32.0
55 | - 32.0
56 | - 32.0
57 | - 32.0
58 | - 32.0
59 | - 32.0
60 | - 32.0
61 | - 32.0
62 | - 32.4
63 | - 32.4
64 | - 32.4
65 | - 32.4
66 | - 32.4
67 | - 32.4
68 | - 32.4
69 | - 32.4
70 | - 32.4
71 | - 32.4
72 | - 32.8
73 | - 32.8
74 | - 32.8
75 | - 32.8
76 | - 32.8
77 | - 32.8
78 | - 32.8
79 | - 32.8
80 | - 32.8
81 | - 32.8
82 | - 33.2
83 | - 33.2
84 | - 33.2
85 | - 33.2
86 | - 33.2
87 | - 33.2
88 | - 33.2
89 | - 33.2
90 | - 33.2
91 | - 33.2
92 | - 33.6
93 | - 33.6
94 | - 33.6
95 | - 33.6
96 | - 33.6
97 | - 33.6
98 | - 33.6
99 | - 33.6
100 | - 33.6
101 | - 33.6
102 | - 37.0
103 | - 37.0
104 | - 37.0
105 | - 37.0
106 | - 37.0
107 | - 37.0
108 | - 37.0
109 | - 37.0
110 | - 37.0
111 | - 37.0
112 | - 37.4
113 | - 37.4
114 | - 37.4
115 | - 37.4
116 | - 37.4
117 | - 37.4
118 | - 37.4
119 | - 37.4
120 | - 37.4
121 | - 37.4
122 | - 37.8
123 | - 37.8
124 | - 37.8
125 | - 37.8
126 | - 37.8
127 | - 37.8
128 | - 37.8
129 | - 37.8
130 | - 37.8
131 | - 37.8
132 | - 38.2
133 | - 38.2
134 | - 38.2
135 | - 38.2
136 | - 38.2
137 | - 38.2
138 | - 38.2
139 | - 38.2
140 | - 38.2
141 | - 38.2
142 | - 38.6
143 | - 38.6
144 | - 38.6
145 | - 38.6
146 | - 38.6
147 | - 38.6
148 | - 38.6
149 | - 38.6
150 | - 38.6
151 | - 38.6
152 | - 39.0
153 | - 39.0
154 | - 39.0
155 | - 39.0
156 | - 39.0
157 | - 39.0
158 | - 39.0
159 | - 39.0
160 | - 39.0
161 | - 39.0
162 | - 39.4
163 | - 39.4
164 | - 39.4
165 | - 39.4
166 | - 39.4
167 | - 39.4
168 | - 39.4
169 | - 39.4
170 | - 39.4
171 | - 39.4
172 | - 39.8
173 | - 39.8
174 | - 39.8
175 | - 39.8
176 | - 39.8
177 | - 39.8
178 | - 39.8
179 | - 39.8
180 | - 39.8
181 | - 39.8
182 | - 40.2
183 | - 40.2
184 | - 40.2
185 | - 40.2
186 | - 40.2
187 | - 40.2
188 | - 40.2
189 | - 40.2
190 | - 40.2
191 | - 40.2
192 | - 40.6
193 | - 40.6
194 | - 40.6
195 | - 40.6
196 | - 40.6
197 | - 40.6
198 | - 40.6
199 | - 40.6
200 | - 40.6
201 | - 40.6
202 | - 20.0
203 | - 20.0
204 | - 20.0
205 | - 20.0
206 | - 20.0
207 | - 20.0
208 | - 20.0
209 | - 20.0
210 | - 20.0
211 | - 20.0
212 | - 20.4
213 | - 20.4
214 | - 20.4
215 | - 20.4
216 | - 20.4
217 | - 20.4
218 | - 20.4
219 | - 20.4
220 | - 20.4
221 | - 20.4
222 | - 20.8
223 | - 20.8
224 | - 20.8
225 | - 20.8
226 | - 20.8
227 | - 20.8
228 | - 20.8
229 | - 20.8
230 | - 20.8
231 | - 20.8
232 | - 21.2
233 | - 21.2
234 | - 21.2
235 | - 21.2
236 | - 21.2
237 | - 21.2
238 | - 21.2
239 | - 21.2
240 | - 21.2
241 | - 21.2
242 | - 21.6
243 | - 21.6
244 | - 21.6
245 | - 21.6
246 | - 21.6
247 | - 21.6
248 | - 21.6
249 | - 21.6
250 | - 21.6
251 | - 21.6
252 | - 22.0
253 | - 22.0
254 | - 22.0
255 | - 22.0
256 | - 22.0
257 | - 22.0
258 | - 22.0
259 | - 22.0
260 | - 22.0
261 | - 22.0
262 | - 22.4
263 | - 22.4
264 | - 22.4
265 | - 22.4
266 | - 22.4
267 | - 22.4
268 | - 22.4
269 | - 22.4
270 | - 22.4
271 | - 22.4
272 | - 22.8
273 | - 22.8
274 | - 22.8
275 | - 22.8
276 | - 22.8
277 | - 22.8
278 | - 22.8
279 | - 22.8
280 | - 22.8
281 | - 22.8
282 | - 23.2
283 | - 23.2
284 | - 23.2
285 | - 23.2
286 | - 23.2
287 | - 23.2
288 | - 23.2
289 | - 23.2
290 | - 23.2
291 | - 23.2
292 | - 23.6
293 | - 23.6
294 | - 23.6
295 | - 23.6
296 | - 23.6
297 | - 23.6
298 | - 23.6
299 | - 23.6
300 | - 23.6
301 | - 23.6
302 | - 20.0
303 | - 20.0
304 | - 20.0
305 | - 20.0
306 | - 20.0
307 | - 20.0
308 | - 20.0
309 | - 20.0
310 | - 20.0
311 | - 20.0
312 | - 20.4
313 | - 20.4
314 | - 20.4
315 | - 20.4
316 | - 20.4
317 | - 20.4
318 | - 20.4
319 | - 20.4
320 | - 20.4
321 | - 20.4
322 | - 20.8
323 | - 20.8
324 | - 20.8
325 | - 20.8
326 | - 20.8
327 | - 20.8
328 | - 20.8
329 | - 20.8
330 | - 20.8
331 | - 20.8
332 | - 21.2
333 | - 21.2
334 | - 21.2
335 | - 21.2
336 | - 21.2
337 | - 21.2
338 | - 21.2
339 | - 21.2
340 | - 21.2
341 | - 21.2
342 | - 21.6
343 | - 21.6
344 | - 21.6
345 | - 21.6
346 | - 21.6
347 | - 21.6
348 | - 21.6
349 | - 21.6
350 | - 21.6
351 | - 21.6
352 | - 22.0
353 | - 22.0
354 | - 22.0
355 | - 22.0
356 | - 22.0
357 | - 22.0
358 | - 22.0
359 | - 22.0
360 | - 22.0
361 | - 22.0
362 | - 22.4
363 | - 22.4
364 | - 22.4
365 | - 22.4
366 | - 22.4
367 | - 22.4
368 | - 22.4
369 | - 22.4
370 | - 22.4
371 | - 22.4
372 | - 22.8
373 | - 22.8
374 | - 22.8
375 | - 22.8
376 | - 22.8
377 | - 22.8
378 | - 22.8
379 | - 22.8
380 | - 22.8
381 | - 22.8
382 | - 23.2
383 | - 23.2
384 | - 23.2
385 | - 23.2
386 | - 23.2
387 | - 23.2
388 | - 23.2
389 | - 23.2
390 | - 23.2
391 | - 23.2
392 | - 23.6
393 | - 23.6
394 | - 23.6
395 | - 23.6
396 | - 23.6
397 | - 23.6
398 | - 23.6
399 | - 23.6
400 | - 23.6
401 | - 23.6
402 | y:
403 | - 1.0
404 | - 1.4
405 | - 1.8
406 | - 2.2
407 | - 2.6
408 | - 3.0
409 | - 3.4000000000000004
410 | - 3.8000000000000003
411 | - 4.2
412 | - 4.6
413 | - 1.0
414 | - 1.4
415 | - 1.8
416 | - 2.2
417 | - 2.6
418 | - 3.0
419 | - 3.4000000000000004
420 | - 3.8000000000000003
421 | - 4.2
422 | - 4.6
423 | - 1.0
424 | - 1.4
425 | - 1.8
426 | - 2.2
427 | - 2.6
428 | - 3.0
429 | - 3.4000000000000004
430 | - 3.8000000000000003
431 | - 4.2
432 | - 4.6
433 | - 1.0
434 | - 1.4
435 | - 1.8
436 | - 2.2
437 | - 2.6
438 | - 3.0
439 | - 3.4000000000000004
440 | - 3.8000000000000003
441 | - 4.2
442 | - 4.6
443 | - 1.0
444 | - 1.4
445 | - 1.8
446 | - 2.2
447 | - 2.6
448 | - 3.0
449 | - 3.4000000000000004
450 | - 3.8000000000000003
451 | - 4.2
452 | - 4.6
453 | - 1.0
454 | - 1.4
455 | - 1.8
456 | - 2.2
457 | - 2.6
458 | - 3.0
459 | - 3.4000000000000004
460 | - 3.8000000000000003
461 | - 4.2
462 | - 4.6
463 | - 1.0
464 | - 1.4
465 | - 1.8
466 | - 2.2
467 | - 2.6
468 | - 3.0
469 | - 3.4000000000000004
470 | - 3.8000000000000003
471 | - 4.2
472 | - 4.6
473 | - 1.0
474 | - 1.4
475 | - 1.8
476 | - 2.2
477 | - 2.6
478 | - 3.0
479 | - 3.4000000000000004
480 | - 3.8000000000000003
481 | - 4.2
482 | - 4.6
483 | - 1.0
484 | - 1.4
485 | - 1.8
486 | - 2.2
487 | - 2.6
488 | - 3.0
489 | - 3.4000000000000004
490 | - 3.8000000000000003
491 | - 4.2
492 | - 4.6
493 | - 1.0
494 | - 1.4
495 | - 1.8
496 | - 2.2
497 | - 2.6
498 | - 3.0
499 | - 3.4000000000000004
500 | - 3.8000000000000003
501 | - 4.2
502 | - 4.6
503 | - -9.0
504 | - -8.6
505 | - -8.2
506 | - -7.8
507 | - -7.4
508 | - -7.0
509 | - -6.6
510 | - -6.199999999999999
511 | - -5.8
512 | - -5.4
513 | - -9.0
514 | - -8.6
515 | - -8.2
516 | - -7.8
517 | - -7.4
518 | - -7.0
519 | - -6.6
520 | - -6.199999999999999
521 | - -5.8
522 | - -5.4
523 | - -9.0
524 | - -8.6
525 | - -8.2
526 | - -7.8
527 | - -7.4
528 | - -7.0
529 | - -6.6
530 | - -6.199999999999999
531 | - -5.8
532 | - -5.4
533 | - -9.0
534 | - -8.6
535 | - -8.2
536 | - -7.8
537 | - -7.4
538 | - -7.0
539 | - -6.6
540 | - -6.199999999999999
541 | - -5.8
542 | - -5.4
543 | - -9.0
544 | - -8.6
545 | - -8.2
546 | - -7.8
547 | - -7.4
548 | - -7.0
549 | - -6.6
550 | - -6.199999999999999
551 | - -5.8
552 | - -5.4
553 | - -9.0
554 | - -8.6
555 | - -8.2
556 | - -7.8
557 | - -7.4
558 | - -7.0
559 | - -6.6
560 | - -6.199999999999999
561 | - -5.8
562 | - -5.4
563 | - -9.0
564 | - -8.6
565 | - -8.2
566 | - -7.8
567 | - -7.4
568 | - -7.0
569 | - -6.6
570 | - -6.199999999999999
571 | - -5.8
572 | - -5.4
573 | - -9.0
574 | - -8.6
575 | - -8.2
576 | - -7.8
577 | - -7.4
578 | - -7.0
579 | - -6.6
580 | - -6.199999999999999
581 | - -5.8
582 | - -5.4
583 | - -9.0
584 | - -8.6
585 | - -8.2
586 | - -7.8
587 | - -7.4
588 | - -7.0
589 | - -6.6
590 | - -6.199999999999999
591 | - -5.8
592 | - -5.4
593 | - -9.0
594 | - -8.6
595 | - -8.2
596 | - -7.8
597 | - -7.4
598 | - -7.0
599 | - -6.6
600 | - -6.199999999999999
601 | - -5.8
602 | - -5.4
603 | - 10.0
604 | - 10.4
605 | - 10.8
606 | - 11.2
607 | - 11.6
608 | - 12.0
609 | - 12.4
610 | - 12.8
611 | - 13.2
612 | - 13.6
613 | - 10.0
614 | - 10.4
615 | - 10.8
616 | - 11.2
617 | - 11.6
618 | - 12.0
619 | - 12.4
620 | - 12.8
621 | - 13.2
622 | - 13.6
623 | - 10.0
624 | - 10.4
625 | - 10.8
626 | - 11.2
627 | - 11.6
628 | - 12.0
629 | - 12.4
630 | - 12.8
631 | - 13.2
632 | - 13.6
633 | - 10.0
634 | - 10.4
635 | - 10.8
636 | - 11.2
637 | - 11.6
638 | - 12.0
639 | - 12.4
640 | - 12.8
641 | - 13.2
642 | - 13.6
643 | - 10.0
644 | - 10.4
645 | - 10.8
646 | - 11.2
647 | - 11.6
648 | - 12.0
649 | - 12.4
650 | - 12.8
651 | - 13.2
652 | - 13.6
653 | - 10.0
654 | - 10.4
655 | - 10.8
656 | - 11.2
657 | - 11.6
658 | - 12.0
659 | - 12.4
660 | - 12.8
661 | - 13.2
662 | - 13.6
663 | - 10.0
664 | - 10.4
665 | - 10.8
666 | - 11.2
667 | - 11.6
668 | - 12.0
669 | - 12.4
670 | - 12.8
671 | - 13.2
672 | - 13.6
673 | - 10.0
674 | - 10.4
675 | - 10.8
676 | - 11.2
677 | - 11.6
678 | - 12.0
679 | - 12.4
680 | - 12.8
681 | - 13.2
682 | - 13.6
683 | - 10.0
684 | - 10.4
685 | - 10.8
686 | - 11.2
687 | - 11.6
688 | - 12.0
689 | - 12.4
690 | - 12.8
691 | - 13.2
692 | - 13.6
693 | - 10.0
694 | - 10.4
695 | - 10.8
696 | - 11.2
697 | - 11.6
698 | - 12.0
699 | - 12.4
700 | - 12.8
701 | - 13.2
702 | - 13.6
703 | - -10.0
704 | - -9.6
705 | - -9.2
706 | - -8.8
707 | - -8.4
708 | - -8.0
709 | - -7.6
710 | - -7.199999999999999
711 | - -6.8
712 | - -6.4
713 | - -10.0
714 | - -9.6
715 | - -9.2
716 | - -8.8
717 | - -8.4
718 | - -8.0
719 | - -7.6
720 | - -7.199999999999999
721 | - -6.8
722 | - -6.4
723 | - -10.0
724 | - -9.6
725 | - -9.2
726 | - -8.8
727 | - -8.4
728 | - -8.0
729 | - -7.6
730 | - -7.199999999999999
731 | - -6.8
732 | - -6.4
733 | - -10.0
734 | - -9.6
735 | - -9.2
736 | - -8.8
737 | - -8.4
738 | - -8.0
739 | - -7.6
740 | - -7.199999999999999
741 | - -6.8
742 | - -6.4
743 | - -10.0
744 | - -9.6
745 | - -9.2
746 | - -8.8
747 | - -8.4
748 | - -8.0
749 | - -7.6
750 | - -7.199999999999999
751 | - -6.8
752 | - -6.4
753 | - -10.0
754 | - -9.6
755 | - -9.2
756 | - -8.8
757 | - -8.4
758 | - -8.0
759 | - -7.6
760 | - -7.199999999999999
761 | - -6.8
762 | - -6.4
763 | - -10.0
764 | - -9.6
765 | - -9.2
766 | - -8.8
767 | - -8.4
768 | - -8.0
769 | - -7.6
770 | - -7.199999999999999
771 | - -6.8
772 | - -6.4
773 | - -10.0
774 | - -9.6
775 | - -9.2
776 | - -8.8
777 | - -8.4
778 | - -8.0
779 | - -7.6
780 | - -7.199999999999999
781 | - -6.8
782 | - -6.4
783 | - -10.0
784 | - -9.6
785 | - -9.2
786 | - -8.8
787 | - -8.4
788 | - -8.0
789 | - -7.6
790 | - -7.199999999999999
791 | - -6.8
792 | - -6.4
793 | - -10.0
794 | - -9.6
795 | - -9.2
796 | - -8.8
797 | - -8.4
798 | - -8.0
799 | - -7.6
800 | - -7.199999999999999
801 | - -6.8
802 | - -6.4
803 |
--------------------------------------------------------------------------------
/config/grid_coords_valid.yaml:
--------------------------------------------------------------------------------
1 | x:
2 | - 24.34782608695652
3 | - 26.08695652173913
4 | - 27.82608695652174
5 | - 29.565217391304348
6 | - 31.304347826086957
7 | - 33.04347826086956
8 | - 34.78260869565217
9 | - 36.52173913043478
10 | - 38.26086956521739
11 | - 40.0
12 | - 19.130434782608695
13 | - 20.869565217391305
14 | - 22.608695652173914
15 | - 24.34782608695652
16 | - 26.08695652173913
17 | - 27.82608695652174
18 | - 29.565217391304348
19 | - 31.304347826086957
20 | - 33.04347826086956
21 | - 34.78260869565217
22 | - 36.52173913043478
23 | - 38.26086956521739
24 | - 40.0
25 | - 13.91304347826087
26 | - 15.652173913043478
27 | - 17.391304347826086
28 | - 19.130434782608695
29 | - 20.869565217391305
30 | - 22.608695652173914
31 | - 24.34782608695652
32 | - 26.08695652173913
33 | - 27.82608695652174
34 | - 29.565217391304348
35 | - 31.304347826086957
36 | - 33.04347826086956
37 | - 34.78260869565217
38 | - 36.52173913043478
39 | - 38.26086956521739
40 | - 40.0
41 | - 12.17391304347826
42 | - 13.91304347826087
43 | - 15.652173913043478
44 | - 17.391304347826086
45 | - 19.130434782608695
46 | - 20.869565217391305
47 | - 22.608695652173914
48 | - 24.34782608695652
49 | - 26.08695652173913
50 | - 27.82608695652174
51 | - 29.565217391304348
52 | - 31.304347826086957
53 | - 33.04347826086956
54 | - 34.78260869565217
55 | - 36.52173913043478
56 | - 38.26086956521739
57 | - 40.0
58 | - 8.695652173913043
59 | - 10.434782608695652
60 | - 12.17391304347826
61 | - 13.91304347826087
62 | - 15.652173913043478
63 | - 17.391304347826086
64 | - 19.130434782608695
65 | - 20.869565217391305
66 | - 22.608695652173914
67 | - 24.34782608695652
68 | - 26.08695652173913
69 | - 27.82608695652174
70 | - 29.565217391304348
71 | - 31.304347826086957
72 | - 33.04347826086956
73 | - 34.78260869565217
74 | - 36.52173913043478
75 | - 38.26086956521739
76 | - 40.0
77 | - 6.956521739130435
78 | - 8.695652173913043
79 | - 10.434782608695652
80 | - 12.17391304347826
81 | - 13.91304347826087
82 | - 15.652173913043478
83 | - 17.391304347826086
84 | - 19.130434782608695
85 | - 20.869565217391305
86 | - 22.608695652173914
87 | - 24.34782608695652
88 | - 26.08695652173913
89 | - 27.82608695652174
90 | - 29.565217391304348
91 | - 31.304347826086957
92 | - 33.04347826086956
93 | - 34.78260869565217
94 | - 36.52173913043478
95 | - 38.26086956521739
96 | - 40.0
97 | - 5.217391304347826
98 | - 6.956521739130435
99 | - 8.695652173913043
100 | - 10.434782608695652
101 | - 12.17391304347826
102 | - 13.91304347826087
103 | - 15.652173913043478
104 | - 17.391304347826086
105 | - 19.130434782608695
106 | - 20.869565217391305
107 | - 22.608695652173914
108 | - 24.34782608695652
109 | - 26.08695652173913
110 | - 27.82608695652174
111 | - 29.565217391304348
112 | - 31.304347826086957
113 | - 33.04347826086956
114 | - 34.78260869565217
115 | - 36.52173913043478
116 | - 38.26086956521739
117 | - 40.0
118 | - 5.217391304347826
119 | - 6.956521739130435
120 | - 8.695652173913043
121 | - 10.434782608695652
122 | - 12.17391304347826
123 | - 13.91304347826087
124 | - 15.652173913043478
125 | - 17.391304347826086
126 | - 19.130434782608695
127 | - 20.869565217391305
128 | - 22.608695652173914
129 | - 24.34782608695652
130 | - 26.08695652173913
131 | - 27.82608695652174
132 | - 29.565217391304348
133 | - 31.304347826086957
134 | - 33.04347826086956
135 | - 34.78260869565217
136 | - 36.52173913043478
137 | - 38.26086956521739
138 | - 40.0
139 | - 3.4782608695652173
140 | - 5.217391304347826
141 | - 6.956521739130435
142 | - 8.695652173913043
143 | - 10.434782608695652
144 | - 12.17391304347826
145 | - 13.91304347826087
146 | - 15.652173913043478
147 | - 17.391304347826086
148 | - 19.130434782608695
149 | - 20.869565217391305
150 | - 22.608695652173914
151 | - 24.34782608695652
152 | - 26.08695652173913
153 | - 27.82608695652174
154 | - 29.565217391304348
155 | - 31.304347826086957
156 | - 33.04347826086956
157 | - 34.78260869565217
158 | - 36.52173913043478
159 | - 38.26086956521739
160 | - 40.0
161 | - 3.4782608695652173
162 | - 5.217391304347826
163 | - 6.956521739130435
164 | - 8.695652173913043
165 | - 10.434782608695652
166 | - 12.17391304347826
167 | - 13.91304347826087
168 | - 15.652173913043478
169 | - 17.391304347826086
170 | - 19.130434782608695
171 | - 20.869565217391305
172 | - 22.608695652173914
173 | - 24.34782608695652
174 | - 26.08695652173913
175 | - 27.82608695652174
176 | - 29.565217391304348
177 | - 31.304347826086957
178 | - 33.04347826086956
179 | - 34.78260869565217
180 | - 36.52173913043478
181 | - 38.26086956521739
182 | - 40.0
183 | - 1.7391304347826086
184 | - 3.4782608695652173
185 | - 5.217391304347826
186 | - 6.956521739130435
187 | - 8.695652173913043
188 | - 10.434782608695652
189 | - 12.17391304347826
190 | - 13.91304347826087
191 | - 15.652173913043478
192 | - 17.391304347826086
193 | - 19.130434782608695
194 | - 20.869565217391305
195 | - 22.608695652173914
196 | - 24.34782608695652
197 | - 26.08695652173913
198 | - 27.82608695652174
199 | - 29.565217391304348
200 | - 31.304347826086957
201 | - 33.04347826086956
202 | - 34.78260869565217
203 | - 36.52173913043478
204 | - 38.26086956521739
205 | - 40.0
206 | - 1.7391304347826086
207 | - 3.4782608695652173
208 | - 5.217391304347826
209 | - 6.956521739130435
210 | - 8.695652173913043
211 | - 10.434782608695652
212 | - 12.17391304347826
213 | - 13.91304347826087
214 | - 15.652173913043478
215 | - 17.391304347826086
216 | - 19.130434782608695
217 | - 20.869565217391305
218 | - 22.608695652173914
219 | - 24.34782608695652
220 | - 26.08695652173913
221 | - 27.82608695652174
222 | - 29.565217391304348
223 | - 31.304347826086957
224 | - 33.04347826086956
225 | - 34.78260869565217
226 | - 36.52173913043478
227 | - 38.26086956521739
228 | - 40.0
229 | - 1.7391304347826086
230 | - 3.4782608695652173
231 | - 5.217391304347826
232 | - 6.956521739130435
233 | - 8.695652173913043
234 | - 10.434782608695652
235 | - 12.17391304347826
236 | - 13.91304347826087
237 | - 15.652173913043478
238 | - 17.391304347826086
239 | - 19.130434782608695
240 | - 20.869565217391305
241 | - 22.608695652173914
242 | - 24.34782608695652
243 | - 26.08695652173913
244 | - 27.82608695652174
245 | - 29.565217391304348
246 | - 31.304347826086957
247 | - 33.04347826086956
248 | - 34.78260869565217
249 | - 36.52173913043478
250 | - 38.26086956521739
251 | - 40.0
252 | - 1.7391304347826086
253 | - 3.4782608695652173
254 | - 5.217391304347826
255 | - 6.956521739130435
256 | - 8.695652173913043
257 | - 10.434782608695652
258 | - 12.17391304347826
259 | - 13.91304347826087
260 | - 15.652173913043478
261 | - 17.391304347826086
262 | - 19.130434782608695
263 | - 20.869565217391305
264 | - 22.608695652173914
265 | - 24.34782608695652
266 | - 26.08695652173913
267 | - 27.82608695652174
268 | - 29.565217391304348
269 | - 31.304347826086957
270 | - 33.04347826086956
271 | - 34.78260869565217
272 | - 36.52173913043478
273 | - 38.26086956521739
274 | - 40.0
275 | - 1.7391304347826086
276 | - 3.4782608695652173
277 | - 5.217391304347826
278 | - 6.956521739130435
279 | - 8.695652173913043
280 | - 10.434782608695652
281 | - 12.17391304347826
282 | - 13.91304347826087
283 | - 15.652173913043478
284 | - 17.391304347826086
285 | - 19.130434782608695
286 | - 20.869565217391305
287 | - 22.608695652173914
288 | - 24.34782608695652
289 | - 26.08695652173913
290 | - 27.82608695652174
291 | - 29.565217391304348
292 | - 31.304347826086957
293 | - 33.04347826086956
294 | - 34.78260869565217
295 | - 36.52173913043478
296 | - 38.26086956521739
297 | - 40.0
298 | - 1.7391304347826086
299 | - 3.4782608695652173
300 | - 5.217391304347826
301 | - 6.956521739130435
302 | - 8.695652173913043
303 | - 10.434782608695652
304 | - 12.17391304347826
305 | - 13.91304347826087
306 | - 15.652173913043478
307 | - 17.391304347826086
308 | - 19.130434782608695
309 | - 20.869565217391305
310 | - 22.608695652173914
311 | - 24.34782608695652
312 | - 26.08695652173913
313 | - 27.82608695652174
314 | - 29.565217391304348
315 | - 31.304347826086957
316 | - 33.04347826086956
317 | - 34.78260869565217
318 | - 36.52173913043478
319 | - 38.26086956521739
320 | - 40.0
321 | - 1.7391304347826086
322 | - 3.4782608695652173
323 | - 5.217391304347826
324 | - 6.956521739130435
325 | - 8.695652173913043
326 | - 10.434782608695652
327 | - 12.17391304347826
328 | - 13.91304347826087
329 | - 15.652173913043478
330 | - 17.391304347826086
331 | - 19.130434782608695
332 | - 20.869565217391305
333 | - 22.608695652173914
334 | - 24.34782608695652
335 | - 26.08695652173913
336 | - 27.82608695652174
337 | - 29.565217391304348
338 | - 31.304347826086957
339 | - 33.04347826086956
340 | - 34.78260869565217
341 | - 36.52173913043478
342 | - 38.26086956521739
343 | - 40.0
344 | - 1.7391304347826086
345 | - 3.4782608695652173
346 | - 5.217391304347826
347 | - 6.956521739130435
348 | - 8.695652173913043
349 | - 10.434782608695652
350 | - 12.17391304347826
351 | - 13.91304347826087
352 | - 15.652173913043478
353 | - 17.391304347826086
354 | - 19.130434782608695
355 | - 20.869565217391305
356 | - 22.608695652173914
357 | - 24.34782608695652
358 | - 26.08695652173913
359 | - 27.82608695652174
360 | - 29.565217391304348
361 | - 31.304347826086957
362 | - 33.04347826086956
363 | - 34.78260869565217
364 | - 36.52173913043478
365 | - 38.26086956521739
366 | - 40.0
367 | - 1.7391304347826086
368 | - 3.4782608695652173
369 | - 5.217391304347826
370 | - 6.956521739130435
371 | - 8.695652173913043
372 | - 10.434782608695652
373 | - 12.17391304347826
374 | - 13.91304347826087
375 | - 15.652173913043478
376 | - 17.391304347826086
377 | - 19.130434782608695
378 | - 20.869565217391305
379 | - 22.608695652173914
380 | - 24.34782608695652
381 | - 26.08695652173913
382 | - 27.82608695652174
383 | - 29.565217391304348
384 | - 31.304347826086957
385 | - 33.04347826086956
386 | - 34.78260869565217
387 | - 36.52173913043478
388 | - 38.26086956521739
389 | - 40.0
390 | - 1.7391304347826086
391 | - 3.4782608695652173
392 | - 5.217391304347826
393 | - 6.956521739130435
394 | - 8.695652173913043
395 | - 10.434782608695652
396 | - 12.17391304347826
397 | - 13.91304347826087
398 | - 15.652173913043478
399 | - 17.391304347826086
400 | - 19.130434782608695
401 | - 20.869565217391305
402 | - 22.608695652173914
403 | - 24.34782608695652
404 | - 26.08695652173913
405 | - 27.82608695652174
406 | - 29.565217391304348
407 | - 31.304347826086957
408 | - 33.04347826086956
409 | - 34.78260869565217
410 | - 36.52173913043478
411 | - 38.26086956521739
412 | - 40.0
413 | - 3.4782608695652173
414 | - 5.217391304347826
415 | - 6.956521739130435
416 | - 8.695652173913043
417 | - 10.434782608695652
418 | - 12.17391304347826
419 | - 13.91304347826087
420 | - 15.652173913043478
421 | - 17.391304347826086
422 | - 19.130434782608695
423 | - 20.869565217391305
424 | - 22.608695652173914
425 | - 24.34782608695652
426 | - 26.08695652173913
427 | - 27.82608695652174
428 | - 29.565217391304348
429 | - 31.304347826086957
430 | - 33.04347826086956
431 | - 34.78260869565217
432 | - 36.52173913043478
433 | - 38.26086956521739
434 | - 40.0
435 | - 3.4782608695652173
436 | - 5.217391304347826
437 | - 6.956521739130435
438 | - 8.695652173913043
439 | - 10.434782608695652
440 | - 12.17391304347826
441 | - 13.91304347826087
442 | - 15.652173913043478
443 | - 17.391304347826086
444 | - 19.130434782608695
445 | - 20.869565217391305
446 | - 22.608695652173914
447 | - 24.34782608695652
448 | - 26.08695652173913
449 | - 27.82608695652174
450 | - 29.565217391304348
451 | - 31.304347826086957
452 | - 33.04347826086956
453 | - 34.78260869565217
454 | - 36.52173913043478
455 | - 38.26086956521739
456 | - 40.0
457 | - 5.217391304347826
458 | - 6.956521739130435
459 | - 8.695652173913043
460 | - 10.434782608695652
461 | - 12.17391304347826
462 | - 13.91304347826087
463 | - 15.652173913043478
464 | - 17.391304347826086
465 | - 19.130434782608695
466 | - 20.869565217391305
467 | - 22.608695652173914
468 | - 24.34782608695652
469 | - 26.08695652173913
470 | - 27.82608695652174
471 | - 29.565217391304348
472 | - 31.304347826086957
473 | - 33.04347826086956
474 | - 34.78260869565217
475 | - 36.52173913043478
476 | - 38.26086956521739
477 | - 40.0
478 | - 5.217391304347826
479 | - 6.956521739130435
480 | - 8.695652173913043
481 | - 10.434782608695652
482 | - 12.17391304347826
483 | - 13.91304347826087
484 | - 15.652173913043478
485 | - 17.391304347826086
486 | - 19.130434782608695
487 | - 20.869565217391305
488 | - 22.608695652173914
489 | - 24.34782608695652
490 | - 26.08695652173913
491 | - 27.82608695652174
492 | - 29.565217391304348
493 | - 31.304347826086957
494 | - 33.04347826086956
495 | - 34.78260869565217
496 | - 36.52173913043478
497 | - 38.26086956521739
498 | - 40.0
499 | - 6.956521739130435
500 | - 8.695652173913043
501 | - 10.434782608695652
502 | - 12.17391304347826
503 | - 13.91304347826087
504 | - 15.652173913043478
505 | - 17.391304347826086
506 | - 19.130434782608695
507 | - 20.869565217391305
508 | - 22.608695652173914
509 | - 24.34782608695652
510 | - 26.08695652173913
511 | - 27.82608695652174
512 | - 29.565217391304348
513 | - 31.304347826086957
514 | - 33.04347826086956
515 | - 34.78260869565217
516 | - 36.52173913043478
517 | - 38.26086956521739
518 | - 40.0
519 | - 8.695652173913043
520 | - 10.434782608695652
521 | - 12.17391304347826
522 | - 13.91304347826087
523 | - 15.652173913043478
524 | - 17.391304347826086
525 | - 19.130434782608695
526 | - 20.869565217391305
527 | - 22.608695652173914
528 | - 24.34782608695652
529 | - 26.08695652173913
530 | - 27.82608695652174
531 | - 29.565217391304348
532 | - 31.304347826086957
533 | - 33.04347826086956
534 | - 34.78260869565217
535 | - 36.52173913043478
536 | - 38.26086956521739
537 | - 40.0
538 | - 12.17391304347826
539 | - 13.91304347826087
540 | - 15.652173913043478
541 | - 17.391304347826086
542 | - 19.130434782608695
543 | - 20.869565217391305
544 | - 22.608695652173914
545 | - 24.34782608695652
546 | - 26.08695652173913
547 | - 27.82608695652174
548 | - 29.565217391304348
549 | - 31.304347826086957
550 | - 33.04347826086956
551 | - 34.78260869565217
552 | - 36.52173913043478
553 | - 38.26086956521739
554 | - 40.0
555 | - 13.91304347826087
556 | - 15.652173913043478
557 | - 17.391304347826086
558 | - 19.130434782608695
559 | - 20.869565217391305
560 | - 22.608695652173914
561 | - 24.34782608695652
562 | - 26.08695652173913
563 | - 27.82608695652174
564 | - 29.565217391304348
565 | - 31.304347826086957
566 | - 33.04347826086956
567 | - 34.78260869565217
568 | - 36.52173913043478
569 | - 38.26086956521739
570 | - 40.0
571 | - 19.130434782608695
572 | - 20.869565217391305
573 | - 22.608695652173914
574 | - 24.34782608695652
575 | - 26.08695652173913
576 | - 27.82608695652174
577 | - 29.565217391304348
578 | - 31.304347826086957
579 | - 33.04347826086956
580 | - 34.78260869565217
581 | - 36.52173913043478
582 | - 38.26086956521739
583 | - 40.0
584 | - 24.34782608695652
585 | - 26.08695652173913
586 | - 27.82608695652174
587 | - 29.565217391304348
588 | - 31.304347826086957
589 | - 33.04347826086956
590 | - 34.78260869565217
591 | - 36.52173913043478
592 | - 38.26086956521739
593 | - 40.0
594 | y:
595 | - -19.902161680671945
596 | - -19.902161680671945
597 | - -19.902161680671945
598 | - -19.902161680671945
599 | - -19.902161680671945
600 | - -19.902161680671945
601 | - -19.902161680671945
602 | - -19.902161680671945
603 | - -19.902161680671945
604 | - -19.902161680671945
605 | - -18.529598806142843
606 | - -18.529598806142843
607 | - -18.529598806142843
608 | - -18.529598806142843
609 | - -18.529598806142843
610 | - -18.529598806142843
611 | - -18.529598806142843
612 | - -18.529598806142843
613 | - -18.529598806142843
614 | - -18.529598806142843
615 | - -18.529598806142843
616 | - -18.529598806142843
617 | - -18.529598806142843
618 | - -17.157035931613745
619 | - -17.157035931613745
620 | - -17.157035931613745
621 | - -17.157035931613745
622 | - -17.157035931613745
623 | - -17.157035931613745
624 | - -17.157035931613745
625 | - -17.157035931613745
626 | - -17.157035931613745
627 | - -17.157035931613745
628 | - -17.157035931613745
629 | - -17.157035931613745
630 | - -17.157035931613745
631 | - -17.157035931613745
632 | - -17.157035931613745
633 | - -17.157035931613745
634 | - -15.784473057084645
635 | - -15.784473057084645
636 | - -15.784473057084645
637 | - -15.784473057084645
638 | - -15.784473057084645
639 | - -15.784473057084645
640 | - -15.784473057084645
641 | - -15.784473057084645
642 | - -15.784473057084645
643 | - -15.784473057084645
644 | - -15.784473057084645
645 | - -15.784473057084645
646 | - -15.784473057084645
647 | - -15.784473057084645
648 | - -15.784473057084645
649 | - -15.784473057084645
650 | - -15.784473057084645
651 | - -14.411910182555545
652 | - -14.411910182555545
653 | - -14.411910182555545
654 | - -14.411910182555545
655 | - -14.411910182555545
656 | - -14.411910182555545
657 | - -14.411910182555545
658 | - -14.411910182555545
659 | - -14.411910182555545
660 | - -14.411910182555545
661 | - -14.411910182555545
662 | - -14.411910182555545
663 | - -14.411910182555545
664 | - -14.411910182555545
665 | - -14.411910182555545
666 | - -14.411910182555545
667 | - -14.411910182555545
668 | - -14.411910182555545
669 | - -14.411910182555545
670 | - -13.039347308026446
671 | - -13.039347308026446
672 | - -13.039347308026446
673 | - -13.039347308026446
674 | - -13.039347308026446
675 | - -13.039347308026446
676 | - -13.039347308026446
677 | - -13.039347308026446
678 | - -13.039347308026446
679 | - -13.039347308026446
680 | - -13.039347308026446
681 | - -13.039347308026446
682 | - -13.039347308026446
683 | - -13.039347308026446
684 | - -13.039347308026446
685 | - -13.039347308026446
686 | - -13.039347308026446
687 | - -13.039347308026446
688 | - -13.039347308026446
689 | - -13.039347308026446
690 | - -11.666784433497346
691 | - -11.666784433497346
692 | - -11.666784433497346
693 | - -11.666784433497346
694 | - -11.666784433497346
695 | - -11.666784433497346
696 | - -11.666784433497346
697 | - -11.666784433497346
698 | - -11.666784433497346
699 | - -11.666784433497346
700 | - -11.666784433497346
701 | - -11.666784433497346
702 | - -11.666784433497346
703 | - -11.666784433497346
704 | - -11.666784433497346
705 | - -11.666784433497346
706 | - -11.666784433497346
707 | - -11.666784433497346
708 | - -11.666784433497346
709 | - -11.666784433497346
710 | - -11.666784433497346
711 | - -10.294221558968246
712 | - -10.294221558968246
713 | - -10.294221558968246
714 | - -10.294221558968246
715 | - -10.294221558968246
716 | - -10.294221558968246
717 | - -10.294221558968246
718 | - -10.294221558968246
719 | - -10.294221558968246
720 | - -10.294221558968246
721 | - -10.294221558968246
722 | - -10.294221558968246
723 | - -10.294221558968246
724 | - -10.294221558968246
725 | - -10.294221558968246
726 | - -10.294221558968246
727 | - -10.294221558968246
728 | - -10.294221558968246
729 | - -10.294221558968246
730 | - -10.294221558968246
731 | - -10.294221558968246
732 | - -8.921658684439146
733 | - -8.921658684439146
734 | - -8.921658684439146
735 | - -8.921658684439146
736 | - -8.921658684439146
737 | - -8.921658684439146
738 | - -8.921658684439146
739 | - -8.921658684439146
740 | - -8.921658684439146
741 | - -8.921658684439146
742 | - -8.921658684439146
743 | - -8.921658684439146
744 | - -8.921658684439146
745 | - -8.921658684439146
746 | - -8.921658684439146
747 | - -8.921658684439146
748 | - -8.921658684439146
749 | - -8.921658684439146
750 | - -8.921658684439146
751 | - -8.921658684439146
752 | - -8.921658684439146
753 | - -8.921658684439146
754 | - -7.549095809910046
755 | - -7.549095809910046
756 | - -7.549095809910046
757 | - -7.549095809910046
758 | - -7.549095809910046
759 | - -7.549095809910046
760 | - -7.549095809910046
761 | - -7.549095809910046
762 | - -7.549095809910046
763 | - -7.549095809910046
764 | - -7.549095809910046
765 | - -7.549095809910046
766 | - -7.549095809910046
767 | - -7.549095809910046
768 | - -7.549095809910046
769 | - -7.549095809910046
770 | - -7.549095809910046
771 | - -7.549095809910046
772 | - -7.549095809910046
773 | - -7.549095809910046
774 | - -7.549095809910046
775 | - -7.549095809910046
776 | - -6.176532935380948
777 | - -6.176532935380948
778 | - -6.176532935380948
779 | - -6.176532935380948
780 | - -6.176532935380948
781 | - -6.176532935380948
782 | - -6.176532935380948
783 | - -6.176532935380948
784 | - -6.176532935380948
785 | - -6.176532935380948
786 | - -6.176532935380948
787 | - -6.176532935380948
788 | - -6.176532935380948
789 | - -6.176532935380948
790 | - -6.176532935380948
791 | - -6.176532935380948
792 | - -6.176532935380948
793 | - -6.176532935380948
794 | - -6.176532935380948
795 | - -6.176532935380948
796 | - -6.176532935380948
797 | - -6.176532935380948
798 | - -6.176532935380948
799 | - -4.803970060851849
800 | - -4.803970060851849
801 | - -4.803970060851849
802 | - -4.803970060851849
803 | - -4.803970060851849
804 | - -4.803970060851849
805 | - -4.803970060851849
806 | - -4.803970060851849
807 | - -4.803970060851849
808 | - -4.803970060851849
809 | - -4.803970060851849
810 | - -4.803970060851849
811 | - -4.803970060851849
812 | - -4.803970060851849
813 | - -4.803970060851849
814 | - -4.803970060851849
815 | - -4.803970060851849
816 | - -4.803970060851849
817 | - -4.803970060851849
818 | - -4.803970060851849
819 | - -4.803970060851849
820 | - -4.803970060851849
821 | - -4.803970060851849
822 | - -3.4314071863227475
823 | - -3.4314071863227475
824 | - -3.4314071863227475
825 | - -3.4314071863227475
826 | - -3.4314071863227475
827 | - -3.4314071863227475
828 | - -3.4314071863227475
829 | - -3.4314071863227475
830 | - -3.4314071863227475
831 | - -3.4314071863227475
832 | - -3.4314071863227475
833 | - -3.4314071863227475
834 | - -3.4314071863227475
835 | - -3.4314071863227475
836 | - -3.4314071863227475
837 | - -3.4314071863227475
838 | - -3.4314071863227475
839 | - -3.4314071863227475
840 | - -3.4314071863227475
841 | - -3.4314071863227475
842 | - -3.4314071863227475
843 | - -3.4314071863227475
844 | - -3.4314071863227475
845 | - -2.0588443117936492
846 | - -2.0588443117936492
847 | - -2.0588443117936492
848 | - -2.0588443117936492
849 | - -2.0588443117936492
850 | - -2.0588443117936492
851 | - -2.0588443117936492
852 | - -2.0588443117936492
853 | - -2.0588443117936492
854 | - -2.0588443117936492
855 | - -2.0588443117936492
856 | - -2.0588443117936492
857 | - -2.0588443117936492
858 | - -2.0588443117936492
859 | - -2.0588443117936492
860 | - -2.0588443117936492
861 | - -2.0588443117936492
862 | - -2.0588443117936492
863 | - -2.0588443117936492
864 | - -2.0588443117936492
865 | - -2.0588443117936492
866 | - -2.0588443117936492
867 | - -2.0588443117936492
868 | - -0.6862814372645474
869 | - -0.6862814372645474
870 | - -0.6862814372645474
871 | - -0.6862814372645474
872 | - -0.6862814372645474
873 | - -0.6862814372645474
874 | - -0.6862814372645474
875 | - -0.6862814372645474
876 | - -0.6862814372645474
877 | - -0.6862814372645474
878 | - -0.6862814372645474
879 | - -0.6862814372645474
880 | - -0.6862814372645474
881 | - -0.6862814372645474
882 | - -0.6862814372645474
883 | - -0.6862814372645474
884 | - -0.6862814372645474
885 | - -0.6862814372645474
886 | - -0.6862814372645474
887 | - -0.6862814372645474
888 | - -0.6862814372645474
889 | - -0.6862814372645474
890 | - -0.6862814372645474
891 | - 0.6862814372645509
892 | - 0.6862814372645509
893 | - 0.6862814372645509
894 | - 0.6862814372645509
895 | - 0.6862814372645509
896 | - 0.6862814372645509
897 | - 0.6862814372645509
898 | - 0.6862814372645509
899 | - 0.6862814372645509
900 | - 0.6862814372645509
901 | - 0.6862814372645509
902 | - 0.6862814372645509
903 | - 0.6862814372645509
904 | - 0.6862814372645509
905 | - 0.6862814372645509
906 | - 0.6862814372645509
907 | - 0.6862814372645509
908 | - 0.6862814372645509
909 | - 0.6862814372645509
910 | - 0.6862814372645509
911 | - 0.6862814372645509
912 | - 0.6862814372645509
913 | - 0.6862814372645509
914 | - 2.0588443117936492
915 | - 2.0588443117936492
916 | - 2.0588443117936492
917 | - 2.0588443117936492
918 | - 2.0588443117936492
919 | - 2.0588443117936492
920 | - 2.0588443117936492
921 | - 2.0588443117936492
922 | - 2.0588443117936492
923 | - 2.0588443117936492
924 | - 2.0588443117936492
925 | - 2.0588443117936492
926 | - 2.0588443117936492
927 | - 2.0588443117936492
928 | - 2.0588443117936492
929 | - 2.0588443117936492
930 | - 2.0588443117936492
931 | - 2.0588443117936492
932 | - 2.0588443117936492
933 | - 2.0588443117936492
934 | - 2.0588443117936492
935 | - 2.0588443117936492
936 | - 2.0588443117936492
937 | - 3.431407186322751
938 | - 3.431407186322751
939 | - 3.431407186322751
940 | - 3.431407186322751
941 | - 3.431407186322751
942 | - 3.431407186322751
943 | - 3.431407186322751
944 | - 3.431407186322751
945 | - 3.431407186322751
946 | - 3.431407186322751
947 | - 3.431407186322751
948 | - 3.431407186322751
949 | - 3.431407186322751
950 | - 3.431407186322751
951 | - 3.431407186322751
952 | - 3.431407186322751
953 | - 3.431407186322751
954 | - 3.431407186322751
955 | - 3.431407186322751
956 | - 3.431407186322751
957 | - 3.431407186322751
958 | - 3.431407186322751
959 | - 3.431407186322751
960 | - 4.803970060851849
961 | - 4.803970060851849
962 | - 4.803970060851849
963 | - 4.803970060851849
964 | - 4.803970060851849
965 | - 4.803970060851849
966 | - 4.803970060851849
967 | - 4.803970060851849
968 | - 4.803970060851849
969 | - 4.803970060851849
970 | - 4.803970060851849
971 | - 4.803970060851849
972 | - 4.803970060851849
973 | - 4.803970060851849
974 | - 4.803970060851849
975 | - 4.803970060851849
976 | - 4.803970060851849
977 | - 4.803970060851849
978 | - 4.803970060851849
979 | - 4.803970060851849
980 | - 4.803970060851849
981 | - 4.803970060851849
982 | - 4.803970060851849
983 | - 6.176532935380951
984 | - 6.176532935380951
985 | - 6.176532935380951
986 | - 6.176532935380951
987 | - 6.176532935380951
988 | - 6.176532935380951
989 | - 6.176532935380951
990 | - 6.176532935380951
991 | - 6.176532935380951
992 | - 6.176532935380951
993 | - 6.176532935380951
994 | - 6.176532935380951
995 | - 6.176532935380951
996 | - 6.176532935380951
997 | - 6.176532935380951
998 | - 6.176532935380951
999 | - 6.176532935380951
1000 | - 6.176532935380951
1001 | - 6.176532935380951
1002 | - 6.176532935380951
1003 | - 6.176532935380951
1004 | - 6.176532935380951
1005 | - 6.176532935380951
1006 | - 7.54909580991005
1007 | - 7.54909580991005
1008 | - 7.54909580991005
1009 | - 7.54909580991005
1010 | - 7.54909580991005
1011 | - 7.54909580991005
1012 | - 7.54909580991005
1013 | - 7.54909580991005
1014 | - 7.54909580991005
1015 | - 7.54909580991005
1016 | - 7.54909580991005
1017 | - 7.54909580991005
1018 | - 7.54909580991005
1019 | - 7.54909580991005
1020 | - 7.54909580991005
1021 | - 7.54909580991005
1022 | - 7.54909580991005
1023 | - 7.54909580991005
1024 | - 7.54909580991005
1025 | - 7.54909580991005
1026 | - 7.54909580991005
1027 | - 7.54909580991005
1028 | - 8.921658684439148
1029 | - 8.921658684439148
1030 | - 8.921658684439148
1031 | - 8.921658684439148
1032 | - 8.921658684439148
1033 | - 8.921658684439148
1034 | - 8.921658684439148
1035 | - 8.921658684439148
1036 | - 8.921658684439148
1037 | - 8.921658684439148
1038 | - 8.921658684439148
1039 | - 8.921658684439148
1040 | - 8.921658684439148
1041 | - 8.921658684439148
1042 | - 8.921658684439148
1043 | - 8.921658684439148
1044 | - 8.921658684439148
1045 | - 8.921658684439148
1046 | - 8.921658684439148
1047 | - 8.921658684439148
1048 | - 8.921658684439148
1049 | - 8.921658684439148
1050 | - 10.29422155896825
1051 | - 10.29422155896825
1052 | - 10.29422155896825
1053 | - 10.29422155896825
1054 | - 10.29422155896825
1055 | - 10.29422155896825
1056 | - 10.29422155896825
1057 | - 10.29422155896825
1058 | - 10.29422155896825
1059 | - 10.29422155896825
1060 | - 10.29422155896825
1061 | - 10.29422155896825
1062 | - 10.29422155896825
1063 | - 10.29422155896825
1064 | - 10.29422155896825
1065 | - 10.29422155896825
1066 | - 10.29422155896825
1067 | - 10.29422155896825
1068 | - 10.29422155896825
1069 | - 10.29422155896825
1070 | - 10.29422155896825
1071 | - 11.666784433497345
1072 | - 11.666784433497345
1073 | - 11.666784433497345
1074 | - 11.666784433497345
1075 | - 11.666784433497345
1076 | - 11.666784433497345
1077 | - 11.666784433497345
1078 | - 11.666784433497345
1079 | - 11.666784433497345
1080 | - 11.666784433497345
1081 | - 11.666784433497345
1082 | - 11.666784433497345
1083 | - 11.666784433497345
1084 | - 11.666784433497345
1085 | - 11.666784433497345
1086 | - 11.666784433497345
1087 | - 11.666784433497345
1088 | - 11.666784433497345
1089 | - 11.666784433497345
1090 | - 11.666784433497345
1091 | - 11.666784433497345
1092 | - 13.039347308026446
1093 | - 13.039347308026446
1094 | - 13.039347308026446
1095 | - 13.039347308026446
1096 | - 13.039347308026446
1097 | - 13.039347308026446
1098 | - 13.039347308026446
1099 | - 13.039347308026446
1100 | - 13.039347308026446
1101 | - 13.039347308026446
1102 | - 13.039347308026446
1103 | - 13.039347308026446
1104 | - 13.039347308026446
1105 | - 13.039347308026446
1106 | - 13.039347308026446
1107 | - 13.039347308026446
1108 | - 13.039347308026446
1109 | - 13.039347308026446
1110 | - 13.039347308026446
1111 | - 13.039347308026446
1112 | - 14.411910182555548
1113 | - 14.411910182555548
1114 | - 14.411910182555548
1115 | - 14.411910182555548
1116 | - 14.411910182555548
1117 | - 14.411910182555548
1118 | - 14.411910182555548
1119 | - 14.411910182555548
1120 | - 14.411910182555548
1121 | - 14.411910182555548
1122 | - 14.411910182555548
1123 | - 14.411910182555548
1124 | - 14.411910182555548
1125 | - 14.411910182555548
1126 | - 14.411910182555548
1127 | - 14.411910182555548
1128 | - 14.411910182555548
1129 | - 14.411910182555548
1130 | - 14.411910182555548
1131 | - 15.78447305708465
1132 | - 15.78447305708465
1133 | - 15.78447305708465
1134 | - 15.78447305708465
1135 | - 15.78447305708465
1136 | - 15.78447305708465
1137 | - 15.78447305708465
1138 | - 15.78447305708465
1139 | - 15.78447305708465
1140 | - 15.78447305708465
1141 | - 15.78447305708465
1142 | - 15.78447305708465
1143 | - 15.78447305708465
1144 | - 15.78447305708465
1145 | - 15.78447305708465
1146 | - 15.78447305708465
1147 | - 15.78447305708465
1148 | - 17.157035931613745
1149 | - 17.157035931613745
1150 | - 17.157035931613745
1151 | - 17.157035931613745
1152 | - 17.157035931613745
1153 | - 17.157035931613745
1154 | - 17.157035931613745
1155 | - 17.157035931613745
1156 | - 17.157035931613745
1157 | - 17.157035931613745
1158 | - 17.157035931613745
1159 | - 17.157035931613745
1160 | - 17.157035931613745
1161 | - 17.157035931613745
1162 | - 17.157035931613745
1163 | - 17.157035931613745
1164 | - 18.529598806142847
1165 | - 18.529598806142847
1166 | - 18.529598806142847
1167 | - 18.529598806142847
1168 | - 18.529598806142847
1169 | - 18.529598806142847
1170 | - 18.529598806142847
1171 | - 18.529598806142847
1172 | - 18.529598806142847
1173 | - 18.529598806142847
1174 | - 18.529598806142847
1175 | - 18.529598806142847
1176 | - 18.529598806142847
1177 | - 19.90216168067195
1178 | - 19.90216168067195
1179 | - 19.90216168067195
1180 | - 19.90216168067195
1181 | - 19.90216168067195
1182 | - 19.90216168067195
1183 | - 19.90216168067195
1184 | - 19.90216168067195
1185 | - 19.90216168067195
1186 | - 19.90216168067195
1187 |
--------------------------------------------------------------------------------
/config/grid_coords_valid_2.yaml:
--------------------------------------------------------------------------------
1 | x:
2 | - 36.52173913043478
3 | - 27.82608695652174
4 | - 19.130434782608695
5 | - 40.0
6 | - 12.17391304347826
7 | - 40.0
8 | - 36.52173913043478
9 | - 31.304347826086957
10 | - 33.04347826086956
11 | - 10.434782608695652
12 | - 24.34782608695652
13 | - 33.04347826086956
14 | - 10.434782608695652
15 | - 10.434782608695652
16 | - 8.695652173913043
17 | - 6.956521739130435
18 | - 3.4782608695652173
19 | - 38.26086956521739
20 | - 5.217391304347826
21 | - 5.217391304347826
22 | - 1.7391304347826086
23 | - 38.26086956521739
24 | - 27.82608695652174
25 | - 40.0
26 | - 12.17391304347826
27 | - 40.0
28 | - 3.4782608695652173
29 | - 27.82608695652174
30 | - 40.0
31 | - 36.52173913043478
32 | - 29.565217391304348
33 | - 38.26086956521739
34 | - 38.26086956521739
35 | - 8.695652173913043
36 | - 33.04347826086956
37 | - 40.0
38 | - 15.652173913043478
39 | - 27.82608695652174
40 | - 20.869565217391305
41 | - 31.304347826086957
42 | - 10.434782608695652
43 | - 38.26086956521739
44 | - 36.52173913043478
45 | - 24.34782608695652
46 | - 17.391304347826086
47 | - 29.565217391304348
48 | - 24.34782608695652
49 | - 27.82608695652174
50 | - 34.78260869565217
51 | - 3.4782608695652173
52 | - 15.652173913043478
53 | - 29.565217391304348
54 | - 10.434782608695652
55 | - 31.304347826086957
56 | - 33.04347826086956
57 | - 26.08695652173913
58 | - 38.26086956521739
59 | - 15.652173913043478
60 | - 26.08695652173913
61 | - 20.869565217391305
62 | - 31.304347826086957
63 | - 1.7391304347826086
64 | - 17.391304347826086
65 | - 5.217391304347826
66 | - 19.130434782608695
67 | - 10.434782608695652
68 | - 20.869565217391305
69 | - 36.52173913043478
70 | - 26.08695652173913
71 | - 40.0
72 | - 22.608695652173914
73 | - 26.08695652173913
74 | - 10.434782608695652
75 | - 33.04347826086956
76 | - 31.304347826086957
77 | - 31.304347826086957
78 | - 31.304347826086957
79 | - 33.04347826086956
80 | - 27.82608695652174
81 | - 3.4782608695652173
82 | - 8.695652173913043
83 | - 19.130434782608695
84 | - 36.52173913043478
85 | - 24.34782608695652
86 | - 1.7391304347826086
87 | - 5.217391304347826
88 | - 17.391304347826086
89 | - 38.26086956521739
90 | - 31.304347826086957
91 | - 6.956521739130435
92 | - 20.869565217391305
93 | - 13.91304347826087
94 | - 36.52173913043478
95 | - 19.130434782608695
96 | - 26.08695652173913
97 | - 29.565217391304348
98 | - 31.304347826086957
99 | - 19.130434782608695
100 | - 27.82608695652174
101 | - 34.78260869565217
102 | - 12.17391304347826
103 | - 34.78260869565217
104 | - 10.434782608695652
105 | - 10.434782608695652
106 | - 27.82608695652174
107 | - 20.869565217391305
108 | - 31.304347826086957
109 | - 10.434782608695652
110 | - 38.26086956521739
111 | - 19.130434782608695
112 | - 29.565217391304348
113 | - 5.217391304347826
114 | - 22.608695652173914
115 | - 26.08695652173913
116 | - 5.217391304347826
117 | - 34.78260869565217
118 | - 13.91304347826087
119 | - 20.869565217391305
120 | - 29.565217391304348
121 | - 33.04347826086956
122 | - 8.695652173913043
123 | - 29.565217391304348
124 | - 36.52173913043478
125 | - 10.434782608695652
126 | - 27.82608695652174
127 | - 40.0
128 | - 26.08695652173913
129 | - 20.869565217391305
130 | - 34.78260869565217
131 | - 31.304347826086957
132 | - 15.652173913043478
133 | - 12.17391304347826
134 | - 20.869565217391305
135 | - 8.695652173913043
136 | - 24.34782608695652
137 | - 29.565217391304348
138 | - 34.78260869565217
139 | - 17.391304347826086
140 | - 34.78260869565217
141 | - 26.08695652173913
142 | - 10.434782608695652
143 | - 15.652173913043478
144 | - 34.78260869565217
145 | - 17.391304347826086
146 | - 6.956521739130435
147 | - 36.52173913043478
148 | - 31.304347826086957
149 | - 36.52173913043478
150 | - 6.956521739130435
151 | - 24.34782608695652
152 | - 17.391304347826086
153 | - 22.608695652173914
154 | - 12.17391304347826
155 | - 36.52173913043478
156 | - 40.0
157 | - 5.217391304347826
158 | - 8.695652173913043
159 | - 34.78260869565217
160 | - 31.304347826086957
161 | - 8.695652173913043
162 | - 27.82608695652174
163 | - 29.565217391304348
164 | - 34.78260869565217
165 | - 27.82608695652174
166 | - 5.217391304347826
167 | - 29.565217391304348
168 | - 26.08695652173913
169 | - 22.608695652173914
170 | - 38.26086956521739
171 | - 24.34782608695652
172 | - 20.869565217391305
173 | - 38.26086956521739
174 | - 36.52173913043478
175 | - 38.26086956521739
176 | - 33.04347826086956
177 | - 24.34782608695652
178 | - 22.608695652173914
179 | - 17.391304347826086
180 | - 13.91304347826087
181 | - 36.52173913043478
182 | - 38.26086956521739
183 | - 19.130434782608695
184 | - 19.130434782608695
185 | - 17.391304347826086
186 | - 19.130434782608695
187 | - 26.08695652173913
188 | - 10.434782608695652
189 | - 40.0
190 | - 38.26086956521739
191 | - 19.130434782608695
192 | - 24.34782608695652
193 | - 34.78260869565217
194 | - 33.04347826086956
195 | - 13.91304347826087
196 | - 19.130434782608695
197 | - 36.52173913043478
198 | - 12.17391304347826
199 | - 1.7391304347826086
200 | - 26.08695652173913
201 | - 5.217391304347826
202 | - 38.26086956521739
203 | - 26.08695652173913
204 | - 20.869565217391305
205 | - 36.52173913043478
206 | - 10.434782608695652
207 | - 38.26086956521739
208 | - 3.4782608695652173
209 | - 29.565217391304348
210 | - 34.78260869565217
211 | - 15.652173913043478
212 | - 17.391304347826086
213 | - 12.17391304347826
214 | - 8.695652173913043
215 | - 13.91304347826087
216 | - 38.26086956521739
217 | - 22.608695652173914
218 | - 6.956521739130435
219 | - 15.652173913043478
220 | - 12.17391304347826
221 | - 36.52173913043478
222 | - 24.34782608695652
223 | - 27.82608695652174
224 | - 13.91304347826087
225 | - 17.391304347826086
226 | - 31.304347826086957
227 | - 34.78260869565217
228 | - 6.956521739130435
229 | - 15.652173913043478
230 | - 31.304347826086957
231 | - 40.0
232 | - 17.391304347826086
233 | - 15.652173913043478
234 | - 12.17391304347826
235 | - 22.608695652173914
236 | - 27.82608695652174
237 | - 17.391304347826086
238 | - 19.130434782608695
239 | - 22.608695652173914
240 | - 33.04347826086956
241 | - 17.391304347826086
242 | - 29.565217391304348
243 | - 13.91304347826087
244 | - 17.391304347826086
245 | - 15.652173913043478
246 | - 1.7391304347826086
247 | - 10.434782608695652
248 | - 40.0
249 | - 17.391304347826086
250 | - 34.78260869565217
251 | - 26.08695652173913
252 | - 34.78260869565217
253 | - 31.304347826086957
254 | - 13.91304347826087
255 | - 3.4782608695652173
256 | - 24.34782608695652
257 | - 34.78260869565217
258 | - 34.78260869565217
259 | - 40.0
260 | - 36.52173913043478
261 | - 17.391304347826086
262 | - 24.34782608695652
263 | - 13.91304347826087
264 | - 6.956521739130435
265 | - 26.08695652173913
266 | - 33.04347826086956
267 | - 15.652173913043478
268 | - 1.7391304347826086
269 | - 27.82608695652174
270 | - 38.26086956521739
271 | - 22.608695652173914
272 | - 12.17391304347826
273 | - 19.130434782608695
274 | - 22.608695652173914
275 | - 33.04347826086956
276 | - 31.304347826086957
277 | - 20.869565217391305
278 | - 36.52173913043478
279 | - 34.78260869565217
280 | - 6.956521739130435
281 | - 33.04347826086956
282 | - 22.608695652173914
283 | - 29.565217391304348
284 | - 3.4782608695652173
285 | - 17.391304347826086
286 | - 12.17391304347826
287 | - 5.217391304347826
288 | - 26.08695652173913
289 | - 33.04347826086956
290 | - 26.08695652173913
291 | - 17.391304347826086
292 | - 31.304347826086957
293 | - 33.04347826086956
294 | - 27.82608695652174
295 | - 33.04347826086956
296 | - 19.130434782608695
297 | - 31.304347826086957
298 | - 12.17391304347826
299 | - 22.608695652173914
300 | - 26.08695652173913
301 | - 6.956521739130435
302 | - 1.7391304347826086
303 | - 40.0
304 | - 26.08695652173913
305 | - 34.78260869565217
306 | - 34.78260869565217
307 | - 40.0
308 | - 27.82608695652174
309 | - 22.608695652173914
310 | - 34.78260869565217
311 | - 6.956521739130435
312 | - 12.17391304347826
313 | - 6.956521739130435
314 | - 13.91304347826087
315 | - 29.565217391304348
316 | - 40.0
317 | - 13.91304347826087
318 | - 40.0
319 | - 36.52173913043478
320 | - 27.82608695652174
321 | - 12.17391304347826
322 | - 19.130434782608695
323 | - 36.52173913043478
324 | - 20.869565217391305
325 | - 26.08695652173913
326 | - 10.434782608695652
327 | - 22.608695652173914
328 | - 22.608695652173914
329 | - 22.608695652173914
330 | - 3.4782608695652173
331 | - 8.695652173913043
332 | - 20.869565217391305
333 | - 40.0
334 | - 34.78260869565217
335 | - 3.4782608695652173
336 | - 36.52173913043478
337 | - 24.34782608695652
338 | - 6.956521739130435
339 | - 13.91304347826087
340 | - 20.869565217391305
341 | - 17.391304347826086
342 | - 22.608695652173914
343 | - 10.434782608695652
344 | - 6.956521739130435
345 | - 29.565217391304348
346 | - 34.78260869565217
347 | - 24.34782608695652
348 | - 19.130434782608695
349 | - 29.565217391304348
350 | - 19.130434782608695
351 | - 8.695652173913043
352 | - 13.91304347826087
353 | - 31.304347826086957
354 | - 3.4782608695652173
355 | - 38.26086956521739
356 | - 40.0
357 | - 38.26086956521739
358 | - 27.82608695652174
359 | - 5.217391304347826
360 | - 20.869565217391305
361 | - 31.304347826086957
362 | - 13.91304347826087
363 | - 19.130434782608695
364 | - 19.130434782608695
365 | - 36.52173913043478
366 | - 40.0
367 | - 13.91304347826087
368 | - 12.17391304347826
369 | - 8.695652173913043
370 | - 31.304347826086957
371 | - 22.608695652173914
372 | - 20.869565217391305
373 | - 34.78260869565217
374 | - 24.34782608695652
375 | - 15.652173913043478
376 | - 17.391304347826086
377 | - 38.26086956521739
378 | - 24.34782608695652
379 | - 5.217391304347826
380 | - 27.82608695652174
381 | - 29.565217391304348
382 | - 13.91304347826087
383 | - 22.608695652173914
384 | - 12.17391304347826
385 | - 38.26086956521739
386 | - 20.869565217391305
387 | - 38.26086956521739
388 | - 20.869565217391305
389 | - 31.304347826086957
390 | - 15.652173913043478
391 | - 3.4782608695652173
392 | - 17.391304347826086
393 | - 15.652173913043478
394 | - 38.26086956521739
395 | - 10.434782608695652
396 | - 33.04347826086956
397 | - 26.08695652173913
398 | - 22.608695652173914
399 | - 36.52173913043478
400 | - 31.304347826086957
401 | - 31.304347826086957
402 | - 10.434782608695652
403 | - 26.08695652173913
404 | - 24.34782608695652
405 | - 15.652173913043478
406 | - 13.91304347826087
407 | - 31.304347826086957
408 | - 33.04347826086956
409 | - 17.391304347826086
410 | - 29.565217391304348
411 | - 19.130434782608695
412 | - 26.08695652173913
413 | - 26.08695652173913
414 | - 20.869565217391305
415 | - 33.04347826086956
416 | - 33.04347826086956
417 | - 26.08695652173913
418 | - 38.26086956521739
419 | - 40.0
420 | - 29.565217391304348
421 | - 22.608695652173914
422 | - 31.304347826086957
423 | - 22.608695652173914
424 | - 19.130434782608695
425 | - 33.04347826086956
426 | - 22.608695652173914
427 | - 24.34782608695652
428 | - 24.34782608695652
429 | - 38.26086956521739
430 | - 29.565217391304348
431 | - 40.0
432 | - 12.17391304347826
433 | - 27.82608695652174
434 | - 17.391304347826086
435 | - 36.52173913043478
436 | - 15.652173913043478
437 | - 24.34782608695652
438 | - 6.956521739130435
439 | - 15.652173913043478
440 | - 13.91304347826087
441 | - 26.08695652173913
442 | - 12.17391304347826
443 | - 29.565217391304348
444 | - 10.434782608695652
445 | - 38.26086956521739
446 | - 33.04347826086956
447 | - 33.04347826086956
448 | - 34.78260869565217
449 | - 12.17391304347826
450 | - 29.565217391304348
451 | - 29.565217391304348
452 | - 20.869565217391305
453 | - 20.869565217391305
454 | - 13.91304347826087
455 | - 17.391304347826086
456 | - 8.695652173913043
457 | - 17.391304347826086
458 | - 27.82608695652174
459 | - 31.304347826086957
460 | - 8.695652173913043
461 | - 12.17391304347826
462 | - 22.608695652173914
463 | - 40.0
464 | - 10.434782608695652
465 | - 15.652173913043478
466 | - 27.82608695652174
467 | - 34.78260869565217
468 | - 27.82608695652174
469 | - 34.78260869565217
470 | - 22.608695652173914
471 | - 17.391304347826086
472 | - 24.34782608695652
473 | - 33.04347826086956
474 | - 19.130434782608695
475 | - 8.695652173913043
476 | - 22.608695652173914
477 | - 12.17391304347826
478 | - 33.04347826086956
479 | - 24.34782608695652
480 | - 8.695652173913043
481 | - 12.17391304347826
482 | - 33.04347826086956
483 | - 8.695652173913043
484 | - 19.130434782608695
485 | - 34.78260869565217
486 | - 13.91304347826087
487 | - 19.130434782608695
488 | - 29.565217391304348
489 | - 20.869565217391305
490 | - 33.04347826086956
491 | - 3.4782608695652173
492 | - 15.652173913043478
493 | - 22.608695652173914
494 | - 1.7391304347826086
495 | - 5.217391304347826
496 | - 38.26086956521739
497 | - 20.869565217391305
498 | - 1.7391304347826086
499 | - 31.304347826086957
500 | - 6.956521739130435
501 | - 19.130434782608695
502 | - 36.52173913043478
503 | - 6.956521739130435
504 | - 10.434782608695652
505 | - 13.91304347826087
506 | - 40.0
507 | - 5.217391304347826
508 | - 33.04347826086956
509 | - 31.304347826086957
510 | - 5.217391304347826
511 | - 38.26086956521739
512 | - 24.34782608695652
513 | - 3.4782608695652173
514 | - 22.608695652173914
515 | - 10.434782608695652
516 | - 36.52173913043478
517 | - 34.78260869565217
518 | - 31.304347826086957
519 | - 24.34782608695652
520 | - 6.956521739130435
521 | - 29.565217391304348
522 | - 24.34782608695652
523 | - 17.391304347826086
524 | - 15.652173913043478
525 | - 40.0
526 | - 24.34782608695652
527 | - 19.130434782608695
528 | - 19.130434782608695
529 | - 40.0
530 | - 29.565217391304348
531 | - 24.34782608695652
532 | - 33.04347826086956
533 | - 27.82608695652174
534 | - 36.52173913043478
535 | - 33.04347826086956
536 | - 31.304347826086957
537 | - 15.652173913043478
538 | - 15.652173913043478
539 | - 13.91304347826087
540 | - 12.17391304347826
541 | - 29.565217391304348
542 | - 40.0
543 | - 38.26086956521739
544 | - 36.52173913043478
545 | - 1.7391304347826086
546 | - 29.565217391304348
547 | - 3.4782608695652173
548 | - 38.26086956521739
549 | - 6.956521739130435
550 | - 36.52173913043478
551 | - 10.434782608695652
552 | - 8.695652173913043
553 | - 5.217391304347826
554 | - 5.217391304347826
555 | - 22.608695652173914
556 | - 15.652173913043478
557 | - 8.695652173913043
558 | - 33.04347826086956
559 | - 26.08695652173913
560 | - 36.52173913043478
561 | - 26.08695652173913
562 | - 27.82608695652174
563 | - 24.34782608695652
564 | - 5.217391304347826
565 | - 38.26086956521739
566 | - 20.869565217391305
567 | - 38.26086956521739
568 | - 34.78260869565217
569 | - 40.0
570 | - 17.391304347826086
571 | - 27.82608695652174
572 | - 13.91304347826087
573 | - 33.04347826086956
574 | - 34.78260869565217
575 | - 6.956521739130435
576 | - 27.82608695652174
577 | - 26.08695652173913
578 | - 6.956521739130435
579 | - 40.0
580 | - 13.91304347826087
581 | - 8.695652173913043
582 | - 40.0
583 | - 36.52173913043478
584 | - 36.52173913043478
585 | - 29.565217391304348
586 | - 19.130434782608695
587 | - 26.08695652173913
588 | - 8.695652173913043
589 | - 20.869565217391305
590 | - 15.652173913043478
591 | - 15.652173913043478
592 | - 20.869565217391305
593 | - 13.91304347826087
594 | - 40.0
595 | - 8.695652173913043
596 | - 26.08695652173913
597 | - 27.82608695652174
598 | - 13.91304347826087
599 | - 20.869565217391305
600 | - 24.34782608695652
601 | - 15.652173913043478
602 | - 40.0
603 | - 27.82608695652174
604 | - 20.869565217391305
605 | - 22.608695652173914
606 | - 34.78260869565217
607 | - 24.34782608695652
608 | - 8.695652173913043
609 | - 29.565217391304348
610 | - 12.17391304347826
611 | - 27.82608695652174
612 | y:
613 | - -12.800506834585123
614 | - 10.105663290461937
615 | - 11.453085062523531
616 | - -4.715976202215572
617 | - 11.453085062523531
618 | - -0.673710886030797
619 | - -8.758241518400347
620 | - -3.3685544301539814
621 | - -15.495350378708308
622 | - -0.673710886030797
623 | - -4.715976202215572
624 | - 15.495350378708306
625 | - 14.147928606646719
626 | - -3.3685544301539814
627 | - 4.715976202215572
628 | - -12.800506834585123
629 | - -4.715976202215572
630 | - 2.0211326580923874
631 | - 11.453085062523531
632 | - -2.0211326580923874
633 | - 2.0211326580923874
634 | - -3.3685544301539814
635 | - -16.8427721507699
636 | - -8.758241518400347
637 | - 7.410819746338756
638 | - 7.410819746338756
639 | - 6.063397974277162
640 | - -18.19019392283149
641 | - -7.410819746338756
642 | - -11.453085062523531
643 | - 19.53761569489308
644 | - 14.147928606646719
645 | - 15.495350378708306
646 | - -10.10566329046194
647 | - -3.3685544301539814
648 | - 3.3685544301539814
649 | - 10.105663290461937
650 | - 4.715976202215572
651 | - -16.8427721507699
652 | - 20.885037466954675
653 | - -4.715976202215572
654 | - -10.10566329046194
655 | - -0.673710886030797
656 | - 16.8427721507699
657 | - 15.495350378708306
658 | - 11.453085062523531
659 | - -10.10566329046194
660 | - -7.410819746338756
661 | - -16.8427721507699
662 | - 0.673710886030797
663 | - -12.800506834585123
664 | - -12.800506834585123
665 | - 3.3685544301539814
666 | - -19.537615694893084
667 | - 8.75824151840035
668 | - 0.673710886030797
669 | - -18.19019392283149
670 | - 0.673710886030797
671 | - -7.410819746338756
672 | - 11.453085062523531
673 | - 15.495350378708306
674 | - -4.715976202215572
675 | - 10.105663290461937
676 | - 0.673710886030797
677 | - -12.800506834585123
678 | - -15.495350378708308
679 | - -4.715976202215572
680 | - -20.885037466954675
681 | - 10.105663290461937
682 | - -2.0211326580923874
683 | - 3.3685544301539814
684 | - -18.19019392283149
685 | - -6.063397974277162
686 | - 11.453085062523531
687 | - -8.758241518400347
688 | - -0.673710886030797
689 | - 10.105663290461937
690 | - -7.410819746338756
691 | - 3.3685544301539814
692 | - -3.3685544301539814
693 | - 0.673710886030797
694 | - -2.0211326580923874
695 | - -3.3685544301539814
696 | - 15.495350378708306
697 | - -2.0211326580923874
698 | - 3.3685544301539814
699 | - -10.10566329046194
700 | - -11.453085062523531
701 | - -16.8427721507699
702 | - 3.3685544301539814
703 | - 7.410819746338756
704 | - -2.0211326580923874
705 | - 3.3685544301539814
706 | - 4.715976202215572
707 | - -0.673710886030797
708 | - -4.715976202215572
709 | - 19.53761569489308
710 | - 6.063397974277162
711 | - -15.495350378708308
712 | - 10.105663290461937
713 | - -14.147928606646715
714 | - -7.410819746338756
715 | - 15.495350378708306
716 | - -2.0211326580923874
717 | - -19.537615694893084
718 | - 0.673710886030797
719 | - 3.3685544301539814
720 | - -10.10566329046194
721 | - -0.673710886030797
722 | - 7.410819746338756
723 | - 10.105663290461937
724 | - 10.105663290461937
725 | - 11.453085062523531
726 | - -6.063397974277162
727 | - -3.3685544301539814
728 | - -4.715976202215572
729 | - 2.0211326580923874
730 | - 18.190193922831494
731 | - -15.495350378708308
732 | - -18.19019392283149
733 | - -3.3685544301539814
734 | - 2.0211326580923874
735 | - 4.715976202215572
736 | - -11.453085062523531
737 | - 15.495350378708306
738 | - -10.10566329046194
739 | - -12.800506834585123
740 | - -18.19019392283149
741 | - -18.19019392283149
742 | - -14.147928606646715
743 | - 7.410819746338756
744 | - -11.453085062523531
745 | - -3.3685544301539814
746 | - -6.063397974277162
747 | - 6.063397974277162
748 | - 16.8427721507699
749 | - -8.758241518400347
750 | - 7.410819746338756
751 | - -12.800506834585123
752 | - 19.53761569489308
753 | - 6.063397974277162
754 | - -8.758241518400347
755 | - 2.0211326580923874
756 | - 3.3685544301539814
757 | - 8.75824151840035
758 | - -7.410819746338756
759 | - 7.410819746338756
760 | - 14.147928606646719
761 | - -7.410819746338756
762 | - -8.758241518400347
763 | - -14.147928606646715
764 | - -19.537615694893084
765 | - 4.715976202215572
766 | - 2.0211326580923874
767 | - 19.53761569489308
768 | - -4.715976202215572
769 | - -11.453085062523531
770 | - -14.147928606646715
771 | - 0.673710886030797
772 | - -0.673710886030797
773 | - 7.410819746338756
774 | - -6.063397974277162
775 | - -6.063397974277162
776 | - -12.800506834585123
777 | - -6.063397974277162
778 | - -11.453085062523531
779 | - 8.75824151840035
780 | - -12.800506834585123
781 | - -16.8427721507699
782 | - 18.190193922831494
783 | - 10.105663290461937
784 | - 3.3685544301539814
785 | - -14.147928606646715
786 | - 4.715976202215572
787 | - 6.063397974277162
788 | - -3.3685544301539814
789 | - 18.190193922831494
790 | - -16.8427721507699
791 | - -10.10566329046194
792 | - -15.495350378708308
793 | - 19.53761569489308
794 | - -3.3685544301539814
795 | - 16.8427721507699
796 | - -2.0211326580923874
797 | - 3.3685544301539814
798 | - -10.10566329046194
799 | - 2.0211326580923874
800 | - -18.19019392283149
801 | - -6.063397974277162
802 | - -15.495350378708308
803 | - -11.453085062523531
804 | - 18.190193922831494
805 | - 7.410819746338756
806 | - -15.495350378708308
807 | - 12.800506834585125
808 | - 10.105663290461937
809 | - -6.063397974277162
810 | - 4.715976202215572
811 | - -2.0211326580923874
812 | - 4.715976202215572
813 | - 11.453085062523531
814 | - -3.3685544301539814
815 | - -6.063397974277162
816 | - -6.063397974277162
817 | - 11.453085062523531
818 | - -8.758241518400347
819 | - -0.673710886030797
820 | - -10.10566329046194
821 | - -0.673710886030797
822 | - 8.75824151840035
823 | - 8.75824151840035
824 | - -15.495350378708308
825 | - 3.3685544301539814
826 | - 4.715976202215572
827 | - 16.8427721507699
828 | - 4.715976202215572
829 | - -3.3685544301539814
830 | - -6.063397974277162
831 | - 15.495350378708306
832 | - 12.800506834585125
833 | - -0.673710886030797
834 | - 8.75824151840035
835 | - -12.800506834585123
836 | - -3.3685544301539814
837 | - 16.8427721507699
838 | - 6.063397974277162
839 | - -8.758241518400347
840 | - -14.147928606646715
841 | - 11.453085062523531
842 | - -12.800506834585123
843 | - 11.453085062523531
844 | - 11.453085062523531
845 | - 3.3685544301539814
846 | - 6.063397974277162
847 | - 11.453085062523531
848 | - -8.758241518400347
849 | - 0.673710886030797
850 | - -8.758241518400347
851 | - 10.105663290461937
852 | - 4.715976202215572
853 | - 6.063397974277162
854 | - 8.75824151840035
855 | - -11.453085062523531
856 | - 2.0211326580923874
857 | - 0.673710886030797
858 | - -8.758241518400347
859 | - 15.495350378708306
860 | - 14.147928606646719
861 | - 16.8427721507699
862 | - -15.495350378708308
863 | - -19.537615694893084
864 | - -7.410819746338756
865 | - 16.8427721507699
866 | - -6.063397974277162
867 | - 10.105663290461937
868 | - 8.75824151840035
869 | - 7.410819746338756
870 | - 14.147928606646719
871 | - -19.537615694893084
872 | - 0.673710886030797
873 | - -18.19019392283149
874 | - 14.147928606646719
875 | - 2.0211326580923874
876 | - -19.537615694893084
877 | - 20.885037466954675
878 | - 15.495350378708306
879 | - -6.063397974277162
880 | - -14.147928606646715
881 | - 12.800506834585125
882 | - -14.147928606646715
883 | - 2.0211326580923874
884 | - 2.0211326580923874
885 | - 19.53761569489308
886 | - 4.715976202215572
887 | - 6.063397974277162
888 | - 2.0211326580923874
889 | - 6.063397974277162
890 | - 4.715976202215572
891 | - 6.063397974277162
892 | - 16.8427721507699
893 | - -10.10566329046194
894 | - 14.147928606646719
895 | - 4.715976202215572
896 | - -12.800506834585123
897 | - -7.410819746338756
898 | - 7.410819746338756
899 | - 15.495350378708306
900 | - 12.800506834585125
901 | - 4.715976202215572
902 | - -4.715976202215572
903 | - -10.10566329046194
904 | - -16.8427721507699
905 | - -2.0211326580923874
906 | - -2.0211326580923874
907 | - -7.410819746338756
908 | - 2.0211326580923874
909 | - -0.673710886030797
910 | - 0.673710886030797
911 | - 11.453085062523531
912 | - -10.10566329046194
913 | - 6.063397974277162
914 | - -19.537615694893084
915 | - -14.147928606646715
916 | - -2.0211326580923874
917 | - 14.147928606646719
918 | - 20.885037466954675
919 | - 18.190193922831494
920 | - 8.75824151840035
921 | - 0.673710886030797
922 | - 10.105663290461937
923 | - -10.10566329046194
924 | - 0.673710886030797
925 | - -6.063397974277162
926 | - -14.147928606646715
927 | - 6.063397974277162
928 | - 0.673710886030797
929 | - -20.885037466954675
930 | - 7.410819746338756
931 | - 6.063397974277162
932 | - 12.800506834585125
933 | - -16.8427721507699
934 | - -4.715976202215572
935 | - 8.75824151840035
936 | - 18.190193922831494
937 | - -12.800506834585123
938 | - 16.8427721507699
939 | - 7.410819746338756
940 | - 10.105663290461937
941 | - 8.75824151840035
942 | - -4.715976202215572
943 | - -2.0211326580923874
944 | - 2.0211326580923874
945 | - -15.495350378708308
946 | - 3.3685544301539814
947 | - 16.8427721507699
948 | - 11.453085062523531
949 | - -11.453085062523531
950 | - -8.758241518400347
951 | - -10.10566329046194
952 | - -7.410819746338756
953 | - -6.063397974277162
954 | - 8.75824151840035
955 | - -6.063397974277162
956 | - -3.3685544301539814
957 | - 11.453085062523531
958 | - 4.715976202215572
959 | - -0.673710886030797
960 | - -18.19019392283149
961 | - 10.105663290461937
962 | - 7.410819746338756
963 | - -16.8427721507699
964 | - 18.190193922831494
965 | - -7.410819746338756
966 | - 0.673710886030797
967 | - -15.495350378708308
968 | - -14.147928606646715
969 | - -4.715976202215572
970 | - -0.673710886030797
971 | - -15.495350378708308
972 | - -20.885037466954675
973 | - 12.800506834585125
974 | - -10.10566329046194
975 | - 18.190193922831494
976 | - 20.885037466954675
977 | - 12.800506834585125
978 | - -14.147928606646715
979 | - -3.3685544301539814
980 | - 12.800506834585125
981 | - -15.495350378708308
982 | - 15.495350378708306
983 | - -14.147928606646715
984 | - 15.495350378708306
985 | - -6.063397974277162
986 | - 6.063397974277162
987 | - 2.0211326580923874
988 | - 7.410819746338756
989 | - -19.537615694893084
990 | - 2.0211326580923874
991 | - -0.673710886030797
992 | - 18.190193922831494
993 | - -7.410819746338756
994 | - -15.495350378708308
995 | - -12.800506834585123
996 | - -4.715976202215572
997 | - 6.063397974277162
998 | - -2.0211326580923874
999 | - 4.715976202215572
1000 | - 12.800506834585125
1001 | - -10.10566329046194
1002 | - -8.758241518400347
1003 | - -15.495350378708308
1004 | - -7.410819746338756
1005 | - -15.495350378708308
1006 | - -14.147928606646715
1007 | - 3.3685544301539814
1008 | - 3.3685544301539814
1009 | - -0.673710886030797
1010 | - 0.673710886030797
1011 | - -18.19019392283149
1012 | - 4.715976202215572
1013 | - 12.800506834585125
1014 | - 14.147928606646719
1015 | - 14.147928606646719
1016 | - -11.453085062523531
1017 | - -4.715976202215572
1018 | - -12.800506834585123
1019 | - -6.063397974277162
1020 | - -18.19019392283149
1021 | - -8.758241518400347
1022 | - -11.453085062523531
1023 | - 16.8427721507699
1024 | - -16.8427721507699
1025 | - 16.8427721507699
1026 | - 19.53761569489308
1027 | - 18.190193922831494
1028 | - 12.800506834585125
1029 | - 10.105663290461937
1030 | - 8.75824151840035
1031 | - -0.673710886030797
1032 | - 2.0211326580923874
1033 | - 8.75824151840035
1034 | - -16.8427721507699
1035 | - -6.063397974277162
1036 | - 2.0211326580923874
1037 | - -7.410819746338756
1038 | - 8.75824151840035
1039 | - -12.800506834585123
1040 | - 8.75824151840035
1041 | - 15.495350378708306
1042 | - 16.8427721507699
1043 | - 0.673710886030797
1044 | - 12.800506834585125
1045 | - -0.673710886030797
1046 | - 18.190193922831494
1047 | - 14.147928606646719
1048 | - 2.0211326580923874
1049 | - -0.673710886030797
1050 | - -4.715976202215572
1051 | - -3.3685544301539814
1052 | - 6.063397974277162
1053 | - 14.147928606646719
1054 | - 8.75824151840035
1055 | - 10.105663290461937
1056 | - 20.885037466954675
1057 | - -20.885037466954675
1058 | - -19.537615694893084
1059 | - 3.3685544301539814
1060 | - 6.063397974277162
1061 | - 0.673710886030797
1062 | - -2.0211326580923874
1063 | - -12.800506834585123
1064 | - -0.673710886030797
1065 | - 10.105663290461937
1066 | - 6.063397974277162
1067 | - 14.147928606646719
1068 | - 16.8427721507699
1069 | - -8.758241518400347
1070 | - -11.453085062523531
1071 | - -12.800506834585123
1072 | - 8.75824151840035
1073 | - -2.0211326580923874
1074 | - 0.673710886030797
1075 | - 0.673710886030797
1076 | - -15.495350378708308
1077 | - 19.53761569489308
1078 | - -3.3685544301539814
1079 | - 0.673710886030797
1080 | - 20.885037466954675
1081 | - -4.715976202215572
1082 | - 18.190193922831494
1083 | - 12.800506834585125
1084 | - -14.147928606646715
1085 | - 14.147928606646719
1086 | - -7.410819746338756
1087 | - -18.19019392283149
1088 | - -8.758241518400347
1089 | - -12.800506834585123
1090 | - -2.0211326580923874
1091 | - -14.147928606646715
1092 | - 10.105663290461937
1093 | - -0.673710886030797
1094 | - 8.75824151840035
1095 | - -14.147928606646715
1096 | - -20.885037466954675
1097 | - 7.410819746338756
1098 | - 8.75824151840035
1099 | - 7.410819746338756
1100 | - 15.495350378708306
1101 | - 14.147928606646719
1102 | - -2.0211326580923874
1103 | - 4.715976202215572
1104 | - 12.800506834585125
1105 | - 3.3685544301539814
1106 | - -8.758241518400347
1107 | - 18.190193922831494
1108 | - -8.758241518400347
1109 | - -3.3685544301539814
1110 | - 14.147928606646719
1111 | - -4.715976202215572
1112 | - -18.19019392283149
1113 | - -10.10566329046194
1114 | - -2.0211326580923874
1115 | - 4.715976202215572
1116 | - 6.063397974277162
1117 | - 10.105663290461937
1118 | - -11.453085062523531
1119 | - -11.453085062523531
1120 | - -4.715976202215572
1121 | - -10.10566329046194
1122 | - -7.410819746338756
1123 | - -7.410819746338756
1124 | - 7.410819746338756
1125 | - -3.3685544301539814
1126 | - 7.410819746338756
1127 | - -2.0211326580923874
1128 | - -11.453085062523531
1129 | - -6.063397974277162
1130 | - -16.8427721507699
1131 | - 11.453085062523531
1132 | - 3.3685544301539814
1133 | - 7.410819746338756
1134 | - 12.800506834585125
1135 | - 12.800506834585125
1136 | - -11.453085062523531
1137 | - -14.147928606646715
1138 | - -4.715976202215572
1139 | - -8.758241518400347
1140 | - 4.715976202215572
1141 | - 12.800506834585125
1142 | - 3.3685544301539814
1143 | - -4.715976202215572
1144 | - 14.147928606646719
1145 | - 19.53761569489308
1146 | - -8.758241518400347
1147 | - -2.0211326580923874
1148 | - 16.8427721507699
1149 | - -16.8427721507699
1150 | - 11.453085062523531
1151 | - -2.0211326580923874
1152 | - -19.537615694893084
1153 | - -16.8427721507699
1154 | - -12.800506834585123
1155 | - -16.8427721507699
1156 | - -0.673710886030797
1157 | - 4.715976202215572
1158 | - 2.0211326580923874
1159 | - 6.063397974277162
1160 | - 4.715976202215572
1161 | - -18.19019392283149
1162 | - -7.410819746338756
1163 | - 6.063397974277162
1164 | - 8.75824151840035
1165 | - -7.410819746338756
1166 | - 14.147928606646719
1167 | - -2.0211326580923874
1168 | - -2.0211326580923874
1169 | - 0.673710886030797
1170 | - 2.0211326580923874
1171 | - 15.495350378708306
1172 | - 7.410819746338756
1173 | - -6.063397974277162
1174 | - 19.53761569489308
1175 | - 6.063397974277162
1176 | - -20.885037466954675
1177 | - 3.3685544301539814
1178 | - -19.537615694893084
1179 | - 19.53761569489308
1180 | - 11.453085062523531
1181 | - -6.063397974277162
1182 | - -11.453085062523531
1183 | - 3.3685544301539814
1184 | - -10.10566329046194
1185 | - 12.800506834585125
1186 | - 12.800506834585125
1187 | - -10.10566329046194
1188 | - -8.758241518400347
1189 | - 7.410819746338756
1190 | - -6.063397974277162
1191 | - -0.673710886030797
1192 | - 2.0211326580923874
1193 | - 18.190193922831494
1194 | - 11.453085062523531
1195 | - 8.75824151840035
1196 | - -7.410819746338756
1197 | - 15.495350378708306
1198 | - -4.715976202215572
1199 | - 10.105663290461937
1200 | - -7.410819746338756
1201 | - -0.673710886030797
1202 | - -3.3685544301539814
1203 | - 12.800506834585125
1204 | - 15.495350378708306
1205 | - -3.3685544301539814
1206 | - 11.453085062523531
1207 | - -11.453085062523531
1208 | - 16.8427721507699
1209 | - -11.453085062523531
1210 | - -11.453085062523531
1211 | - -15.495350378708308
1212 | - 3.3685544301539814
1213 | - -14.147928606646715
1214 | - -3.3685544301539814
1215 | - 14.147928606646719
1216 | - -11.453085062523531
1217 | - -10.10566329046194
1218 | - 0.673710886030797
1219 | - -8.758241518400347
1220 | - -16.8427721507699
1221 | - -4.715976202215572
1222 | - 2.0211326580923874
1223 |
--------------------------------------------------------------------------------
/config/params.yaml:
--------------------------------------------------------------------------------
1 | # run settings
2 | run:
3 | resolution: [256,256] #[width,height] in pixels
4 | view_angle: 16 #in degrees, horizontal view angle
5 | origin: [0,0]
6 | min_angle: 0.001 #in degrees, minimal eccentricity
7 | fps: 35
8 | gpu: 0 #if using cuda, enter gpu nr here (e.g. 0)
9 | print_stats: False #print simulator values for sanity check
10 | seed: 42
11 | dtype: float32
12 | use_gaussian_lut: False # Whether to approximate Gaussian activation with a
13 | # look-up table.
14 | batch_size: 0 # Set to zero when simulator is not used for computational optimization
15 |
16 | # display specs to accurately diplay sizes in dva
17 | display:
18 | screen_resolution: [1920,1080] #width & height in pixels
19 | #screen_size: [294,166] #width & height in mm
20 | screen_diagonal: 13.3 #inches
21 | dist_to_screen: 600 # eyes to screen in mm
22 |
23 | # for sampling from images/video
24 | sampling:
25 | sampling_method: receptive_fields #receptive_fields or center
26 | RF_size: 0.5 # millimeters of cortical surface (when sampling receptive fields)
27 | stimulus_scale: 1.e-4 # Only used when the sample_stimulus method is called with 'rescale=True'. The default behaviour
28 | # is no scaling (i.e., the stim amplitude equals the intensity of the sampled image).
29 |
30 | # settings for electrode coords to visual field coords
31 | cortex_model:
32 | model: dipole
33 | k: 17.3
34 | a: 0.75
35 | b: 120
36 | alpha: 0.95
37 | dropout_rate: 0.2
38 | noise_scale: 0.4
39 |
40 | # habituation and other temporal dynamics
41 | temporal_dynamics:
42 | trace_increase_rate: 13.95528162 # how much the trace increases when there is input, per second
43 | activation_decay_per_second: 0.00012340980408667956 # The decay of tissue activation per second
44 | trace_decay_per_second: 0.99949191 # The decay of the memory trace, per second
45 |
46 | # current strength effect on size (Bosking et al., 2017),
47 | size:
48 | size_equation: sqrt #which equation to use for current->size computations. sqrt or sigmoid
49 | MD: 0.7 # predicted maximum diameter of activated cortex in mm
50 | I_half: 40 # mu-A
51 | slope_size: 0.08 # slope of size saturation curve in mm/mu-A
52 | current_spread: 675.e-6 #A/mm2
53 | radius_to_sigma: 0.5 #circle to gaussian factor, sigma = r/2
54 |
55 | # sigmoid on activation
56 | brightness_saturation:
57 | cps_half: 1.057631326853325e-07 # calibrated on fig. 6A Fernández et al., (2021)
58 | slope_brightness: 19152642.500946816 # calibrated on fig. 6A/B Fernández et al., (2021)
59 |
60 | # Stimulation threshold
61 | thresholding:
62 | use_threshold: True
63 | rheobase: 23.9e-6 # The minimal current (Ampere) for infinite stimulation duration. Is used as the constant leak current.
64 | activation_threshold: 9.141886000943878e-08 # Threshold of tissue activation for the perception of phosphenes
65 | activation_threshold_sd: 6.715877869833961e-08 # Standard deviation of the tissue activation threshold (for random initialization)
66 |
67 | # Pulse width (pw), frequency (freq) default values, in case they aren't specified in the input
68 | default_stim:
69 | relative_stim_duration: 1 # range: [0-1]. stim_duration = rel_stim_dur * frame_duration
70 | pw_default: 170.e-6 #Seconds
71 | freq_default: 300 #Hertz
72 |
73 | # Gabor filters
74 | gabor:
75 | gabor_filtering: False
76 | gamma: 1.5
77 |
--------------------------------------------------------------------------------
/dynaphos/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/dynaphos/__init__.py
--------------------------------------------------------------------------------
/dynaphos/cortex_models.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import torch
3 | from typing import Optional, Tuple, Callable, Union
4 |
5 | import numpy as np
6 |
7 | from dynaphos.utils import (Map, cartesian_to_complex, polar_to_complex,
8 | complex_to_polar)
9 |
10 |
11 | def get_visual_field_coordinates_from_cortex(
12 | params: dict, coordinates_cortex: Optional[Map] = None,
13 | rng: Optional[np.random.Generator] = None) -> Map:
14 | """Map electrode locations from cortex to visual field.
15 |
16 | :param params: Parameters for visuotopic model.
17 | :param coordinates_cortex: Locations of electrodes on a cortex map.
18 | :param rng: Numpy random number generator.
19 | :return: Location of electrodes / phosphenes in the visual field.
20 | """
21 | if coordinates_cortex is None:
22 | coordinates_cortex = get_cortex_coordinates_grid(params, 32, 32,
23 | x_max=40)
24 |
25 | x, y = coordinates_cortex.cartesian
26 | x, y = add_noise(x, y, params['noise_scale'], rng)
27 | x, y = add_dropout(x, y, params['dropout_rate'], rng)
28 |
29 | cortex_to_visual_field = get_mapping_from_cortex_to_visual_field(params)
30 | z = cortex_to_visual_field(cartesian_to_complex(x, y))
31 | z = remove_out_of_view(z)
32 |
33 | return Map(z=z).flip(hor=True, vert=True) # Flip x and y-coordinates to account for upside-down orientation of visual
34 |
35 |
36 | def get_visual_field_coordinates_from_cortex_full(
37 | params: dict, coordinates_cortex: Optional[Map] = None,
38 | rng: Optional[np.random.Generator] = None) -> Map:
39 | """Initialize phosphene locations in the full field of view.
40 |
41 | :param params: dictionary with the several parameters in subdictionaries.
42 | :param coordinates_cortex: Visuotopic map of with electrode locations on
43 | cortex.
44 | If None, default coordinates will be used.
45 | :param rng: Numpy random number generator.
46 | :return: Phosphene locations.
47 | """
48 | args = (params, coordinates_cortex, rng)
49 | r_left, phi_left = get_visual_field_coordinates_from_cortex(*args).polar
50 | r_right, phi_right = get_visual_field_coordinates_from_cortex(*args).polar
51 | r = np.concatenate([r_left, r_right])
52 | phi = np.concatenate([phi_left, np.pi - phi_right])
53 | return Map(r=r, phi=phi)
54 |
55 |
56 | def get_visual_field_coordinates_probabilistically(
57 | params: dict, n_phosphenes: int,
58 | rng: Optional[np.random.Generator] = None) -> Map:
59 | """Generate a number of phosphene locations probabilistically.
60 |
61 | :param params: Model parameters.
62 | :param n_phosphenes: Number of phosphenes.
63 | :param rng: Numpy random number generator.
64 | :return: Polar coordinates of n_phosphenes phosphenes.
65 | """
66 | if rng is None:
67 | rng = np.random.default_rng()
68 |
69 | max_r = params['run']['view_angle'] / 2
70 | min_r = params['run']['min_angle']
71 |
72 | valid_ecc = np.linspace(min_r, max_r, 1000)
73 | weights = get_cortical_magnification(valid_ecc, params['cortex_model'])
74 |
75 | probs = weights / np.sum(weights)
76 | r = rng.choice(valid_ecc, size=n_phosphenes, replace=True, p=probs)
77 | phi = 2 * np.pi * rng.random(n_phosphenes)
78 |
79 | return Map(r=r, phi=phi)
80 |
81 |
82 | def get_visual_field_coordinates_grid() -> Map:
83 | ecc_range = np.arange(0, 90, 1)
84 | ang_range = np.linspace(-np.pi / 2, np.pi / 2, 10)
85 | r, phi = np.meshgrid(ecc_range, ang_range)
86 | return Map(r=r.ravel(), phi=phi.ravel())
87 |
88 |
89 | def get_cortex_coordinates_grid(params: dict, n_electrodes_x: int,
90 | n_electrodes_y: int,
91 | x_max: Optional[int] = None) -> Map:
92 | coordinates = get_cortex_coordinates_default(params)
93 | x, y = coordinates.cartesian
94 | x_min, x_max = np.min(x), x_max or np.max(x)
95 | y_min, y_max = np.min(y), np.max(y)
96 | xrange = np.linspace(x_min, x_max, n_electrodes_x)
97 | yrange = np.linspace(y_min, y_max, n_electrodes_y)
98 | x, y = np.meshgrid(xrange, yrange)
99 |
100 | return Map(x.ravel(), y.ravel())
101 |
102 |
103 | def get_cortex_coordinates_default(params: dict) -> Map:
104 | """Generate cortical map.
105 |
106 | :return: Cortical coordinates.
107 | """
108 | coordinates_visual_field = get_visual_field_coordinates_grid()
109 | visual_field_to_cortex = get_mapping_from_visual_field_to_cortex(params)
110 | z = visual_field_to_cortex(coordinates_visual_field.complex)
111 | return Map(z=z)
112 |
113 |
114 | def get_mapping_from_visual_field_to_cortex(params: dict) -> Callable:
115 | mapping_model = params['model']
116 | a = params['a']
117 | b = params['b']
118 | k = params['k']
119 | alpha = params['alpha']
120 | if mapping_model == 'monopole':
121 | def f(z): return k * np.log(1 + z / a)
122 | elif mapping_model == 'dipole':
123 | def f(z): return k * np.log(b * (z + a) / (a * (z + b)))
124 | elif mapping_model == 'wedge-dipole':
125 | def wedge(r, phi): return polar_to_complex(r, alpha * phi)
126 | def dipole(z): return k * np.log(b * (z + a) / (a * (z + b)))
127 | def f(z): return dipole(wedge(*complex_to_polar(z)))
128 | else:
129 | raise NotImplementedError
130 | return f
131 |
132 |
133 | def get_mapping_from_cortex_to_visual_field(params: dict) -> Callable:
134 | mapping_model = params['model']
135 | a = params['a']
136 | b = params['b']
137 | k = params['k']
138 | alpha = params['alpha']
139 | if mapping_model == 'monopole':
140 | def f(w): return a * np.exp(w / k) - a
141 | elif mapping_model == 'dipole':
142 | def f(w):
143 | e = np.exp(w / k)
144 | return a * b * (e - 1) / (b - a * e)
145 | elif mapping_model == 'wedge-dipole':
146 | def wedge_inverse(z):
147 | r, phi = complex_to_polar(z)
148 | return polar_to_complex(r, phi / alpha)
149 |
150 | def dipole_inverse(w):
151 | e = np.exp(w / k)
152 | return a * b * (e - 1) / (b - a * e)
153 |
154 | def f(w): return wedge_inverse(dipole_inverse(w))
155 | else:
156 | raise NotImplementedError
157 | return f
158 |
159 |
160 | def get_cortical_magnification(
161 | r: Union[np.ndarray, torch.Tensor],
162 | params: dict) -> Union[np.ndarray, torch.Tensor]:
163 | mapping_model = params['model']
164 | a = params['a']
165 | b = params['b']
166 | k = params['k']
167 | if mapping_model == 'monopole':
168 | return k / (r + a)
169 | if mapping_model in ['dipole', 'wedge-dipole']:
170 | return k * (1 / (r + a) - 1 / (r + b))
171 | raise NotImplementedError
172 |
173 |
174 | def remove_out_of_view(z: np.ndarray) -> np.ndarray:
175 | r, phi = complex_to_polar(z)
176 |
177 | z = z[(r >= 0) & (r <= 90) & (phi > -np.pi / 2) & (phi < np.pi / 2)]
178 |
179 | logging.info(f"Removed {len(r) - len(z)} of {len(r)} phosphene locations.")
180 |
181 | return z
182 |
183 |
184 | def add_noise(x: np.ndarray, y: np.ndarray, noise_scale: Optional[float] = 0.,
185 | rng: Optional[np.random.Generator] = None) -> Tuple[np.ndarray,
186 | np.ndarray]:
187 | if rng is None:
188 | rng = np.random.default_rng()
189 |
190 | noise = rng.normal(scale=noise_scale, size=(2, len(x)))
191 |
192 | return x + noise[0], y + noise[1]
193 |
194 |
195 | def add_dropout(x: np.ndarray, y: np.ndarray,
196 | dropout_rate: Optional[float] = 0.,
197 | rng: Optional[np.random.Generator] = None
198 | ) -> Tuple[np.ndarray, np.ndarray]:
199 | if rng is None:
200 | rng = np.random.default_rng()
201 |
202 | n = len(x)
203 | active = rng.choice(np.arange(n), int(n * (1 - dropout_rate)),
204 | replace=False)
205 |
206 | return x[active], y[active]
207 |
--------------------------------------------------------------------------------
/dynaphos/image_processing.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from typing import Optional, Union
3 |
4 | import cv2
5 | import numpy as np
6 |
7 |
8 | def canny_processor(frame: np.ndarray, threshold_low: float,
9 | threshold_high: float) -> np.ndarray:
10 | return cv2.Canny(frame, threshold_low, threshold_high)
11 |
12 |
13 | def sobel_processor(frame: np.ndarray) -> np.ndarray:
14 | kwargs = dict(ksize=3, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
15 | grad_x = cv2.Sobel(frame, cv2.CV_16S, 1, 0, **kwargs)
16 | grad_y = cv2.Sobel(frame, cv2.CV_16S, 0, 1, **kwargs)
17 | xy = np.stack([grad_x, grad_y])
18 | grad = np.linalg.norm(xy, axis=0)
19 | return grad
20 |
21 |
22 | def to_n_dim(image: Union[np.ndarray, torch.Tensor], n: Optional[int] = 3
23 | ) -> Union[np.ndarray, torch.Tensor]:
24 | while image.ndim < n:
25 | if isinstance(image, torch.Tensor):
26 | image = torch.unsqueeze(image, 0)
27 | else:
28 | image = np.expand_dims(image, 0)
29 | return image
30 |
31 |
32 | def scale_image(image: Union[np.ndarray, torch.Tensor],
33 | f: Optional[float] = None, use_max: Optional[bool] = False
34 | ) -> Union[np.ndarray, torch.Tensor]:
35 | if use_max:
36 | m = np.max if isinstance(image, np.ndarray) else torch.max
37 | image = image / m(image)
38 | if f is not None:
39 | image = image * f
40 | return image
41 |
--------------------------------------------------------------------------------
/dynaphos/plotting.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from matplotlib import pyplot as plt
4 |
5 | from dynaphos.cortex_models import get_cortex_coordinates_default, get_cortex_coordinates_grid
6 |
7 |
8 | def plot_coordinates(params: dict, n_electrodes_x: int, n_electrodes_y: int,
9 | x_max: Optional[int] = None):
10 | coordinates_cortex = get_cortex_coordinates_default(params)
11 | grid_cortex = get_cortex_coordinates_grid(params, n_electrodes_x,
12 | n_electrodes_y, x_max)
13 | plt.scatter(*coordinates_cortex.cartesian, c='r')
14 | plt.scatter(*grid_cortex.cartesian)
15 | plt.xlabel('Cortical distance (mm)')
16 | plt.ylabel('Cortical distance (mm)')
17 | plt.show()
18 |
--------------------------------------------------------------------------------
/dynaphos/simulator.py:
--------------------------------------------------------------------------------
1 | import math
2 | from typing import Optional, Tuple, Union
3 |
4 | import logging
5 | import numpy as np
6 | import torch
7 | import warnings
8 |
9 | from dynaphos.cortex_models import get_cortical_magnification
10 | from dynaphos.image_processing import scale_image, to_n_dim
11 | from dynaphos.utils import (to_tensor, get_data_kwargs, get_truncated_normal,
12 | get_deg2pix_coeff, set_deterministic,
13 | print_stats, sigmoid, to_numpy, Map)
14 |
15 | class State:
16 | def __init__(self, params: dict, shape: Tuple[int, ...],
17 | verbose: Optional[bool] = False):
18 | self.params = params
19 | self.shape = shape
20 | self.verbose = verbose
21 | self.state = None
22 | self.data_kwargs = get_data_kwargs(self.params)
23 |
24 | self.reset()
25 |
26 | def reset(self):
27 | self.state = torch.zeros(self.shape, **self.data_kwargs)
28 |
29 | def get(self) -> torch.Tensor:
30 | return self.state
31 |
32 | def update(self, x: torch.Tensor):
33 | raise NotImplementedError
34 |
35 | def to_tensor(self, x: np.ndarray) -> torch.Tensor:
36 | return to_tensor(x, **self.data_kwargs)
37 |
38 |
39 | class Activation(State):
40 | def __init__(self, params: dict, shape: Tuple[int, ...],
41 | verbose: Optional[bool] = False):
42 | super().__init__(params, shape, verbose)
43 |
44 | self.fps = self.to_tensor(self.params['run']['fps'])
45 | # By default, the stimulus lasts as long as a frame. Can be adjusted:
46 | self.rel_stim_duration = self.to_tensor(
47 | self.params['default_stim']['relative_stim_duration'])
48 | # Convert decay-per-second to exponential decay constant.
49 | self.decay_rate = -torch.log(self.to_tensor(
50 | self.params['temporal_dynamics']['activation_decay_per_second']))
51 | self.num_steps = int(torch.ceil(self.decay_rate / self.fps))
52 |
53 | def update(self, x: torch.Tensor):
54 | """Update activation with leaky integrator.
55 |
56 | :param x: Effective stimulation current.
57 | """
58 |
59 | # If decay rate > frame rate, perform extra simulation steps for
60 | # numerical stability.
61 | for _ in range(self.num_steps):
62 | # eq: \Delta A = (-\gamma * A + I) * \Delta t
63 | self.state = self.state.detach() + (
64 | (-self.state.detach() * self.decay_rate + x * self.rel_stim_duration) /
65 | self.fps / self.num_steps)
66 |
67 | print_stats('activation', self.state, self.verbose)
68 |
69 | class ActivationThreshold(State):
70 | def __init__(self, params: dict, shape: Tuple[int, ...],
71 | rng: np.random.Generator, verbose: Optional[bool] = False):
72 | super().__init__(params, shape, verbose)
73 | self.rng = rng
74 | self._mu = self.params['thresholding']['activation_threshold']
75 | self._sd = self.params['thresholding']['activation_threshold_sd']
76 | self.reinitialize()
77 |
78 | def reinitialize(self, activation_thresholds: Optional[np.ndarray] = None):
79 | """Set or re-initialize the activation thresholds for each electrode. Default: sample from truncated random
80 | normal distribution."""
81 | if self.params['thresholding']['use_threshold']:
82 | if activation_thresholds is None:
83 | activation_thresholds = self.rng.standard_normal(self.shape) * self._sd + self._mu
84 | self.state = self.to_tensor(activation_thresholds).clip(0, None)
85 | else:
86 | self.state = torch.zeros(self.shape, **self.data_kwargs)
87 |
88 | class Trace(State):
89 | def __init__(self, params: dict, shape: Tuple[int, ...],
90 | verbose: Optional[bool] = False):
91 | super().__init__(params, shape, verbose)
92 |
93 | fps = self.params['run']['fps']
94 |
95 | # By default, the stimulus lasts as long as a frame. Can be adjusted:
96 | rel_stim_duration = \
97 | self.params['default_stim']['relative_stim_duration']
98 |
99 | # Convert decay-per-second to exponential decay constant.
100 | decay_rate = -math.log(
101 | self.params['temporal_dynamics']['trace_decay_per_second'])
102 |
103 | # Scaling of the trace increment.
104 | scale = self.params['temporal_dynamics']['trace_increase_rate']
105 |
106 | # If decay rate > frame rate, perform extra simulation steps for
107 | # numerical stability.
108 | self.num_steps = math.ceil(decay_rate / fps)
109 |
110 | self._a = self.to_tensor(-decay_rate / fps / self.num_steps)
111 | self._b = self.to_tensor(rel_stim_duration * scale / fps /
112 | self.num_steps)
113 |
114 | def update(self, x: torch.Tensor):
115 | """Update memory trace using a leaky integrator.
116 |
117 | :param x: Effective stimulation current.
118 | """
119 | for _ in range(self.num_steps):
120 | self.state = self.state.detach() + self._a * self.state.detach() + self._b * x
121 |
122 | print_stats('trace', self.state, self.verbose)
123 |
124 |
125 | class Brightness(State):
126 | def __init__(self, params: dict, shape: Tuple[int, ...], verbose: Optional[bool] = False):
127 | super().__init__(params, shape, verbose)
128 | self.slope = self.to_tensor(
129 | self.params['brightness_saturation']['slope_brightness'])
130 | self.cps_half = self.to_tensor(
131 | self.params['brightness_saturation']['cps_half'])
132 |
133 | def update(self, x: torch.Tensor):
134 | """Saturate activation values."""
135 |
136 | self.state = sigmoid(self.slope * (x - self.cps_half))
137 | print_stats('sigmoided activation', self.state, self.verbose)
138 |
139 |
140 | class Sigma(State):
141 | def __init__(self, params: dict, shape: Tuple[int, ...],
142 | magnification: torch.Tensor, verbose: Optional[bool] = False):
143 | super().__init__(params, shape, verbose)
144 |
145 | p = self.params['size']
146 | if p['size_equation'] == 'sqrt': # Tehovnik 2007
147 | def f(x):
148 | return torch.sqrt(torch.div(x, p['current_spread']))
149 | elif p['size_equation'] == 'sigmoid': # Bosking et al., 2017
150 | def f(x):
151 | return 0.5 * p['MD'] * sigmoid(p['slope_size'] *
152 | (x - p['I_half']))
153 | else:
154 | raise ValueError("Size equation should be 'sqrt' or 'sigmoid'.")
155 | self.f = f
156 | self.scale = p['radius_to_sigma'] / magnification
157 | def update(self, x: torch.Tensor):
158 | """Compute the effect of the input current on phosphene size."""
159 |
160 | # Current spread to sigma in pixels.
161 | self.state = torch.mul(self.f(x), self.scale)
162 |
163 | print_stats('Sigma (in degrees)', self.state, self.verbose)
164 |
165 |
166 | class GaussianSimulator:
167 | def __init__(self, params: dict, coordinates: Map,
168 | rng: Optional[np.random.Generator] = None,
169 | theta: Optional[np.ndarray] = None):
170 | """initialize a simulator with provided parameters settings,
171 | given phosphene locations in polar coordinates
172 |
173 | :param params: dict of dicts with all setting parameters.
174 | :param coordinates: Eccentricities and angles of phosphenes.
175 | :param theta: Orientations for gabor filtering (if 'gabor_filtering' set to True)
176 | :param rng: Numpy random number generator.
177 | """
178 |
179 | self.params = params
180 | self.data_kwargs = get_data_kwargs(self.params)
181 |
182 | rng = np.random.default_rng() if rng is None else rng
183 | set_deterministic(self.params['run']['seed'])
184 |
185 | self.deg2pix_coeff = get_deg2pix_coeff(self.params['run'])
186 |
187 | self.phosphene_maps = \
188 | self.generate_phosphene_maps(coordinates, theta=theta)
189 |
190 | batch_size = self.params['run']['batch_size']
191 | if batch_size != 0:
192 | self.shape = (batch_size, self.num_phosphenes, 1, 1)
193 | self._electrode_dimension = 1
194 | else:
195 | self.shape = (self.num_phosphenes, 1, 1)
196 | self._electrode_dimension = 0
197 |
198 | r, phi = coordinates.polar
199 | r = torch.reshape(self.to_tensor(r), self.shape[-3:])
200 | self.magnification = get_cortical_magnification(
201 | r, self.params['cortex_model'])
202 |
203 | verbose = self.params['run']['print_stats']
204 | self.activation = Activation(params, self.shape, verbose=verbose)
205 | self.trace = Trace(params, self.shape)
206 | self.sigma = Sigma(params, self.shape, self.magnification)
207 | self.brightness = Brightness(params, self.shape)
208 | self.threshold = ActivationThreshold(params, self.shape, rng)
209 | self.effective_charge_per_second = None
210 |
211 | # Pre-allocate some helper variables.
212 | self._sampling_mask = None
213 | self._phosphene_centers = None
214 | params_sampling = self.params['sampling']
215 | self._sampling_method = params_sampling['sampling_method']
216 | self._sqrt_pi_inv = 1 / torch.sqrt(self.to_tensor(torch.pi))
217 | self._pulse_width = (self.params['default_stim']['pw_default'] *
218 | torch.ones(self.shape, **self.data_kwargs))
219 | self._frequency = (self.params['default_stim']['freq_default'] *
220 | torch.ones(self.shape, **self.data_kwargs))
221 |
222 | self._zero = self.to_tensor(0)
223 | self._inf = self.to_tensor(torch.inf)
224 |
225 | self.reset()
226 |
227 | @property
228 | def num_phosphenes(self):
229 | return len(self.phosphene_maps)
230 |
231 | def to_tensor(self, x: Union[int, float, np.ndarray]) -> torch.Tensor:
232 | return to_tensor(x, **self.data_kwargs)
233 |
234 | def reset(self):
235 | """Reset Memory of previous timestep."""
236 | self.activation.reset()
237 | self.trace.reset()
238 | self.sigma.reset()
239 |
240 | def gabor_rotation(self, x, y, theta=None) -> torch.Tensor:
241 | """Rotation of ellipsis."""
242 | num_phosphenes = len(x)
243 | if theta is None:
244 | theta = torch.mul(2 * math.pi, torch.rand((num_phosphenes, 1, 1), **self.data_kwargs)) # Random rotation
245 | else:
246 | theta = torch.reshape(self.to_tensor(theta), (-1, 1, 1))
247 | y_rotated = -x * torch.sin(theta) + y * torch.cos(theta)
248 | x_rotated = x * torch.cos(theta) + y * torch.sin(theta)
249 | gamma = self.params['gabor']['gamma']
250 | phosphene_maps = torch.sqrt(x_rotated ** 2 + y_rotated ** 2 * gamma ** 2)
251 | return phosphene_maps
252 |
253 | def generate_phosphene_maps(self, coordinates: Map,
254 | remove_invalid: Optional[bool] = True,
255 | theta: Optional[np.ndarray] = None,
256 | ) -> torch.Tensor:
257 | """Generate phosphene maps (for each phosphene distance to each pixel).
258 |
259 | :param coordinates: Coordinates of phosphenes.
260 | :param remove_invalid: Whether to remove phosphenes out of view.
261 | :param theta: Orientations for gabor filtering (if 'gabor_filtering' set to True)
262 | :return: an (n_phosphenes x resolution[0] x resolution[1]) array
263 | describing distances from phosphene locations
264 | """
265 |
266 | # Phosphene coordinates
267 | x_coords, y_coords = coordinates.cartesian
268 | x_coords = torch.reshape(self.to_tensor(x_coords), (-1, 1, 1))
269 | y_coords = torch.reshape(self.to_tensor(y_coords), (-1, 1, 1))
270 |
271 | # x,y limits of the simulation
272 | res_x, res_y = self.params['run']['resolution']
273 | x_org, y_org = self.params['run']['origin']
274 | hemi_fov = self.params['run']['view_angle'] / 2
275 | x_min, x_max = x_org - hemi_fov, x_org + hemi_fov
276 | y_min, y_max = y_org - hemi_fov, y_org + hemi_fov
277 |
278 | if remove_invalid:
279 | # Check if phosphene locations are inside of view angle.
280 | valid = (
281 | torch.ge(x_coords, x_min) & torch.less(x_coords, x_max) &
282 | torch.ge(y_coords, y_min) & torch.less(y_coords, y_max)).ravel()
283 | num_total = len(x_coords)
284 | num_valid = torch.sum(valid)
285 | logging.debug(f"{num_total - num_valid} of {num_total} phosphenes "
286 | f"are outside of view and will be removed.")
287 | x_coords = x_coords[valid]
288 | y_coords = y_coords[valid]
289 | coordinates.use_subset(to_numpy(valid))
290 |
291 | # Get distance maps to phosphene centres (in degrees of visual angle).
292 | device = self.data_kwargs['device']
293 | num_phosphenes = len(x_coords)
294 |
295 | x_range = torch.linspace(x_min, x_max, res_x, device=device)
296 | y_range = torch.linspace(y_min, y_max, res_y, device=device)
297 |
298 | grid = torch.meshgrid(x_range, y_range, indexing='xy')
299 | grid_x = torch.tile(grid[0], (num_phosphenes, 1, 1))
300 | grid_y = torch.tile(grid[1], (num_phosphenes, 1, 1))
301 | x = grid_x - x_coords
302 | y = grid_y - y_coords
303 |
304 | if self.params['gabor']['gabor_filtering']:
305 | phosphene_maps = self.gabor_rotation(x, y, theta)
306 | else:
307 | phosphene_maps = torch.sqrt(x ** 2 + y ** 2)
308 |
309 | return phosphene_maps
310 |
311 | def update(self, amplitude: torch.Tensor,
312 | pulse_width: Optional[torch.Tensor] = None,
313 | frequency: Optional[torch.Tensor] = None):
314 | """Update phosphene states (brightness, size, tissue activation) as
315 | function of the electrical stimulation input and the previous state.
316 |
317 | :param amplitude: Stimulation amplitudes for each electrode.
318 | :param pulse_width: Stimulation pulse widths for each electrode.
319 | :param frequency: Stimulation frequencies for each electrode.
320 | """
321 |
322 | if pulse_width is None:
323 | pulse_width = self._pulse_width
324 | if frequency is None:
325 | frequency = self._frequency
326 |
327 | charge_per_s = self.get_current(amplitude.view(self.shape),
328 | frequency.view(self.shape),
329 | pulse_width.view(self.shape))
330 |
331 | self.activation.update(charge_per_s)
332 |
333 | self.trace.update(charge_per_s)
334 |
335 | self.sigma.update(amplitude.view(self.shape))
336 |
337 | self.brightness.update(self.activation.get())
338 |
339 | def get_current(self, amplitude: torch.Tensor, frequency: torch.Tensor,
340 | pulse_width: torch.Tensor) -> torch.Tensor:
341 | """Caclulate effective current (charge per second) from the square wave
342 | pulse. Cannot be negative.
343 |
344 | :param amplitude: Stimulation amplitudes for each electrode.
345 | :param pulse_width: Stimulation pulse widths for each electrode.
346 | :param frequency: Stimulation frequencies for each electrode.
347 | """
348 |
349 | leak_current = \
350 | self.trace.get() + self.params['thresholding']['rheobase']
351 | charge_per_s = torch.relu((amplitude - leak_current) *
352 | pulse_width * frequency)
353 | self.effective_charge_per_second = charge_per_s
354 |
355 | print_stats('charge per second', charge_per_s)
356 |
357 | return charge_per_s
358 |
359 | def gaussian_activation(self) -> torch.Tensor:
360 | """Generate gaussian activation maps, based on sigmas and phosphene
361 | mapping.
362 |
363 | :return: Stack of Gaussian-shaped phosphene images
364 | (n_phosphenes, resolution_y, resolution_x)
365 | """
366 |
367 | # Calculate normalized Gaussian (peak has value 1).
368 | sigma = self.sigma.get().clamp(1e-22, None) # TODO: clamping redundant? Default division by zero gives inf.
369 | exp = torch.exp(-0.5 * (self.phosphene_maps / sigma) ** 2)
370 | return exp
371 |
372 | def get_state(self):
373 | state = {
374 | 'brightness': self.brightness.get(),
375 | 'sigma': self.sigma.get(),
376 | 'activation': self.activation.get(),
377 | 'trace': self.trace.get(),
378 | 'threshold': self.threshold.get(),
379 | 'effective_charge_per_second':
380 | self.effective_charge_per_second}
381 | return state
382 |
383 | def __call__(self, amplitude: torch.Tensor,
384 | pulse_width: Optional[torch.Tensor] = None,
385 | frequency: Optional[torch.Tensor] = None) -> torch.Tensor:
386 | """Generate simulated phosphene representation based on the
387 | electrical stimulation parameters and the previous state.
388 |
389 | :param amplitude: Stimulation amplitudes for each electrode.
390 | :param pulse_width: Stimulation pulse widths for each electrode.
391 | :param frequency: Stimulation frequencies for each electrode.
392 |
393 | :return: image with simulated phosphene representation
394 | """
395 |
396 | # Update phosphene state.
397 | self.update(amplitude, pulse_width, frequency)
398 |
399 | # Generate phosphene map.
400 | activation = self.gaussian_activation()
401 |
402 | # Thresholding: Set phosphene intensity to zero if tissue activation is lower than threshold.
403 | supra_threshold = torch.greater(self.activation.get(), self.threshold.get())
404 | intensity = torch.where(supra_threshold, self.brightness.get(), self._zero)
405 |
406 | # Return phosphene image.
407 | return torch.sum(intensity * activation, dim=self._electrode_dimension).clamp(0, 1)
408 |
409 | @property
410 | def phosphene_centers(self):
411 | """Indices (flat indexing) of the phosphene centers"""
412 | if self._phosphene_centers is None:
413 | self._phosphene_centers = self.phosphene_maps.flatten(start_dim=1).argmin(dim=-1)
414 | return self._phosphene_centers
415 |
416 | def sample_centers(self, x: torch.Tensor) -> torch.Tensor:
417 | """Extracts the value of the activation mask at the center pixel of each phosphene"""
418 | # instead of multiplying with sampling mask, values are retrieved using the indices of the center pixels
419 | return x.flatten(-2)[..., self.phosphene_centers]
420 |
421 | def sample_receptive_fields(self, x: torch.Tensor) -> torch.Tensor:
422 | """Extracts the maximum value of activation mask x within the 'receptive field' of each phosphene"""
423 | return torch.amax(self.sampling_mask * x, dim=(-2,-1))
424 |
425 | @property
426 | def sampling_mask(self):
427 | """Boolean mask (tensor) that defines which pixels are inside the receptive field / center of each phosphene"""
428 | if self._sampling_mask is None:
429 | params = self.params['sampling']
430 | if self._sampling_method == 'receptive_fields':
431 | self._sampling_mask = torch.less(self.phosphene_maps, params['RF_size'] / self.magnification)
432 | elif self._sampling_method == 'center':
433 | # Sampling mask is not used anymore in 'center' mode (pixels are directly retrieved using indexing),
434 | # but still implemented here for backwards compatibility
435 | p_map = self.phosphene_maps
436 | flat_idx = torch.arange(p_map.shape[0], device=p_map.device) * p_map.shape[-2] * p_map.shape[-1]
437 | self._sampling_mask = torch.zeros_like(p_map)
438 | self._sampling_mask.flatten()[self.phosphene_centers + flat_idx] = 1
439 | else:
440 | raise NotImplementedError
441 | return self._sampling_mask
442 |
443 | def sample_stimulus(self, activation_mask: Union[np.ndarray, torch.Tensor], rescale=False,
444 | ) -> torch.Tensor:
445 | """Obtain a stimulation vector from an activation mask image that indicates the regional stimulation intensity.
446 |
447 | param activation_mask: Image (or batch of images: N, 1, H, W). The pixel intensities indicate the
448 | stimulation amplitude for each visual region.
449 |
450 | param rescale: If False (default), the pixel intensities indicate the stimulation amplitude in Amperes.
451 | If True, the input pixels (in range [0, 1] or [0, 255]) are mapped to stimulation amplitudes
452 | using the default stimulus scale parameter specified in the params configuration file.
453 |
454 | return: Stimulation tensor with the stimulation amplitudes for each phosphene. """
455 |
456 | if isinstance(activation_mask, np.ndarray):
457 | dtype = activation_mask.dtype
458 | activation_mask = self.to_tensor(activation_mask)
459 | if (dtype == np.dtype('uint8')) or (activation_mask.max() > 1):
460 | activation_mask = scale_image(activation_mask, 1 / 255)
461 | if self._sampling_method == 'receptive_fields':
462 | electrode_activation = self.sample_receptive_fields(activation_mask)
463 | elif self._sampling_method == 'center':
464 | electrode_activation = self.sample_centers(activation_mask) # electrode activations between 0 and 1
465 | else:
466 | raise NotImplementedError
467 | if rescale:
468 | electrode_activation = torch.mul(electrode_activation, self.params['sampling']['stimulus_scale'])
469 | elif electrode_activation.max() >= 1e-3:
470 | warnings.warn("High values detected! Activation mask not longer rescaled as default behaviour. Please set "
471 | "rescale=True to map pixels in range [0, 1] or [0, 255] to the default stimulus scale.",
472 | category=DeprecationWarning, stacklevel=2)
473 | return electrode_activation
474 |
--------------------------------------------------------------------------------
/dynaphos/utils.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import numpy as np
3 | import torch
4 | import yaml
5 | from matplotlib import pyplot as plt
6 | from scipy.stats import truncnorm
7 | from typing import Optional, Tuple, Union, Iterable
8 |
9 |
10 | def get_deg2pix_coeff(run_params: dict) -> float:
11 | view_angle = run_params['view_angle']
12 | resolution = run_params['resolution']
13 | deg2pix = resolution[0] / view_angle
14 | logging.debug(f"Displaying {view_angle} degrees of vision in a resolution "
15 | f"of {resolution}.")
16 | logging.debug(f"One degree is equivalent to {deg2pix} pixels.")
17 | return deg2pix
18 |
19 |
20 | def calculate_dpi(params: dict) -> float:
21 | w_pixels = params['display']['screen_resolution'][0]
22 | h_pixels = params['display']['screen_resolution'][1]
23 | diagonal = params['display']['screen_diagonal']
24 | w_inches = (diagonal ** 2 / (1 + h_pixels ** 2 / w_pixels ** 2)) ** 0.5
25 | dpi = round(w_pixels / w_inches)
26 | return dpi
27 |
28 |
29 | def display_real_size(params: dict, image: np.ndarray):
30 | mm_per_degree = \
31 | params['display']['dist_to_screen'] * np.tan(2 * np.pi / 360)
32 | view_angle = params['run']['view_angle']
33 | resolution = params['run']['resolution']
34 | aspect_ratio = resolution[0] / resolution[1]
35 |
36 | mm = 0.1 / 2.54
37 | fig_width = mm_per_degree * view_angle * mm
38 | fig_height = mm_per_degree * (view_angle / aspect_ratio) * mm
39 | dpi = calculate_dpi(params)
40 | logging.debug(f"Display sizes: {fig_width}, {fig_height} | dpi: {dpi}")
41 |
42 | fig = plt.figure(figsize=(fig_width, fig_height), dpi=dpi)
43 | ax = fig.add_axes([0, 0, 1, 1])
44 |
45 | # Hide spines, ticks, etc.
46 | ax.axis('off')
47 |
48 | # Display the image.
49 | ax.imshow(image, cmap='gray', vmin=0, vmax=255, origin='lower')
50 | plt.show()
51 |
52 |
53 | def load_coordinates_from_yaml(path: str, n_coordinates: Optional[int] = None,
54 | rng: Optional[np.random.Generator] = None
55 | ) -> Tuple[np.ndarray, np.ndarray]:
56 | with open(path, 'r') as f:
57 | coordinates = yaml.load(f, Loader=yaml.FullLoader)
58 | x = np.array(coordinates['x'])
59 | y = np.array(coordinates['y'])
60 |
61 | if n_coordinates:
62 | if rng is None:
63 | rng = np.random.default_rng()
64 | sample = rng.choice(len(x), n_coordinates)
65 | x = x[sample]
66 | y = y[sample]
67 |
68 | return x, y
69 |
70 |
71 | def load_params(path: str) -> dict:
72 | with open(path, 'r') as f:
73 | params = yaml.load(f, Loader=yaml.FullLoader)
74 | return params
75 |
76 |
77 | def to_tensor(x: Union[int, float, np.ndarray], **data_kwargs) -> torch.Tensor:
78 | return torch.tensor(x, **data_kwargs)
79 |
80 |
81 | def to_numpy(x: torch.Tensor) -> np.ndarray:
82 | return x.cpu().numpy()
83 |
84 |
85 | def get_data_kwargs(params: dict) -> dict:
86 | dtype = getattr(torch, params['run']['dtype'])
87 | gpu = params['run']['gpu']
88 | device = 'cpu' if not torch.cuda.device_count() or gpu is None \
89 | else f'cuda:{gpu}'
90 | return dict(device=device, dtype=dtype)
91 |
92 |
93 | def cartesian_to_complex(x: np.ndarray, y: np.ndarray) -> np.ndarray:
94 | return x + 1j * y
95 |
96 |
97 | def polar_to_complex(r: np.ndarray, phi: np.ndarray) -> np.ndarray:
98 | return r * np.exp(1j * phi)
99 |
100 |
101 | def complex_to_cartesian(z: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
102 | return np.real(z), np.imag(z)
103 |
104 |
105 | def complex_to_polar(z: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
106 | return np.abs(z), np.angle(z)
107 |
108 |
109 | def cartesian_to_polar(x: np.ndarray, y: np.ndarray
110 | ) -> Tuple[np.ndarray, np.ndarray]:
111 | r = np.sqrt(x * x + y * y)
112 | phi = np.arctan2(y, x)
113 | return r, phi
114 |
115 |
116 | def get_truncated_normal(size: Union[int, Iterable], mean: float, sd: float,
117 | low: Optional[float] = 0.,
118 | upp: Optional[float] = 1e-4) -> np.ndarray:
119 | return truncnorm.rvs(
120 | (low - mean) / sd, (upp - mean) / sd, loc=mean, scale=sd, size=size)
121 |
122 |
123 | def set_deterministic(seed):
124 | torch.manual_seed(seed)
125 | torch.cuda.manual_seed(seed)
126 | torch.cuda.manual_seed_all(seed)
127 | torch.backends.cudnn.benchmark = False
128 | torch.backends.cudnn.deterministic = True
129 | torch.use_deterministic_algorithms(True)
130 | np.random.seed(seed)
131 |
132 |
133 | class Map:
134 | def __init__(self,
135 | x: Optional[np.ndarray] = None,
136 | y: Optional[np.ndarray] = None,
137 | z: Optional[np.ndarray] = None,
138 | r: Optional[np.ndarray] = None,
139 | phi: Optional[np.ndarray] = None):
140 | assert ((x is not None and y is not None) ^ (z is not None) ^
141 | (r is not None and phi is not None)), "Invalid arguments."
142 |
143 | self._x = x
144 | self._y = y
145 | self._z = z
146 | self._r = r
147 | self._phi = phi
148 |
149 | if self._x is not None and self._y is not None:
150 | self._z = cartesian_to_complex(self._x, self._y)
151 | self._r, self._phi = complex_to_polar(self._z)
152 | elif self._z is not None:
153 | self._x, self._y = complex_to_cartesian(self._z)
154 | self._r, self._phi = complex_to_polar(self._z)
155 | elif self._r is not None and self._phi is not None:
156 | self._z = polar_to_complex(self._r, self._phi)
157 | self._x, self._y = complex_to_cartesian(self._z)
158 |
159 | def __len__(self):
160 | if self._x is None:
161 | return 0
162 | return len(self._x)
163 |
164 | @property
165 | def polar(self):
166 | return self._r, self._phi
167 |
168 | @property
169 | def cartesian(self):
170 | return self._x, self._y
171 |
172 | @property
173 | def complex(self):
174 | return self._z
175 |
176 | def use_subset(self, indexes: np.ndarray):
177 | self._x = self._x[indexes]
178 | self._y = self._y[indexes]
179 | self._z = self._z[indexes]
180 | self._r = self._r[indexes]
181 | self._phi = self._phi[indexes]
182 |
183 | def flip(self, hor=False, vert=False):
184 | z = np.array(self._z) # copy
185 | if hor:
186 | z.real *= -1
187 | if vert:
188 | z.imag *= -1
189 | return Map(z=z)
190 |
191 |
192 |
193 | def sigmoid(x: torch.Tensor) -> torch.Tensor:
194 | """Sigmoid for brightness saturation and thresholding psychometric curves.
195 | """
196 | return torch.div(1, 1 + torch.exp(-x))
197 |
198 |
199 | def print_stats(stat_name: str, stat: torch.Tensor, verbose=False):
200 | if verbose:
201 | msg = f"""{stat_name}:
202 | size: {stat.size()}
203 | min: {stat.min():.2E}
204 | max: {stat.max():.2E}
205 | mean: {stat.mean():.2E}
206 | std: {stat.std():.2E}"""
207 | logging.debug(msg)
208 |
--------------------------------------------------------------------------------
/examples/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/__init__.py
--------------------------------------------------------------------------------
/examples/demo_webcam.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import time
3 |
4 | import cv2
5 | import numpy as np
6 |
7 | from dynaphos.image_processing import sobel_processor, canny_processor
8 | from dynaphos.simulator import GaussianSimulator
9 | from dynaphos.utils import load_params, load_coordinates_from_yaml, Map
10 | from dynaphos.cortex_models import \
11 | get_visual_field_coordinates_from_cortex_full
12 |
13 | FILTER = 'canny' # choose canny or sobel
14 | THRESHOLD_HIGH = 200 # the high threshold for the canny edge detection
15 |
16 | def main(params: dict, in_video: int):
17 | params['thresholding']['use_threshold'] = False
18 | coordinates_cortex = load_coordinates_from_yaml(
19 | '../config/grid_coords_dipole_valid.yaml', n_coordinates=100)
20 | coordinates_cortex = Map(*coordinates_cortex)
21 | coordinates_visual_field = get_visual_field_coordinates_from_cortex_full(
22 | params['cortex_model'], coordinates_cortex)
23 | simulator = GaussianSimulator(params, coordinates_visual_field)
24 | resolution = params['run']['resolution']
25 | fps = params['run']['fps']
26 |
27 | prev = 0
28 | cap = cv2.VideoCapture(in_video)
29 | ret, frame = cap.read()
30 | while ret:
31 |
32 | # Capture the video frame by frame
33 | ret, frame = cap.read()
34 |
35 | time_elapsed = time.time() - prev
36 | if time_elapsed > 1 / fps:
37 | prev = time.time()
38 |
39 | # Create Canny edge detection mask
40 | frame = cv2.resize(frame, resolution)
41 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
42 | frame = cv2.GaussianBlur(frame, (3, 3), 0)
43 |
44 | method = FILTER
45 | if method == 'sobel':
46 | processed_img = sobel_processor(frame)
47 | elif method == 'canny':
48 | processed_img = canny_processor(frame, THRESHOLD_HIGH//2, THRESHOLD_HIGH)
49 | elif method == 'none':
50 | processed_img = frame
51 | else:
52 | raise ValueError(f"{method} is not a valid filter keyword.")
53 |
54 | # Generate phosphenes
55 | stim_pattern = simulator.sample_stimulus(processed_img, rescale=True)
56 | phosphenes = simulator(stim_pattern)
57 | phosphenes = phosphenes.cpu().numpy() * 255
58 |
59 | # Concatenate results
60 | cat = np.concatenate([frame, processed_img, phosphenes],
61 | axis=1).astype('uint8')
62 |
63 | # Display the resulting frame
64 | cv2.imshow('Simulator', cat)
65 |
66 | # the 'q' button is set as the quit button
67 | if cv2.waitKey(1) & 0xFF == ord('q'):
68 | break
69 |
70 | cap.release()
71 | # Destroy all the windows
72 | cv2.destroyAllWindows()
73 |
74 |
75 | if __name__ == '__main__':
76 | _params = load_params('../config/params.yaml')
77 | _in_video = 0 # use 0 for webcam, or string with video path
78 | main(_params, _in_video)
79 | sys.exit()
80 |
--------------------------------------------------------------------------------
/examples/example_video.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/example_video.mp4
--------------------------------------------------------------------------------
/examples/example_video_gaze_contingent_object_grabbing.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/example_video_gaze_contingent_object_grabbing.mp4
--------------------------------------------------------------------------------
/examples/example_video_gaze_contingent_walking.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/example_video_gaze_contingent_walking.mp4
--------------------------------------------------------------------------------
/examples/eye_tracked_i1344739819_subject_hp.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/eye_tracked_i1344739819_subject_hp.mp4
--------------------------------------------------------------------------------
/examples/eye_tracked_i1344739819_subject_hp_orig.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/eye_tracked_i1344739819_subject_hp_orig.mp4
--------------------------------------------------------------------------------
/examples/readme.md:
--------------------------------------------------------------------------------
1 | # Example videos
2 |
3 | ### Semantic segmentation example
4 |
5 | 
6 |
7 | Left: video and the semantic segmentation labels (from the [KITTI dataset](https://www.cvlibs.net/datasets/kitti/)).
8 | Middle: preprocessed image that was used to sample the electrode activations.
9 | Right: output of the dynaphos phosphene simulator.
10 |
11 | ### Example videos gaze-contingent processing
12 |
13 | 
14 |
15 | 
16 |
17 | Left: input video. The red circle indicates the gaze-direction of the wearer of the camera.
18 | Middle: the input video after processing with sobel edge detection (which was used to sample the electrode activations). The electrode activations are created by sampling the gaze-contingent patches (indicated by the circle).
19 | Right: output of the dynaphos phosphene simulator. The simulated phosphes are rendered contingent with the gaze direction.
20 |
21 | **Acknowledgement:** Videos and gaze data are obtained by and used here with permission from Ashkan Nejad and Eva Postuma, Laboratory of Experimental Ophthalmology, University Medical Center Groningen.
22 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools>=61.0"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [project]
6 | name = "dynaphos"
7 | version = "0.1.3"
8 | authors = [
9 | { name="Maureen van der Grinten", email="maureen.vandergrinten@ru.nl" },
10 | { name="Jaap de Ruyter", email="jaap.deruyter@donders.ru.nl" },
11 | { name="Bodo Rueckauer", email="bodo.rueckauer@donders.ru.nl" },
12 | ]
13 | description = "Fully differentiable and biologically plausible simulation of prosthetic vision."
14 | readme = "README.md"
15 | requires-python = ">=3.7"
16 | classifiers = [
17 | "Programming Language :: Python :: 3",
18 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
19 | "Operating System :: OS Independent",
20 | ]
21 |
22 | [project.urls]
23 | "Homepage" = "https://github.com/neuralcodinglab/dynaphos.git"
24 |
25 | [tool.setuptools]
26 | packages = ["dynaphos"]
27 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | anyio==4.3.0
2 | argon2-cffi==23.1.0
3 | argon2-cffi-bindings==21.2.0
4 | arrow==1.3.0
5 | asttokens==2.4.1
6 | async-lru==2.0.4
7 | attrs==23.2.0
8 | Babel==2.14.0
9 | beautifulsoup4==4.12.3
10 | bleach==6.1.0
11 | certifi==2024.2.2
12 | cffi==1.16.0
13 | charset-normalizer==3.3.2
14 | colorama==0.4.6
15 | comm==0.2.1
16 | contourpy==1.2.0
17 | cycler==0.12.1
18 | debugpy==1.8.1
19 | decorator==5.1.1
20 | defusedxml==0.7.1
21 | executing==2.0.1
22 | fastjsonschema==2.19.1
23 | filelock==3.13.1
24 | fonttools==4.49.0
25 | fqdn==1.5.1
26 | fsspec==2024.2.0
27 | h11==0.14.0
28 | httpcore==1.0.4
29 | httpx==0.27.0
30 | idna==3.6
31 | iniconfig==2.0.0
32 | ipykernel==6.29.3
33 | ipython==8.22.2
34 | ipywidgets==8.1.2
35 | isoduration==20.11.0
36 | jedi==0.19.1
37 | Jinja2==3.1.3
38 | json5==0.9.20
39 | jsonpointer==2.4
40 | jsonschema==4.21.1
41 | jsonschema-specifications==2023.12.1
42 | jupyter==1.0.0
43 | jupyter-console==6.6.3
44 | jupyter-events==0.9.0
45 | jupyter-lsp==2.2.3
46 | jupyter_client==8.6.0
47 | jupyter_core==5.7.1
48 | jupyter_server==2.13.0
49 | jupyter_server_terminals==0.5.2
50 | jupyterlab==4.1.3
51 | jupyterlab_pygments==0.3.0
52 | jupyterlab_server==2.25.3
53 | jupyterlab_widgets==3.0.10
54 | kiwisolver==1.4.5
55 | MarkupSafe==2.1.5
56 | matplotlib==3.8.3
57 | matplotlib-inline==0.1.6
58 | mistune==3.0.2
59 | mpmath==1.3.0
60 | nbclient==0.9.0
61 | nbconvert==7.16.2
62 | nbformat==5.9.2
63 | nest-asyncio==1.6.0
64 | networkx==3.2.1
65 | notebook==7.1.1
66 | notebook_shim==0.2.4
67 | numpy==1.26.4
68 | opencv-contrib-python==4.9.0.80
69 | opencv-python==4.9.0.80
70 | overrides==7.7.0
71 | packaging==23.2
72 | pandas==2.2.1
73 | pandocfilters==1.5.1
74 | parso==0.8.3
75 | pillow==10.2.0
76 | platformdirs==4.2.0
77 | pluggy==1.4.0
78 | prometheus_client==0.20.0
79 | prompt-toolkit==3.0.43
80 | psutil==5.9.8
81 | pure-eval==0.2.2
82 | pycparser==2.21
83 | Pygments==2.17.2
84 | pyparsing==3.1.1
85 | pytest==8.0.2
86 | python-dateutil==2.9.0
87 | python-json-logger==2.0.7
88 | pytz==2024.1
89 | pywin32==306
90 | pywinpty==2.0.13
91 | PyYAML==6.0.1
92 | pyzmq==25.1.2
93 | qtconsole==5.5.1
94 | QtPy==2.4.1
95 | referencing==0.33.0
96 | requests==2.31.0
97 | rfc3339-validator==0.1.4
98 | rfc3986-validator==0.1.1
99 | rpds-py==0.18.0
100 | scipy==1.12.0
101 | Send2Trash==1.8.2
102 | six==1.16.0
103 | sniffio==1.3.1
104 | soupsieve==2.5
105 | stack-data==0.6.3
106 | sympy==1.12
107 | terminado==0.18.0
108 | tinycss2==1.2.1
109 | torch==2.2.1
110 | tornado==6.4
111 | traitlets==5.14.1
112 | types-python-dateutil==2.8.19.20240106
113 | typing_extensions==4.10.0
114 | tzdata==2024.1
115 | uri-template==1.3.0
116 | urllib3==2.2.1
117 | wcwidth==0.2.13
118 | webcolors==1.13
119 | webencodings==0.5.1
120 | websocket-client==1.7.0
121 | widgetsnbextension==4.0.10
122 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | if __name__ == "__main__":
4 | setuptools.setup()
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/__init__.py
--------------------------------------------------------------------------------
/test/benchmark.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/benchmark.pkl
--------------------------------------------------------------------------------
/test/benchmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/benchmark.png
--------------------------------------------------------------------------------
/test/benchmark.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | import pandas as pd
4 | import timeit
5 | import numpy as np
6 | import torch
7 | import matplotlib.pyplot as plt
8 | import seaborn as sns
9 | import tqdm
10 |
11 | from dynaphos.simulator import GaussianSimulator
12 | from dynaphos.utils import load_params, load_coordinates_from_yaml, Map, \
13 | get_data_kwargs
14 | from dynaphos.cortex_models import \
15 | get_visual_field_coordinates_from_cortex_full
16 |
17 |
18 | def get_random(resolution, num_phosphenes, num_frames=1000):
19 | params = load_params('../config/params.yaml')
20 | data_kwargs = get_data_kwargs(params)
21 | rng = np.random.default_rng(seed=params['run']['seed'])
22 | params['run']['resolution'] = list(resolution)
23 | shape = [num_frames] + params['run']['resolution']
24 | coordinates_cortex = load_coordinates_from_yaml(
25 | '../config/grid_coords_dipole_valid.yaml', num_phosphenes, rng)
26 | coordinates_cortex = Map(*coordinates_cortex)
27 | coordinates_visual_field = get_visual_field_coordinates_from_cortex_full(
28 | params['cortex_model'], coordinates_cortex, rng)
29 | simulator = GaussianSimulator(params, coordinates_visual_field, rng)
30 | frames = torch.mul(torch.rand(shape, **data_kwargs), 100e-6) # range [0, 100µA]
31 |
32 | stim_sequence = []
33 | for frame in frames:
34 | stim_sequence.append(simulator.sample_stimulus(frame))
35 | return simulator, stim_sequence
36 |
37 | def run_simulation(simulator, stim_sequence):
38 | for stimulus in stim_sequence:
39 | simulator(stimulus)
40 |
41 |
42 | def run_single(n=5):
43 | simulator, stim_sequence = get_random([256, 256], 100, 1000)
44 | timer = timeit.Timer(lambda: run_simulation(simulator, stim_sequence))
45 | result = timer.timeit(n)
46 | print(result / n)
47 |
48 |
49 | def run_sweep():
50 | num_frames = 1000
51 | num_repetitions = 5
52 | num_phosphenes = []
53 | resolutions = []
54 | fps = []
55 | for _ in tqdm.tqdm(range(num_repetitions), 'Repetition', leave=False):
56 | for m in tqdm.tqdm([128, 256, 512, 1024], 'Phosphenes', leave=False):
57 | for k in tqdm.tqdm([64, 128, 256, 512], 'Resolution', leave=False):
58 | simulator, stim_sequence = get_random([k, k], m, num_frames)
59 | timer = timeit.Timer(lambda: run_simulation(simulator, stim_sequence))
60 | t = timer.timeit(1)
61 | num_phosphenes.append(m)
62 | resolutions.append(k)
63 | fps.append(num_frames / t)
64 | data = pd.DataFrame(dict(num_phosphenes=num_phosphenes,
65 | resolution=resolutions, fps=fps))
66 | summary = data.groupby(['resolution', 'num_phosphenes']).mean()
67 | print(summary)
68 | pd.to_pickle(data, 'benchmark.pkl')
69 | sns.relplot(data=data, x='num_phosphenes', y='fps', hue='resolution',
70 | style='resolution', kind='line', markers=True)
71 | plt.savefig('benchmark.png')
72 |
73 |
74 | if __name__ == '__main__':
75 | run_sweep()
76 | # run_single()
77 |
78 | sys.exit()
79 |
--------------------------------------------------------------------------------
/test/data/Fernandez_2021_fig6A.csv:
--------------------------------------------------------------------------------
1 | amplitude,brightness,description
2 | 0.00001,0.04, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
3 | 0.00002,0.08, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
4 | 0.00003,0.2, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
5 | 0.00004,0.36, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
6 | 0.00005,0.48, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
7 | 0.00006,0.8, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
8 | 0.00007,0.8, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
9 | 0.00008,0.8, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
10 | 0.00009,1.0, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
11 | 0.00010,0.92, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331"
--------------------------------------------------------------------------------
/test/data/activation.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/activation.npy
--------------------------------------------------------------------------------
/test/data/coordinates_dipole.npz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/coordinates_dipole.npz
--------------------------------------------------------------------------------
/test/data/coordinates_monopole.npz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/coordinates_monopole.npz
--------------------------------------------------------------------------------
/test/data/coordinates_wedge-dipole.npz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/coordinates_wedge-dipole.npz
--------------------------------------------------------------------------------
/test/data/donders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/donders.png
--------------------------------------------------------------------------------
/test/data/fernandez_activation_fit.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/fernandez_activation_fit.npy
--------------------------------------------------------------------------------
/test/data/fernandez_brightness_fit.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/fernandez_brightness_fit.npy
--------------------------------------------------------------------------------
/test/data/output.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/output.npy
--------------------------------------------------------------------------------
/test/data/phosphene_map.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/phosphene_map.npy
--------------------------------------------------------------------------------
/test/data/phosphenes_donders.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/phosphenes_donders.npy
--------------------------------------------------------------------------------
/test/data/results_dynamics.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/results_dynamics.pkl
--------------------------------------------------------------------------------
/test/data/sigma.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/sigma.npy
--------------------------------------------------------------------------------
/test/data/stimulus.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/stimulus.npy
--------------------------------------------------------------------------------
/test/data/trace.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/trace.npy
--------------------------------------------------------------------------------
/test/data/valid_electrodes.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/valid_electrodes.npy
--------------------------------------------------------------------------------
/test/data/z_full_view.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/z_full_view.npy
--------------------------------------------------------------------------------
/test/test_all.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import pytest
3 | import torch
4 | import numpy as np
5 | import pandas as pd
6 |
7 | from dynaphos.simulator import GaussianSimulator
8 | from dynaphos.cortex_models import (
9 | get_visual_field_coordinates_from_cortex, remove_out_of_view,
10 | get_visual_field_coordinates_grid, get_mapping_from_cortex_to_visual_field,
11 | get_cortex_coordinates_default, get_cortex_coordinates_grid,
12 | get_visual_field_coordinates_from_cortex_full,
13 | get_visual_field_coordinates_probabilistically)
14 | from dynaphos.utils import (to_tensor, to_numpy, get_data_kwargs, load_params,
15 | load_coordinates_from_yaml, Map)
16 |
17 |
18 | PARAMS_PATH = '../config/params.yaml'
19 | MAPPING_MODELS = ['monopole', 'dipole', 'wedge-dipole']
20 |
21 |
22 | @pytest.fixture
23 | def params():
24 | return load_params(PARAMS_PATH)
25 |
26 |
27 | @pytest.fixture
28 | def rng(params):
29 | return np.random.default_rng(seed=params['run']['seed'])
30 |
31 |
32 | @pytest.fixture
33 | def simulator(params, rng):
34 | params['sampling']['sampling_method'] = 'center'
35 | return get_simulator(params, rng)
36 |
37 |
38 | def get_simulator(params, rng):
39 | coordinates_cortex = load_coordinates_from_yaml(
40 | '../config/grid_coords_dipole_valid.yaml', n_coordinates=100, rng=rng)
41 | coordinates_cortex = Map(*coordinates_cortex)
42 | coordinates_visual_field = get_visual_field_coordinates_from_cortex_full(
43 | params['cortex_model'], coordinates_cortex, rng)
44 | return GaussianSimulator(params, coordinates_visual_field, rng)
45 |
46 |
47 | @pytest.fixture
48 | def stimulus(params):
49 | stimulus = np.load('data/stimulus.npy')
50 | data_kwargs = get_data_kwargs(params)
51 | return to_tensor(stimulus, **data_kwargs)
52 |
53 | class TestInit:
54 | def test_init_probabilistically(self, params, rng):
55 | r_expected = [4.18866466, 1.41023323, 5.35768769, 3.33191491,
56 | 0.18516116, 7.47153754, 4.03653153, 4.3407978,
57 | 0.26523123, 1.47428929]
58 | phi_expected = [2.3297927, 5.82303616, 4.04552386, 5.16956368,
59 | 2.78605358, 1.427783, 3.48455899, 0.40097565,
60 | 5.20016002, 3.96886447]
61 | coordinates_cortex = get_visual_field_coordinates_probabilistically(
62 | params, len(r_expected), rng)
63 | r, phi = coordinates_cortex.polar
64 | assert np.isclose(r, r_expected).all()
65 | assert np.isclose(phi, phi_expected).all()
66 |
67 |
68 | class TestCorticalModels:
69 | def test_init_covering_electrode_grid(self, params):
70 | x_expected = [0., 26.27987687, 52.55975374, 78.83963061, 0.,
71 | 26.27987687, 52.55975374, 78.83963061, 0., 26.27987687,
72 | 52.55975374, 78.83963061, 0., 26.27987687, 52.55975374,
73 | 78.83963061]
74 | y_expected = [-24.44135778, -24.44135778, -24.44135778, -24.44135778,
75 | -8.14711926, -8.14711926, -8.14711926, -8.14711926,
76 | 8.14711926, 8.14711926, 8.14711926, 8.14711926,
77 | 24.44135778, 24.44135778, 24.44135778, 24.44135778]
78 | coordinates_cortex = get_cortex_coordinates_grid(
79 | params['cortex_model'], 4, 4)
80 | x, y = coordinates_cortex.cartesian
81 | assert np.isclose(x, x_expected).all()
82 | assert np.isclose(y, y_expected).all()
83 |
84 | def test_get_phosphene_map_from_electrodes(self, params, rng):
85 | p = params['cortex_model']
86 | r_expected = [17.3140795, 17.0009518]
87 | phi_expected = [-2.56560138, 2.61408701]
88 | coordinates_cortex = get_cortex_coordinates_grid(p, 4, 4)
89 | coordinates_visual_field = get_visual_field_coordinates_from_cortex(
90 | p, coordinates_cortex, rng)
91 | r, phi = coordinates_visual_field.polar
92 | assert np.isclose(r, r_expected).all()
93 | assert np.isclose(phi, phi_expected).all()
94 |
95 | def test_init_full_view(self):
96 | visual_field = get_visual_field_coordinates_grid()
97 | z_expected = np.load('data/z_full_view.npy')
98 | assert np.isclose(visual_field.complex, z_expected).all()
99 |
100 | @pytest.mark.parametrize('mapping_model', MAPPING_MODELS)
101 | def test_generate_cortical_map(self, params, mapping_model):
102 | p = params['cortex_model']
103 | p['model'] = mapping_model
104 | cortex_map = get_cortex_coordinates_default(p)
105 | x, y = cortex_map.cartesian
106 | coordinates = np.load(f'data/coordinates_{mapping_model}.npz')
107 | assert np.isclose(x, coordinates['x']).all()
108 | assert np.isclose(y, coordinates['y']).all()
109 |
110 | @pytest.mark.parametrize('mapping_model', MAPPING_MODELS)
111 | def test_generate_phosphene_map(self, params, mapping_model):
112 | p = params['cortex_model']
113 | p['model'] = mapping_model
114 | cortex_map = get_cortex_coordinates_default(p)
115 | cortex_to_visual_field = get_mapping_from_cortex_to_visual_field(p)
116 | z = cortex_to_visual_field(cortex_map.complex)
117 | z_expected = get_visual_field_coordinates_grid().complex
118 | assert np.isclose(z, z_expected, atol=1e-8).all()
119 |
120 | def test_filter_invalid_electrodes(self):
121 | coordinates_visual_field = get_visual_field_coordinates_grid()
122 | z_all = coordinates_visual_field.complex
123 | z = remove_out_of_view(z_all)
124 | valid_electrodes = np.load('data/valid_electrodes.npy')
125 | assert np.array_equal(z, z_all[valid_electrodes])
126 |
127 |
128 | class TestSimulator:
129 | def test_generate_phosphene_maps(self, simulator):
130 | phosphene_maps = to_numpy(simulator.phosphene_maps)
131 | phosphene_maps_expected = np.load('data/phosphene_map.npy')
132 | assert np.isclose(phosphene_maps, phosphene_maps_expected, atol=1e-8).all()
133 |
134 | def test_update(self, simulator, stimulus):
135 | simulator.update(stimulus)
136 | sigma = to_numpy(simulator.sigma.get())
137 | trace = to_numpy(simulator.trace.get())
138 | sigma_expected = np.load('data/sigma.npy')
139 | trace_expected = np.load('data/trace.npy')
140 | assert np.isclose(sigma, sigma_expected, atol=1e-8).all()
141 | assert np.isclose(trace, trace_expected, atol=1e-8).all()
142 |
143 | def test_gaussian_activation(self, simulator, stimulus):
144 | simulator.update(stimulus)
145 | activation = to_numpy(simulator.gaussian_activation())
146 | activation_expected = np.load('data/activation.npy')
147 | assert np.isclose(activation, activation_expected, atol=1e-8).all()
148 |
149 | def test_call(self, simulator, stimulus):
150 | phosphenes = to_numpy(simulator(stimulus))
151 | phosphenes_expected = np.load('data/output.npy')
152 | assert np.isclose(phosphenes, phosphenes_expected, atol=1e-8).all()
153 |
154 |
155 | class TestFunctional:
156 | def test_sampling(self, params, rng):
157 | simulator = get_simulator(params, rng)
158 | shape = params['run']['resolution']
159 | image = rng.random(shape) * 1e-4
160 | stimulus = simulator.sample_stimulus(image)
161 | stimulus_expected = np.load('data/stimulus.npy')
162 | assert np.isclose(stimulus, stimulus_expected, atol=1e-8).all()
163 |
164 | def test_image(self, params, rng):
165 | params['thresholding']['use_threshold'] = False
166 | shape = params['run']['resolution']
167 | frame = cv2.imread('data/donders.png')
168 | frame = cv2.resize(frame, shape)
169 | frame = frame[::-1]
170 | frame = 255 - cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
171 | frame = cv2.GaussianBlur(frame, (3, 3), 0)
172 | frame = frame.clip(0, 1) * 255
173 | simulator = get_simulator(params, rng)
174 | stimulus = simulator.sample_stimulus(frame, rescale=True)
175 | phosphenes = to_numpy(simulator(stimulus))
176 | phosphenes_expected = np.load('data/phosphenes_donders.npy')
177 | assert np.isclose(phosphenes, phosphenes_expected, atol=1e-8).all()
178 |
179 | def test_brightness(self, params, rng):
180 | fps = 500
181 | stimulus_sequence = np.concatenate([np.ones(83), np.zeros(417)])
182 | data = pd.read_csv('data/Fernandez_2021_fig6A.csv')
183 |
184 | params['cortex_model']['dropout_rate'] = 0
185 | params['default_stim']['pw_default'] = 170e-6
186 | params['default_stim']['freq_default'] = 300
187 | params['run']['fps'] = fps
188 | params['thresholding']['use_threshold'] = False
189 | coordinates_cortex = Map(np.array([35.]), np.array([10.]))
190 | coordinates_visual_field = get_visual_field_coordinates_from_cortex(
191 | params['cortex_model'], coordinates_cortex, rng)
192 | simulator = GaussianSimulator(params, coordinates_visual_field, rng)
193 |
194 | n_phosphenes = len(coordinates_visual_field)
195 | data_kwargs = get_data_kwargs(params)
196 | electrodes = torch.ones(n_phosphenes, **data_kwargs)
197 | results = []
198 | for stim_condition, amplitude in enumerate(data.amplitude):
199 | simulator.reset()
200 | states = []
201 | for i, stim in enumerate(stimulus_sequence):
202 | simulator.update(electrodes * stim * amplitude)
203 | state = {key: val.item() for key, val in simulator.get_state().items()} # state as numpy
204 | states.append(state)
205 | states[-1]['amplitude'] = stim * amplitude
206 | states[-1]['stim_condition'] = stim_condition
207 | states[-1]['time'] = i / fps
208 |
209 | results.append(pd.DataFrame(states))
210 | results = pd.concat(results, ignore_index=True)
211 |
212 | # Find the peaks in activation and brightness for each stim_condition
213 | brightness = []
214 | activation = []
215 | for i in results.stim_condition.unique():
216 | brightness.append(
217 | results.loc[results.stim_condition == i, 'brightness'].max())
218 | activation.append(
219 | results.loc[results.stim_condition == i, 'activation'].max())
220 | activation = np.array(activation)
221 | brightness = np.array(brightness)
222 | activation_expected = np.load('data/fernandez_activation_fit.npy')
223 | brightness_expected = np.load('data/fernandez_brightness_fit.npy')
224 | assert np.isclose(activation, activation_expected).all()
225 | assert np.isclose(brightness, brightness_expected).all()
226 |
227 | def test_dynamics(self, params, rng):
228 | stimulus_amplitude = 90e-6
229 |
230 | # Stimulation sequences for 1200 seconds
231 | fps = 256
232 | total_duration = 200 # seconds
233 | train_duration = 0.125 # seconds
234 | stim_moments = np.concatenate(
235 | [np.linspace(0, 200, 50, endpoint=False), # Fast part
236 | np.linspace(200, 1200, 6, endpoint=True)]) # Slow part
237 |
238 | num_frames = int(fps * train_duration)
239 | stim_sequences = np.zeros(int(fps * total_duration))
240 | for t in stim_moments:
241 | idx = int(t * fps)
242 | stim_sequences[idx:idx + num_frames] = stimulus_amplitude
243 |
244 | params['cortex_model']['dropout_rate'] = 0
245 | params['default_stim']['pw_default'] = 100e-6
246 | params['default_stim']['freq_default'] = 200
247 | params['run']['fps'] = fps
248 | params['thresholding']['use_threshold'] = False
249 | coordinates_cortex = Map(np.array([35.]), np.array([10.]))
250 | coordinates_visual_field = get_visual_field_coordinates_from_cortex(
251 | params['cortex_model'], coordinates_cortex, rng)
252 | simulator = GaussianSimulator(params, coordinates_visual_field, rng)
253 |
254 | data_kwargs = get_data_kwargs(params)
255 | states = []
256 | for i, stimulus in enumerate(to_tensor(stim_sequences, **data_kwargs)):
257 | simulator.update(stimulus)
258 | state = {key: val.item() for key, val in simulator.get_state().items()} # state as numpy
259 | states.append(state)
260 |
261 | results = pd.DataFrame(states)
262 | results['stimulation'] = stim_sequences
263 | results['fps'] = fps
264 | results['time'] = results.index.copy() / fps
265 | results_expected = pd.read_pickle('data/results_dynamics.pkl')
266 | assert np.isclose(results.to_numpy(),
267 | results_expected.to_numpy()).all()
268 |
--------------------------------------------------------------------------------